1.创建表
CREATE TABLE `t_operate_log` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`project_type` varchar(100) DEFAULT NULL COMMENT '项目类型',
`user_account` varchar(100) DEFAULT NULL COMMENT '操作用户账号',
`username` varchar(100) DEFAULT '' COMMENT '操作用户名',
`operation` varchar(200) DEFAULT '' COMMENT '操作描述',
`method` varchar(500) DEFAULT '' COMMENT '操作方法',
`params` text COMMENT '操作参数',
`ip` varchar(50) DEFAULT '' COMMENT '操作IP地址',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_username` (`username`),
KEY `idx_create_time` (`create_time`)
) ENGINE=InnoDB AUTO_INCREMENT=1749060808100294658 DEFAULT CHARSET=utf8mb4 COMMENT='操作日志表';
2.引入依赖
<!-- 使用mybatis-plus对数据库进行操作-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!-- 日志-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
<version>1.7.25</version>
<scope>compile</scope>
</dependency>
3.创建实体类
package com.remote.domain.pojo;
import lombok.Data;
import java.util.Date;
/**
* @Author: majinzhong
* @Data:2024/1/19
*/
@Data
public class TOperateLog {
private Long id;
private String projectType;
private String userAccount;
private String username;
private String operation;
private String method;
private String params;
private String ip;
private Date createTime;
// 省略 getter 和 setter 方法
}
4.Mapper
package com.remote.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.remote.domain.pojo.TOperateLog;
import org.apache.ibatis.annotations.Mapper;
/**
* @Author: majinzhong
* @Data:2024/1/19
*/
@Mapper
public interface OperateLogMapper extends BaseMapper<TOperateLog> {
}
5.自定义注解
package com.remote.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author: majinzhong
* @Data:2024/1/19
* 自定义操作日志注解
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OperateLog {
/**
* 操作描述,默认为空字符串
* @return String
*/
String value() default "";
}
6.配置aop切面
package com.remote.aop;
/**
* @Author: majinzhong
* @Data:2024/1/19
*/
import javax.servlet.http.HttpServletRequest;
import cn.hutool.json.JSONUtil;
import com.remote.annotation.OperateLog;
import com.remote.domain.pojo.ExperimentInfo;
import com.remote.domain.pojo.TOperateLog;
import com.remote.domain.pojo.UserInfo;
import com.remote.mapper.ExperimentInfoMapper;
import com.remote.mapper.UserInfoMapper;
import com.remote.service.OperateLogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
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.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.Date;
import java.util.List;
@Aspect
@Component
public class OperateLogAspect {
@Autowired
private OperateLogService operateLog;
@Autowired
UserInfoMapper userInfoMapper;
@Autowired
ExperimentInfoMapper experimentInfoMapper;
/**
* 切点
* 针对带有@OperateLog注解的方法进行切面处理
*/
@Pointcut("@annotation(com.remote.annotation.OperateLog)")
public void operateLogAspect() {}
/**
* 环绕通知
* 在方法执行前后进行日志记录
*/
@Around("operateLogAspect()")
public Object operateLog(ProceedingJoinPoint joinPoint) throws Throwable {
// 获取HttpServletRequest
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 获取操作的用户
String accesstoken = request.getHeader("Accesstoken");
String projectType=null;
String userAccount=null;
String username=null;
/**
* 添加逻辑,获取用户信息
*/
if(!StringUtils.isEmpty(userAccount)) {
// 获取操作方式
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String method = signature.getDeclaringTypeName() + "." + signature.getName();
OperateLog logAnnotation = signature.getMethod().getAnnotation(OperateLog.class);
String operation = logAnnotation.value();
// 获取操作参数
JSONObject params = new JSONObject();
Object[] args = joinPoint.getArgs();
String[] parameterNames = signature.getParameterNames();
for (int i = 0; i < args.length; i++) {
params.put(parameterNames[i], JSON.toJSONString(args[i]));
}
// 获取IP地址
String ip = request.getRemoteAddr();
TOperateLog log = new TOperateLog();
log.setProjectType(projectType);
log.setUserAccount(userAccount);
log.setUsername(username);
log.setOperation(operation);
log.setMethod(method);
log.setParams(params.toString());
log.setIp(ip);
log.setCreateTime(new Date());
operateLog.saveLog(log);
}
// 执行方法并记录日志
Object result = joinPoint.proceed();
return result;
}
}
7.在想要记录用户操作的接口上添加@OperateLog("用户请求量增加接口")就可以了
8.执行之后数据库中的记录如下图
补充:(待优化)因为接口中有上传或者下载文件的接口,但是表中存储的入参和返回值都是字符串,所以会存在上传或者下载接口时的报错