SpringBoot(四):AOP(自定义注解)记录用户操作日志

/ SpringBoot / 0 条评论 / 468人围观

在SpringBoot项目中,使用AOP配合自定义注解可以方便的实现用户操作的监控。前提是已经整合过了MyBatis。

自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    String value() default "";
}

创建库表和实体

CREATE TABLE `sys_log` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `USERNAME` varchar(50) DEFAULT NULL COMMENT '用户名',
  `OPERATION` varchar(50) DEFAULT NULL COMMENT '用户操作记录',
  `TIME` int(11) DEFAULT NULL COMMENT '执行时间',
  `METHOD` varchar(200) DEFAULT NULL COMMENT '执行方法',
  `PARAMS` varchar(500) DEFAULT NULL COMMENT '方法参数',
  `IP` varchar(64) DEFAULT NULL COMMENT 'ip地址',
  `CREATE_TIME` date DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/**
 * @author 70KG
 * @Title: SysLog
 * @Description: 用户操作日志表
 * @date 2018/10/24下午10:35
 * @From www.nmyswls.com
 */
@Data
public class SysLog implements Serializable {

    private static final long serialVersionUID = 1L;

    private Integer id;

    private String username;

    private String operation;

    private Integer time;

    private String method;

    private String params;

    private String ip;

    private Date createTime;

}

保存日志的接口

public interface SysLogMapper {

    void saveSysLog(SysLog syslog);
    
}
/**
 * @author 70KG
 * @Title: SysLogServiceImpl
 * @Description: 用户日志记录
 * @date 2018/10/24下午10:48
 * @From www.nmyswls.com
 */
@Service
public class SysLogServiceImpl {

    @Autowired
    private SysLogMapper sysLogMapper;

    public void saveSysLog(SysLog syslog){
        sysLogMapper.saveSysLog(syslog);
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.SysLogMapper">

    <insert id="saveSysLog" parameterType="com.example.demo.Entity.pojo.SysLog" useGeneratedKeys="true"
            keyProperty="id">
        INSERT INTO sys_log (id, username, operation,
                             time, method, params,
                             ip, create_time)
        VALUES (
            #{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{operation,jdbcType=INTEGER},
            #{time,jdbcType=INTEGER},
            #{method,jdbcType=VARCHAR}, #{params,jdbcType=VARCHAR}, #{ip,jdbcType=VARCHAR},
            #{createTime,jdbcType=DATE})
    </insert>


</mapper>

切面和切点

/**
 * @author 70KG
 * @Title: LogAspect
 * @Description: 用户切面切点类
 * @date 2018/10/24下午10:52
 * @From www.nmyswls.com
 */
@Aspect// 声明它是一个切面
@Component// 必须将切面作为bean交给spring管理
public class LogAspect {

    @Autowired
    private SysLogServiceImpl sysLogService;

    // 声明切点
    @Pointcut("@annotation(com.example.demo.annotation.Log)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) {
        Object result = null;
        long beginTime = System.currentTimeMillis();
        try {
            // 此处调用的是目标方法
            result = point.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        // 保存日志
        saveLog(point, time);
        return result;
    }

    private void saveLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SysLog sysLog = new SysLog();
        Log logAnnotation = method.getAnnotation(Log.class);
        if (logAnnotation != null) {
            // 获取注解上的描述
            sysLog.setOperation(logAnnotation.value());
        }
        // 请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setMethod(className + "." + methodName + "()");
        // 请求的方法参数值
        Object[] args = joinPoint.getArgs();
        // 请求的方法参数名称
        LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
        // 获取方法的参数列表
        String[] paramNames = u.getParameterNames(method);
        if (args != null && paramNames != null) {
            String params = "";
            for (int i = 0; i < args.length; i++) {
                params += "  " + paramNames[i] + ": " + args[i];
            }
            sysLog.setParams(params);
        }
        // 设置IP地址
        sysLog.setIp("127.0.0.1");
        // 模拟一个用户名
        sysLog.setUsername("70KG");
        sysLog.setTime((int) time);
        sysLog.setCreateTime(new Date());
        // 保存系统日志
        sysLogService.saveSysLog(sysLog);
    }

}

测试

/**
 * @author 70KG
 * @Title: SysLogController
 * @Description: 用户行为日志记录
 * @date 2018/10/24下午11:05
 * @From www.nmyswls.com
 */
@RestController
public class SysLogController {

    @Log("执行方法一")
    @GetMapping("/one")
    public void methodOne(String name) {
    }

    @Log("执行方法二")
    @GetMapping("/two")
    public void methodTwo() throws InterruptedException {
        Thread.sleep(2000);
    }

    @Log("执行方法三")
    @GetMapping("/three")
    public void methodThree(String name, String age) {
    }

}

数据库有结果就ok啦。