前言:

任何一个项目都会有一个用户操作日志(也叫行为日志)的模块,它主要用来记录某个用户做了某个操作,当出现操作失败时,通过日志就可以快速的查找是哪个用户在哪个模块出现了错误,以便于开发人员快速定位问题所在。

实现这一功能一般有两种方法:第一种就是很传统的做法,就是在每个模块进行插入日志的操作(不推荐),这种做法虽然实现了记录用户的操作,但很繁琐而且基本上是重复的工作。

第二种就是使用Spring的AOP来实现记录用户操作,也是推荐的现如今都使用的一种做法。它的优势在于这种记录用户操作的代码独立于其他业务逻辑代码,不仅实现了解耦,而且避免了冗余代码。

具体实现步骤在pom.xml中添加AOP依赖

org.springframework.boot

spring-boot-starter-aop

`设计操作日志记录表

新增日志实体类、dao层 接口

自定义操作日志记录的注解

package com.example.springcloud.aop;

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

* @author lyz

* @title: OperationLog

* @projectName springcloud

* @date 2020/9/23

* @description: 自定义操作日志注解

*/

@Target(ElementType.METHOD)//注解放置的目标位置即方法级别

@Retention(RetentionPolicy.RUNTIME)//注解在哪个阶段执行

@Documented

public @interface OperationLogAnnotation {

String operModul() default ""; // 操作模块

String operType() default ""; // 操作类型

String operDesc() default ""; // 操作说明

}自定义操作日志切面类,该类是将操作日志保存到数据库

package com.example.springcloud.aop;

import com.example.springcloud.dao.OperationLogDao;

import com.example.springcloud.domain.OperationLog;

import com.example.springcloud.utils.IPUtil;

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.RequestAttributes;

import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;

import java.lang.reflect.Method;

import java.sql.Timestamp;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Map;

/**

* @author lyz

* @title: OperationAspect

* @projectName springcloud

* @date 2020/9/23

* @description: 操作日志切面处理类

*/

@Aspect

@Component

public class OperationLogAspect {

@Autowired

OperationLogDao logDao;

private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

/**

* 设置操作日志切入点 在注解的位置切入代码

*/

@Pointcut("@annotation(com.example.springcloud.aop.OperationLogAnnotation)")

public void operLogPoinCut() {

}

@AfterReturning(returning /**

* 记录操作日志

* @param joinPoint 方法的执行点

* @param result 方法返回值

* @throws Throwable

*/ = "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);

try {

//将返回值转换成map集合

Map map = (Map) result;

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());

operationLog.setType(annotation.operType());

operationLog.setDescription(annotation.operDesc());

}

//操作时间

operationLog.setOperationTime(Timestamp.valueOf(sdf.format(new Date())));

//操作用户

operationLog.setUserCode(request.getHeader("userCode"));

//操作IP

operationLog.setIp(IPUtil.getIpAdrress(request));

//返回值信息

operationLog.setResult(map.get("message"));

//保存日志

logDao.save(operationLog);

} catch (Exception e) {

e.printStackTrace();

}

}

}在controller层的某一个方法加入@OperationLogAnnotation 注解

package com.example.springcloud.controller;

import com.example.springcloud.aop.OperationLogAnnotation;

import com.example.springcloud.domain.User;

import com.example.springcloud.service.UserService;

import io.swagger.annotations.Api;

import io.swagger.annotations.ApiOperation;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.HttpRequest;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

import java.util.Map;

/*** @author lyz* @title: UserController* @projectName springcloud* @date 2020/9/12* @description:*/

@Api(tags = "用户表")

@RestController

@RequestMapping("/user")

public class UserController {

@Autowired

UserService userService;

@OperationLogAnnotation(operModul = "用户模块-用户列表",operType = "查询",operDesc = "查询所有用户")

@ApiOperation(value = "查询所有用户",notes = "这是用来查询所有用户列表")

@GetMapping("/users")

public Object findAll(@RequestParam(required = false)String userName,

@RequestParam(required = false)Integer sex,

@RequestParam(required = false, defaultValue = "10") int limit,

@RequestParam(required = false, defaultValue = "0") int offset,

@RequestParam(required = false, defaultValue = "createTime") String sortBy,

@RequestParam(required = false, defaultValue = "DESC") String sortFlag, HttpServletRequest request){

offset=offset/limit;

request.setAttribute("userCode","admin");

return userService.findAll(userName,sex,sortBy,sortFlag,offset,limit);

}

@OperationLogAnnotation(operModul = "用户模块-新增用户",operType = "新增",operDesc = "新增用户")

@PostMapping("/addUser")

@ApiOperation(value = "新增用户",notes = "通过这个方法可以添加新用户")

public Object createUser(@RequestBody Mapmap){

return userService.save(map);

}

}通过swagger或者postmain进行测试,最后在数据库中查看操作日志记录

总结:用户操作日志是AOP最常见的一种业务场景,这里使用了后置通知,当然也可以也可以使用异常通知记录异常信息,方法如上。

原文出处:CSDN

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