SpringAOP实现日志操作功能

1. 创建一个日志记录表

CREATE TABLE `t_log` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '日志编号',
  `operator` varchar(50) DEFAULT NULL COMMENT '操作人(工号表示)',
  `operate_type` varchar(50) DEFAULT NULL COMMENT '日志类型',
  `operate_object` varchar(100) DEFAULT NULL COMMENT '操作对象',
  `cost_time` int(11) DEFAULT NULL COMMENT '耗时',
  `method` varchar(100) DEFAULT NULL COMMENT '操作的方法',
  `params` text COMMENT '方法的参数',
  `created_time` datetime DEFAULT NULL COMMENT '操作时间',
  `created_by` varchar(50) DEFAULT NULL COMMENT '创建人',
  `is_deleted` tinyint(1) DEFAULT NULL COMMENT '是否删除:0未删除,1已删除',
  `remark` text COMMENT '备注',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=571 DEFAULT CHARSET=utf8;

对应实体类:

@Data
@EqualsAndHashCode(callSuper = false)
@TableName("t_log")
@ApiModel(value="Log对象", description="")
public class LogEntity implements Serializable {

    private static final long serialVersionUID=1L;


    @ApiModelProperty(value = "日志编号")
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    @ApiModelProperty(value = "操作人(工号表示)")
    @TableField("operator")
    private String operator;

    @ApiModelProperty(value = "日志类型")
    @TableField("operate_type")
    private String operateType;

    @ApiModelProperty(value = "操作对象")
    @TableField("operate_object")
    private String operateObject;

    @ApiModelProperty(value = "操作的方法")
    @TableField("method")
    private String method;

    @ApiModelProperty(value = "方法的参数")
    @TableField("params")
    private String params;
    
    @ApiModelProperty(value = "花费时间")
    @TableField("cost_time")
    private Long costTime;
    
    @ApiModelProperty(value = "备注")
    @TableField("remark")
    private String remark;
    
    @ApiModelProperty(value = "创建人")
    @TableField("created_by")
    private String createdBy;
    
    @ApiModelProperty(value = "创建人")
    @TableField("created_time")
    private Date createdTime;
    
    @ApiModelProperty(value = "是否删除")
    @TableField(value = "is_deleted")
    private Integer isDeleted;

}

2. 创建一个数据库操作类

public interface LogMapper extends BaseMapper<LogEntity> {

    /**
     * @Description  分页查询
     * @param
     * @return
     */
    List<LogVo> selectLogPage(LogDto logDto);

    /**
     * @Description  详情查询
     * @param
     * @return
     */
    LogVo selectLog(@Param("id")Integer id);

    /**
     * @Description  增加记录
     * @param
     * @return
     */
    int insertLog(LogEntity entity);

    /**
     * @Description  通过主键修改记录
     * @param
     * @return
     */
    int updateLogByPrimaryKey(LogEntity entity);

    /**
     * @Description  通过主键删除记录
     * @param
     * @return
     */
    int deleteLogByPrimaryKey(LogEntity entity);
    
    /**
     * 
     * @Description: 清理日志(当前日期6个月之前的数据)   
     * @param: @return      
     * @return: int      
     * @throws
     */
    int cleanLog();
    
    /**
     * 
     * @Description: 查询待清理的日志记录   
     * @param: @return      
     * @return: List<LogEntity>      
     * @throws
     */
    List<LogEntity> getCleanLog();
}

3. 创建一个常量类

public class Constant {

    /**
     * 有效
     */
    public static final Integer IS_DELETED_VALID = 0;

    /**
     * 无效
     */
    public static final Integer IS_DELETED_INVALID = 1;
 

    public static final String LOG_OPERATE_TYPE_ADD = "新增";

    public static final String LOG_OPERATE_TYPE_EDIT = "编辑";

    public static final String LOG_OPERATE_OBJECT_COLLECT_TASK = "采集任务";

}

4.创建一个自定义注解类

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiredLog {
    /**
     * 日志内容
     * 
     * @return
     */
    String value() default "";

    /**
     * 日志操作对象
     * 
     */
    String operateObject() default "";
    
    /**
     * 日志操作类型
     *
     */
    String operateType() default "";
}

5. 创建一个aop拦截类

/**
 * 系统日志,切面处理类
 *
 */
@Aspect
@Component
public class LogAspect {
    

 // 数据库操作类LogMapper
    @Autowired
    private LogMapper logMapper;

    @Pointcut("@annotation(com.luox.web.annotation.RequiredLog)")
    public void logPointCut() {

    }


    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        //执行方法
        Object result = point.proceed();
        //执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;

        //保存日志
        saveSysLog(point, time);

