Spring boot 使用 AOP做操作记录日志入库

引言:最近项目当中需要对用户的一些重要操作日志记录存入数据库,以便维护查看。因为记录的地方比较多,所有想想可以使用Spring AOP ,这样一次代码开发,在需要的方法添加 自定义注解就好了
如果相同的代码需要重复写两三次以上,就该考虑是不是有更好的办法了

一、引入Spring Boot 的AOP MAVEN依赖

org.springframework.boot spring-boot-starter-aop 2.0.9.RELEASE org.aspectj aspectjrt 1.9.0 eu.bitwalker UserAgentUtils 1.21

二、添加自定义注解

import java.lang.annotation.*;
/**

  • 自定义 操作日志记录 注解
  • 被这个注解注释的方法 都将被OperationAspect 切面
  • 版本 @version 1.0
  • 文件名 OperationInterceptor
  • 创建时间 2019/6/27 18:07
    */

@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationInterceptor {
}

三、编写切点类

注释:因为我的@OperationInterceptor 是加在controller 上,且捕获了所有异常,就没有再写 aop 的异常增强了
package com.eiot.e_view.util.aop;

import com.eiot.e_view.entity.Account;
import com.eiot.e_view.entity.Operation;
import com.eiot.e_view.model.constants.ReturnCodeConstant;
import com.eiot.e_view.model.dto.BaseDataRespDTO;
import com.eiot.e_view.service.IOperationService;
import com.eiot.e_view.util.common.EViewMethod;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
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.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * 操作记录 切面 环绕增强
 * 用来记录部分用户操作的记录
 * Before: 前置通知, 在方法执行之前执行
 * After: 后置通知, 在方法执行之后执行
 * AfterRunning: 返回通知, 在方法返回结果之后执行
 * AfterThrowing: 异常通知, 在方法抛出异常之后
 * Around: 环绕通知, 围绕着方法执行
 * 版本 @version 1.0
 * 文件名 OperationAspect
 * 创建时间 2019/6/27  17:49
 */
@Component
@Aspect
@Slf4j
	public class OperationAspect {
	    @Resource
	    private IOperationService iOperationService;
	
	    //匹配所有添加 了 OperationInterceptor 自定义注解的类
	    @Pointcut("@annotation(com.eiot.e_view.util.aop.OperationInterceptor)")
	    public void executeService() {
	
	    }
	
	    /**
	     * 后置通知, 在方法执行之后执行
	     * ProceedingJoinPoint 类 只能环绕增强使用,其他可以使用JoinPoint
	     * @return
	     */
	    @Around("executeService()")
	    public Object before(ProceedingJoinPoint joinPoint){
	
	        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
	        Operation operation = new Operation();
	
	        Object[] args = joinPoint.getArgs();
	        // 获取
	        Account account = null;
	        for (Object arg : args) {
	            // 获取方法中当前登录用户信息
	            int indexOF = StringUtils.indexOf(arg.toString(),"Account");
	            if(indexOF != -1 ){
	                account =(Account) arg;
	            }
	        }
	
	        Object object = null;
	        try {
	            //获取切点 方法的返回值
	            object=joinPoint.proceed();
	        } catch (Throwable throwable) {
	            throwable.printStackTrace();
	        }
	
	        if(account == null || object == null){
	            log.info("OperationAspect Around获取当前登录用户信息/返回值为null,不记录这条操作");
	            return  object;
	        }
	
	        //获取用户的真实请求ip
	        String url = request.getRequestURI();
	        BaseDataRespDTO baseDataRespDTO =(BaseDataRespDTO)(object);
	        operation.setIp(EViewMethod.getIpAddress(request));
	        operation.setAccountId(account.getId());
	        operation.setCreator(account.getName());
	        operation.setCreateTime(new Date());
	        operation.setUpdateTime(new Date());
	        //获取请求路径的中最后一个 / 的字符串 ,操作类型(insert,update,delete)
	        operation.setName(url.substring(url.lastIndexOf("/")+1));
	        operation.setAccountAction(url);
	        operation.setDetail(baseDataRespDTO.getMeassageInfo());
	        operation.setIsSuccess(baseDataRespDTO.getCode() == ReturnCodeConstant.SUCCESS );
	        operation.setDetail(baseDataRespDTO.getMeassageInfo());
	        operation.setOperationTerrace(EViewMethod.getDeviceType(request));
	        //执行数据库新增
	        iOperationService.insertOperation(operation);
	        return  object;
	    }
    } 

四、验证

Spring boot 使用 AOP做操作记录日志入库_第1张图片
数据库是否有记录
在这里插入图片描述
这样就需要在做操作记录的控制器加上自定义的注解就好了

你可能感兴趣的:(备忘)