自定義注解+AOP實(shí)現(xiàn)操作日志記錄方式
步驟:
- 引入AOP依賴
- 創(chuàng)建操作日志表和實(shí)體類
- 創(chuàng)建自定義注解(用于記錄哪些方法需要記錄日志)
- 創(chuàng)建切面,監(jiān)聽自定義的注解
一.Maven依賴
Swagger也是用來記錄日志的,可加可不加
<!-- AOP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>二.創(chuàng)建日志記錄表和實(shí)體類

create_time和update_time字段在BaseEntity里面,且為自動(dòng)填充
package com.dhp.ets.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* @Description
* @Author dhp
* @create 2025-05-12 10:29
*/
@Data
@TableName(value = "sys_action_log")
public class SysActionLogBean extends BaseEntity{
@TableId
private String id;
/*
操作人
*/
private String userId ;
/*
操作人姓名
*/
private String userName ;
/*
操作類型
*/
private String actionType ;
/*
操作對象
*/
private String actionClass ;
/*
操作方法
*/
private String actionMethod ;
/*
操作參數(shù)
*/
private String actionParams ;
/*
操作時(shí)間
*/
private Date actionTime ;
/*
操作IP
*/
private String actionIp ;
}
三.創(chuàng)建記錄日志自定義注解
該注解的value值用于記錄操作類型是什么,比如新增,修改,刪除.....
/**
* 用于操作日志記錄
*/
@Target(ElementType.METHOD) //該注解用于方法上
@Retention(RetentionPolicy.RUNTIME) //運(yùn)行期間仍然有效,可以在運(yùn)行時(shí)通過反射獲取注解的屬性和值
public @interface SysLog {
/**
* 是否允許為空
* @return
*/
String value() default "";
}四.創(chuàng)建切面類
controller類用Swagger的@Api注解記錄該控制層的所有方法是針對什么的,在方法上用@SysLog自定義注解用于記錄該方法具體做什么的,該切面類用于監(jiān)聽用了@SysLog注解的方法,獲取該方法和類的信息
該切面類沒有記錄人員信息,具體根據(jù)實(shí)際項(xiàng)目來寫入
package com.dhp.utils.syslog;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dhp.ets.entity.SysActionLogBean;
import com.dhp.ets.service.SysActionLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.regex.Pattern;
/**
* 系統(tǒng)日志:切面處理類
*/
@Aspect
@Component
public class SysLogAspect {
private static Logger logger = LoggerFactory.getLogger(SysLogAspect.class);
@Autowired
private SysActionLogService sysActionLogService;
//定義切點(diǎn) @Pointcut
//在注解的位置切入代碼
@Pointcut("@annotation(com.dhp.utils.syslog.SysLog)")
public void logPoinCut() {
logger.info("記錄操作日志");
}
//切面 配置通知
//@AfterReturning("logPoinCut()")
@Before("logPoinCut()")
public void saveSysLog(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
//保存日志
SysActionLogBean sysActionLog = new SysActionLogBean();
//從切面織入點(diǎn)處通過反射機(jī)制獲取織入點(diǎn)處的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//獲取切入點(diǎn)所在的方法
Method method = signature.getMethod();
//獲取操作
SysLog sysLog = method.getAnnotation(SysLog.class);
if (sysLog != null) {
String value = sysLog.value();
sysActionLog.setActionType(value);//保存獲取的操作
}
//獲取請求的類名
String className = joinPoint.getTarget().getClass().getName();
String classChineseName = "";
//獲取類的注解
Annotation[] annotations = joinPoint.getTarget().getClass().getAnnotations();
for(Annotation annotation :annotations){
if(annotation.annotationType().getName().indexOf("io.swagger.annotations.Api")>=0){
//提取中文字符串
classChineseName = getAnnotationDesc(annotation.toString());
}
}
//獲取請求的方法名
String methodName = method.getName();
//處理請求的類名,只保留最后一段 并過濾掉操作日志本身
String classSimpleName ;
String[] classPaths = className.split("\\.");
if(classPaths.length>0){
classSimpleName = classPaths[classPaths.length-1];
}else{
classSimpleName = className;
}
//請求的參數(shù)
Object[] args = joinPoint.getArgs();
//將參數(shù)所在的數(shù)組轉(zhuǎn)換成json
String params = JSON.toJSONString(args);
//處理新增和修改參數(shù),過濾掉不重要的字段
if (methodName.equals("save")) {
JSONArray jsonArray = JSONArray.parseArray(params);
JSONObject jsonObject = JSONObject.parseObject(jsonArray.get(0).toString());
jsonObject.remove("createTime");
jsonObject.remove("updateTime");
if (jsonObject.containsKey("id")) {
methodName = "update";
sysActionLog.setActionType("修改");
}
params = jsonObject.toJSONString();
}
sysActionLog.setActionClass(classSimpleName);
if(classChineseName!=null&&classChineseName.length()>0){
sysActionLog.setActionClass(classChineseName);
}
sysActionLog.setActionMethod(methodName);
sysActionLog.setActionParams(params);
logger.info("操作參數(shù):{}",params);
sysActionLog.setActionTime(new Date());
//獲取用戶名
// if(ShiroUtils.getUser()!=null) {
// sysActionLog.setUserId(ShiroUtils.getUser().getId());
// sysActionLog.setUserName(ShiroUtils.getUser().getUserName());
// }
sysActionLog.setActionIp(getIpAddress(request));
//調(diào)用service保存SysLog實(shí)體類到數(shù)據(jù)庫
sysActionLogService.saveOrUpdate(sysActionLog);
}
public final String getIpAddress(HttpServletRequest request) {
String ipAddress = request.getHeader("x-forwarded-for");
if (ipAddress == null || ipAddress.length() == 0 || "".equalsIgnoreCase(ipAddress)) {
ipAddress = request.getRemoteAddr();
if (ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")) {
//根據(jù)網(wǎng)卡取本機(jī)配置的IP
InetAddress inet = null;
try {
inet = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
logger.error("獲取IP異常", e );
}
if(inet!=null){
ipAddress = inet.getHostAddress();
}
}
}
if (ipAddress != null && ipAddress.length() > 15 && ipAddress.indexOf(',') >= 0) { //"***.***.***.***".length() = 15
ipAddress = ipAddress.substring(0,ipAddress.indexOf(','));
}
return ipAddress;
}
//提取中文字符串
public String getAnnotationDesc(String desc){
String pattern = "[\\u4E00-\\u9FA5]+";
StringBuilder sb = new StringBuilder();
String[] splitStr = desc.split("");
for(String str:splitStr) {
if(Pattern.matches(pattern, str)){
sb = sb.append(str) ;
}
}
return sb.toString();
}
}五.測試
5.1controller類
@Api注解記錄該類的方法是人員管理的方法,@SysLog用于記錄保存操作
/**
* @Author dhp
* @create 2025-02-24 15:07
*/
@Api(description = "人員管理")
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@ApiOperation(value = "保存用戶")
@PostMapping("save")
@SysLog("保存")
public WebResult save(@RequestBody User user){
return userService.saveUsers(user);
}
}5.2 postman測試數(shù)據(jù)

人員表:

操作日志記錄表:

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
淺談SpringBoot項(xiàng)目如何讓前端開發(fā)提高效率(小技巧)
這篇文章主要介紹了淺談SpringBoot項(xiàng)目如何讓前端開發(fā)提高效率(小技巧),主要介紹了Swagger和Nginx提高效率的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04
java 中使用maven shade plugin 打可執(zhí)行Jar包
這篇文章主要介紹了java 中使用maven shade plugin 打可執(zhí)行Jar包的相關(guān)資料,需要的朋友可以參考下2017-05-05
基于mybatis中<include>標(biāo)簽的作用說明
這篇文章主要介紹了基于mybatis中<include>標(biāo)簽的作用說明,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
Spring Boot 中PageHelper 插件使用配置思路詳解
這篇文章主要介紹了Spring Boot 中PageHelper 插件使用配置及實(shí)現(xiàn)思路,通過引入myabtis和pagehelper依賴,在yml中配置mybatis掃描和實(shí)體類,具體實(shí)現(xiàn)方法跟隨小編一起看看吧2021-08-08

