【轉載】 spring 利用註解類添加日誌到mysql

一、前言

我們寫完一個項目,運維時,如果出現了bug,我們需要查看控制檯的日誌,但是那個日誌無關方法太多,查找不是很方便,還有就是一個項目上線之後,我們需要記錄誰操作了那些功能,以防出現矛盾知道是誰點了這個功能造成的問題,由誰來負責,爲了解決這兩個問題,我在SpringBoot項目中使用了對控制層切面+註解的方法來實現將日誌存儲在數據庫裏面

核心邏輯:

  1、創建註解類 Mylog ——用以在其他controller類的方法上添加註解

     如: @Mylog(value = "獲取枚舉")

  2、創建切面類SysLogAspect——實現具體切入點方法

二、實現詳細源碼

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;

 

 

 

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、啓動項目之後我們的日誌就存儲在數據庫裏面了

 

 

 

 

轉載網址:https://www.lmlphp.com/user/613733/article/item/10733391

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章