项目中常常会出现需要记录系统日志的情况,这时使用自定义注解和切面可以很好地解决这个需求。
自定义注解 - SysLog
定义在方法上的注解,需要指定操作类型还有资源类型。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
/**
* @see indi.zhuyst.skyblog.entity.SysLogDO#type
* @return 操作类型
*/
SysLogTypeEnum type() default SysLogTypeEnum.UNDEFINED;
/**
* @see indi.zhuyst.skyblog.entity.SysLogDO#resource
* @return 资源
*/
String resource() default "";
}
操作类型枚举类 - SysLogTypeEnum
包含了增删改查还有一个默认值的枚举类。
public enum SysLogTypeEnum {
/**
* 未定义
* @see SysLog#type() 默认值
*/
UNDEFINED("未定义"),
/**
* 查询
*/
QUERY("查询"),
/**
* 新增
*/
INSERT("新增"),
/**
* 更新
*/
UPDATE("更新"),
/**
* 删除
*/
DELETE("删除");
@Getter
private String name;
SysLogTypeEnum(String name){
this.name = name;
}
}
切面处理类 - SysLogAspect
以注解了SysLog
的方法作为切面,进行系统日志的生成与保存。
@Aspect
@Component
@Order(-100)
public class SysLogAspect {
@Autowired
private SysLogService sysLogService;
@Pointcut("@annotation(indi.zhuyst.skyblog.annotation.SysLog)")
public void pointCut() {}
@Around("pointCut()")
public Object doAround(ProceedingJoinPoint point) throws Throwable {
Object result = point.proceed();
this.saveLog(point);
return result;
}
/**
* 保存系统日志
* @param point 切面
*/
private void saveLog(ProceedingJoinPoint point) throws JsonProcessingException {
SysLogDO log = new SysLogDO();
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
// 设置操作类型以及信息
SysLog annotation = method.getAnnotation(SysLog.class);
log.setType(annotation.type().getName());
log.setResource(annotation.resource());
// 设置方法名
String className = point.getTarget().getClass().getName();
String methodName = signature.getName();
log.setMethod(className + "." + methodName + "()");
// 设置方法参数
Object[] args = point.getArgs();
log.setParams(JsonUtils.toJsonString(args));
// 设置操作用户ID
SecurityUser user = SecurityUtils.getUser();
log.setUserId(user.getId());
// 设置操作时间
log.setCreateDate(new Date());
log = sysLogService.save(log);
if(log == null){
throw new CommonException("系统日志保存失败");
}
}
}
调用
最后只需要在想要打印系统日志的方法上使用SysLog
便可以了
例子:
/**
* 更新文章
* @param id 文章ID
* @param article 文章对象
* @return 更新后的文章DTO
*/
@PutMapping("/{id}")
@ApiOperation("更新文章")
@PreAuthorize("hasAnyRole('SYS_ADMIN','ADMIN')")
@SysLog(resource = RESOURCE_ARTICLE,type = SysLogTypeEnum.UPDATE)
public Result<ArticleDTO> updateArticle(@ApiParam("文章ID") @PathVariable("id")Integer id,
@ApiParam("文章对象") @Valid @RequestBody ArticleDO article)