一、前言
我們寫完一個項目,運維時,如果出現了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