【Spring Boot 快速入门】二十、Spring Boot 基于AOP注解实现日志记录功能

简介: 【Spring Boot 快速入门】二十、Spring Boot 基于AOP注解实现日志记录功能

前言


  在很多后台管理系统中,有明确的权限和角色的管控,当然也少不了操作日志的记录。本文将基于Spring 的AOP特性开发一个日志记录功能。下面记录一下整个开发工程


快速开始


  使用Spring的AOP特性,首先了解AOP是什么,AOP在程序开发过程中是指面向切面编程,通过预编译和动态代理实现程序功能。AOP中主要有切点、切面、连接点、目标群、通知、织入方式等。通知类型常用的有前置通知、环绕通知、后置通知等,在日志记录的过程中一般使用环绕通知。具体的AOP的相关概念大家不熟悉的可以去查询一下。


版本信息


  本次Spring Boot 基于AOP注解实现日志记录功能,主要版本信息如下:


Spring Boot 2.3.0.RELEASE
aspectjweaver 1.9.6
maven 3

 

 主要引入的依赖是aspectjweaver,如果aspectjweaver 和Spring Boot 版本不一致,可能会报找不到切点等相关的异常,可以替换位相关版本即可解决。


<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.6</version>
</dependency>


基础信息


  实现日志记录功能,主要是将操作日志记录到数据库中或者搜索引擎中,方便查询。在日志中需要记录操作人、操作时间、请求的参数、请求的ip、请求的连接、操作类型等信息。本次示例的建表SQL如下:


CREATE TABLE `log_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `model` varchar(255) DEFAULT NULL COMMENT '模块',
  `log_type` tinyint(4) DEFAULT NULL COMMENT '类型0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=登录,9=清空数据,10查询',
  `url` varchar(255) DEFAULT NULL COMMENT '请求链接',
  `method` varchar(255) DEFAULT NULL COMMENT '请求方法',
  `class_name` varchar(255) DEFAULT NULL COMMENT '类名',
  `method_name` varchar(255) DEFAULT NULL COMMENT '方法名',
  `params` varchar(500) DEFAULT NULL COMMENT '请求参数',
  `ip` varchar(255) DEFAULT NULL COMMENT 'ip地址',
  `user_id` int(11) DEFAULT NULL COMMENT '操作人id',
  `user_name` varchar(255) DEFAULT NULL COMMENT '操作人',
  `sys_info` varchar(255) DEFAULT NULL COMMENT '系统信息',
  `create_user` varchar(200) CHARACTER SET utf8 DEFAULT NULL COMMENT '创建人',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_user` varchar(200) CHARACTER SET utf8 DEFAULT NULL COMMENT '更新人',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `data_state` tinyint(4) NOT NULL DEFAULT '1' COMMENT '0 删除   1未删除',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

 

 本次将操作类型分为11类包登录、退出、增删改查、导入导出、清空等相关日志操作类别。


@Getter
@AllArgsConstructor
public enum LogTypeEnum {
    /**
     * 0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=登录,9=清空数据,10查询
     * */
    OTHER(0,"其它"),
    ADD(1,"新增"),
    UPDATE(2,"修改"),
    DEL(3,"删除"),
    AUTH(4,"授权"),
    EXPORT(5,"导出"),
    IMPORT(6,"导入"),
    QUIT(7,"强退"),
    GENERATE_CODE(8,"登录"),
    CLEAR(9,"清空"),
    QUERY(10,"查询"),
    ;
    @EnumValue
    private int value;
    private String desc;
}


Log注解


  当数据初始化完成之后,就是编写一个自定义的Log注解。本次使用的注解主要是针对方法进行注解。具体如下:

  • @Target:注解的目标位置,主要可以有接口、类、枚举、字段、方法、构造函数、包等位置。可以根据需要进行配置。日志使用的本次基于方法注解。
  • @Retention:是指注解保留的位置,可以在源码中、类中、运行中。本次日志操作记录肯定是在运行中使用,所以选择RUNTIME。
  • @Documented:字面意思文档,也就是说明该注解将被包含在javadoc中。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log {
    /**
     * 模块
     * */
    String model() default "";
    /**
     * 操作
     * */
    LogTypeEnum logType() default LogTypeEnum.OTHER;
}


LogAspect


  定义一个日志的LogAspect切面。在类中需要使用@Aspect和 @Component指明这是一个切面方法在运行中进行扫描包。需要注意的是这个方法中需要定义切面和通知类型。最后根据注解和请求参数中的信息,查询到操作日志需要的信息。由于本次无需登录直接接口请求,所以操作人和操作id在演示中使用了默认值。本次示例只提取了部分操作日志信息,在项目中需要加入的日志信息多,可以根据需求进行修改。