        return result;
    }

    private void saveSysLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        LogEntity sysLog = new LogEntity();
        RequiredLog syslog = method.getAnnotation(RequiredLog.class);
        if (syslog != null) {
            //注解上的描述,操作日志内容
            sysLog.setOperateObject(syslog.operateObject());
            sysLog.setOperateType(syslog.operateType());
        }

        //请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");
        
        
        // 获取方法的参数
        Object[] args = joinPoint.getArgs();
        LocalVariableTableParameterNameDiscoverer parameter = new LocalVariableTableParameterNameDiscoverer();
        String[] parameterNames = parameter.getParameterNames(method);
        if (args != null && parameterNames != null) {
          StringBuilder param = new StringBuilder();
          for (int i = 0; i < args.length; i++) {
            param.append(" ").append(parameterNames[i]).append(":").append(args[i]);
          }
          sysLog.setParams(param.toString());
        }

        //获取登录用户信息(这里为了测试给固定值,根据自己系统可动态获取)
        String userId =  "luox1111";
        if (StringUtils.isNotBlank(userId)) {
            sysLog.setOperator(userId); 
            sysLog.setCreatedBy(userId);
        }
        //耗时
        sysLog.setCostTime(time);
        sysLog.setCreatedTime(new Date());
        sysLog.setIsDeleted(Constant.IS_DELETED_VALID);
        //保存系统日志
        logMapper.insert(sysLog);
    }
    
    
    @AfterThrowing(pointcut = "logPointCut()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Throwable ex) {
        // 获取登录用户信息
        String userId =  "luox1111";
        // 如果获取登录用户信息失败则不用记录日志,否则才记录
        if (StringUtils.isNotBlank(userId)) {
             MethodSignature signature = (MethodSignature) joinPoint.getSignature();
                Method method = signature.getMethod();

                LogEntity sysLog = new LogEntity();

                StackTraceElement[] stackTraceElements = ex.getStackTrace();
                String rootExceptionName = ex.getClass().getName();

                StringBuilder resultContent = new StringBuilder("异常类:" + rootExceptionName);

                int count = 0;
                int maxTrace = 3;
                for (StackTraceElement stackTraceElement : stackTraceElements) {
                    if (stackTraceElement.getClassName().contains("com.zt") && count < maxTrace) {
                        resultContent.append("\n出现于").append(stackTraceElement.getClassName())
                                .append("类中的").append(stackTraceElement.getMethodName())
                                .append("方法中 位于该类文件的第").append(stackTraceElement.getLineNumber())
                                .append("行)");
                        count++;
                        if (count == maxTrace) {
                            break;
                        }
                    }
                }


               // sysLog.setExceptionContent(resultContent.toString());

                RequiredLog syslog = method.getAnnotation(RequiredLog.class);


                if (syslog != null) {
                    //注解上的描述,操作日志内容
                    sysLog.setRemark(ex.getMessage());
                    sysLog.setOperateObject(syslog.operateObject());
                    sysLog.setOperateType(syslog.operateType());
                }

                //请求的方法名
                String className = joinPoint.getTarget().getClass().getName();
                String methodName = signature.getName();
                sysLog.setMethod(className + "." + methodName + "()");

               // 获取方法的参数
                Object[] args = joinPoint.getArgs();
                LocalVariableTableParameterNameDiscoverer parameter = new LocalVariableTableParameterNameDiscoverer();
                String[] parameterNames = parameter.getParameterNames(method);
                if (args != null && parameterNames != null) {
                  StringBuilder param = new StringBuilder();
                  for (int i = 0; i < args.length; i++) {
                    param.append(" ").append(parameterNames[i]).append(":").append(args[i]);
                  }
                  sysLog.setParams(param.toString());
                }

                if (StringUtils.isNotBlank(userId)) {
                    sysLog.setOperator(userId); 
                    sysLog.setCreatedBy(userId);
                }
                sysLog.setIsDeleted(Constant.IS_DELETED_VALID);
                sysLog.setCreatedTime(new Date());
                //保存系统日志
                logMapper.insert(sysLog);
        } 
    }
}

4. 创建一个控制器类,通过注解进行日志收集,通过@RequiredLog注解就可以实现日志记录操作

@Api(tags = "任务管理")
@RestController
@RequestMapping("/web/task")
public class TaskController {

    @RequiredLog(value = "创建任务", operateType = Constant.LOG_OPERATE_TYPE_ADD, operateObject = Constant.LOG_OPERATE_OBJECT_COLLECT_TASK)
    @ApiOperation(value = "创建任务", notes = "作者: luox 功能: 创建任务, 增加时不需要传主键id")
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public ResultVo<Boolean> addTask(@RequestBody @Valid CollectDto dto) {
        Boolean result = collectTaskService.addTask(dto);
        return ResultVo.success(result, "创建成功");
    }

}

经过上面几部,在新增任务时就会往日志表了加入新增创建任务的日志记录,如果有新的其他方法也需要引入日志,只需要按照相同操作,在方法上加入@RequiredLog注解,分别对operateType和operateObject进行赋值即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值