From a429feb9a87e107a837192bd2121642d245fce60 Mon Sep 17 00:00:00 2001 From: xinsin Date: Wed, 19 Apr 2023 23:21:10 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9E=95=20Feat:=20add=20login=20interface?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 13 ++ .../top/xinsin/config/GlobalWebMvcConfig.java | 23 -- .../config/GlobalWebMvcConfiguration.java | 38 ++++ .../InterceptResponseConfiguration.java | 45 ++++ .../top/xinsin/config/InterceptorConfig.java | 24 --- ...fig.java => MybatisPlusConfiguration.java} | 3 +- .../xinsin/config/SecurityConfiguration.java | 112 ++++++++++ .../xinsin/controller/AccountController.java | 29 +++ .../controller/PermissionsController.java | 20 ++ .../xinsin/controller/RolesController.java | 20 ++ .../AuthenticationInterceptor.java | 56 ----- .../interceptor/AuthorizeInterceptor.java | 34 +++ .../interceptor/GlobalWebInterceptor.java | 15 ++ .../java/top/xinsin/mapper/AccountMapper.java | 18 ++ .../top/xinsin/mapper/PermissionsMapper.java | 18 ++ .../java/top/xinsin/mapper/RolesMapper.java | 18 ++ src/main/java/top/xinsin/pojo/Account.java | 50 +++++ .../java/top/xinsin/pojo/Permissions.java | 50 +++++ src/main/java/top/xinsin/pojo/Roles.java | 50 +++++ .../top/xinsin/service/AccountService.java | 46 ++++ .../xinsin/service/PermissionsService.java | 18 ++ .../java/top/xinsin/service/RolesService.java | 18 ++ src/main/java/top/xinsin/util/HttpCodes.java | 8 +- .../java/top/xinsin/util/ServletUtils.java | 20 ++ src/main/resources/application.yml | 3 + src/main/resources/mapper/AccountMapper.xml | 19 ++ .../resources/mapper/PermissionsMapper.xml | 18 ++ src/main/resources/mapper/RolesMapper.xml | 17 ++ src/test/java/top/xinsin/CodeGenerator.java | 73 +++++++ src/test/java/top/xinsin/MainTest.java | 201 ++++++++++++++++++ src/test/resources/myentity.java.ftl | 135 ++++++++++++ 31 files changed, 1103 insertions(+), 109 deletions(-) delete mode 100644 src/main/java/top/xinsin/config/GlobalWebMvcConfig.java create mode 100644 src/main/java/top/xinsin/config/GlobalWebMvcConfiguration.java create mode 100644 src/main/java/top/xinsin/config/InterceptResponseConfiguration.java delete mode 100644 src/main/java/top/xinsin/config/InterceptorConfig.java rename src/main/java/top/xinsin/config/{MybatisPlusConfig.java => MybatisPlusConfiguration.java} (96%) create mode 100644 src/main/java/top/xinsin/config/SecurityConfiguration.java create mode 100644 src/main/java/top/xinsin/controller/AccountController.java create mode 100644 src/main/java/top/xinsin/controller/PermissionsController.java create mode 100644 src/main/java/top/xinsin/controller/RolesController.java delete mode 100644 src/main/java/top/xinsin/interceptor/AuthenticationInterceptor.java create mode 100644 src/main/java/top/xinsin/interceptor/AuthorizeInterceptor.java create mode 100644 src/main/java/top/xinsin/interceptor/GlobalWebInterceptor.java create mode 100644 src/main/java/top/xinsin/mapper/AccountMapper.java create mode 100644 src/main/java/top/xinsin/mapper/PermissionsMapper.java create mode 100644 src/main/java/top/xinsin/mapper/RolesMapper.java create mode 100644 src/main/java/top/xinsin/pojo/Account.java create mode 100644 src/main/java/top/xinsin/pojo/Permissions.java create mode 100644 src/main/java/top/xinsin/pojo/Roles.java create mode 100644 src/main/java/top/xinsin/service/AccountService.java create mode 100644 src/main/java/top/xinsin/service/PermissionsService.java create mode 100644 src/main/java/top/xinsin/service/RolesService.java create mode 100644 src/main/java/top/xinsin/util/ServletUtils.java create mode 100644 src/main/resources/mapper/AccountMapper.xml create mode 100644 src/main/resources/mapper/PermissionsMapper.xml create mode 100644 src/main/resources/mapper/RolesMapper.xml create mode 100644 src/test/java/top/xinsin/CodeGenerator.java create mode 100644 src/test/java/top/xinsin/MainTest.java create mode 100644 src/test/resources/myentity.java.ftl diff --git a/pom.xml b/pom.xml index 2a4f80e..0638a16 100644 --- a/pom.xml +++ b/pom.xml @@ -87,6 +87,7 @@ mysql mysql-connector-java 8.0.32 + runtime @@ -106,5 +107,17 @@ velocity-engine-core 2.3 + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.session + spring-session-data-redis + + + org.freemarker + freemarker + \ No newline at end of file diff --git a/src/main/java/top/xinsin/config/GlobalWebMvcConfig.java b/src/main/java/top/xinsin/config/GlobalWebMvcConfig.java deleted file mode 100644 index 44a3bfd..0000000 --- a/src/main/java/top/xinsin/config/GlobalWebMvcConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package top.xinsin.config; - -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -/** - * @author xinsin - * Created On 2023/4/3 15:55 - * @version 1.0 - */ -@SpringBootConfiguration -public class GlobalWebMvcConfig implements WebMvcConfigurer { - @Override - public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowCredentials(true) - .allowedOriginPatterns("*") - .allowedMethods("GET", "POST", "DELETE", "PUT", "HEAD") - .allowedHeaders("*") - .exposedHeaders("*"); - } -} diff --git a/src/main/java/top/xinsin/config/GlobalWebMvcConfiguration.java b/src/main/java/top/xinsin/config/GlobalWebMvcConfiguration.java new file mode 100644 index 0000000..60a13fc --- /dev/null +++ b/src/main/java/top/xinsin/config/GlobalWebMvcConfiguration.java @@ -0,0 +1,38 @@ +package top.xinsin.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import top.xinsin.interceptor.AuthorizeInterceptor; +import top.xinsin.interceptor.GlobalWebInterceptor; + +/** + * @author xinsin + * Created On 2023/4/3 15:55 + * @version 1.0 + */ +@Configuration +public class GlobalWebMvcConfiguration implements WebMvcConfigurer { + + @Autowired + private AuthorizeInterceptor interceptor; + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowCredentials(true) + .allowedOriginPatterns("*") + .allowedMethods("*") + .allowedHeaders("*") + .exposedHeaders("*"); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(interceptor) + .addPathPatterns("/**") + .excludePathPatterns("/api/auth/**"); + } +} diff --git a/src/main/java/top/xinsin/config/InterceptResponseConfiguration.java b/src/main/java/top/xinsin/config/InterceptResponseConfiguration.java new file mode 100644 index 0000000..3e0bcdb --- /dev/null +++ b/src/main/java/top/xinsin/config/InterceptResponseConfiguration.java @@ -0,0 +1,45 @@ +package top.xinsin.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.MethodParameter; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.server.ServerHttpRequest; +import org.springframework.http.server.ServerHttpResponse; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; +import top.xinsin.util.R; + +@Slf4j +@ControllerAdvice +public class InterceptResponseConfiguration implements ResponseBodyAdvice { + @Override + public boolean supports(MethodParameter returnType, Class converterType) { + return true; + } + + @Override + public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { +// 只有返回数据为自定义返回格式,才对数据进行处理 + if (body instanceof R r){ + String controllerMethodName = returnType.getMethod().getName(); + String controllerClassName = returnType.getDeclaringClass().getSimpleName(); + String controllerClassURlPath = returnType.getDeclaringClass().getAnnotation(RequestMapping.class).value()[0]; + RequestMapping annotation = returnType.getMethod().getAnnotation(RequestMapping.class); + String controllerUrlPath = annotation.path()[0]; + String controllerUrlMethod = annotation.method()[0].name(); + log.info("[全局响应体后处理器]-请求类:{}-请求方法:{}-请求地址:{}{}-请求方法:{}-响应状态码:{}-响应数据:{}", + controllerClassName, + controllerMethodName, + controllerClassURlPath, + controllerUrlPath, + controllerUrlMethod, + r.getStatus(), + r.getData()); + response.setStatusCode(HttpStatusCode.valueOf(r.getStatus())); + } + return body; + } +} diff --git a/src/main/java/top/xinsin/config/InterceptorConfig.java b/src/main/java/top/xinsin/config/InterceptorConfig.java deleted file mode 100644 index c8e5e0a..0000000 --- a/src/main/java/top/xinsin/config/InterceptorConfig.java +++ /dev/null @@ -1,24 +0,0 @@ -package top.xinsin.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import top.xinsin.interceptor.AuthenticationInterceptor; - -/** - * @author xinsin - * Created On 2023/4/3 15:54 - * @version 1.0 - */ -@Configuration -public class InterceptorConfig implements WebMvcConfigurer { - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(new AuthenticationInterceptor()). - //拦截 - addPathPatterns("/**"). - //放行登录接口 - excludePathPatterns("/user/login"). - excludePathPatterns("/user/register"); - } -} diff --git a/src/main/java/top/xinsin/config/MybatisPlusConfig.java b/src/main/java/top/xinsin/config/MybatisPlusConfiguration.java similarity index 96% rename from src/main/java/top/xinsin/config/MybatisPlusConfig.java rename to src/main/java/top/xinsin/config/MybatisPlusConfiguration.java index 984427b..eed577f 100644 --- a/src/main/java/top/xinsin/config/MybatisPlusConfig.java +++ b/src/main/java/top/xinsin/config/MybatisPlusConfiguration.java @@ -8,8 +8,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration -public class MybatisPlusConfig{ - +public class MybatisPlusConfiguration { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); diff --git a/src/main/java/top/xinsin/config/SecurityConfiguration.java b/src/main/java/top/xinsin/config/SecurityConfiguration.java new file mode 100644 index 0000000..6562516 --- /dev/null +++ b/src/main/java/top/xinsin/config/SecurityConfiguration.java @@ -0,0 +1,112 @@ +package top.xinsin.config; + +import com.alibaba.fastjson2.JSONObject; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl; +import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import top.xinsin.service.AccountService; +import top.xinsin.util.HttpCodes; +import top.xinsin.util.R; + +import javax.sql.DataSource; +import java.io.IOException; + +@Configuration +@EnableWebSecurity +public class SecurityConfiguration { + @Resource + AccountService authorizeService; + + @Autowired + DataSource dataSource; + @Bean + public SecurityFilterChain filterChain(HttpSecurity httpSecurity, PersistentTokenRepository persistentTokenRepository) throws Exception { + return httpSecurity + .authorizeHttpRequests() + .requestMatchers("/api/auth/**") + .permitAll() + .anyRequest() + .authenticated() + .and() + .formLogin() + .loginProcessingUrl("/api/auth/login") + .successHandler(this::onsuccessLoginHandler) + .failureHandler(this::onFailureLoginHandler) + .and() + .logout() + .logoutUrl("/api/auth/logout") + .logoutSuccessHandler(this::onsuccessLoginHandler) + .and() + .rememberMe() + .rememberMeParameter("remember") + .tokenRepository(persistentTokenRepository) + .tokenValiditySeconds(60 * 60 * 12) + .and() + .csrf() + .disable() + .cors() + .configurationSource(this.corsConfigurationSource()) + .and() + .exceptionHandling() + .authenticationEntryPoint(this::onFailureLoginHandler) + .and() + .build(); + } + @Bean + public PersistentTokenRepository tokenRepository(){ + JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl(); + jdbcTokenRepository.setDataSource(dataSource); + jdbcTokenRepository.setCreateTableOnStartup(false); + return jdbcTokenRepository; + } + @Bean + public AuthenticationManager authenticationManager(HttpSecurity security) throws Exception { + return security + .getSharedObject(AuthenticationManagerBuilder.class) + .userDetailsService(authorizeService) + .and() + .build(); + } + @Bean + public BCryptPasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } + private CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration cors = new CorsConfiguration(); + cors.addAllowedOriginPattern("*"); + cors.setAllowCredentials(true); + cors.addAllowedHeader("*"); + cors.addAllowedMethod("*"); + cors.addExposedHeader("*"); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", cors); + return source; + } + private void onsuccessLoginHandler(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException { + httpServletResponse.setCharacterEncoding("utf-8"); + if(httpServletRequest.getRequestURI().endsWith("/login")) + httpServletResponse.getWriter().write(JSONObject.toJSONString(R.success("登陆成功"))); + else if(httpServletRequest.getRequestURI().endsWith("/logout")) + httpServletResponse.getWriter().write(JSONObject.toJSONString(R.success("退出登录成功"))); + } + private void onFailureLoginHandler(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,AuthenticationException authentication) throws IOException { + httpServletResponse.setCharacterEncoding("utf-8"); + httpServletResponse.getWriter().write(JSONObject.toJSONString(R.failed(HttpCodes.ACCESS_DENIED,"登录时出现了错误"))); + } +} diff --git a/src/main/java/top/xinsin/controller/AccountController.java b/src/main/java/top/xinsin/controller/AccountController.java new file mode 100644 index 0000000..b118cb9 --- /dev/null +++ b/src/main/java/top/xinsin/controller/AccountController.java @@ -0,0 +1,29 @@ +package top.xinsin.controller; + + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import top.xinsin.util.HttpCodes; +import top.xinsin.util.R; + +/** + *

+ * 前端控制器 + *

+ * + * @author xinsin + * @since 2023-04-12 + */ +@RestController +@RequestMapping("/account") +public class AccountController { + + @RequestMapping(path = "/get",method = RequestMethod.GET) + public R get(){ + return R.failed(HttpCodes.HTTP_CODES500,"234567890"); + } + +} diff --git a/src/main/java/top/xinsin/controller/PermissionsController.java b/src/main/java/top/xinsin/controller/PermissionsController.java new file mode 100644 index 0000000..c6ce729 --- /dev/null +++ b/src/main/java/top/xinsin/controller/PermissionsController.java @@ -0,0 +1,20 @@ +package top.xinsin.controller; + + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 前端控制器 + *

+ * + * @author xinsin + * @since 2023-04-12 + */ +@RestController +@RequestMapping("/permissions") +public class PermissionsController { + +} diff --git a/src/main/java/top/xinsin/controller/RolesController.java b/src/main/java/top/xinsin/controller/RolesController.java new file mode 100644 index 0000000..17bab9b --- /dev/null +++ b/src/main/java/top/xinsin/controller/RolesController.java @@ -0,0 +1,20 @@ +package top.xinsin.controller; + + +import org.springframework.web.bind.annotation.RequestMapping; + +import org.springframework.web.bind.annotation.RestController; + +/** + *

+ * 前端控制器 + *

+ * + * @author xinsin + * @since 2023-04-12 + */ +@RestController +@RequestMapping("/roles") +public class RolesController { + +} diff --git a/src/main/java/top/xinsin/interceptor/AuthenticationInterceptor.java b/src/main/java/top/xinsin/interceptor/AuthenticationInterceptor.java deleted file mode 100644 index 6bfdf1f..0000000 --- a/src/main/java/top/xinsin/interceptor/AuthenticationInterceptor.java +++ /dev/null @@ -1,56 +0,0 @@ -package top.xinsin.interceptor; - -import com.alibaba.fastjson2.JSONObject; -import com.auth0.jwt.exceptions.AlgorithmMismatchException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.exceptions.TokenExpiredException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.servlet.HandlerInterceptor; -import top.xinsin.util.HttpCodes; -import top.xinsin.util.JWTUtils; -import top.xinsin.util.R; - -/** - * @author xinsin - * Created On 2023/4/3 15:49 - * @version 1.0 - */ -@Slf4j -public class AuthenticationInterceptor implements HandlerInterceptor { - public static final String OPTIONS = "OPTIONS"; - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - - if (OPTIONS.equals(request.getMethod())) { - return true; - } - // 从http请求头中取出token - final String token = request.getHeader("Access-Token"); - //解决跨域问题 - response.setHeader("Access-Control-Allow-Origin","*"); - //解决跨域问题 - response.setHeader("Access-Control-Allow-Headers","*"); - R responseData; - try { - JWTUtils.verify(token); - return true; - } catch (SignatureVerificationException e) { - log.info("用户验证了无效签名"); - responseData = R.failed(HttpCodes.ACCESS_DENIED,"无效签名"); - }catch (TokenExpiredException e){ - log.info("用户验证的签名已过期"); - responseData = R.failed(HttpCodes.INVALID_TOKEN,"签名已过期"); - }catch (AlgorithmMismatchException e){ - log.info("用户验证的token算法不一致"); - responseData = R.failed(HttpCodes.INVALID_TOKEN,"token算法不一致"); - }catch (Exception e){ - log.info("token无效或者是空的"); - responseData = R.failed(HttpCodes.INVALID_TOKEN,"token无效"); - } - response.setContentType("application/json;charset=UTF-8"); - response.getWriter().write(JSONObject.toJSONString(responseData)); - return false; - } -} diff --git a/src/main/java/top/xinsin/interceptor/AuthorizeInterceptor.java b/src/main/java/top/xinsin/interceptor/AuthorizeInterceptor.java new file mode 100644 index 0000000..8a7fa89 --- /dev/null +++ b/src/main/java/top/xinsin/interceptor/AuthorizeInterceptor.java @@ -0,0 +1,34 @@ +package top.xinsin.interceptor; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; +import top.xinsin.mapper.AccountMapper; +import top.xinsin.pojo.Account; + +@Component +public class AuthorizeInterceptor implements HandlerInterceptor { + @Autowired + private AccountMapper accountMapper; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + SecurityContext context = SecurityContextHolder.getContext(); + Authentication authentication = context.getAuthentication(); + User user = (User)authentication.getPrincipal(); + String username = user.getUsername(); + Account account = accountMapper.selectOne(new LambdaQueryWrapper() + .eq(Account::getUsername,username) + .or() + .eq(Account::getEmail,username)); + request.getSession().setAttribute("account", account); + return true; + } +} diff --git a/src/main/java/top/xinsin/interceptor/GlobalWebInterceptor.java b/src/main/java/top/xinsin/interceptor/GlobalWebInterceptor.java new file mode 100644 index 0000000..af8d72f --- /dev/null +++ b/src/main/java/top/xinsin/interceptor/GlobalWebInterceptor.java @@ -0,0 +1,15 @@ +package top.xinsin.interceptor; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +@Slf4j +public class GlobalWebInterceptor implements HandlerInterceptor { + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + HandlerMethod handler1 = (HandlerMethod) handler; + } +} diff --git a/src/main/java/top/xinsin/mapper/AccountMapper.java b/src/main/java/top/xinsin/mapper/AccountMapper.java new file mode 100644 index 0000000..f225809 --- /dev/null +++ b/src/main/java/top/xinsin/mapper/AccountMapper.java @@ -0,0 +1,18 @@ +package top.xinsin.mapper; + +import top.xinsin.pojo.Account; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author xinsin + * @since 2023-04-12 + */ +@Mapper +public interface AccountMapper extends BaseMapper { + +} diff --git a/src/main/java/top/xinsin/mapper/PermissionsMapper.java b/src/main/java/top/xinsin/mapper/PermissionsMapper.java new file mode 100644 index 0000000..9a8bb8d --- /dev/null +++ b/src/main/java/top/xinsin/mapper/PermissionsMapper.java @@ -0,0 +1,18 @@ +package top.xinsin.mapper; + +import top.xinsin.pojo.Permissions; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author xinsin + * @since 2023-04-12 + */ +@Mapper +public interface PermissionsMapper extends BaseMapper { + +} diff --git a/src/main/java/top/xinsin/mapper/RolesMapper.java b/src/main/java/top/xinsin/mapper/RolesMapper.java new file mode 100644 index 0000000..77b8bf3 --- /dev/null +++ b/src/main/java/top/xinsin/mapper/RolesMapper.java @@ -0,0 +1,18 @@ +package top.xinsin.mapper; + +import top.xinsin.pojo.Roles; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * Mapper 接口 + *

+ * + * @author xinsin + * @since 2023-04-12 + */ +@Mapper +public interface RolesMapper extends BaseMapper { + +} diff --git a/src/main/java/top/xinsin/pojo/Account.java b/src/main/java/top/xinsin/pojo/Account.java new file mode 100644 index 0000000..d781070 --- /dev/null +++ b/src/main/java/top/xinsin/pojo/Account.java @@ -0,0 +1,50 @@ +package top.xinsin.pojo; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; +import java.time.LocalDateTime; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +/** +*

+ * + *

+* +* @author xinsin +* @since 2023-04-12 +*/ +@Data +@TableName("account") +public class Account implements Serializable { + +private static final long serialVersionUID = 1L; +@TableId("id") +private Integer id; +@TableField("username") +private String username; +@TableField("email") +private String email; +@TableField("rel_name") +private String relName; +@TableField("password") +private String password; +@TableField("status") +private Boolean status; +@TableField("role_id") +private Integer roleId; +@TableField("create_time") +@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") +@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") +private LocalDateTime createTime; +@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") +@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") +@TableField("update_time") +private LocalDateTime updateTime; +@TableField("del") +private Boolean del; +} \ No newline at end of file diff --git a/src/main/java/top/xinsin/pojo/Permissions.java b/src/main/java/top/xinsin/pojo/Permissions.java new file mode 100644 index 0000000..fb0a111 --- /dev/null +++ b/src/main/java/top/xinsin/pojo/Permissions.java @@ -0,0 +1,50 @@ +package top.xinsin.pojo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; +import java.time.LocalDateTime; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +/** +*

+* +*

+* +* @author xinsin +* @since 2023-04-12 +*/ +@Data +@TableName("permissions") +public class Permissions implements Serializable { + +private static final long serialVersionUID = 1L; + +@TableId(value = "id", type = IdType.AUTO) +private Integer id; +@TableField("permission_name") +private String permissionName; +@TableField("permission_code") +private String permissionCode; +@TableField("description") +private String description; +@TableField("account_id") +private Integer accountId; +@TableField("create_time") +@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") +@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") +private LocalDateTime createTime; +@TableField("update_time") +@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") +@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") +private LocalDateTime updateTime; +@TableField("status") +private Boolean status; +@TableField("del") +private Boolean del; +} \ No newline at end of file diff --git a/src/main/java/top/xinsin/pojo/Roles.java b/src/main/java/top/xinsin/pojo/Roles.java new file mode 100644 index 0000000..e1d6190 --- /dev/null +++ b/src/main/java/top/xinsin/pojo/Roles.java @@ -0,0 +1,50 @@ +package top.xinsin.pojo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; +import java.time.LocalDateTime; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +/** +*

+* +*

+* +* @author xinsin +* @since 2023-04-12 +*/ +@Data +@TableName("roles") +public class Roles implements Serializable { + +private static final long serialVersionUID = 1L; + +@TableId(value = "id", type = IdType.AUTO) +private Integer id; +@TableField("role_name") +private String roleName; +@TableField("description") +private String description; +@TableField("account_id") +private Integer accountId; +@TableField("create_time") +@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") +@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") +private LocalDateTime createTime; +@TableField("update_time") +@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") +@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") +private LocalDateTime updateTime; +@TableField("status") +private Boolean status; +@TableField("del") +private Boolean del; + + +} \ No newline at end of file diff --git a/src/main/java/top/xinsin/service/AccountService.java b/src/main/java/top/xinsin/service/AccountService.java new file mode 100644 index 0000000..7e88dd2 --- /dev/null +++ b/src/main/java/top/xinsin/service/AccountService.java @@ -0,0 +1,46 @@ +package top.xinsin.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; +import top.xinsin.mapper.AccountMapper; +import top.xinsin.pojo.Account; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 服务类 + *

