前言:在后台管理系统中,我们通常会有一个用户操作日志的模块,方便管理和日常bug排查修复,最常用的就是使用aop切面实现。
1.添加maven依赖,只贴出了aop包,其他缺失的自己添加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2.创建系统操作日志注解类(简单的只需要一个描述属性)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationLog {
String description() default "";
}
3.创建aop切面实现类
@Component
@Aspect
public class OperationLogAspect {
/**
* 日志
*/
private static final Logger logger = LogManager.getLogger(OperationLogAspect.class);
@Autowired
private HttpServletRequest request;
//此处是日志实现service类
@Resource
private SysOperationLogService sysOperationLogService;
//Pointcut里面是刚创建的注解全类名
@Pointcut("@annotation(com.XX.anno.OperationLog)")
public void operationLogPointcut() {
}
//此处可以用before,around,之所以用afterReturning是想把接口的返回结果记录下来
//如果要获取接口返回结果returning = "result"是必须的,入参里也加入Object result
//之所以用Object result类型,是因为怕接口返回值不一致
//我的项目中 是使用自定义的父抽象类ResultResponse 代替Object result
//否则某接口返回类型对应不上,该aop在此接口中不起作用
@AfterReturning(value = "operationLogPointcut()", returning = "result")
public void saveSysOperationLog(JoinPoint joinPoint, ResultResponse result) {
//自定义的系统操作日志实体类
SysOperationLog log=new SysOperationLog();
try {
//joinPoint.getArgs()是入参
log.setInputBody(JSONObject.toJSONString(joinPoint.getArgs()));
//result是返回结果,对返回结果做字符长度限制
String response=JSONObject.toJSONString(result);
if(response.length()>4950){
log.setOputputBody(response.substring(0,4950));
}else{
log.setOputputBody(response);
}
//返回值中自定义的状态,判断接口成功还是失败
log.setStatus(String.valueOf(result.getErrorNo()));
//请求路径,例如/login/adminlogin
log.setApiAddress(request.getRequestURI());
try {
//获取类名,方法名,和注解里的description属性值
Class clazz = joinPoint.getTarget().getClass();
String methodName = joinPoint.getSignature().getName();
Class[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();
Method method = clazz.getMethod(methodName,parameterTypes);
OperationLog anno = method.getAnnotation(OperationLog.class);
log.setDescription(anno.description());
log.setMethod(method.getName());
log.setCreateTime(new Date());
} catch (Exception ex) {
logger.error("获取方法注解失败!");
}
//系统操作日志新增方法
sysOperationLogService.insert(log);
}catch (Exception e){
logger.error("记录系统操作日志失败!"+e.toString());
}
}
}
4.在controller层的方法中添加日志注解
@GetMapping("/findDepartment")
@OperationLog(description = "查询诊所启用的科室")
public ResultResponse<List<Department>> findDepartment() {
}
主要的几个类完成了,至于日志实体类和日志service类,根据需求自己创建就行。