Springboot AOP 自定义注解实现系统日志

一、添加AOP依赖


    org.springframework.boot
    spring-boot-starter-aop

二、AOP切点类

@Slf4j
@Component
@Aspect
@AllArgsConstructor
public class SysLogAspect implements Ordered {

    private final SysLogRepository sysLogRepository;

    private final SmUserQuery smUserQuery;

    private static final ThreadLocal SYS_LOG_THREAD_LOCAL = ThreadLocal.withInitial(SysLog::new);

    /**
     * 通过AOP方式,拦截注解的日志
     **/
    @Pointcut(value = "@annotation(com.huiju.piccre.lfxy.system.annotation.SysLogging)")
    public void logAspect() {
    }

    /**
     * 环绕增强,相当于MethodInterceptor
     **/
    @Around("logAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object res = null;
        long time = System.currentTimeMillis();
        SysLog sysLog = SYS_LOG_THREAD_LOCAL.get();
        try {
            res = joinPoint.proceed();
            time = System.currentTimeMillis() - time;
            return res;
        } catch (Exception ex) {
            sysLog.setOperationStatus("FAILED");
            sysLog.setReturnMsg("操作失败!异常信息:——> " + ex.getMessage());
            throw ex;
        } finally {
            try {
                MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = attributes.getRequest();
                sysLog.setOperator(smUserQuery.currentUserCode());
                sysLog.setMethodName(signature.getDeclaringTypeName() + "." + signature.getName());
                sysLog.setMethodArgs(JSON.toJSONString(joinPoint.getArgs()));
                sysLog.setReturnValue(JSON.toJSONString(res));
                sysLog.setRunningTime(time);
                sysLog.setRequestUrl(request.getRequestURL().toString());
                sysLog.setIpAddr(request.getRemoteAddr());
                sysLog.setOperationTime(DateUtil.getNowDate());
                SysLogging annotation = signature.getMethod().getAnnotation(SysLogging.class);
                if (annotation != null) {
                    sysLog.setOperationType(annotation.operationType().getValue());
                    sysLog.setOperateContent(annotation.operateContent());
                    sysLog.setModuleName(annotation.moduleName());
                }
            } catch (Exception ex) {
                log.error("LogAspect 操作失败:" + ex.getMessage());
                ex.printStackTrace();
            }
        }
    }

    /**
     * 持久化日志数据
     **/
    private void saveSysLog(SysLog sysLog) {
        log.info("记录日志:" + sysLog.toString());
        //持久化日志数据
        sysLogRepository.saveAndFlush(sysLog);
    }

    @Before("logAspect()")
    public void doBeforeAdvice(JoinPoint joinPoint) {
        log.info("进入方法前执行.....");
        SysLog sysLog = SYS_LOG_THREAD_LOCAL.get();
        sysLog.setGid(IdUtils.uuid32());
        sysLog.setOperationStatus("SUCCESS");
        sysLog.setReturnMsg("操作成功!");
    }

    /**
     * 处理完请求,返回内容
     *
     * @param ret
     */
    @AfterReturning(returning = "ret", pointcut = "logAspect()")
    public void doAfterReturning(Object ret) {
        log.info("方法的返回值 : " + ret);
    }

    /**
     * 后置异常通知
     */
    @AfterThrowing("logAspect()")
    public void doAfterThrowing(JoinPoint joinPoint) {
        log.info("方法异常时执行.....");
    }

    /**
     * 后置最终通知,final增强,不管是抛出异常或者正常退出都会执行
     */
    @After("logAspect()")
    public void doAfterAll(JoinPoint joinPoint) {
        log.info("方法最后执行.....");
        //方法执行完成后增加日志
        saveSysLog(SYS_LOG_THREAD_LOCAL.get());
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

三、自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLogging {

    /**
     * 操作类型
     **/
    OperationTypeEnum operationType() default OperationTypeEnum.UNDEFINE;

    /**
     * 执行模块
     **/
    String moduleName() default "";

    /**
     * 操作内容描述
     **/
    String operateContent() default "";

}

四、实体类

@Builder
@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
public class SysLog implements Serializable {
    @Id
    @ApiModelProperty(value = "操作日志id")
    private String gid;
    @ApiModelProperty(value = "操作人")
    private String operator;
    @ApiModelProperty(value = "操作类型")
    private String operationType;
    @ApiModelProperty(value = "执行模块")
    private String moduleName;
    @ApiModelProperty(value = "执行方法")
    private String methodName;
    @ApiModelProperty(value = "执行参数")
    private String methodArgs;
    @ApiModelProperty(value = "返回值")
    private String returnValue;
    @ApiModelProperty(value = "返回消息")
    private String returnMsg;
    @ApiModelProperty(value = "执行时长")
    private long runningTime;
    @ApiModelProperty(value = "操作内容")
    private String operateContent;
    @ApiModelProperty(value = "请求路径")
    private String requestUrl;
    @ApiModelProperty(value = "IP地址")
    private String ipAddr;
    @ApiModelProperty(value = "操作时间")
    private Date operationTime;
    @ApiModelProperty(value = "执行描述(1:执行成功、2:执行失败)")
    private String operationStatus;
}

五、操作类型枚举

public enum OperationTypeEnum {
    /**
     * 操作类型
     */
    UNDEFINE("undefine"),
    DELETE("delete"),
    SELECT("select"),
    UPDATE("update"),
    INSERT("insert");

    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    OperationTypeEnum(String s) {
        this.value = s;
    }
}

六、日志表设计

CREATE TABLE `sys_log` (
  `gid` varchar(32) NOT NULL COMMENT '操作日志id',
  `operator` varchar(32) DEFAULT NULL COMMENT '操作人',
  `operation_type` varchar(10) DEFAULT '' COMMENT '操作类型',
  `running_time` bigint(20) DEFAULT NULL COMMENT '方法执行时间',
  `module_name` varchar(32) DEFAULT NULL COMMENT '执行模块',
  `method_name` varchar(200) DEFAULT NULL COMMENT '执行方法',
  `method_args` text COMMENT '执行参数',
  `return_value` text COMMENT '返回值',
  `return_msg` varchar(640) DEFAULT NULL COMMENT '返回消息',
  `operate_content` varchar(480) DEFAULT NULL COMMENT '操作内容',
  `request_url` varchar(360) DEFAULT NULL COMMENT '请求路径',
  `ip_addr` varchar(200) DEFAULT NULL COMMENT 'IP地址',
  `operation_time` datetime DEFAULT NULL COMMENT '操作时间',
  `operation_status` char(10) DEFAULT NULL COMMENT '执行描述(1:执行成功、2:执行失败)',
  PRIMARY KEY (`gid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

你可能感兴趣的:(Java)