在SpringBoot项目中使用AOP记录功能操作日志

文章目录

  • 一、介绍
  • 二、实现
    • 添加依赖
    • 创建自定义注解@Log
    • SysOperLog
    • 日志切面类
    • 在Controller层方法添加@Log注解
  • 三、运行描述


一、介绍

在最近的项目中,需要实现对一些重要功能操作记录日志的需求。我们可以在需要的方法中增加记录日志的代码,把记录的日志存到数据库中。Spring AOP 的主要功能就是将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来。在项目中,使用的是AOP的后置通知@AfterReturning,每当后台执行完用户的请求后,执行切面中的内容。

二、实现

添加依赖

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-aopartifactId>
    dependency>
     <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjweaverartifactId>
        dependency>

创建自定义注解@Log

package tech.niua.core.annotation;



import tech.niua.core.enums.BusinessType;

import java.lang.annotation.*;

/**
 * 自定义操作日志记录注解
 * 
 */
@Target({ ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Log
{

    public String value() default "";

    /**
     * 功能
     */
    public BusinessType businessType() default BusinessType.OTHER;

}


BusinessType是自己定义的一个业务操作类型的枚举类。

package tech.niua.core.enums;

/**
 * 业务操作类型
 * 
 */
public enum BusinessType
{
    /**
     * 其它
     */
    OTHER,

    /**
     * 新增
     */
    INSERT,

    /**
     * 修改
     */
    UPDATE,

    /**
     * 删除
     */
    DELETE,

    /**
     * 授权
     */
    GRANT,

    /**
     * 导出
     */
    EXPORT,

    /**
     * 导入
     */
    IMPORT,

    /**
     * 强退
     */
    FORCE,

    /**
     * 生成代码
     */
    GENCODE,
    
    /**
     * 清空数据
     */
    CLEAN,
    /**
     * 浏览
     */
    LIST,
    /**
     * 添加或修改
     */
    INSERTORUPDATE,

    /**
     * 根据id查询*/
    FINDBYID
}

SysOperLog

@Data
@TableName("sys_oper_log")
public class SysOperLog {

        @TableId(type = IdType.AUTO)
        @Excel(name = "序号", cellType = Excel.ColumnType.NUMERIC)
        private Long id;

        @Excel(name = "操作")
        private String operation;

        @Excel(name = "业务类型")
        private String businessType;

        @Excel(name = "方法名称")
        private String method;

        @ApiModelProperty(value = "创建时间")
        @TableField(fill = FieldFill.INSERT)
        @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime createTime;

        @TableField(exist=false)
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
        private LocalDateTime createTimeBegin;
        @TableField(exist=false)
        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern="yyyy-MM-dd HH:mm:ss")
        private LocalDateTime createTimeEnd;


        @Excel(name = "操作用户")
        private String operName;

        @Excel(name = "参数")
        private String params;

        @Excel(name = "请求的ip地址")
        private String ip;





}

日志切面类

这里的重点是定义切点以及配置通知。

package tech.niua.admin.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
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.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import tech.niua.admin.operlog.domain.SysOperLog;
import tech.niua.admin.operlog.service.ISysOperLogService;
import tech.niua.auth.utils.JwtUtils;
import tech.niua.common.utils.IpUtil;
import tech.niua.core.annotation.Log;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Aspect
@Component
public class SysLogAspect {
    @Autowired
    private ISysOperLogService sysOperLogService;

    @Resource
    private JwtUtils jwtUtils;

    @Value("${jwt.tokenHead}")
    private String authTokenStart;

    @Autowired
    private HttpServletRequest request;

    @Value("${jwt.header}")
    private String token_header;

    //定义切点 @Pointcut
    //在注解的位置切入代码
    @Pointcut("@annotation(tech.niua.core.annotation.Log)")
    public void logPoinCut() {
    }

    //切面 配置通知
    @AfterReturning("logPoinCut()")
    public void saveSysLog(JoinPoint joinPoint) {
        System.out.println("切面。。。。。");
        //保存日志
        SysOperLog sysOperLog = new SysOperLog();

        //从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取切入点所在的方法
        Method method = signature.getMethod();

        //获取操作
        Log log = method.getAnnotation(Log.class);
        if (log != null) {
            String value = log.value();
            sysOperLog.setOperation(value);//保存获取的操作
        }

        //获取请求的类名
        String className = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = method.getName();
        sysOperLog.setMethod(className + "." + methodName);

        //请求的参数
        Object[] args = joinPoint.getArgs();
        ObjectMapper objectMapper = new ObjectMapper();
        String params = "";
        try{
            //将参数所在的数组转换成json
            params = objectMapper.writeValueAsString(args);
        }catch (Exception e){
            e.printStackTrace();;
        }


        sysOperLog.setParams(params);
        String auth_token = request.getHeader(this.token_header);
        if (StringUtils.isNotEmpty(auth_token) && auth_token.startsWith(authTokenStart)) {
            auth_token = auth_token.substring(authTokenStart.length());
            String username = jwtUtils.getUsernameFromToken(auth_token);
            sysOperLog.setOperName(username);
        } else {
            sysOperLog.setOperName("未授权操作");
        }


        sysOperLog.setIp(IpUtil.getIpAddr(request));

        sysOperLog.setBusinessType(log.businessType().toString());

        sysOperLogService.save(sysOperLog);
    }
}

在Controller层方法添加@Log注解

在SpringBoot项目中使用AOP记录功能操作日志_第1张图片

三、运行描述

每次执行带有@Log注解的操作后,都会在数据库中添加具体的日志。

你可能感兴趣的:(spring,boot,java,spring)