使用AOP写一个简单的日志拦截

发布时间:2023年12月27日

根据AOP写一个简单的日志拦截,即创建一个注解,再对应接口注释即可查看访问的ip等信息,可以进行一些比如拉黑,限流等操作

sql脚本如下

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for log
-- ----------------------------
DROP TABLE IF EXISTS `log`;
CREATE TABLE `log`  (
  `id` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL COMMENT '主键',
  `post_ip` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL COMMENT '请求ip',
  `request_time` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL COMMENT '请求时间',
  `request_name` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL COMMENT '请求路径名称',
  `respone_time` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL COMMENT '响应时间',
  `respone_json` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL COMMENT '请求数据(过大返会提示)',
  `exception` int(3) NULL DEFAULT NULL COMMENT '异常标识',
  `exception_info` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL COMMENT '异常数据(过大返会提示)',
  `request_param` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL COMMENT '请求参数',
  `user_time` datetime NULL DEFAULT NULL COMMENT '当前时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Compact;

-- ----------------------------
-- Records of log
-- ----------------------------

SET FOREIGN_KEY_CHECKS = 1;

先定义类

@Data
public class LogEntity {
    private String id;
    private String postIp;
    private String requestType;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private String requestTime;
    private String requestName;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private String responeTime;
    private String responeJSon;
    //是否有异常1--是2--否
    private Integer exception;
    private String exceptionInfo;
    private String requestParam;
    private Integer userTime;
}

在定义注解

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
}

根据环绕写一个切面

@Slf4j
public class LogAspent {
    @Resource
    LogMapper logMapper;

    //线程安全的日志对象
    ThreadLocal<LogEntity> threadLocal = new ThreadLocal<>();

    /**
     * 定义一个切面
     */
    @Pointcut("annotation(com.example.dabaimao.configuration.Log)")
    public void logPontCut() {
    }

    /**
     * 前置增强
     *
     * @param point
     */
    @Before("logPontCut()")
    public void logBefore(JoinPoint point) {
        LogEntity logEntity = new LogEntity();
        logEntity.setIp(UUID.randomUUID().toString());
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        HttpServletRequest request = requestAttributes.getRequest();
        logEntity.setRequestName(request.getServletPath());
        logEntity.setRequestTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "." + LocalDateTime.now().getNano() / 1000000);
        logEntity.setPostId(IpUtils.getIpAddress(request));
        logEntity.setRequestType(request.getMethod());
        threadLocal.set(logEntity);
    }

    /**
     * 后置增强
     *
     * @param joinPoint
     * @param jsonResult 返回JSON
     */
    @AfterReturning(value = "logPontCut()", returning = "jsonResult")
    public void logAfterReturning(JoinPoint joinPoint, Object jsonResult) {
        LogEntity logEntity = threadLocal.get();
        logEntity.setResponeTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "." + LocalDateTime.now().getNano() / 1000000);
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        HttpServletResponse response = requestAttributes.getResponse();
        StringBuilder param = new StringBuilder();
        for (Object arg : joinPoint.getArgs()) {
            param.append(arg.toString());
        }
        logEntity.setRequestParam(param.toString());
        logEntity.setException(0);
        logEntity.setUserTime(LocalDateTime.now().getNano() / 1000000 - Integer.parseInt(logEntity.getRequestTime().substring(logEntity.getRequestTime().indexOf(".") + 1)));
        if (!Objects.isNull(jsonResult)) {

        } else {
            logEntity.setResponeJSon("无返回值");
        }
        //执行代码logMapper.insert(threadlocal.get())
        //记得remove避免内存泄漏
        threadLocal.remove();
        log.info("接口响应成功");
    }

    /**
     * 异常增强
     *
     * @param joinPoint
     * @param e 异常
     */
    @AfterThrowing(value = "logPontCut()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Exception e) {
        LogEntity logEntity = threadLocal.get();
        if (Objects.isNull(logEntity)) {
            try {
                logEntity.setException(1);
                if (!Objects.isNull(e) && !Objects.isNull(e.getMessage())) {
                    if (e.getMessage().length() > 2000) {
                        logEntity.setExceptionInfo("出现异常,异常过长请查看日志");
                    } else {
                        logEntity.setExceptionInfo(e.getMessage());
                    }
                }
                //执行代码logMapper.insert(threadlocal.get())
                //记得remove避免内存泄漏
                log.error("接口出现异常");
            } catch (Exception exception) {
                log.info("threadLocal出现异常:" + exception.getMessage());
            }
        } else {
            log.error("threadLocal出现异常:threalLocal读取失败");
        }
    }
}

设计一个数据库log表

最后的话加上@Scheduled注解实现几天一清除处理就可以了(也可以实现异步)

参考@Async异步注解的使用-CSDN博客

@Scheduled定时任务的使用_大白猫~的博客-CSDN博客

文章来源:https://blog.csdn.net/m0_69156017/article/details/135234556
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。