@Aspect
@Component
public class LogAspect {
    @Resource
    private LogInfoMapper logInfoMapper;
    /**
     * @ClassName logPointCut
     * @Description:切点信息
     * @Author JavaZhan @公众号:Java全栈架构师
     * @Version V1.0
     **/
    @Pointcut("@annotation(com.example.demo.log.Log)")
    public void logPointCut(){
    }
    /**
     * @ClassName aroundForLog
     * @Description:环绕通知
     * @Author JavaZhan @公众号:Java全栈架构师
     * @Version V1.0
     **/
    @Around("logPointCut()")
    public Object aroundForLog(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        Object result = point.proceed();
        saveSmsLog(point);
        return result;
    }
    /**
     * @ClassName saveLogInfo
     * @Description: 保存操作日志
     * @Author JavaZhan @公众号:Java全栈架构师
     * @Version V1.0
     **/
    private void saveLogInfo(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        LogInfo logInfo = new LogInfo();
        logInfo.setClassName(joinPoint.getTarget().getClass().getName());
        logInfo.setMethodName(signature.getName());
        Log log = method.getAnnotation(Log.class);
        if(log != null){
            logInfo.setModel(log.model());
            logInfo.setLogType(log.logType().getValue());
        }
        Object[] args = joinPoint.getArgs();
        try{
            String params = JSONObject.toJSONString(args);
            logInfo.setParams(params);
        }catch (Exception e){
        }
        ServletRequestAttributes servletRequestAttributes =   (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        logInfo.setIp(IpUtils.getIpAddr(request));
        logInfo.setUrl(request.getServletPath());
        logInfo.setMethod(request.getMethod());
        logInfo.setUserId(123);
        logInfo.setUserName("admin");
        logInfo.setCreateTime(new Date());
        logInfo.setDataState(1);
        //保存操作日志
        logInfoMapper.insert(logInfo);
    }
}


测试日志


  本示例将基于常用的接口进行测试。在Controller方法中,我们调用自定义注解,根据方法的实际使用含义指定方法的model信息和操作类型信息即可。


@RequestMapping("user")
@Controller
public class UserController {
    @Resource
    private UserService userService;
    @RequestMapping("getAllUser")
    @ResponseBody
    @Log(model = "查询用户列表",logType = LogTypeEnum.QUERY)
    public List<User> getAllUser(){
        return userService.getAllUser();
    }
    @RequestMapping("getUserById")
    @ResponseBody
    @Log(model = "获取指定用户",logType = LogTypeEnum.QUERY)
    public User getUserById(Integer id ){
        return userService.getById(id);
    }
}


调用接口:http://127.0.0.1:8888/user/getAllUser 返回的数据信息如下。


image.png


查看日志表中,可以看到已经新增一条查询用户列表的日志信息。


image.png


下面访问其他接口:http://127.0.0.1:8888/user/getUserById?id=1 返回的数据信息如下。


image.png


查看日志表中,可以看到已经新增一条获取指定用户的日志信息。


image.png


结语


  好了,以上就是Spring Boot 基于AOP注解实现日志记录功能的示例



相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
目录
相关文章
|
Java 微服务 Spring
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录——使用Logger在项目中打印日志
本文介绍了如何在项目中使用Logger打印日志。通过SLF4J和Logback,可设置不同日志级别(如DEBUG、INFO、WARN、ERROR)并支持占位符输出动态信息。示例代码展示了日志在控制器中的应用,说明了日志配置对问题排查的重要性。附课程源码下载链接供实践参考。
1575 0
|
Prometheus 监控 Java
日志收集和Spring 微服务监控的最佳实践
在微服务架构中,日志记录与监控对系统稳定性、问题排查和性能优化至关重要。本文介绍了在 Spring 微服务中实现高效日志记录与监控的最佳实践,涵盖日志级别选择、结构化日志、集中记录、服务ID跟踪、上下文信息添加、日志轮转,以及使用 Spring Boot Actuator、Micrometer、Prometheus、Grafana、ELK 堆栈等工具进行监控与可视化。通过这些方法,可提升系统的可观测性与运维效率。
1096 1
日志收集和Spring 微服务监控的最佳实践
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
926 2
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
2025 5
|
机器学习/深度学习 XML Java
【spring boot logback】日志logback格式解析
在 Spring Boot 中,Logback 是默认的日志框架,它支持灵活的日志格式配置。通过配置 logback.xml 文件,可以定义日志的输出格式、日志级别、日志文件路径等。
2138 5
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
467 32
|
安全 Java API
Spring Boot 功能模块全解析:构建现代Java应用的技术图谱
Spring Boot不是一个单一的工具,而是一个由众多功能模块组成的生态系统。这些模块可以根据应用需求灵活组合,构建从简单的REST API到复杂的微服务系统,再到现代的AI驱动应用。
1838 8
|
SQL 前端开发 Java
深入理解 Spring Boot 项目中的分页与排序功能
本文深入讲解了在Spring Boot项目中实现分页与排序功能的完整流程。通过实际案例,从Service层接口设计到Mapper层SQL动态生成,再到Controller层参数传递及前端页面交互,逐一剖析每个环节的核心逻辑与实现细节。重点包括分页计算、排序参数校验、动态SQL处理以及前后端联动,确保数据展示高效且安全。适合希望掌握分页排序实现原理的开发者参考学习。
981 4
|
监控 安全 Java
Java 开发中基于 Spring Boot 3.2 框架集成 MQTT 5.0 协议实现消息推送与订阅功能的技术方案解析
本文介绍基于Spring Boot 3.2集成MQTT 5.0的消息推送与订阅技术方案,涵盖核心技术栈选型(Spring Boot、Eclipse Paho、HiveMQ)、项目搭建与配置、消息发布与订阅服务实现,以及在智能家居控制系统中的应用实例。同时,详细探讨了安全增强(TLS/SSL)、性能优化(异步处理与背压控制)、测试监控及生产环境部署方案,为构建高可用、高性能的消息通信系统提供全面指导。附资源下载链接:[https://pan.quark.cn/s/14fcf913bae6](https://pan.quark.cn/s/14fcf913bae6)。
2890 0