spring Aop切面中的@Before @Around等执行顺序与请求参数统一解码

1.背景

  在实际开发中,我可能会对请求接口做统一日志输出,或者统一参数解析,验签,统一响应加密等,通常会用到aop,实际案例如下

2.代码

package com.qianxingniwo.log;


import com.alibaba.fastjson.JSON;
import com.qianxingniwo.exception.ParamException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @Copyright (C) 
 * @Author: 
 * @Date: 2019/4/8 10:11
 * @Description: <p>
 * aop的几个重要概念
 * 切面(做什么事情,切入后要执行的业务)
 * 切入点(在什么地点,具体到方法,一般使用通配符 或 注解)
 * 切入时机(在什么时候,方法执行前,方法执行后,抛异常的时候)
 * </p>
 */
@Aspect//定义切面
@Component //加入spring容器
@SuppressWarnings("all")//注解主要用在取消一些编译器产生的警告
public class SystemLogAspect {
    /**
     * 本地异常日志记录对象
     */
    private static final Logger log = LoggerFactory.getLogger(SystemLogAspect.class);

    /**
     * Controller层切点
     */
    @Pointcut("execution(* com.qianxingniwo.*.controller.*Controller.*(..))")
    public void controllerAspect() {
    }

    /**
     * 可以修改请求参数,如实际生成中,将请求参数解密等
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("controllerAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("@Around=1=方法执行前" + System.currentTimeMillis());
        Object[] obj = joinPoint.getArgs();
        System.out.println("@Around=2=请求参数" + JSON.toJSONString(obj));
        //  Object obj2 = joinPoint.proceed();
        // System.out.println("@Around=3=方法后" + System.currentTimeMillis() + "--" + obj2);
        //  System.out.println("@Around:被织入的目标对象为:" + joinPoint.getTarget());
        //  System.out.println("@Around:原返回值:" + JSON.toJSONString(obj2) + ",这是返回结果的后缀");
        // JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(obj[0]));
        //通过反射实例化参数对象
        //获取字节码
        Class<?> aClass = obj[0].getClass();
        //实例化对象
        Object instance = aClass.newInstance();
        //获取执行方法 获取父类方法 setDataList
        //Method method = aClass.getDeclaredMethod("put", Object.class);
        Method method = aClass.getSuperclass().getMethod("put", Object.class);


        List<Integer> dataList = new ArrayList<>();
        dataList.add(1);
        dataList.add(2);
        //执行方法
        method.invoke(instance, dataList);
        // jsonObject.put("dataList", dataList);

        obj[0] = instance;
        //obj[0] = MAPPER.writeValueAsString("");
        System.out.println("=====修改参数==========");
        return joinPoint.proceed(obj);
    }

    /**
     * 切入时机
     *
     * @param joinPoint
     * @Description 前置通知  用于拦截Controller层记录用户的操作
     */
    @Before("controllerAspect()")
    public void doBefore(JoinPoint joinPoint) throws ParamException {
        System.out.println("@Before==" + System.currentTimeMillis());
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        Thread.currentThread().setName(UUID.randomUUID().toString().substring(0, 12));
        String params = "";
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            String data = JSON.toJSONString(joinPoint.getArgs()[0]);
            params += data;
        }
        //获取用户请求方法的参数并序列化为JSON格式字符串
        //打印请求内容
        String url = request.getRequestURL().toString();
        log.info("===============请求内容===============");
        log.info("请求地址:" + url);
        log.info("请求方式:" + request.getMethod());
        log.info("请求类方法:" + joinPoint.getSignature());
        log.info("请求类方法参数:" + params);
        log.info("===============请求内容===============");
    }

    @After("controllerAspect()")
    public void After(JoinPoint point) {
        System.out.println("@After==" + System.currentTimeMillis());
       /* System.out.println("@After:模拟释放资源...");
        System.out.println("@After:目标方法为:" +
                point.getSignature().getDeclaringTypeName() +
                "." + point.getSignature().getName());
        System.out.println("@After:参数为:" + Arrays.toString(point.getArgs()));
        System.out.println("@After:被织入的目标对象为:" + point.getTarget());*/
    }


    /**
     * 统一修改响应结果,如加密等
     *
     * @param joinPoint
     * @param o
     * @throws Exception
     */
    @AfterReturning(returning = "o", pointcut = "controllerAspect()")
    public void methodAfterReturing(JoinPoint joinPoint, Object o) throws Exception {
        System.out.println("@AfterReturning==" + System.currentTimeMillis());
        System.out.println("@AfterReturning:模拟日志记录功能...");
        log.info("--------------返回内容----------------");
        log.info("Response内容:" + JSON.toJSONString(o));
        log.info("--------------返回内容----------------");

       /* ResponseMessage responseMessage = (ResponseMessage) o;
        byte[] a = Base64Utils.encode(JSON.toJSONString(o).getBytes());
        responseMessage.setMsg(new String(a ));

        log.info("请求返回值【{}】", object.toString());*/
    }

    @AfterThrowing("controllerAspect()")
    public void AfterThrowing() {
        System.out.println("@AfterThrowing==" + System.currentTimeMillis());
        System.out.println("异常通知....");
    }


}

   执行结果如下:

  

3.执行流程图解

  

4.aop统一处理空字符串转为null的处理

 

package com.common.aop;

import com.alibaba.fastjson.JSON;
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 java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @Copyright (C) 
 * @Author: LI DONG PING
 * @Date: 2020-10-20 11:15
 * @Description:
 */
@Aspect
@Component
@SuppressWarnings("all")
public class ParamAspect {

    /**
     *
     */
    @Pointcut("execution(* com.sys.controller.*Controller.*(..))")
    public void controllerAspect2() {
    }

    @Pointcut("execution(* com.common.base.BaseController.*(..))")
    public void controllerAspect() {
    }


    /**
     * 将空字符串参数设置为null
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("controllerAspect() || controllerAspect2()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] obj = joinPoint.getArgs();
        for (int i = 0; i < obj.length; i++) {
            Object o = obj[i];
            String jsonString = JSON.toJSONString(o);
            Class<?> aClass = o.getClass();
            Field[] fields = aClass.getDeclaredFields();
            for (int j = 0; j < fields.length; j++) {
                String fieldName = fields[j].getName();
                if ("serialVersionUID".equals(fieldName)) {
                    continue;
                }
                Class type = fields[j].getType();
                if (type != String.class) {
                    continue;
                }
                Object value = aClass.getMethod("get" + upperCase(fieldName)).invoke(o);
                if (value != null && "".equals(value.toString())) {
                    Method method = o.getClass().getMethod("set" + upperCase(fieldName), type);
                    //将值设为null
                    method.invoke(o, new Object[]{null});
                }
            }
        }
        return joinPoint.proceed(obj);
    }

    public String upperCase(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }


}

 

完美!

 

posted @ 2019-10-31 14:34  李东平|一线码农  阅读(11520)  评论(0编辑  收藏  举报