SpringBoot使用在控制层切面注解配置的方式将日志存储在mysql

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: 🍅程序员小王的博客:程序员小王的博客🍅CSDN地址:程序员小王java🍅 欢迎点赞 👍 收藏 ⭐留言 📝🍅 如有编辑错误联系作者,如果有比较好的文章欢迎分享给我,我会取其精华去其糟粕🍅java自学的学习路线:java自学的学习路线

一、前言

我们写完一个项目,运维时,如果出现了bug,我们需要查看控制台的日志,但是那个日志无关方法太多,查找不是很方便,还有就是一个项目上线之后,我们需要记录谁操作了那些功能,以防出现矛盾知道是谁点了这个功能造成的问题,由谁来负责,为了解决这两个问题,我在SpringBoot项目中使用了对控制层切面+注解的方法来实现将日志存储在数据库里面


二、实现详细源码

1、相关依赖

springboot项目的依赖需要,还需要一个aop切面的依赖,mybatis的依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
        <dependencies>
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
           <!-- aop -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>     
       </dependencies>


2、配置文件

在application.properties文件里加这样一条配置

server.port: 8080
spring.aop.auto=true

3、我们首先需要准备mysql表

DROP TABLE IF EXISTS `syslog`;
CREATE TABLE `syslog`  (
  `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
  `username` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名',
  `operation` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '操作',
  `method` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '方法名',
  `createDate` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '日志' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;

SET FOREIGN_KEY_CHECKS = 1;



4、创建数据库表之后就需要写实体类了

package com.sgsg.verification.entity;
/**
 * @author 王恒杰
 * @date 2022/10/25 14:54
 * @Description:
 */
import java.io.Serializable;
public class Syslog implements Serializable {
    private String id;  //我用的UUIT
    private String username; //用户名
    private String operation; //操作
    private String method; //方法名
    private String createDate; //操作时间,这里可以使用Date来实现。我写的有个工具类。用的String接收
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getOperation() {
        return operation;
    }
    public void setOperation(String operation) {
        this.operation = operation;
    }
    public String getMethod() {
        return method;
    }
    public void setMethod(String method) {
        this.method = method;
    }
    public String getCreateDate() {
        return createDate;
    }
    public void setCreateDate(String createDate) {
        this.createDate = createDate;
    }
}

这里如果用lombok的话,只需要一个@Data注解

@Data
public class Syslog implements Serializable {
    private String id;  //我用的全宇宙唯一的子串串、也是直接用的工具类
    private String username; //用户名
    private String operation; //操作
    private String method; //方法名
    private String createDate; //操作时间,这里可以使用Date来实现。我写的有个工具类。用的String接收
}


5、先写dao层和mapper层

(1)dao层

/**
 * @author 王恒杰
 * @date 2022/10/25 14:59
 * @Description:
 */
@Mapper
public interface SysLogMapper {
    /**
     * 写入日志
     * @param syslog
     * @return
     */
    int addLog(Syslog syslog);
}


(2)mapper层

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sgsg.verification.dao.SysLogMapper">
    <insert id="addLog" parameterType="com.sgsg.verification.entity.Syslog">
        insert into syslog(id, username, operation, method, createDate)
        values (#{id}, #{username}, #{operation}, #{method}, #{createDate})
    </insert>
</mapper>


6、写业务层

接口层

import com.sgsg.verification.entity.Syslog;
/**
 * @author 王恒杰
 * @date 2022/10/25 14:58
 * @Description:
 */
public interface SysLogService {
    //写入日志
    int addLog(Syslog syslog);
}


实现类

/**
 * @author 王恒杰
 * @date 2022/10/25 14:58
 * @Description:
 */
@Service
public class SysLogServiceImpl implements SysLogService {
    @Autowired
    public SysLogMapper sysLogMapper;
        //写入日志
        @Override
        public int addLog(Syslog syslog) {
            return sysLogMapper.addLog(syslog);
        }
}


7、切面核心方法

package com.sgsg.verification.aspect;
/**
 * @author 王恒杰
 * @date 2022/10/25 14:57
 * @Description:
 */
import com.auth0.jwt.interfaces.Claim;
import com.sgsg.verification.dao.UserDao;
import com.sgsg.verification.entity.Result;
import com.sgsg.verification.entity.Syslog;
import com.sgsg.verification.entity.UserInfoEntity;
import com.sgsg.verification.log.Mylog;
import com.sgsg.verification.service.SysLogService;
import com.sgsg.verification.service.UserService;
import com.sgsg.verification.utils.JwtUtil;
import com.sgsg.verification.utils.UserInfoUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
/**
 * 系统日志:切面处理类
 */
@Aspect
@Component
public class SysLogAspect {
    @Autowired
    private SysLogService sysLogService;//将数据写入数据库的操作
    @Autowired
    private UserDao userDao;
    @Autowired
    private JwtUtil jwtUtil;
    //定义切点 @Pointcut
    //在注解的位置切入代码
    @Pointcut("@annotation(com.sgsg.verification.log.Mylog ))")
    public void logPoinCut() {
    }
    //切面 配置通知
    @AfterReturning("logPoinCut()")
    public void saveSysLog(JoinPoint joinPoint) {
        System.out.println("切面。。。。。");
        //保存日志
        Syslog sysLog = new Syslog();
        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();
        //获取操作
        Mylog myLog = method.getAnnotation(Mylog.class);
        if (myLog != null) {
            String value = myLog.value();
            sysLog.setOperation(value);//保存获取的操作
        }
        //设置id
        String id = UUID.randomUUID().toString();
        sysLog.setId(id);
        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = method.getName();
        sysLog.setMethod(className + "." + methodName);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
        sysLog.setCreateDate(simpleDateFormat.format(new Date()));
        //获取用户名
        //拿到当前用户的信息、我这里使用的Token。直接从Token中获取当前用户信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        // 从 http 请求头中取出 token
        String token = request.getHeader("authorization");
        // 解析token并获取token中的用户信息
        Map<String, Claim> claims = jwtUtil.verity(token);
        Claim userId = claims.get("userId");
        //获取用户
        UserInfoEntity user = userDao.getInfoById(userId.asInt());
        sysLog.setUsername(user.getCname());
        //调用service保存SysLog实体类到数据库
        sysLogService.addLog(sysLog);
    }
}


8、我们自己定义注解类

package com.sgsg.verification.log;
/**
 * @author 王恒杰
 * @date 2022/10/25 14:56
 * @Description: 自定义注解类
 */
import java.lang.annotation.*;
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented //生成文档
public @interface  Mylog {
    String value() default "";
}

9、在控制层使用我们自定义的注解

package com.sgsg.verification.controller;
import com.sgsg.verification.entity.Result;
import com.sgsg.verification.log.Mylog;
import com.sgsg.verification.service.EnumService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * @author 王恒杰
 * @date 2022/10/6 12:30
 * @Description:
 */
@Slf4j
@RestController
@RequestMapping("/enums")
public class EnumController {
    @Autowired
    private EnumService enumService;
    @Mylog(value = "获取枚举")
    @GetMapping("/selectAll")
    public Result selectAll() {
        return enumService.selectAll();
    }
}




10、启动项目之后我们的日志就存储在数据库里面了


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2天前
|
JavaScript Java 程序员
SpringBoot自动配置及自定义Starter
Java程序员依赖Spring框架简化开发,但复杂的配置文件增加了负担。SpringBoot以“约定大于配置”理念简化了这一过程,通过引入各种Starter并加载默认配置,几乎做到开箱即用。
37 10
SpringBoot自动配置及自定义Starter
|
6天前
|
SQL 关系型数据库 MySQL
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
MySQL事务日志-Undo Log工作原理分析
|
16天前
|
Java Maven Spring
SpringBoot配置跨模块扫描问题解决方案
在分布式项目中,使用Maven进行多模块开发时,某些模块(如xxx-common)没有启动类。如何将这些模块中的类注册为Spring管理的Bean对象?本文通过案例分析,介绍了两种解决方案:常规方案是通过`@SpringBootApplication(scanBasePackages)`指定扫描路径;推荐方案是保持各模块包结构一致(如com.xxx),利用SpringBoot默认扫描规则自动识别其他模块中的组件,简化配置。
SpringBoot配置跨模块扫描问题解决方案
|
2天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
26 8
|
23天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
77 14
|
21天前
|
SQL 存储 关系型数据库
Mysql并发控制和日志
通过深入理解和应用 MySQL 的并发控制和日志管理技术,您可以显著提升数据库系统的效率和稳定性。
94 10
|
17天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
47 3
|
2月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
63 1
SpringBoot入门(7)- 配置热部署devtools工具
|
1月前
|
SQL 存储 缓存
MySQL进阶突击系列(02)一条更新SQL执行过程 | 讲透undoLog、redoLog、binLog日志三宝
本文详细介绍了MySQL中update SQL执行过程涉及的undoLog、redoLog和binLog三种日志的作用及其工作原理,包括它们如何确保数据的一致性和完整性,以及在事务提交过程中各自的角色。同时,文章还探讨了这些日志在故障恢复中的重要性,强调了合理配置相关参数对于提高系统稳定性的必要性。
|
2月前
|
存储 前端开发 JavaScript
springboot中路径默认配置与重定向/转发所存在的域对象
Spring Boot 提供了简便的路径默认配置和强大的重定向/转发机制,通过合理使用这些功能,可以实现灵活的请求处理和数据传递。理解并掌握不同域对象的生命周期和使用场景,是构建高效、健壮 Web 应用的关键。通过上述详细介绍和示例,相信读者能够更好地应用这些知识,优化自己的 Spring Boot 应用。
48 3
下一篇
开通oss服务