+ * + * @author xinsin + * @since 2023-04-12 + */ +@Service +public class AccountService implements UserDetailsService { + + @Autowired + private AccountMapper accountMapper; + + BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + System.out.println(username); + if(username == null) throw new UsernameNotFoundException("用户名不能为空"); + Account account = accountMapper.selectOne(new LambdaQueryWrapper() + .eq(Account::getUsername,username) + .or() + .eq(Account::getEmail,username)); + if(account == null) throw new UsernameNotFoundException("用户名或密码错误"); + return User + .withUsername(account.getUsername()) + .password(account.getPassword()) + .roles(String.valueOf(account.getRoleId())) + .build(); + } +} diff --git a/src/main/java/top/xinsin/service/PermissionsService.java b/src/main/java/top/xinsin/service/PermissionsService.java new file mode 100644 index 0000000..63c917b --- /dev/null +++ b/src/main/java/top/xinsin/service/PermissionsService.java @@ -0,0 +1,18 @@ +package top.xinsin.service; + +import org.springframework.stereotype.Service; +import top.xinsin.pojo.Permissions; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 服务类 + *

+ * + * @author xinsin + * @since 2023-04-12 + */ +@Service +public class PermissionsService { + +} diff --git a/src/main/java/top/xinsin/service/RolesService.java b/src/main/java/top/xinsin/service/RolesService.java new file mode 100644 index 0000000..e44ed52 --- /dev/null +++ b/src/main/java/top/xinsin/service/RolesService.java @@ -0,0 +1,18 @@ +package top.xinsin.service; + +import org.springframework.stereotype.Service; +import top.xinsin.pojo.Roles; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + *

