一、思路
利用spring aop 对方法进行增强,获取用户操作的各种信息。
二、自定义注解
/**
* 操作日志注解
*
* @author chenjiayan
* @date 2022/12/21
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OptLog {
/**
* @return 操作类型
*/
String optType() default "";
}
三、编写操作日志
包括实体类,service,mapper等,这里就不再过多赘述
操作日志实体类 仅供参考
/**
* <p>
* 操作日志
* </p>
*
* @author chenjiayan
* @since 2022-12-21
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("tb_operation_log")
@ApiModel(value="OperationLog对象", description="")
public class OperationLog implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "日志id")
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty(value = "操作模块")
private String optModule;
@ApiModelProperty(value = "操作类型")
private String optType;
@ApiModelProperty(value = "操作url")
private String optUrl;
@ApiModelProperty(value = "操作方法")
private String optMethod;
@ApiModelProperty(value = "操作描述")
private String optDesc;
@ApiModelProperty(value = "请求参数")
private String requestParam;
@ApiModelProperty(value = "请求方式")
private String requestMethod;
@ApiModelProperty(value = "返回数据")
private String responseData;
@ApiModelProperty(value = "用户id")
private Integer userId;
@ApiModelProperty(value = "用户昵称")
private String nickname;
@ApiModelProperty(value = "操作ip")
private String ipAddress;
@ApiModelProperty(value = "操作地址")
private String ipSource;
@ApiModelProperty(value = "创建时间")
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@ApiModelProperty(value = "更新时间")
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
service和mapper我就不写了,请自行编写。
四、编写操作日志切面\增强
这里运用到了swagger的相关注解,不了解的可以先去学习一下,比较简单
/**
* 操作日志切面处理
* chenjiayan
* 2022/12/21
*/
@Aspect
@Component
public class OptLongAspect {
@Autowired
private OperationLogService operationLogService = new OperationLogServiceImpl();
/**
* 设置操作日志切入点 记录操作日志 在注解的位置切入代码
*/
@Pointcut("@annotation(fit.littlefox.blog.annotation.OptLog)")
public void optLogPointCut(){
}
@AfterReturning(value = "optLogPointCut()",returning = "keys")
public void saveOptLog(JoinPoint joinPoint,Object keys){
// 获取RequestAttributes
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
// 从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes).resolveReference(RequestAttributes.REFERENCE_REQUEST);
OperationLog operationLog = new OperationLog();
// 从切面织入点处通过反射机制获取织入点处的方法
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 获取切入点所在的方法
Method method = signature.getMethod();
// 获取操作(类上的注解)
Api api = (Api) signature.getDeclaringType().getAnnotation(Api.class);
ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
OptLog optLog = method.getAnnotation(OptLog.class);
// 操作模块
operationLog.setOptModule(api.tags()[0]);
// 操作类型 (增删改查)
operationLog.setOptType(optLog.optType());
// 操作url
operationLog.setOptUrl(request.getRequestURI());
// 操作方法
// 1.获取请求的类名
String className = joinPoint.getTarget().getClass().getName();
// 2.获取请求的方法名
String methodName = method.getName();
methodName = className+"."+methodName;
operationLog.setOptMethod(methodName);
// 操作描述
operationLog.setOptDesc(apiOperation.value());
// 请求参数
operationLog.setRequestParam(JSON.toJSONString(joinPoint.getArgs()));
// 请求方式(GET,POST,PUT...)
operationLog.setRequestMethod(Objects.requireNonNull(request).getMethod());
// 返回数据
operationLog.setResponseData(JSON.toJSONString(keys));
// 操作用户id
operationLog.setUserId(UserUtils.getLoginUser().getId());
// 操作用户昵称
operationLog.setNickname(UserUtils.getLoginUser().getNickname());
// 操作/请求 ip
String ipAddress = IpUtils.getIpAddress(request);
operationLog.setIpAddress(ipAddress);
// 操作/请求 地址
operationLog.setIpSource(IpUtils.getIpSource(ipAddress));
// 保存
operationLogService.save(operationLog);
}
}
五、使用
编写完上述代码,使用就非常简单了,只需在想要记录操作日志的方法上添加自定义的注解(@OptLog(“操作类型”))就行了
例如:
/**
* 添加或修改文章
*
* @param articleVO 文章信息
* @return {@link Result<>}
*/
@OptLog(optType = SAVE_OR_UPDATE)
@ApiOperation(value = "添加或修改文章")
@PostMapping("/admin/articles")
public Result<?> saveOrUpdateArticle(@Valid @RequestBody ArticleVO articleVO) {
articleService.saveOrUpdateArticle(articleVO);
return Result.ok();
}
六、注意
上述代码用到了很多工具类(IpUtils用来解析ip的工具类、UserUtils用来获取用户信息的工具类),这里就不再提供了,可以根据自己的情况编写或者在网上进行搜索。
总之,上述代码只是教你如何使用 spring aop 自定义注解保存操作日志到mysql数据库,具体的很多地方都可以根据自己的情况进行添加修改。