若依框架(RuoYi)是一个基于Spring Boot和Spring Cloud的快速开发平台,其功能丰富且易于扩展。在实际项目中,记录用户行为日志是一项非常重要的功能,它可以帮助我们追踪用户的操作历史、排查问题以及分析系统使用情况。本文将详细介绍如何在若依框架中实现用户行为日志记录方案。
在设计用户行为日志功能时,需要明确以下几点核心需求:
首先,在数据库中创建一张用于存储用户行为日志的表。以下是表结构的设计示例:
CREATE TABLE sys_oper_log (
oper_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
title VARCHAR(50) DEFAULT '' COMMENT '模块标题',
business_type INT(2) DEFAULT 0 COMMENT '业务类型(0其他 1新增 2修改 3删除)',
method VARCHAR(100) DEFAULT '' COMMENT '方法名称',
request_method VARCHAR(10) DEFAULT '' COMMENT '请求方式 GET/POST',
operator_type INT(1) DEFAULT 0 COMMENT '操作类别(0其它 1后台用户 2手机端用户)',
oper_name VARCHAR(50) DEFAULT '' COMMENT '操作人员',
dept_name VARCHAR(50) DEFAULT '' COMMENT '部门名称',
oper_url VARCHAR(255) DEFAULT '' COMMENT '请求URL',
oper_ip VARCHAR(128) DEFAULT '' COMMENT '主机地址',
oper_location VARCHAR(255) DEFAULT '' COMMENT '操作地点',
oper_param VARCHAR(2000) DEFAULT '' COMMENT '请求参数',
json_result VARCHAR(2000) DEFAULT '' COMMENT '返回参数',
status INT(1) DEFAULT 0 COMMENT '操作状态(0正常 1异常)',
error_msg VARCHAR(2000) DEFAULT '' COMMENT '错误消息',
oper_time DATETIME DEFAULT NULL COMMENT '操作时间',
PRIMARY KEY (oper_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='操作日志记录';
为了实现非侵入式的日志记录,可以使用Spring AOP技术拦截目标方法并记录日志。
创建一个自定义注解@OperLog
,用于标记需要记录日志的方法。
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperLog {
String title() default ""; // 日志标题
int businessType() default 0; // 业务类型
}
通过切面类拦截带有@OperLog
注解的方法,并记录日志。
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.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspect {
@Pointcut("@annotation(com.example.annotation.OperLog)")
public void logPointCut() {}
@Around("logPointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
// 记录日志逻辑
saveOperLog(joinPoint, result, endTime - startTime);
return result;
}
private void saveOperLog(ProceedingJoinPoint joinPoint, Object result, long time) {
try {
// 获取方法签名、参数、返回值等信息
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 获取注解信息
OperLog operLog = method.getAnnotation(OperLog.class);
// 构造日志对象
SysOperLog sysOperLog = new SysOperLog();
sysOperLog.setTitle(operLog.title());
sysOperLog.setBusinessType(operLog.businessType());
sysOperLog.setMethod(signature.getName());
sysOperLog.setRequestMethod(joinPoint.getArgs()[0].toString());
sysOperLog.setOperName(getCurrentUserName()); // 获取当前用户
sysOperLog.setOperIp(getRequestIp()); // 获取IP地址
sysOperLog.setOperParam(JSON.toJSONString(joinPoint.getArgs()));
sysOperLog.setJsonResult(JSON.toJSONString(result));
sysOperLog.setStatus(0); // 默认成功
sysOperLog.setOperTime(new Date());
// 异常处理
if (result instanceof Exception) {
sysOperLog.setStatus(1);
sysOperLog.setErrorMsg(ExceptionUtils.getMessage((Exception) result));
}
// 异步保存日志
logService.save(sysOperLog);
} catch (Exception e) {
// 记录日志失败处理
}
}
private String getCurrentUserName() {
// 获取当前登录用户
return SecurityUtils.getUsername();
}
private String getRequestIp() {
// 获取请求IP
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
return IpUtils.getIpAddr(request);
}
}
为了避免日志记录影响主业务流程,建议采用异步方式存储日志。可以通过Spring的@Async
注解实现。
在Spring Boot配置类上添加@EnableAsync
注解。
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync
public class AsyncConfig {
}
在日志服务类中添加异步方法。
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class LogService {
@Async
public void save(SysOperLog operLog) {
// 调用DAO层保存日志
operLogMapper.insertOperLog(operLog);
}
}
在保存日志之前,应对请求参数中的敏感信息进行脱敏处理。例如,手机号码、身份证号等。
private String desensitize(String param) {
if (param.contains("password")) {
param = param.replaceAll("(?<=password=)[^&]*", "******");
}
return param;
}
完成上述实现后,可以在控制器中添加测试接口,并标注@OperLog
注解。
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/hello")
@OperLog(title = "测试接口", businessType = 1)
public String hello() {
return "Hello World!";
}
}
访问该接口后,检查数据库中的sys_oper_log
表是否正确记录了操作日志。
本文详细介绍了在若依框架中实现用户行为日志记录的完整方案,包括数据库表设计、AOP切面实现、异步日志存储以及敏感信息脱敏处理等内容。通过这种方式,我们可以高效地记录和管理用户行为日志,为系统的运维和分析提供有力支持。