创建数据库表
首先,通过建表语句,创建日志表,这里是mysql的,如果是oracle记得把varchar换成varchar2
CREATE TABLE `diary` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`user_name` varchar(255) DEFAULT NULL COMMENT '用户姓名',
`type` varchar(255) DEFAULT NULL COMMENT '操作类型',
`description` varchar(255) DEFAULT NULL COMMENT '操作描述',
`model` varchar(255) DEFAULT NULL COMMENT '操作模块',
`result` varchar(255) DEFAULT NULL COMMENT '操作结果',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时默认当前时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更改时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户操作日志表'
创建实体类
@Data
@NoArgsConstructor
public class OperationLog {
//自增主键id
private Integer id;
//用户姓名
private String userName;
//操作类型
private String type;
//操作描述
private String description;
//操作模块
private String model;
//操作结果
private String result;
}
创建mapper层和service层
<?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="xxx.OperationLogMapper">
<insert id="insertOperationLog" parameterType="xxx.OperationLog">
insert into diary_list(user_name,type,description,model,result) values (#{userName},#{type},#{description},#{model},#{result})
</insert>
</mapper>
@Repository
public interface OperationLogMapper {
void insertOperationLog(OperationLog log);
}
public interface OperationLogService {
void insertOperationLog(OperationLog log);
}
@Service
public class OperationLogServiceImpl implements OperationLogService{
@Autowired
OperationLogMapper operationLogMapper;
public void insertOperationLog(OperationLog log) {
operationLogMapper.insertOperationLog(log);
}
}
创建自定义注解
@Target(ElementType.METHOD)//注解放置的目标位置即方法级别
@Retention(RetentionPolicy.RUNTIME)//注解在哪个阶段执行
@Documented
public @interface OperationLogAnnotation {
String operModul() default ""; // 操作模块
String operType() default ""; // 操作类型
String operDesc() default ""; // 操作说明
String operResult() default ""; // 操作结果
}
创建切面
@Aspect
@Component
@Slf4j
public class OperationLogAspect {
@Autowired
OperationLogService operationLogService;
private Object[] args;
private String[] argNames;
/**
* 设置操作日志切入点 在注解的位置切入代码
*/
@Pointcut("@annotation(xxx.OperationLogAnnotation)")
public void operLogPoinCut() {
}
//对切点方法进行前置增强,就是在调用切点方法前进行做一些必要的操作,这就成为增强
@Before("operLogPoinCut()")
public void getRes(JoinPoint joinPoint) {
args = joinPoint.getArgs();
argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
}
/**
* 记录操作日志
* @param joinPoint 方法的执行点
* @param result 方法返回值
* @throws Throwable
*/
@AfterReturning(returning = "result", value = "operLogPoinCut()")
public void saveOperLog(JoinPoint joinPoint, Object result) throws Throwable {
// 获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
String token = request.getHeader("token");
String username = JwtUtil.getUsername(token);
try {
OperationLog operationLog = new OperationLog();
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
//获取切入点所在的方法
Method method = signature.getMethod();
//获取操作
OperationLogAnnotation annotation = method.getAnnotation(OperationLogAnnotation.class);
if (annotation != null) {
operationLog.setModel(annotation.operModul());
String operType = annotation.operType();
operationLog.setType(operType);
operationLog.setDescription(annotation.operDesc());
ResultJson resultJson = (ResultJson) result;
if ("查询".equals(operType)) {
if (resultJson.getCode() == ResultCode.SUCCESS.getCode()) {
operationLog.setResult("查询成功");
} else {
operationLog.setResult("查询失败");
}
} else {
String operResult = annotation.operResult();
JSONObject jsonObject = new JSONObject();
for (String s : operResult.split(",")) {
Map<String,Object> map = new HashMap<>();
if (s.contains("[")) {
String s2 = s.split("\\[")[0];
for (int i = 0; i < argNames.length; i++) {
String argName = argNames[i];
if (s2.equals(argName)) {
map.put(s2,args[i]);
}
}
for (String s1 : s.split("\\[")[1].split("\\]")[0].split(" ")) {
Field declaredField = map.get(s2).getClass().getDeclaredField(s1);
declaredField.setAccessible(true);
Object o = declaredField.get(map.get(s2));
jsonObject.put(s1,o);
}
} else {
for (int i = 0; i < argNames.length; i++) {
String argName = argNames[i];
if (s.equals(argName)) {
jsonObject.put(argName,args[i]);
}
}
}
}
operationLog.setResult(jsonObject.toString());
}
}
//操作用户
operationLog.setUserName(username);
//保存日志
operationLogService.insertOperationLog(operationLog);
} catch (Exception e) {
e.printStackTrace();
}
}
}
controller层中加入自定义注解
@OperationLogAnnotation(operModul = "操作模块",operType = "操作类型",operDesc = "操作详情",operResult = "操作结果")
操作结果用逗号分割需要入库的参数,比如
operResult = "id,name,age"
如果入参中有对象的话,可以用[]框住字段,用空格分割
operResult = "id,name,age,demo[id num]"
@Data
@NoArgsConstructor
public class Demo {
private Integer id;
private Integer num;
}