spring aop 拦截处理生成日志并保存到数据库

Spring AOP 简介
AOP 即 Aspect Oriented Program 面向切面编程
首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。
所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
所谓的周边功能,比如性能统计,日志,事务管理等等
周边功能在 Spring 的面向切面编程AOP思想里,即被定义为切面
在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发,然后把切面功能和核心业务功能 “编织” 在一起,这就叫AOP
AOP 的目的
AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
AOP 当中的概念:
切入点(Pointcut)
在哪些类,哪些方法上切入(where)
通知(Advice)
在方法执行的什么实际(when:方法前/方法后/方法前后)做什么(what:增强的功能)
切面(Aspect)
切面 = 切入点 + 通知,通俗点就是:在什么时机,什么地方,做什么增强!
织入(Weaving)
把切面加入到对象,并创建出代理对象的过程。(由 Spring 来完成)
AOP 的一个思想:让关注点代码与业务代码分离!
来自 https://www.jianshu.com/p/994027425b44
一、自定义注解
方法上的注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OpLog {

    String name() default "";

    XX value();

}

参数上的注解

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OpLogParam {


    String name() default "";
}

二、切面类

@Aspect
@Component
@Slf4j
public class SystemLogAspect {

    @Autowired
    private XXXDao xx;
    @Autowired
    private SessionService sessionService;

    /**
     * 切入点
     */
    @Pointcut("execution (* com.xx.xx.controller.*.*(..))")
    public  void xxxControllerAspect() {
        throw new UnsupportedOperationException();
    }

    /**
     * 配置后置返回通知,使用在方法aspect()上注册的切入点
     * @param joinPoint JoinPoint
     * @param rvt BaseResponse
     */
    @AfterReturning(value = "xxxControllerAspect()",returning = "rvt")
    public void afterReturn(JoinPoint joinPoint, BaseResponse<Object> rvt){
        try {
            SysOperateLog sysOperateLog = joinPoint(joinPoint);
            if (!BaseResponse.DEFAULT_CODE.equals(rvt.getCode())) {
                xx.setDes("输入: " + xx.getDes() + ",输出非200: " + rvt.getMessage());
            }
            xxxDao.insert(xxx);
        } catch (Exception e) {
            log.error("AOP操作异常: {}",e);
        }
    }
    @AfterThrowing(value = "xxControllerAspect()",throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint,Throwable ex) {
        XX xx = joinPoint(joinPoint);
        xx.setDes("输入: "+xxx.getDes()+",输出异常: "+ex.getMessage());
        xxxDao.insert(sysOperateLog);

    }

    private XXX  joinPoint(JoinPoint joinPoint) {
        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        //获取IP
        String ip = getIp(sra);
        //获取用户名
        String userName = sessionService.getUserName();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //获取方法上的注解
        OpLog opLog = getType(method);
        //给对象赋值
        SysOperateLog sysOperateLog = new SysOperateLog();
        if (opLog!=null){
            //获取方法参数上的注解
            String des = getDes(method, joinPoint);
            xxx.setType(opLog.value().toString());
            xxx.setDes(des);
            xxx.setIp(ip);
            xxx.setUsername(userName);
        }
        return sysOperateLog;
    }
    /**
     * 获取IP
     * @param sra
     * @return
     */
    private String getIp(ServletRequestAttributes sra){
        String ip = "" ;
        if(sra != null){
            HttpServletRequest request=sra.getRequest();
            ip = IPUtil.getIPAddress(request) ;
        }
        return ip;
    }

    /**
     * 方法参数处理
     * @param method
     * @return
     */
    private OpLog getType(Method method){
        //获取方法上的注解
        return method.getDeclaredAnnotation(OpLog.class);
    }

    /**
     * 参数注解处理
     * @param method
     * @param joinPoint
     * @return
     */
    private String getDes(Method method,JoinPoint joinPoint)  {
        Annotation[][] parameterAnnotations= method.getParameterAnnotations();
        //获取所有参数注解返回的是一个二维数组Annotation[][],每个参数上可能有多个注解,是一个一维数组,
        //再根据Object[] args= joinPoint.getArgs();拿到所有的参数,根据指定的下标即可拿到对象的值
        Object[] args= joinPoint.getArgs();
        for (Annotation[] parameterAnnotation: parameterAnnotations) {
            int paramIndex= ArrayUtils.indexOf(parameterAnnotations, parameterAnnotation);
            for (Annotation annotation: parameterAnnotation) {
                if (annotation instanceof OpLogParam){
                    String name = ((OpLogParam) annotation).name();
                    Object paramValue = args[paramIndex];
                    //判断是否是MultipartFile类型
                    Class<?> aClass = paramValue.getClass();
                    if (MultipartFile.class.isAssignableFrom(aClass)){
                        MultipartFile multipartFile = (MultipartFile) paramValue;
                        return name+":"+multipartFile.getOriginalFilename();
                    }
                    return name+":"+paramValue;
                }
            }
        }
        return null;
    }
}

IPUtil类

public class IPUtil {

    private static final String UNKNOWN = "unknown";

    private IPUtil(){}
    public static String getIPAddress(HttpServletRequest request) {
        String ip = null;

        //X-Forwarded-For:Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");
        if (ipAddresses == null || ipAddresses.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddresses)) {
            //Proxy-Client-IP:apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddresses)) {
            //WL-Proxy-Client-IP:weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddresses)) {
            //HTTP_CLIENT_IP:有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddresses)) {
            //X-Real-IP:nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        //还是不能获取到,最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }

        return ip != null && ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip;
    }
}

controller层

@PostMapping(value = "/insert")
@OpLog(name = " ",value = XX.XX)
public void insert(@OpLogParam(name = "设备类型信息") @RequestBody  XX  xx) {
   //获取service层代码
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值