spring boot自定义注解AOP实现操作日志写入数据库

330 阅读2分钟

“携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

生命无罪,健康万岁,我是laity。

我曾七次鄙视自己的灵魂:

第一次,当它本可进取时,却故作谦卑;

第二次,当它在空虚时,用爱欲来填充;

第三次,在困难和容易之间,它选择了容易;

第四次,它犯了错,却借由别人也会犯错来宽慰自己;

第五次,它自由软弱,却把它认为是生命的坚韧;

第六次,当它鄙夷一张丑恶的嘴脸时,却不知那正是自己面具中的一副;

第七次,它侧身于生活的污泥中,虽不甘心,却又畏首畏尾。

1:创建好要保存的实体类

package com.example.springboot.entity;
 
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
 
import java.util.Date;
 
@Data
@ApiModel("操作日志实体类")
@Accessors(chain = true)
public class OperationLogEntity {
 
    @ApiModelProperty(value="请求记录")
    private String request;
 
    @ApiModelProperty(value="返回记录")
    private String response;
 
    @ApiModelProperty(value="操作人")
    private String logName;
 
    @ApiModelProperty(value="操作记录:1:新增 2:删除  3:修改 ")
    private String type;
 
    @ApiModelProperty(value="操作时间 ")
    private Date createDate;
 
    @ApiModelProperty(value="操作内容描述")
    private String content;
 
    @ApiModelProperty(value="接口名称")
    private String interfaceName;
 
}

二:自定义注解和要接收的字段

package com.example.springboot.annotation;
 
import java.lang.annotation.*;
 
 
/**
 * 用于记录操作日志
 */
@Target(value = ElementType.METHOD)//用于描述方法
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
@Documented
public @interface OperationLog {
 
    //操作类型
    String logType() default "";
 
    //操作记录
    String content() default "";
 
    //操作人
    String operationName() default "";
}

三:编写aop切入

package com.example.springboot.config;
 
import com.alibaba.fastjson.JSON;
import com.example.springboot.annotation.OperationLog;
import com.example.springboot.entity.OperationLogEntity;
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.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
 
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;
 
@Aspect
@Component
public class OperationLogAspect {
 
 
    /**
     * 定义切点
     *
     * @Pointcut 注解的所在路径
     */
    @Pointcut("@annotation(com.example.springboot.annotation.OperationLog)")
    public void logPointCut() {
    }
 
 
    @AfterReturning(value = "logPointCut() && @annotation(logger)", returning = "ret")
    public void saveOperationLog(JoinPoint joinPoint, OperationLog logger, Object ret) throws IOException {
 
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //请求记录
        String s = JSON.toJSONString(joinPoint.getArgs());
        //创建一个操作日志实体类存放此次操作信息
        OperationLogEntity operationLog = new OperationLogEntity();
        //操作人
        operationLog.setLogName(logger.operationName());
        //请求json
        operationLog.setRequest(s);
        //操作内容描述
        operationLog.setContent(logger.content());
        //操作类型
        operationLog.setType(logger.logType());
        //操作时间
        operationLog.setCreateDate(new Date());
        //获取uri
        String requestURI = request.getRequestURI();
        //操作的url
        operationLog.setInterfaceName(requestURI);
        //若有返回结果,封装返回信息
        if (null != ret) {
            //响应内容
            operationLog.setResponse(ret.toString());
        }
        //将操作日志写入数据库
        System.out.println(operationLog);
    }
}

应为我这里没有写保存数据,只把实体类进行了输出。

四:将注解放在方法上

    @ApiOperation(value = "登陆")
    @PostMapping(value = "/login")
    @OperationLog(logType = "sign",operationName = "heqiang",content = "登录")
    public Result login(@RequestBody UserEntity user) {
        if (StringUtils.isNotBlank(user.getUserName()) && StringUtils.isNotBlank(user.getPassword())) {
                    try {
                        Subject subject = SecurityUtils.getSubject();
                        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUserName(), user.getPassword());
                subject.login(usernamePasswordToken);
            } catch (UnknownAccountException e) {
                return Result.error(CodeMsg.USERERROR, "账号不存在");
            } catch (LockedAccountException lock) {
                return Result.error(CodeMsg.USERERROR, "用户被锁定");
            } catch (IncorrectCredentialsException exception) {
                return Result.error(CodeMsg.USERERROR, "密码错误");
            }
            return Result.success("登陆成功");
        }
        return Result.error(CodeMsg.USERERROR, "用户名密码不能为空");
    }

可以看到在调用接口的时候,会进行一个输出操作。

image.png