From 36bb721f82b6b6cc7d36c55d0fa7c299d8d252d9 Mon Sep 17 00:00:00 2001 From: luogw <3132758203@qq.com> Date: Mon, 2 Feb 2026 14:18:20 +0800 Subject: [PATCH] =?UTF-8?q?AOP=E6=B3=A8=E8=A7=A3=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=EF=BC=8C=E8=AE=B0=E5=BD=95=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ProductLineController.java | 2 + .../operation/annotation/OperationLog.java | 16 +++ .../operation/aop/OperationLogAspect.java | 115 ++++++++++++++++++ .../OperationLogApplicationServiceImpl.java | 24 ++++ .../impl/OperationLogApplicationService.java | 10 ++ .../operation/domain/dto/OperationLogDTO.java | 29 +++++ .../domain/entity/OperationLogEntity.java | 49 ++++++++ .../service/OperationLogBaseService.java | 8 ++ .../SaveOperationLogDomainService.java | 10 ++ .../impl/OperationLogBaseServiceImpl.java | 12 ++ .../SaveOperationLogDomainServiceImpl.java | 21 ++++ .../operation/mapper/OperationLogMapper.java | 9 ++ 12 files changed, 305 insertions(+) create mode 100644 src/main/java/com/project/operation/annotation/OperationLog.java create mode 100644 src/main/java/com/project/operation/aop/OperationLogAspect.java create mode 100644 src/main/java/com/project/operation/application/OperationLogApplicationServiceImpl.java create mode 100644 src/main/java/com/project/operation/application/impl/OperationLogApplicationService.java create mode 100644 src/main/java/com/project/operation/domain/dto/OperationLogDTO.java create mode 100644 src/main/java/com/project/operation/domain/entity/OperationLogEntity.java create mode 100644 src/main/java/com/project/operation/domain/service/OperationLogBaseService.java create mode 100644 src/main/java/com/project/operation/domain/service/SaveOperationLogDomainService.java create mode 100644 src/main/java/com/project/operation/domain/service/impl/OperationLogBaseServiceImpl.java create mode 100644 src/main/java/com/project/operation/domain/service/impl/SaveOperationLogDomainServiceImpl.java create mode 100644 src/main/java/com/project/operation/mapper/OperationLogMapper.java diff --git a/src/main/java/com/project/information/controller/ProductLineController.java b/src/main/java/com/project/information/controller/ProductLineController.java index 5867371..f8a69e5 100644 --- a/src/main/java/com/project/information/controller/ProductLineController.java +++ b/src/main/java/com/project/information/controller/ProductLineController.java @@ -5,6 +5,7 @@ import com.project.base.domain.result.Result; import com.project.information.application.ProductLineApplicationService; import com.project.information.domain.dto.ProductLineDTO; import com.project.information.domain.param.ProductLineParam; +import com.project.operation.annotation.OperationLog; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; @@ -29,6 +30,7 @@ public class ProductLineController { } @GetMapping("/treeList") + @OperationLog(module = "查询",description = "查询树形产品线") public Result> treeList(ProductLineParam param) throws Exception { return productLineApplicationService.treeList(param); } diff --git a/src/main/java/com/project/operation/annotation/OperationLog.java b/src/main/java/com/project/operation/annotation/OperationLog.java new file mode 100644 index 0000000..365bc1f --- /dev/null +++ b/src/main/java/com/project/operation/annotation/OperationLog.java @@ -0,0 +1,16 @@ +package com.project.operation.annotation; + +import java.lang.annotation.*; + +/** + * 自定义操作日志注解 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface OperationLog { + //操作模块 + String module() default ""; + //操作描述 + String description() default ""; +} diff --git a/src/main/java/com/project/operation/aop/OperationLogAspect.java b/src/main/java/com/project/operation/aop/OperationLogAspect.java new file mode 100644 index 0000000..293675b --- /dev/null +++ b/src/main/java/com/project/operation/aop/OperationLogAspect.java @@ -0,0 +1,115 @@ +package com.project.operation.aop; + +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.project.base.domain.result.Result; +import com.project.ding.domain.dto.LoginDTO; +import com.project.ding.utils.JwtUtils; +import com.project.operation.annotation.OperationLog; +import com.project.operation.application.impl.OperationLogApplicationService; +import com.project.operation.domain.dto.OperationLogDTO; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.lang.reflect.Method; + +/** + * 操作日志AOP切面 + */ +@Slf4j +@Aspect +@Component +@RequiredArgsConstructor +public class OperationLogAspect { + + @Autowired + private JwtUtils jwtUtils; + @Autowired + private OperationLogApplicationService operationLogApplicationService; + + private final ThreadLocal operationLogDTOThreadLocal = new ThreadLocal<>(); + + //定义切点,拦截所有添加@OperationLog注解的方法 + @Pointcut("@annotation(com.project.operation.annotation.OperationLog)") + public void pointcutOperationLog() {} + + //环绕通知,在方法执行前后拦截,收集日志 + @Around("pointcutOperationLog()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + //获取开始时间 + long startTime = System.currentTimeMillis(); + + OperationLogDTO operationLogDTO = new OperationLogDTO(); + //获取客户端IP和操作用户 + ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (requestAttributes != null) { + HttpServletRequest request = requestAttributes.getRequest(); + operationLogDTO.setClientIp(request.getRemoteAddr()); + + String header = request.getHeader("Authorization"); + if (StringUtils.isNotBlank(header) && header.startsWith("Bearer ")) { + String token = header.substring(7); + String userId = jwtUtils.parseToken(token).getSubject(); + operationLogDTO.setCreatorId(Long.parseLong(userId)); + } + } + + //获取方法信息 + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + // 方法全路径:包名+类名+方法名 + operationLogDTO.setMethod(method.getDeclaringClass().getName() + "." + method.getName()); + + //获取操作信息 + OperationLog annotation = method.getAnnotation(OperationLog.class); + operationLogDTO.setModule(annotation.module()); + operationLogDTO.setDescription(annotation.description()); + + + Object businessResult; + try { + operationLogDTOThreadLocal.set(operationLogDTO); + businessResult = joinPoint.proceed(); + operationLogDTO.setResult(0); + }catch (Exception e){ + operationLogDTO.setResult(1); + operationLogDTO.setException(e.getMessage()); + throw e; + }finally { + operationLogDTO.setCostTime(System.currentTimeMillis() - startTime); + //保存日志 + operationLogApplicationService.saveOperationLog(operationLogDTO); + } + + return businessResult; + } + + @AfterReturning(returning = "result",pointcut = "pointcutOperationLog()") + public void afterReturning(Object result) throws Throwable { + OperationLogDTO operationLogDTO = operationLogDTOThreadLocal.get(); + if (operationLogDTO == null) { + return; // 无上下文,直接返回 + } + try { + //获取当前登陆用户 + if(operationLogDTO.getMethod().contains("getToken") && result instanceof Result){ + LoginDTO data = ((Result) result).getData(); + String userId = jwtUtils.parseToken(data.getToken()).getSubject(); + operationLogDTO.setCreatorId(Long.parseLong(userId)); + } + }finally { + operationLogDTOThreadLocal.remove(); + } + } + +} diff --git a/src/main/java/com/project/operation/application/OperationLogApplicationServiceImpl.java b/src/main/java/com/project/operation/application/OperationLogApplicationServiceImpl.java new file mode 100644 index 0000000..0c4cb67 --- /dev/null +++ b/src/main/java/com/project/operation/application/OperationLogApplicationServiceImpl.java @@ -0,0 +1,24 @@ +package com.project.operation.application; + +import com.project.operation.application.impl.OperationLogApplicationService; +import com.project.operation.domain.dto.OperationLogDTO; +import com.project.operation.domain.service.OperationLogBaseService; +import com.project.operation.domain.service.SaveOperationLogDomainService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class OperationLogApplicationServiceImpl implements OperationLogApplicationService { + + @Autowired + private SaveOperationLogDomainService saveOperationLogDomainService; + + /** + * 保存日志 + */ + @Override + public void saveOperationLog(OperationLogDTO operationLogDTO) { + saveOperationLogDomainService.saveOperationLog(operationLogDTO); + } + +} diff --git a/src/main/java/com/project/operation/application/impl/OperationLogApplicationService.java b/src/main/java/com/project/operation/application/impl/OperationLogApplicationService.java new file mode 100644 index 0000000..b7f5724 --- /dev/null +++ b/src/main/java/com/project/operation/application/impl/OperationLogApplicationService.java @@ -0,0 +1,10 @@ +package com.project.operation.application.impl; + +import com.project.operation.domain.dto.OperationLogDTO; + +public interface OperationLogApplicationService { + /** + * 保存操作日志 + */ + void saveOperationLog(OperationLogDTO operationLogDTO); +} diff --git a/src/main/java/com/project/operation/domain/dto/OperationLogDTO.java b/src/main/java/com/project/operation/domain/dto/OperationLogDTO.java new file mode 100644 index 0000000..d0c9b68 --- /dev/null +++ b/src/main/java/com/project/operation/domain/dto/OperationLogDTO.java @@ -0,0 +1,29 @@ +package com.project.operation.domain.dto; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.project.base.domain.dto.BaseDTO; +import jakarta.persistence.Column; +import jakarta.persistence.Id; +import lombok.Data; +import org.hibernate.annotations.Comment; + +@Data +public class OperationLogDTO extends BaseDTO { + private Long id; + + private String module; + + private String description; + + private Integer result; + + private String method; + + private String exception; + + private Long costTime; + + private String clientIp; +} diff --git a/src/main/java/com/project/operation/domain/entity/OperationLogEntity.java b/src/main/java/com/project/operation/domain/entity/OperationLogEntity.java new file mode 100644 index 0000000..830483d --- /dev/null +++ b/src/main/java/com/project/operation/domain/entity/OperationLogEntity.java @@ -0,0 +1,49 @@ +package com.project.operation.domain.entity; + +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 com.project.base.domain.entity.BaseEntity; +import jakarta.persistence.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.hibernate.annotations.Comment; + +@Data +@Table(name = "evaluator_operation_log") +@Entity +@TableName(value = "evaluator_operation_log") +@EqualsAndHashCode(callSuper = true) +public class OperationLogEntity extends BaseEntity { + @TableId(value = "id" , type = IdType.ASSIGN_ID) + @Id + private Long id; + + @Column(name = "module", columnDefinition = "varchar(255) comment '操作模块'") + private String module; + + @Column(name = "description" , columnDefinition="varchar(255) comment '操作描述'") + private String description; + + /** 操作结果 */ + @Column(name = "result") + @Comment("操作结果,0-成功, 1-失败") + private Integer result; + + @Column(name = "method", columnDefinition="varchar(255) comment '操作方法路径'") + private String method; + + @Column(name = "exception", columnDefinition="varchar(255) comment '异常信息(失败时记录)'") + private String exception; + + /** 操作耗时(毫秒) */ + @Column(name = "cost_time") + @Comment("操作耗时(毫秒)") + @TableField("cost_time") + private Long costTime; + + @Column(name = "client_ip", columnDefinition="varchar(100) comment '客户端IP'") + @TableField("client_ip") + private String clientIp; +} diff --git a/src/main/java/com/project/operation/domain/service/OperationLogBaseService.java b/src/main/java/com/project/operation/domain/service/OperationLogBaseService.java new file mode 100644 index 0000000..24ea56e --- /dev/null +++ b/src/main/java/com/project/operation/domain/service/OperationLogBaseService.java @@ -0,0 +1,8 @@ +package com.project.operation.domain.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.project.operation.domain.dto.OperationLogDTO; +import com.project.operation.domain.entity.OperationLogEntity; + +public interface OperationLogBaseService extends IService { +} diff --git a/src/main/java/com/project/operation/domain/service/SaveOperationLogDomainService.java b/src/main/java/com/project/operation/domain/service/SaveOperationLogDomainService.java new file mode 100644 index 0000000..a5737e2 --- /dev/null +++ b/src/main/java/com/project/operation/domain/service/SaveOperationLogDomainService.java @@ -0,0 +1,10 @@ +package com.project.operation.domain.service; + +import com.project.operation.domain.dto.OperationLogDTO; + +public interface SaveOperationLogDomainService { + /** + * 保存操作日志 + */ + void saveOperationLog(OperationLogDTO operationLogDTO); +} diff --git a/src/main/java/com/project/operation/domain/service/impl/OperationLogBaseServiceImpl.java b/src/main/java/com/project/operation/domain/service/impl/OperationLogBaseServiceImpl.java new file mode 100644 index 0000000..e7d3e62 --- /dev/null +++ b/src/main/java/com/project/operation/domain/service/impl/OperationLogBaseServiceImpl.java @@ -0,0 +1,12 @@ +package com.project.operation.domain.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.project.operation.domain.dto.OperationLogDTO; +import com.project.operation.domain.entity.OperationLogEntity; +import com.project.operation.domain.service.OperationLogBaseService; +import com.project.operation.mapper.OperationLogMapper; +import org.springframework.stereotype.Service; + +@Service +public class OperationLogBaseServiceImpl extends ServiceImpl implements OperationLogBaseService { +} diff --git a/src/main/java/com/project/operation/domain/service/impl/SaveOperationLogDomainServiceImpl.java b/src/main/java/com/project/operation/domain/service/impl/SaveOperationLogDomainServiceImpl.java new file mode 100644 index 0000000..72309f2 --- /dev/null +++ b/src/main/java/com/project/operation/domain/service/impl/SaveOperationLogDomainServiceImpl.java @@ -0,0 +1,21 @@ +package com.project.operation.domain.service.impl; + +import com.project.operation.domain.dto.OperationLogDTO; +import com.project.operation.domain.entity.OperationLogEntity; +import com.project.operation.domain.service.OperationLogBaseService; +import com.project.operation.domain.service.SaveOperationLogDomainService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class SaveOperationLogDomainServiceImpl implements SaveOperationLogDomainService { + + @Autowired + private OperationLogBaseService operationLogBaseService; + + @Override + public void saveOperationLog(OperationLogDTO operationLogDTO) { + OperationLogEntity entity = operationLogDTO.toEntity(OperationLogEntity::new); + operationLogBaseService.save(entity); + } +} diff --git a/src/main/java/com/project/operation/mapper/OperationLogMapper.java b/src/main/java/com/project/operation/mapper/OperationLogMapper.java new file mode 100644 index 0000000..357ee62 --- /dev/null +++ b/src/main/java/com/project/operation/mapper/OperationLogMapper.java @@ -0,0 +1,9 @@ +package com.project.operation.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.project.operation.domain.entity.OperationLogEntity; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface OperationLogMapper extends BaseMapper { +}