diff --git a/aurora-springboot/src/main/java/com/aurora/annotation/AccessLimit.java b/aurora-springboot/src/main/java/com/aurora/annotation/AccessLimit.java index dc8dbc8..8a1f5a8 100644 --- a/aurora-springboot/src/main/java/com/aurora/annotation/AccessLimit.java +++ b/aurora-springboot/src/main/java/com/aurora/annotation/AccessLimit.java @@ -2,12 +2,15 @@ package com.aurora.annotation; import java.lang.annotation.*; -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@Documented +// 定义一个注解:AccessLimit,用于方法级别的访问频率限制 +@Target(ElementType.METHOD) // 该注解只能用于方法上 +@Retention(RetentionPolicy.RUNTIME) // 注解在运行时保留,这样可以通过反射读取 +@Documented // 该注解会包含在 JavaDoc 中 public @interface AccessLimit { + // 限制的时间窗口,单位为秒,例如 60 表示 1 分钟内 int seconds(); + // 在指定的时间窗口内,允许的最大访问次数,例如 10 表示最多 10 次 int maxCount(); -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/annotation/OptLog.java b/aurora-springboot/src/main/java/com/aurora/annotation/OptLog.java index cf286e6..849f778 100644 --- a/aurora-springboot/src/main/java/com/aurora/annotation/OptLog.java +++ b/aurora-springboot/src/main/java/com/aurora/annotation/OptLog.java @@ -2,10 +2,12 @@ package com.aurora.annotation; import java.lang.annotation.*; -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@Documented +// 定义一个注解:OptLog,用于标记需要进行操作日志记录的方法 +@Target(ElementType.METHOD) // 该注解只能用于方法上 +@Retention(RetentionPolicy.RUNTIME) // 注解在运行时保留,以便通过反射读取(通常用于AOP切面) +@Documented // 该注解会包含在 JavaDoc 中 public @interface OptLog { + // 操作类型,比如:"新增文章"、"删除评论"、"用户登录",默认值为空字符串 String optType() default ""; -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/aspect/ExceptionLogAspect.java b/aurora-springboot/src/main/java/com/aurora/aspect/ExceptionLogAspect.java index d6c8870..325d391 100644 --- a/aurora-springboot/src/main/java/com/aurora/aspect/ExceptionLogAspect.java +++ b/aurora-springboot/src/main/java/com/aurora/aspect/ExceptionLogAspect.java @@ -22,31 +22,69 @@ import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.Objects; +/** + * 异常日志切面类,用于捕获和处理控制器层抛出的异常,并记录异常日志。 + */ @Aspect @Component public class ExceptionLogAspect { + /** + * 自动注入 Spring 应用上下文,用于发布事件。 + */ @Autowired private ApplicationContext applicationContext; + /** + * 定义一个切入点,匹配 com.aurora.controller 包及其子包下的所有方法。 + * 这意味着所有控制器层的方法都会被这个切面拦截。 + */ @Pointcut("execution(* com.aurora.controller..*.*(..))") public void exceptionLogPointcut() { + // 切入点方法体为空,仅用于定义切入点 } + /** + * 在切入点方法抛出异常后执行的方法。 + * 该方法会在控制器层方法抛出异常时被调用,用于记录异常日志。 + * + * @param joinPoint 切入点对象,包含方法执行的相关信息 + * @param e 抛出的异常对象 + */ @AfterThrowing(value = "exceptionLogPointcut()", throwing = "e") public void saveExceptionLog(JoinPoint joinPoint, Exception e) { + // 获取当前请求的上下文 RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); - HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes).resolveReference(RequestAttributes.REFERENCE_REQUEST); + // 从请求上下文中获取 HttpServletRequest 对象 + HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes) + .resolveReference(RequestAttributes.REFERENCE_REQUEST); + + // 创建一个 ExceptionLog 实体对象,用于存储异常日志信息 ExceptionLog exceptionLog = new ExceptionLog(); + + // 获取方法的签名信息 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); + + // 获取方法上的 @ApiOperation 注解,用于获取操作的描述 ApiOperation apiOperation = method.getAnnotation(ApiOperation.class); + + // 设置操作的 URI,即请求的路径 exceptionLog.setOptUri(Objects.requireNonNull(request).getRequestURI()); + + // 获取当前类的全限定名和方法名,组合成完整的操作方法名称 String className = joinPoint.getTarget().getClass().getName(); String methodName = method.getName(); methodName = className + "." + methodName; + + // 设置操作的完整方法名称 exceptionLog.setOptMethod(methodName); + + // 设置请求的方法类型,如 GET、POST 等 exceptionLog.setRequestMethod(Objects.requireNonNull(request).getMethod()); + + // 获取方法的参数,如果第一个参数是 MultipartFile 类型,则记录为 "file" + // 否则,将所有参数序列化为 JSON 字符串 if (joinPoint.getArgs().length > 0) { if (joinPoint.getArgs()[0] instanceof MultipartFile) { exceptionLog.setRequestParam("file"); @@ -54,16 +92,26 @@ public class ExceptionLogAspect { exceptionLog.setRequestParam(JSON.toJSONString(joinPoint.getArgs())); } } + + // 如果方法上有 @ApiOperation 注解,则设置操作的描述 if (Objects.nonNull(apiOperation)) { exceptionLog.setOptDesc(apiOperation.value()); } else { + // 否则,设置为空字符串 exceptionLog.setOptDesc(""); } + + // 获取异常的堆栈信息,用于调试和排查 exceptionLog.setExceptionInfo(ExceptionUtil.getTrace(e)); + + // 获取客户端的 IP 地址 String ipAddress = IpUtil.getIpAddress(request); exceptionLog.setIpAddress(ipAddress); + + // 获取 IP 地址的来源信息,如国家、城市等 exceptionLog.setIpSource(IpUtil.getIpSource(ipAddress)); + + // 通过应用上下文发布一个异常日志事件,以便其他监听器处理 applicationContext.publishEvent(new ExceptionLogEvent(exceptionLog)); } - -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/aspect/OperationLogAspect.java b/aurora-springboot/src/main/java/com/aurora/aspect/OperationLogAspect.java index d47d4de..e7bfb1e 100644 --- a/aurora-springboot/src/main/java/com/aurora/aspect/OperationLogAspect.java +++ b/aurora-springboot/src/main/java/com/aurora/aspect/OperationLogAspect.java @@ -24,36 +24,85 @@ import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.Objects; +/** + * 操作日志切面类,用于捕获和处理带有 @OptLog 注解的方法的成功执行,并记录操作日志。 + */ @Aspect @Component public class OperationLogAspect { + /** + * 自动注入 Spring 应用上下文,用于发布事件。 + */ @Autowired private ApplicationContext applicationContext; + /** + * 定义一个切入点,匹配所有使用了 @OptLog 注解的方法。 + * 这意味着只有被 @OptLog 注解标记的方法才会被这个切面拦截。 + */ @Pointcut("@annotation(com.aurora.annotation.OptLog)") public void operationLogPointCut() { + // 切入点方法体为空,仅用于定义切入点 } + /** + * 在切入点方法成功执行后执行的方法。 + * 该方法会在带有 @OptLog 注解的方法成功返回后调用,用于记录操作日志。 + * + * @param joinPoint 切入点对象,包含方法执行的相关信息 + * @param keys 方法的返回值,通常为操作的结果或数据 + */ @AfterReturning(value = "operationLogPointCut()", returning = "keys") @SuppressWarnings("unchecked") public void saveOperationLog(JoinPoint joinPoint, Object keys) { + // 获取当前请求的上下文 RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); - HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes).resolveReference(RequestAttributes.REFERENCE_REQUEST); + // 从请求上下文中获取 HttpServletRequest 对象 + HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes) + .resolveReference(RequestAttributes.REFERENCE_REQUEST); + + // 创建一个 OperationLog 实体对象,用于存储操作日志信息 OperationLog operationLog = new OperationLog(); + + // 获取方法的签名信息 MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); + + // 获取类上的 @Api 注解,用于获取操作所属的模块 Api api = (Api) signature.getDeclaringType().getAnnotation(Api.class); + + // 获取方法上的 @ApiOperation 注解,用于获取操作的描述 ApiOperation apiOperation = method.getAnnotation(ApiOperation.class); + + // 获取方法上的 @OptLog 注解,用于获取操作类型 OptLog optLog = method.getAnnotation(OptLog.class); + + // 设置操作所属的模块,通常来自 @Api 注解的 tags operationLog.setOptModule(api.tags()[0]); + + // 设置操作类型,来自 @OptLog 注解的 optType operationLog.setOptType(optLog.optType()); + + // 设置操作描述,来自 @ApiOperation 注解的 value operationLog.setOptDesc(apiOperation.value()); + + // 获取目标类的全限定名和方法名,组合成完整的操作方法名称 String className = joinPoint.getTarget().getClass().getName(); String methodName = method.getName(); methodName = className + "." + methodName; - operationLog.setRequestMethod(Objects.requireNonNull(request).getMethod()); + + // 设置操作的完整方法名称 operationLog.setOptMethod(methodName); + + // 获取请求的方法类型,如 GET、POST 等 + operationLog.setRequestMethod(Objects.requireNonNull(request).getMethod()); + + // 获取请求的 URI,即请求的路径 + operationLog.setOptUri(request.getRequestURI()); + + // 获取方法的参数,如果第一个参数是 MultipartFile 类型,则记录为 "file" + // 否则,将所有参数序列化为 JSON 字符串 if (joinPoint.getArgs().length > 0) { if (joinPoint.getArgs()[0] instanceof MultipartFile) { operationLog.setRequestParam("file"); @@ -61,14 +110,22 @@ public class OperationLogAspect { operationLog.setRequestParam(JSON.toJSONString(joinPoint.getArgs())); } } + + // 设置方法的返回值,序列化为 JSON 字符串 operationLog.setResponseData(JSON.toJSONString(keys)); + + // 获取当前登录用户的详细信息,包括用户ID和昵称 operationLog.setUserId(UserUtil.getUserDetailsDTO().getId()); operationLog.setNickname(UserUtil.getUserDetailsDTO().getNickname()); + + // 获取客户端的 IP 地址 String ipAddress = IpUtil.getIpAddress(request); operationLog.setIpAddress(ipAddress); + + // 获取 IP 地址的来源信息,如国家、城市等 operationLog.setIpSource(IpUtil.getIpSource(ipAddress)); - operationLog.setOptUri(request.getRequestURI()); + + // 通过应用上下文发布一个操作日志事件,以便其他监听器处理 applicationContext.publishEvent(new OperationLogEvent(operationLog)); } - -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/config/Knife4jConfig.java b/aurora-springboot/src/main/java/com/aurora/config/Knife4jConfig.java index 318e6a2..5afe9b3 100644 --- a/aurora-springboot/src/main/java/com/aurora/config/Knife4jConfig.java +++ b/aurora-springboot/src/main/java/com/aurora/config/Knife4jConfig.java @@ -1,6 +1,5 @@ package com.aurora.config; - import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; @@ -14,30 +13,45 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; import java.util.Collections; +/** + * Swagger API 文档配置类,用于生成在线接口文档。 + * 本配置基于 Swagger 2,并启用了 Knife4j 增强功能(通常通过依赖引入)。 + */ @Configuration @EnableSwagger2WebMvc public class Knife4jConfig { + /** + * 创建并配置一个 Docket Bean,这是 Swagger 的核心配置对象, + * 用于定义 API 文档的生成规则、扫描路径、协议、主机等信息。 + * + * @return 配置好的 Docket 实例 + */ @Bean public Docket createRestApi() { - return new Docket(DocumentationType.SWAGGER_2) - .protocols(Collections.singleton("https")) - .host("https://www.linhaojun.top") - .apiInfo(apiInfo()) - .select() - .apis(RequestHandlerSelectors.basePackage("com.aurora.controller")) - .paths(PathSelectors.any()) - .build(); + return new Docket(DocumentationType.SWAGGER_2) // 指定使用 Swagger 2 规范 + .protocols(Collections.singleton("https")) // 指定支持的协议,这里只支持 HTTPS + .host("https://www.linhaojun.top") // 指定 API 的主机地址 + .apiInfo(apiInfo()) // 设置 API 文档的基本信息,如标题、描述、联系人等 + .select() // 开始选择哪些接口会被扫描并生成文档 + .apis(RequestHandlerSelectors.basePackage("com.aurora.controller")) // 指定扫描的包路径,这里只扫描 com.aurora.controller 包下的 Controller + .paths(PathSelectors.any()) // 指定扫描所有路径,也可以根据需求使用 PathSelectors.ant(...) 等进行筛选 + .build(); // 构建 Docket 实例 } + /** + * 构建并返回 ApiInfo 对象,用于定义 API 文档的元信息, + * 包括标题、描述、联系方式、服务条款 URL 和版本号等。 + * + * @return 配置好的 ApiInfo 实例 + */ private ApiInfo apiInfo() { return new ApiInfoBuilder() - .title("aurora文档") - .description("aurora") - .contact(new Contact("花未眠", "", "1909925152@qq.com")) - .termsOfServiceUrl("https://www.linhaojun.top/api") - .version("1.0") - .build(); + .title("aurora文档") // API 文档的标题,通常显示在文档首页 + .description("aurora") // API 文档的描述,简要介绍该 API 的用途或功能 + .contact(new Contact("花未眠", "", "1909925152@qq.com")) // 联系人信息,包括姓名、网址(可为空)、邮箱 + .termsOfServiceUrl("https://www.linhaojun.top/api") // 服务条款的 URL,通常为 API 的使用条款或相关文档链接 + .version("1.0") // API 的版本号 + .build(); // 构建 ApiInfo 实例 } - -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/config/MybatisPlusConfig.java b/aurora-springboot/src/main/java/com/aurora/config/MybatisPlusConfig.java index dd70b18..47224d4 100644 --- a/aurora-springboot/src/main/java/com/aurora/config/MybatisPlusConfig.java +++ b/aurora-springboot/src/main/java/com/aurora/config/MybatisPlusConfig.java @@ -7,14 +7,31 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.transaction.annotation.EnableTransactionManagement; -@EnableTransactionManagement -@Configuration +/** + * MyBatis-Plus 配置类,用于配置 MyBatis-Plus 的插件和功能, + * 比如分页插件、事务管理等。 + */ +@EnableTransactionManagement // 启用 Spring 的事务管理功能,允许使用 @Transactional 注解管理事务 +@Configuration // 声明这是一个 Spring 配置类,Spring 会加载该类中定义的 Bean public class MybatisPlusConfig { + /** + * 创建并配置 MybatisPlusInterceptor Bean, + * 这是 MyBatis-Plus 提供的全局拦截器,用于集成各种功能插件, + * 比如分页插件、乐观锁插件、动态表名插件等。 + * + * @return 配置好的 MybatisPlusInterceptor 实例 + */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { + // 创建 MybatisPlusInterceptor 实例,它是 MyBatis-Plus 的核心拦截器容器 MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + + // 添加分页插件,用于支持 MyBatis-Plus 的分页查询功能 + // DbType.MYSQL 表示当前使用的数据库类型是 MySQL,根据实际情况可替换为其他数据库类型 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + + // 返回配置好的拦截器实例 return interceptor; } diff --git a/aurora-springboot/src/main/java/com/aurora/config/WebMvcConfig.java b/aurora-springboot/src/main/java/com/aurora/config/WebMvcConfig.java index 1609e61..2a66fe9 100644 --- a/aurora-springboot/src/main/java/com/aurora/config/WebMvcConfig.java +++ b/aurora-springboot/src/main/java/com/aurora/config/WebMvcConfig.java @@ -1,6 +1,5 @@ package com.aurora.config; - import com.aurora.interceptor.PaginationInterceptor; import com.aurora.interceptor.AccessLimitInterceptor; import org.springframework.beans.factory.annotation.Autowired; @@ -9,28 +8,54 @@ import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +/** + * Web MVC 配置类,用于配置 Spring MVC 的相关功能, + * 包括跨域资源共享(CORS)和自定义拦截器(Interceptors)。 + */ @Configuration -public class WebMvcConfig implements WebMvcConfigurer { //这是注释 -//这是注释 +public class WebMvcConfig implements WebMvcConfigurer { // 这是注释 + + // 自动注入自定义的分页拦截器,可能用于处理分页逻辑(如解析分页参数) @Autowired private PaginationInterceptor paginationInterceptor; + // 自动注入自定义的访问限流拦截器,可能用于接口防刷、频率控制等 @Autowired private AccessLimitInterceptor accessLimitInterceptor; + /** + * 配置跨域资源共享(CORS, Cross-Origin Resource Sharing)规则, + * 允许前端应用(可能运行在不同域名或端口)访问本后端 API。 + * + * @param registry CORS 注册器,用于定义跨域规则 + */ @Override public void addCorsMappings(CorsRegistry registry) { + // 对所有路径(/**)启用跨域配置 registry.addMapping("/**") + // 允许跨域请求携带凭证(如 cookies、HTTP认证等),注意:与 allowedOrigins("*") 一起使用时有限制 .allowCredentials(true) + // 允许所有请求头(如 Content-Type, Authorization 等) .allowedHeaders("*") + // 允许所有来源(即任何域名、IP、端口都可访问,生产环境建议指定具体域名) .allowedOrigins("*") + // 允许所有 HTTP 请求方法(如 GET, POST, PUT, DELETE, OPTIONS 等) .allowedMethods("*"); } + /** + * 配置 Spring MVC 的拦截器,将自定义的拦截器添加到请求处理链中, + * 拦截器可以用于实现权限控制、日志记录、限流、分页参数解析等功能。 + * + * @param registry 拦截器注册器,用于注册自定义拦截器 + */ @Override public void addInterceptors(InterceptorRegistry registry) { + // 注册分页拦截器,用于处理分页相关逻辑(如自动解析页码、页大小等参数) registry.addInterceptor(paginationInterceptor); + + // 注册访问限流拦截器,用于限制接口的访问频率,防止恶意请求或接口滥用 registry.addInterceptor(accessLimitInterceptor); } -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/config/WebSecurityConfig.java b/aurora-springboot/src/main/java/com/aurora/config/WebSecurityConfig.java index 858028d..0531ae1 100644 --- a/aurora-springboot/src/main/java/com/aurora/config/WebSecurityConfig.java +++ b/aurora-springboot/src/main/java/com/aurora/config/WebSecurityConfig.java @@ -23,70 +23,127 @@ import org.springframework.security.web.authentication.AuthenticationFailureHand import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +/** + * Spring Security 配置类,用于配置认证、授权、CSRF 保护、会话管理等安全功能。 + */ @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + // 自动注入认证失败处理器,用于处理认证失败的请求 @Autowired - private AuthenticationEntryPoint authenticationEntryPoint; + private AuthenticationFailureHandler authenticationFailureHandler; + // 自动注入认证成功处理器,用于处理认证成功的请求 @Autowired - private AccessDeniedHandler accessDeniedHandler; + private AuthenticationSuccessHandler authenticationSuccessHandler; + // 自动注入访问被拒绝处理器,用于处理权限不足的请求 @Autowired - private AuthenticationSuccessHandler authenticationSuccessHandler; + private AccessDeniedHandler accessDeniedHandler; + // 自动注入认证入口点,用于处理未认证的请求 @Autowired - private AuthenticationFailureHandler authenticationFailureHandler; + private AuthenticationEntryPoint authenticationEntryPoint; + // 自动注入 JWT 认证过滤器,用于处理 JWT 令牌的认证 @Autowired private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; + /** + * 定义安全元数据源,用于定义哪些 URL 需要哪些权限。 + * 这里返回一个自定义的 FilterInvocationSecurityMetadataSource 实现类。 + * + * @return 自定义的安全元数据源 Bean + */ @Bean public FilterInvocationSecurityMetadataSource securityMetadataSource() { return new FilterInvocationSecurityMetadataSourceImpl(); } + /** + * 定义访问决策管理器,用于决定用户是否有权限访问某个资源。 + * 这里返回一个自定义的 AccessDecisionManager 实现类。 + * + * @return 自定义的访问决策管理器 Bean + */ @Bean public AccessDecisionManager accessDecisionManager() { return new AccessDecisionManagerImpl(); } + /** + * 暴露 AuthenticationManager Bean,供其他组件使用。 + * 通常用于自定义认证逻辑或其他需要 AuthenticationManager 的地方。 + * + * @return AuthenticationManager Bean + * @throws Exception 如果出现异常 + */ @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } + /** + * 定义密码编码器,用于加密和验证用户密码。 + * 这里使用 BCrypt 加密算法,具有较高的安全性。 + * + * @return BCryptPasswordEncoder Bean + */ @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } + /** + * 配置 HttpSecurity,定义安全规则和过滤器链。 + * + * @param http HttpSecurity 对象,用于配置安全规则 + * @throws Exception 如果配置过程中出现异常 + */ @Override protected void configure(HttpSecurity http) throws Exception { + // 配置表单登录相关设置 http.formLogin() + // 设置登录处理的 URL,通常为用户提交登录表单的路径 .loginProcessingUrl("/users/login") + // 设置认证成功后的处理器 .successHandler(authenticationSuccessHandler) + // 设置认证失败后的处理器 .failureHandler(authenticationFailureHandler); + + // 配置请求授权规则 http.authorizeRequests() + // 使用 ObjectPostProcessor 来注入自定义的 FilterInvocationSecurityMetadataSource 和 AccessDecisionManager .withObjectPostProcessor(new ObjectPostProcessor() { @Override public O postProcess(O fsi) { + // 设置安全元数据源,定义哪些 URL 需要哪些权限 fsi.setSecurityMetadataSource(securityMetadataSource()); + // 设置访问决策管理器,决定用户是否有权限访问某个资源 fsi.setAccessDecisionManager(accessDecisionManager()); return fsi; } }) + // 对所有请求进行权限配置,这里设置为允许所有请求通过 .anyRequest().permitAll() .and() - .csrf().disable().exceptionHandling() + // 禁用 CSRF 保护,适用于 RESTful API,不需要浏览器端的会话 + .csrf().disable() + // 配置异常处理,包括认证失败和权限不足的处理 + .exceptionHandling() + // 设置认证入口点,处理未认证的请求 .authenticationEntryPoint(authenticationEntryPoint) + // 设置访问被拒绝处理器,处理权限不足的请求 .accessDeniedHandler(accessDeniedHandler) .and() + // 配置会话管理策略,这里设置为无状态,适用于 RESTful API .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS); + + // 在 UsernamePasswordAuthenticationFilter 之前添加 JWT 认证过滤器 + // 这样可以优先处理 JWT 令牌的认证,而不是依赖传统的表单登录 http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); } - -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/exception/BizException.java b/aurora-springboot/src/main/java/com/aurora/exception/BizException.java index d19fbd9..789722c 100644 --- a/aurora-springboot/src/main/java/com/aurora/exception/BizException.java +++ b/aurora-springboot/src/main/java/com/aurora/exception/BizException.java @@ -1,22 +1,45 @@ package com.aurora.exception; - import com.aurora.enums.StatusCodeEnum; import lombok.AllArgsConstructor; import lombok.Getter; +/** + * 自定义业务异常类,用于在业务逻辑中抛出具有特定错误码和错误信息的异常。 + * 继承自 RuntimeException,表示这是一个非受检异常(Unchecked Exception)。 + */ @Getter @AllArgsConstructor public class BizException extends RuntimeException { + /** + * 错误码,默认值为 StatusCodeEnum.FAIL 的错误码。 + * 表示业务操作失败时返回的通用错误码。 + */ private Integer code = StatusCodeEnum.FAIL.getCode(); + /** + * 错误信息,描述具体的业务异常情况。 + * 该字段为 final,表示一旦在构造时赋值后便不可更改。 + */ private final String message; + /** + * 构造方法:仅接收错误信息。 + * 使用默认的错误码(StatusCodeEnum.FAIL.getCode())。 + * + * @param message 错误信息,描述业务异常的具体情况 + */ public BizException(String message) { this.message = message; } + /** + * 构造方法:接收 StatusCodeEnum 枚举,从中提取错误码和错误信息。 + * 用于根据预定义的状态码枚举快速构造业务异常。 + * + * @param statusCodeEnum 状态码枚举,包含错误码和对应的描述信息 + */ public BizException(StatusCodeEnum statusCodeEnum) { this.code = statusCodeEnum.getCode(); this.message = statusCodeEnum.getDesc(); diff --git a/aurora-springboot/src/main/java/com/aurora/exception/TaskException.java b/aurora-springboot/src/main/java/com/aurora/exception/TaskException.java index 3022b06..48089be 100644 --- a/aurora-springboot/src/main/java/com/aurora/exception/TaskException.java +++ b/aurora-springboot/src/main/java/com/aurora/exception/TaskException.java @@ -6,20 +6,47 @@ public class TaskException extends Exception { private final Code code; + /** + * 构造方法:接收错误信息和错误码。 + * 不包含导致该异常的底层异常。 + * + * @param msg 错误信息,描述任务异常的具体情况 + * @param code 错误码,表示具体的任务异常类型 + */ public TaskException(String msg, Code code) { this(msg, code, null); } + /** + * 构造方法:接收错误信息、错误码和导致该异常的底层异常。 + * + * @param msg 错误信息,描述任务异常的具体情况 + * @param code 错误码,表示具体的任务异常类型 + * @param exception 导致该异常的底层异常,可以为 null + */ public TaskException(String msg, Code code, Exception exception) { super(msg, exception); this.code = code; } + /** + * 获取错误码。 + * + * @return 错误码枚举实例,表示具体的任务异常类型 + */ public Code getCode() { return code; } + /** + * 错误码枚举,定义了各种任务相关的异常类型。 + */ public enum Code { - TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE + TASK_EXISTS, // 任务已存在 + NO_TASK_EXISTS, // 任务不存在 + TASK_ALREADY_STARTED, // 任务已经启动 + UNKNOWN, // 未知错误 + CONFIG_ERROR, // 配置错误 + TASK_NODE_NOT_AVAILABLE // 任务节点不可用 } } diff --git a/aurora-springboot/src/main/java/com/aurora/handler/AccessDecisionManagerImpl.java b/aurora-springboot/src/main/java/com/aurora/handler/AccessDecisionManagerImpl.java index c4078ff..81edd3f 100644 --- a/aurora-springboot/src/main/java/com/aurora/handler/AccessDecisionManagerImpl.java +++ b/aurora-springboot/src/main/java/com/aurora/handler/AccessDecisionManagerImpl.java @@ -12,29 +12,68 @@ import java.util.Collection; import java.util.List; import java.util.stream.Collectors; +/** + * 自定义的访问决策管理器,实现 Spring Security 的 AccessDecisionManager 接口, + * 用于决定当前认证用户是否具备访问特定资源(如 URL 或方法)所需的权限。 + */ @Component public class AccessDecisionManagerImpl implements AccessDecisionManager { + + /** + * 核心方法:根据当前用户的权限和访问资源所需的权限,决定是否允许访问。 + * 如果用户具备所需权限,则允许访问;否则,抛出 AccessDeniedException 异常。 + * + * @param authentication 当前用户的认证信息,包含用户的权限(Authorities) + * @param object 被保护的资源对象,通常是 FilterInvocation(用于 URL 授权)或其他类型 + * @param configAttributes 访问该资源所需的权限配置集合,每个 ConfigAttribute 代表一个所需的权限 + * @throws AccessDeniedException 如果用户不具备所需的权限,抛出此异常表示访问被拒绝 + * @throws InsufficientAuthenticationException 如果用户认证信息不足以进行权限判断(如未认证),抛出此异常 + */ @Override - public void decide(Authentication authentication, Object o, Collection collection) throws AccessDeniedException, InsufficientAuthenticationException { + public void decide(Authentication authentication, Object object, Collection configAttributes) + throws AccessDeniedException, InsufficientAuthenticationException { + + // 从当前用户的认证信息中提取所有的权限(GrantedAuthority),并将权限字符串收集到一个 List 中 + // GrantedAuthority 是 Spring Security 中表示一个权限或角色的接口,通常权限字符串以 "ROLE_" 开头表示角色 List permissionList = authentication.getAuthorities() .stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.toList()); - for (ConfigAttribute item : collection) { + + // 遍历访问该资源所需的权限配置集合 + for (ConfigAttribute item : configAttributes) { + // 检查用户的权限列表中是否包含当前所需的权限(即 ConfigAttribute 的属性值) if (permissionList.contains(item.getAttribute())) { + // 如果用户具备所需的权限,直接返回,允许访问该资源 return; } } + + // 如果遍历完所有所需的权限后,用户不具备任何一个所需的权限,则抛出 AccessDeniedException 异常,表示权限不足,访问被拒绝 throw new AccessDeniedException("权限不足"); } + /** + * 判断当前的 AccessDecisionManager 是否支持指定的 ConfigAttribute。 + * 这里返回 true,表示支持所有的 ConfigAttribute。 + * + * @param configAttribute 需要判断的 ConfigAttribute 对象 + * @return 始终返回 true,表示支持所有的 ConfigAttribute + */ @Override public boolean supports(ConfigAttribute configAttribute) { return true; } + /** + * 判断当前的 AccessDecisionManager 是否支持指定的安全对象类型(Class)。 + * 这里返回 true,表示支持所有的安全对象类型。 + * + * @param aClass 需要判断的安全对象类型(通常是 FilterInvocation.class 或其他类型) + * @return 始终返回 true,表示支持所有的安全对象类型 + */ @Override public boolean supports(Class aClass) { return true; } -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/handler/AccessDeniedHandlerImpl.java b/aurora-springboot/src/main/java/com/aurora/handler/AccessDeniedHandlerImpl.java index 5b843d0..0a98698 100644 --- a/aurora-springboot/src/main/java/com/aurora/handler/AccessDeniedHandlerImpl.java +++ b/aurora-springboot/src/main/java/com/aurora/handler/AccessDeniedHandlerImpl.java @@ -11,11 +11,30 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +/** + * 自定义的访问被拒绝处理器,实现 Spring Security 的 AccessDeniedHandler 接口, + * 用于在用户访问受保护资源但权限不足时,统一处理并返回一个预定义的 JSON 格式错误响应。 + */ @Component public class AccessDeniedHandlerImpl implements AccessDeniedHandler { + + /** + * 处理用户访问受保护资源但权限不足的情况。 + * 当用户尝试访问需要特定权限的资源但当前不具备这些权限时, + * Spring Security 会调用此方法,返回一个表示“权限不足”的 JSON 响应。 + * + * @param request 当前 HTTP 请求对象,包含请求的详细信息 + * @param response 当前 HTTP 响应对象,用于设置响应内容和状态码 + * @param accessDeniedException 表示访问被拒绝的异常,包含相关的异常信息 + * @throws IOException 如果在写入响应时发生 I/O 错误 + */ @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { + // 设置响应的内容类型为 JSON,通常为 "application/json" response.setContentType(CommonConstant.APPLICATION_JSON); + + // 将一个表示“权限不足”的 ResultVO 对象序列化为 JSON 字符串,并写入 HTTP 响应体 + // ResultVO.fail("权限不足") 创建一个表示操作失败的 ResultVO 实例,其中包含错误信息“权限不足” response.getWriter().write(JSON.toJSONString(ResultVO.fail("权限不足"))); } -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/handler/AuthenticationEntryPointImpl.java b/aurora-springboot/src/main/java/com/aurora/handler/AuthenticationEntryPointImpl.java index 5ebd4bd..7d90af2 100644 --- a/aurora-springboot/src/main/java/com/aurora/handler/AuthenticationEntryPointImpl.java +++ b/aurora-springboot/src/main/java/com/aurora/handler/AuthenticationEntryPointImpl.java @@ -12,11 +12,32 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +/** + * 自定义的认证入口点,实现 Spring Security 的 AuthenticationEntryPoint 接口, + * 用于在用户访问受保护资源但未认证(未登录)时,统一处理并返回一个预定义的 JSON 格式错误响应。 + */ @Component public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { + + /** + * 处理用户未认证(未登录)时尝试访问受保护资源的情况。 + * 当用户尝试访问需要认证的资源但当前未登录时, + * Spring Security 会调用此方法,返回一个表示“用户未登录”的 JSON 响应。 + * + * @param request 当前 HTTP 请求对象,包含请求的详细信息 + * @param response 当前 HTTP 响应对象,用于设置响应内容和状态码 + * @param authException 表示认证异常的异常对象,包含相关的异常信息 + * @throws IOException 如果在写入响应时发生 I/O 错误 + * @throws ServletException 如果在处理请求时发生 Servlet 相关的异常 + */ @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { + // 设置响应的内容类型为 JSON,通常为 "application/json" response.setContentType(CommonConstant.APPLICATION_JSON); + + // 将一个表示“用户未登录”的 ResultVO 对象序列化为 JSON 字符串,并写入 HTTP 响应体 + // ResultVO.fail(40001, "用户未登录") 创建一个表示操作失败的 ResultVO 实例, + // 其中包含错误码 40001 和错误信息“用户未登录” response.getWriter().write(JSON.toJSONString(ResultVO.fail(40001, "用户未登录"))); } -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/handler/AuthenticationSuccessHandlerImpl.java b/aurora-springboot/src/main/java/com/aurora/handler/AuthenticationSuccessHandlerImpl.java index 572838b..2ea33f4 100644 --- a/aurora-springboot/src/main/java/com/aurora/handler/AuthenticationSuccessHandlerImpl.java +++ b/aurora-springboot/src/main/java/com/aurora/handler/AuthenticationSuccessHandlerImpl.java @@ -23,36 +23,87 @@ import java.io.IOException; import java.util.Objects; +/** + * 自定义的认证成功处理器,实现 Spring Security 的 AuthenticationSuccessHandler 接口, + * 用于在用户成功认证后,统一处理并返回一个预定义的 JSON 格式成功响应, + * 同时异步更新用户的最后登录信息。 + */ @Component public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler { + // 自动注入 UserAuthMapper,用于更新用户的最后登录信息 @Autowired private UserAuthMapper userAuthMapper; + // 自动注入 TokenService,用于生成用户的认证令牌(Token) @Autowired private TokenService tokenService; + /** + * 处理用户成功认证后的逻辑。 + * 当用户成功认证后,Spring Security 会调用此方法,返回一个表示成功的 JSON 响应, + * 并异步更新用户的最后登录信息。 + * + * @param request 当前 HTTP 请求对象,包含请求的详细信息 + * @param response 当前 HTTP 响应对象,用于设置响应内容和状态码 + * @param authentication 当前用户的认证信息,包含用户的身份和权限 + * @throws IOException 如果在写入响应时发生 I/O 错误 + * @throws ServletException 如果在处理请求时发生 Servlet 相关的异常 + */ @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { + // 使用 BeanCopyUtil 将 UserUtil 中的 UserDetailsDTO 复制为 UserInfoDTO 对象 + // UserInfoDTO 通常用于返回给客户端,包含用户的基本信息 UserInfoDTO userLoginDTO = BeanCopyUtil.copyObject(UserUtil.getUserDetailsDTO(), UserInfoDTO.class); + + // 检查 authentication 对象是否非空 if (Objects.nonNull(authentication)) { + // 从 authentication 对象中获取 UserDetailsDTO,通常包含用户的详细信息 UserDetailsDTO userDetailsDTO = (UserDetailsDTO) authentication.getPrincipal(); + + // 使用 TokenService 生成用户的认证令牌(Token) String token = tokenService.createToken(userDetailsDTO); + + // 将生成的 Token 设置到 UserInfoDTO 对象中,以便返回给客户端 userLoginDTO.setToken(token); } + + // 设置响应的内容类型为 JSON,通常为 "application/json" response.setContentType(CommonConstant.APPLICATION_JSON); + + // 将一个表示成功的 ResultVO 对象序列化为 JSON 字符串,并写入 HTTP 响应体 + // ResultVO.ok(userLoginDTO) 创建一个表示操作成功的 ResultVO 实例,其中包含用户信息 response.getWriter().write(JSON.toJSONString(ResultVO.ok(userLoginDTO))); + + // 调用异步方法,更新用户的最后登录信息 updateUserInfo(); } + /** + * 异步更新用户的最后登录信息。 + * 该方法使用 @Async 注解,表示该方法将在一个独立的线程中异步执行, + * 不会影响主线程(即用户的请求响应线程)的执行。 + * 该方法更新用户的 IP 地址、IP 来源、最后登录时间等信息。 + */ @Async public void updateUserInfo() { + // 使用 UserUtil 获取当前认证的用户详情 UserAuth userAuth = UserAuth.builder() + // 设置用户的唯一标识 ID .id(UserUtil.getUserDetailsDTO().getId()) + + // 设置用户的 IP 地址,通常从请求中获取 .ipAddress(UserUtil.getUserDetailsDTO().getIpAddress()) + + // 设置用户的 IP 来源,如国家、城市等 .ipSource(UserUtil.getUserDetailsDTO().getIpSource()) + + // 设置用户的最后登录时间,通常为当前时间 .lastLoginTime(UserUtil.getUserDetailsDTO().getLastLoginTime()) .build(); + + // 使用 UserAuthMapper 更新用户认证信息表中的记录 + // 假设 updateById 方法根据用户的 ID 更新对应的记录 userAuthMapper.updateById(userAuth); } -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/handler/ControllerAdviceHandler.java b/aurora-springboot/src/main/java/com/aurora/handler/ControllerAdviceHandler.java index 8a01827..6f3d84a 100644 --- a/aurora-springboot/src/main/java/com/aurora/handler/ControllerAdviceHandler.java +++ b/aurora-springboot/src/main/java/com/aurora/handler/ControllerAdviceHandler.java @@ -10,25 +10,64 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.Objects; - +/** + * 全局异常处理器,使用 @RestControllerAdvice 和 @ExceptionHandler 注解, + * 用于统一捕获和处理应用中抛出的各类异常,并返回标准化的错误响应。 + * 该类能够处理自定义业务异常(BizException)、参数校验异常(MethodArgumentNotValidException) + * 以及其他未捕获的通用异常(Exception)。 + */ @Log4j2 @RestControllerAdvice public class ControllerAdviceHandler { + /** + * 处理自定义业务异常(BizException)。 + * 当应用中抛出 BizException 时,该方法会被调用,返回一个包含错误码和错误信息的失败响应。 + * + * @param e 捕获的 BizException 异常实例,包含错误码和错误信息 + * @return 包含错误码和错误信息的 ResultVO 失败响应 + */ @ExceptionHandler(value = BizException.class) public ResultVO errorHandler(BizException e) { + // 调用 ResultVO.fail 方法,传入 BizException 中的错误码和错误信息,生成一个失败的响应对象 return ResultVO.fail(e.getCode(), e.getMessage()); } + /** + * 处理参数校验异常(MethodArgumentNotValidException)。 + * 当方法参数校验失败时(如使用 @Valid 注解进行参数校验),该方法会被调用, + * 返回一个包含参数校验错误信息的失败响应。 + * + * @param e 捕获的 MethodArgumentNotValidException 异常实例,包含参数校验的错误详情 + * @return 包含参数校验错误码和具体错误信息的 ResultVO 失败响应 + */ @ExceptionHandler(MethodArgumentNotValidException.class) public ResultVO errorHandler(MethodArgumentNotValidException e) { - return ResultVO.fail(StatusCodeEnum.VALID_ERROR.getCode(), Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage()); + // 从异常中获取绑定结果(BindingResult),并提取第一个字段错误(FieldError)的默认错误信息 + // 使用 Objects.requireNonNull 确保 FieldError 不为 null,避免潜在的 NullPointerException + return ResultVO.fail( + StatusCodeEnum.VALID_ERROR.getCode(), // 使用预定义的参数校验错误码 + Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage() // 获取具体的错误信息 + ); } + /** + * 处理其他未捕获的通用异常(Exception)。 + * 当应用中抛出未明确处理的异常时,该方法会被调用, + * 返回一个包含系统错误码和系统错误信息的失败响应。 + * 同时,通过 e.printStackTrace() 打印异常堆栈信息,便于开发人员调试和定位问题。 + * + * @param e 捕获的通用 Exception 异常实例,包含异常的详细信息 + * @return 包含系统错误码和系统错误信息的 ResultVO 失败响应 + */ @ExceptionHandler(value = Exception.class) public ResultVO errorHandler(Exception e) { + // 打印异常堆栈信息到控制台,便于调试和问题定位 e.printStackTrace(); - return ResultVO.fail(StatusCodeEnum.SYSTEM_ERROR.getCode(), StatusCodeEnum.SYSTEM_ERROR.getDesc()); + // 调用 ResultVO.fail 方法,传入系统错误码和系统错误描述,生成一个表示系统错误的失败响应 + return ResultVO.fail( + StatusCodeEnum.SYSTEM_ERROR.getCode(), // 使用预定义的系统错误码 + StatusCodeEnum.SYSTEM_ERROR.getDesc() // 使用预定义的系统错误描述 + ); } - -} +} \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/handler/FilterInvocationSecurityMetadataSourceImpl.java b/aurora-springboot/src/main/java/com/aurora/handler/FilterInvocationSecurityMetadataSourceImpl.java index 2d3202c..e07f35e 100644 --- a/aurora-springboot/src/main/java/com/aurora/handler/FilterInvocationSecurityMetadataSourceImpl.java +++ b/aurora-springboot/src/main/java/com/aurora/handler/FilterInvocationSecurityMetadataSourceImpl.java @@ -15,52 +15,82 @@ import javax.annotation.PostConstruct; import java.util.Collection; import java.util.List; +/** + * 自定义的 FilterInvocationSecurityMetadataSource 实现类, + * 用于定义哪些 URL 需要哪些权限,并在请求到达时提供相应的权限配置信息。 + */ @Component public class FilterInvocationSecurityMetadataSourceImpl implements FilterInvocationSecurityMetadataSource { - + // 自动注入 RoleMapper,用于从数据库中获取资源与角色的映射关系 @Autowired private RoleMapper roleMapper; + // 静态列表,用于缓存资源与角色的映射关系,避免每次请求都查询数据库 private static List resourceRoleList; + /** + * 在类实例化后,通过 @PostConstruct 注解的方法初始化资源与角色的映射关系。 + * 该方法从数据库中加载资源与角色的映射数据,并缓存到 resourceRoleList 中。 + */ @PostConstruct private void loadResourceRoleList() { + // 调用 RoleMapper 的 listResourceRoles 方法,从数据库中获取资源与角色的映射列表 resourceRoleList = roleMapper.listResourceRoles(); } + /** + * 清除缓存的资源与角色映射关系,通常在资源或角色发生变化时调用。 + * 这样下次请求时会重新加载最新的映射关系。 + */ public void clearDataSource() { resourceRoleList = null; } + /** + * 根据传入的 FilterInvocation 对象(即当前的 HTTP 请求), + * 返回该请求所需的权限配置(ConfigAttribute)。 + * 该方法用于在访问决策时,确定用户是否有权限访问请求的资源。 + * + * @param object 传入的对象,通常是 FilterInvocation 类型的 HTTP 请求 + * @return 该请求所需的权限配置列表,如果没有匹配的权限配置,则返回 null + * @throws IllegalArgumentException 如果传入的对象类型不正确 + */ @Override public Collection getAttributes(Object object) throws IllegalArgumentException { + // 检查资源与角色的映射列表是否为空,如果为空,则重新加载 if (CollectionUtils.isEmpty(resourceRoleList)) { this.loadResourceRoleList(); } + + // 将传入的对象强制转换为 FilterInvocation 类型,以获取请求的详细信息 FilterInvocation fi = (FilterInvocation) object; + + // 获取请求的 HTTP 方法(如 GET、POST 等) String method = fi.getRequest().getMethod(); + + // 获取请求的 URL 路径 String url = fi.getRequest().getRequestURI(); + + // 创建 AntPathMatcher 实例,用于匹配 URL 路径 AntPathMatcher antPathMatcher = new AntPathMatcher(); + + // 遍历资源与角色的映射列表,查找与当前请求匹配的权限配置 for (ResourceRoleDTO resourceRoleDTO : resourceRoleList) { + // 使用 AntPathMatcher 匹配请求的 URL 是否符合资源RoleDTO中定义的 URL 模式 + // 同时检查请求的 HTTP 方法是否与资源RoleDTO中定义的方法一致 if (antPathMatcher.match(resourceRoleDTO.getUrl(), url) && resourceRoleDTO.getRequestMethod().equals(method)) { + // 获取该资源所需的角色列表 List roleList = resourceRoleDTO.getRoleList(); + + // 如果角色列表为空,表示该资源对所有用户都是受限的,返回一个表示禁用的 ConfigAttribute if (CollectionUtils.isEmpty(roleList)) { return SecurityConfig.createList("disable"); } + + // 将角色列表转换为 ConfigAttribute 列表,表示该资源需要的角色权限 return SecurityConfig.createList(roleList.toArray(new String[]{})); } } - return null; - } - @Override - public Collection getAllConfigAttributes() { - return null; - } - - @Override - public boolean supports(Class clazz) { - return FilterInvocation.class.isAssignableFrom(clazz); - } -} + // 如果没有找到匹配的权限配置,返回 null,表示该请求不需要任何权限(或未定义权限 \ No newline at end of file diff --git a/aurora-springboot/src/main/java/com/aurora/handler/MyMetaObjectHandler.java b/aurora-springboot/src/main/java/com/aurora/handler/MyMetaObjectHandler.java index 15f8d47..a728565 100644 --- a/aurora-springboot/src/main/java/com/aurora/handler/MyMetaObjectHandler.java +++ b/aurora-springboot/src/main/java/com/aurora/handler/MyMetaObjectHandler.java @@ -8,19 +8,52 @@ import org.springframework.stereotype.Component; import java.time.LocalDateTime; +/** + * 自定义的元对象处理器,实现 MyBatis-Plus 的 MetaObjectHandler 接口, + * 用于自动填充实体类中的创建时间(createTime)和更新时间(updateTime)字段。 + * 该处理器会在插入和更新数据库记录时,自动设置相应的时间字段为当前时间。 + */ @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { + /** + * 在插入数据时自动填充字段。 + * 该方法会在执行插入操作之前被调用,用于设置需要自动填充的字段,如创建时间。 + * + * @param metaObject MyBatis 反射得到的元对象,包含实体类的所有字段信息 + */ @Override public void insertFill(MetaObject metaObject) { + // 记录日志,表示开始执行插入填充操作 log.info("start insert fill ...."); + + // 使用 strictInsertFill 方法,严格填充 "createTime" 字段 + // 参数说明: + // - metaObject: MyBatis 的元对象 + // - "createTime": 需要填充的字段名 + // - LocalDateTime.class: 字段的类型 + // - LocalDateTime.now(): 填充的值,即当前时间 this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); } + /** + * 在更新数据时自动填充字段。 + * 该方法会在执行更新操作之前被调用,用于设置需要自动填充的字段,如更新时间。 + * + * @param metaObject MyBatis 反射得到的元对象,包含实体类的所有字段信息 + */ @Override public void updateFill(MetaObject metaObject) { + // 记录日志,表示开始执行更新填充操作 log.info("start update fill ...."); + + // 使用 strictUpdateFill 方法,严格填充 "updateTime" 字段 + // 参数说明: + // - metaObject: MyBatis 的元对象 + // - "updateTime": 需要填充的字段名 + // - LocalDateTime.class: 字段的类型 + // - LocalDateTime.now(): 填充的值,即当前时间 this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } -} +} \ No newline at end of file