+ * 服务类 + *

+ * + * @author xinsin + * @since 2023-04-12 + */ +@Service +public class RolesService { + +} diff --git a/src/main/java/top/xinsin/util/HttpCodes.java b/src/main/java/top/xinsin/util/HttpCodes.java index ac26849..b027c05 100644 --- a/src/main/java/top/xinsin/util/HttpCodes.java +++ b/src/main/java/top/xinsin/util/HttpCodes.java @@ -10,18 +10,18 @@ public enum HttpCodes { * 200 * 成功执行 */ - HTTP_CODES200(200,"接口一不小心执行成功啦!"), + HTTP_CODES200(202,"接口执行成功"), /** * 500 * 服务器错误 */ - HTTP_CODES500(500,"哎呀,错误了请节哀!"), + HTTP_CODES500(500,"服务器出现错误,请联系服务器管理员"), /** * 401 * 数据错误 */ - HTTP_CODES401(401,"你这请求是坏的,你不会写吗?"), + HTTP_CODES401(401,"这是一个坏的请求,请重新写入参数"), /** * 501 * 账号密码错误 @@ -36,7 +36,7 @@ public enum HttpCodes { * 251 * 无权限访问 */ - ACCESS_DENIED( 251,"你没有权限访问"); + ACCESS_DENIED( 251,"无权访问"); private final int code; private final String message; diff --git a/src/main/java/top/xinsin/util/ServletUtils.java b/src/main/java/top/xinsin/util/ServletUtils.java new file mode 100644 index 0000000..717e695 --- /dev/null +++ b/src/main/java/top/xinsin/util/ServletUtils.java @@ -0,0 +1,20 @@ +package top.xinsin.util; + +import com.alibaba.fastjson2.JSON; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.SneakyThrows; + +/** + * 将数据渲染到前端 + */ +public class ServletUtils { + @SneakyThrows + public static void render(HttpServletRequest request, HttpServletResponse response,R o){ + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified"); + response.setHeader("Content-type", "application/json;charset=UTF-8"); + + response.getWriter().print(JSON.toJSONString(o)); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8075273..d592f3d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -26,6 +26,9 @@ spring: connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500 mvc: static-path-pattern: /static/** + security: + user: + password: 123456 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl diff --git a/src/main/resources/mapper/AccountMapper.xml b/src/main/resources/mapper/AccountMapper.xml new file mode 100644 index 0000000..79a23ac --- /dev/null +++ b/src/main/resources/mapper/AccountMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/mapper/PermissionsMapper.xml b/src/main/resources/mapper/PermissionsMapper.xml new file mode 100644 index 0000000..a99f96a --- /dev/null +++ b/src/main/resources/mapper/PermissionsMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/mapper/RolesMapper.xml b/src/main/resources/mapper/RolesMapper.xml new file mode 100644 index 0000000..9dab3cc --- /dev/null +++ b/src/main/resources/mapper/RolesMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/test/java/top/xinsin/CodeGenerator.java b/src/test/java/top/xinsin/CodeGenerator.java new file mode 100644 index 0000000..a078d45 --- /dev/null +++ b/src/test/java/top/xinsin/CodeGenerator.java @@ -0,0 +1,73 @@ +package top.xinsin; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.generator.FastAutoGenerator; +import com.baomidou.mybatisplus.generator.config.OutputFile; +import com.baomidou.mybatisplus.generator.config.TemplateConfig; +import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +public class CodeGenerator { + public static void main(String[] args) { + List tables = new ArrayList<>(); + tables.add("account"); + tables.add("roles"); + tables.add("permissions"); + + FastAutoGenerator.create("jdbc:mysql://wzpmc.cn:3306/commerce_system?serverTimezone=UTC-8","commerce_system","Jix656dzD6St4YCn") + .globalConfig(builder -> { + builder.author("xinsin") //作者 + .outputDir(System.getProperty("user.dir")+"\\src\\main\\java") //输出路径(写到java目录) + .enableSwagger() //开启swagger + .commentDate("yyyy-MM-dd") + .fileOverride(); //开启覆盖之前生成的文件 + + }) + .packageConfig(builder -> { + builder.parent("top.xinsin") + .entity("pojo") + .service("service") + .serviceImpl("service.impl") + .controller("controller") + .mapper("mapper") + .xml("mapper") + .pathInfo(Collections.singletonMap(OutputFile.mapperXml,System.getProperty("user.dir")+"\\src\\main\\resources\\mapper")); + }) + .strategyConfig(builder -> { + builder.addInclude(tables) + .serviceBuilder() + .formatServiceFileName("%sService") + .formatServiceImplFileName("%sServiceImpl") + .entityBuilder() + .enableLombok() + .logicDeleteColumnName("deleted") + .enableTableFieldAnnotation() + .controllerBuilder() + // 映射路径使用连字符格式,而不是驼峰 + .enableHyphenStyle() + .formatFileName("%sController") + .enableRestStyle() + .mapperBuilder() + //生成通用的resultMap + .enableBaseResultMap() + .superClass(BaseMapper.class) + .formatMapperFileName("%sMapper") + .enableMapperAnnotation() + .formatXmlFileName("%sMapper"); + }) + .templateConfig(new Consumer() { + @Override + public void accept(TemplateConfig.Builder builder) { + // 实体类使用我们自定义模板 + builder.entity("myentity.java"); + } + }) + .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板 + .execute(); + } +} + diff --git a/src/test/java/top/xinsin/MainTest.java b/src/test/java/top/xinsin/MainTest.java new file mode 100644 index 0000000..17985cf --- /dev/null +++ b/src/test/java/top/xinsin/MainTest.java @@ -0,0 +1,201 @@ +package top.xinsin; + +import org.apache.commons.codec.digest.DigestUtils; +import org.junit.Test; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Scanner; + +@SuppressWarnings("resource") +public class MainTest { + + @Test + public void test01(){ + System.out.println(new BCryptPasswordEncoder().encode(DigestUtils.md5Hex("xinsin"))); + System.out.println(DigestUtils.md5Hex("xinsin")); + } + + public static void main(String[] args) throws ClassNotFoundException, SQLException { + MainTest m = new MainTest(); + Scanner sc = new Scanner(System.in); + while(true) { + int ch = m.menu(); + switch(ch) { + case 1:m.SelectAll();break; + case 2: + System.out.println("请输入需要添加的学生的数量:"); + int n = sc.nextInt(); + int countInsert = m.insertStudent(n); + if(countInsert==n) { + System.out.println("学生信息添加成功!"); + }else { + System.out.println("信息输入有误,学生添加失败。"); + } + break; + case 3: + System.out.println("请输入需要修改的学生的学号:"); + String IDUpdate= sc.next(); + int countUpdate = m.updateStudent(IDUpdate); + if(countUpdate>0) { + System.out.println("学生信息修改成功。"); + } + break; + case 4: + System.out.println("请输入需要删除的学生的学号:"); + String IDDelete = sc.next(); + int countDelete = m.deleteStudentByID(IDDelete); + if(countDelete>0) { + System.out.println("删除成功。"); + }else { + System.out.println("删除失败。"); + } + break; + case 5:System.out.println("感谢使用,系统退出中......");;System.exit(0); + default:System.err.println("请选择相应的功能......"); + } + System.out.println("请输入回车键继续......"); + sc.nextLine(); + } + } + public int menu() { + Scanner sc = new Scanner(System.in); + System.out.println("******************************欢迎使用学生信息管理系统******************************"); + System.out.println("\t\t功能列表如下:"); + System.out.println("\t\t1、查询学生信息。"); + System.out.println("\t\t2、添加学生信息。"); + System.out.println("\t\t3、修改学生信息。"); + System.out.println("\t\t4、删除学生信息。"); + System.out.println("\t\t5、退出系统。"); + System.out.println("请选择你需要的功能:"); + return sc.nextInt(); + } + // 连接数据库 + public Connection getConnection() throws SQLException, ClassNotFoundException { + String Driver = "com.mysql.cj.jdbc.Driver"; + String url="jdbc:mysql://localhost:3306/StuIMS"; + String user="root"; + String pwd="123456"; + Class.forName(Driver); + Connection con = DriverManager.getConnection(url,user,pwd); + if(con.isClosed()) { + System.err.println("数据库连接失败。"); + return null; + }else { + System.out.println("连接成功。"); + return con; + } + + } + // 查询所有数据 + public void SelectAll() throws ClassNotFoundException, SQLException { + Connection con = getConnection(); + PreparedStatement ps = con.prepareStatement("select * from Student"); + ResultSet rs = ps.executeQuery(); + System.out.println(" 学号\t\t姓名\t 性别\t 生日\t\t学分"); + while(rs.next()) { + System.out.println(rs.getString("studentID")+"\t"+rs.getString("studentName")+"\t "+rs.getString("studentSex")+"\t " + +rs.getString("studentBirthday")+"\t"+rs.getString("credit")+"\t"); + } + } + // 插入数据 + public int insertStudent(int num) throws ClassNotFoundException, SQLException { + Connection con = getConnection(); + String sql = "insert into Student values(?,?,?,?,?,'202105')"; + PreparedStatement ps = con.prepareStatement(sql); + Scanner sc = new Scanner(System.in); + int count=0; + for(int i=1;i<=num;i++) { + System.out.println("请输入第"+i+"个学生的学号:"); + String ID = sc.next(); + System.out.println("请输入第"+i+"个学生的姓名:"); + String name = sc.next(); + System.out.println("请输入第"+i+"个学生的性别:"); + String sex = sc.next(); + System.out.println("请输入第"+i+"个学生的生日:"); + String birthday = sc.next(); + System.out.println("请输入第"+i+"个学生的学分:"); + int credit = sc.nextInt(); + ps.setString(1, ID); + ps.setString(2, name); + ps.setString(3, sex); + ps.setString(4, birthday); + ps.setInt(5, credit); + if(ps.executeUpdate()>0) { + count++; + }else { + System.out.println("数据插入失败。"); + break; + } + } + return count; + } + // 修改数据 + public int updateStudent(String ID) throws ClassNotFoundException, SQLException { + Connection con = getConnection(); + String sql="update Student set studentName=?,studentSex=?,studentBirthday=? where studentID="+ID; + PreparedStatement ps = con.prepareStatement(sql); + Scanner sc = new Scanner(System.in); + int count=0; + System.out.println("请输入学生的姓名:"); + String name = sc.next(); + System.out.println("请输入学生的性别:"); + String sex = sc.next(); + System.out.println("请输入学生的生日:"); + String birthday = sc.next(); +// System.out.println("请输入学生的学分:"); +// int credit = sc.nextInt(); + ps.setString(1, name); + ps.setString(2, sex); + ps.setString(3, birthday); +// ps.setInt(4, credit); + count = ps.executeUpdate(); + return count; + } + public int deleteStudentByID(String ID) throws ClassNotFoundException, SQLException { + Connection con = getConnection(); + Scanner sc = new Scanner(System.in); + PreparedStatement psS = con.prepareStatement("select * from Student where studentID="+ID); + ResultSet rs = psS.executeQuery(); + System.out.println("即将删除的学生的信息:"); + System.out.println(" 学号\t\t姓名\t 性别\t 生日\t\t学分"); + while(rs.next()) { + System.out.println(rs.getString("studentID")+"\t"+rs.getString("studentName")+"\t "+rs.getString("studentSex")+"\t " + +rs.getString("studentBirthday")+"\t"+rs.getString("credit")+"\t"); + } + System.out.println("请确认信息是否无误(y/Y)?"); + char ch1 = sc.next().charAt(0); + if(ch1=='Y'||ch1=='y') { + System.out.println("请确认是否删除(y/Y)?"); + char ch2 = sc.next().charAt(0); + if(ch2=='y'||ch2=='Y') { + PreparedStatement psD = con.prepareStatement("delete from Student where studentID="+ID); + int count = psD.executeUpdate(); + return count; + }else { + System.out.println("删除取消。"); + return -1; + } + }else { + System.out.println("信息有误,请重新选择......"); + return -1; + } + + } +} + + + + + + + + + + + + diff --git a/src/test/resources/myentity.java.ftl b/src/test/resources/myentity.java.ftl new file mode 100644 index 0000000..0f9d28b --- /dev/null +++ b/src/test/resources/myentity.java.ftl @@ -0,0 +1,135 @@ +package ${package.Entity}; + +<#list table.importPackages as pkg> + import ${pkg}; + +<#if entityLombokModel> + import lombok.Data; + <#if chainModel> + import lombok.experimental.Accessors; + + + +/** +*

+ * ${table.comment!} + *

+* +* @author ${author} +* @since ${date} +*/ +<#if entityLombokModel> + @Data + <#if chainModel> + @Accessors(chain = true) + + +<#if table.convert> + @TableName("${schemaName}${table.name}") + +<#if superEntityClass??> + public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}> { +<#elseif activeRecord> + public class ${entity} extends Model<${entity}> { +<#elseif entitySerialVersionUID> + public class ${entity} implements Serializable { +<#else> + public class ${entity} { + +<#if entitySerialVersionUID> + + private static final long serialVersionUID = 1L; + +<#-- ---------- BEGIN 字段循环遍历 ----------> +<#list table.fields as field> + <#if field.keyFlag> + <#assign keyPropertyName="${field.propertyName}"/> + + <#if field.keyFlag> + <#-- 主键 --> + <#if field.keyIdentityFlag> + @TableId(value = "${field.annotationColumnName}", type = IdType.AUTO) + <#elseif idType??> + @TableId(value = "${field.annotationColumnName}", type = IdType.${idType}) + <#elseif field.convert> + @TableId("${field.annotationColumnName}") + + <#-- 普通字段 --> + <#elseif field.fill??> + <#-- ----- 存在字段填充设置 -----> + <#if field.convert> + @TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill}) + <#else> + @TableField(fill = FieldFill.${field.fill}) + + <#elseif field.convert> + @TableField("${field.annotationColumnName}") + +<#-- 乐观锁注解 --> + <#if field.versionField> + @Version + +<#-- 逻辑删除注解 --> + <#if field.logicDeleteField> + @TableLogic + + private ${field.propertyType} ${field.propertyName}; + +<#------------ END 字段循环遍历 ----------> + +<#if !entityLombokModel> + <#list table.fields as field> + <#if field.propertyType == "boolean"> + <#assign getprefix="is"/> + <#else> + <#assign getprefix="get"/> + + public ${field.propertyType} ${getprefix}${field.capitalName}() { + return ${field.propertyName}; + } + + <#if chainModel> + public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) { + <#else> + public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) { + + this.${field.propertyName} = ${field.propertyName}; + <#if chainModel> + return this; + + } + + + +<#if entityColumnConstant> + <#list table.fields as field> + public static final String ${field.name?upper_case} = "${field.name}"; + + + +<#if activeRecord> + @Override + public Serializable pkVal() { + <#if keyPropertyName??> + return this.${keyPropertyName}; + <#else> + return null; + + } + + +<#if !entityLombokModel> + @Override + public String toString() { + return "${entity}{" + + <#list table.fields as field> + <#if field_index==0> + "${field.propertyName}=" + ${field.propertyName} + + <#else> + ", ${field.propertyName}=" + ${field.propertyName} + + + + "}"; + } + +} \ No newline at end of file