• 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.执行流程图解

      

       完美!

  • 相关阅读:
    Spring Boot下的一种导入Excel文件的代码框架
    Spring Boot下的一种导出CSV文件的代码框架
    Spring Boot下的一种导出Excel文件的代码框架
    使用系统参数表,提升系统的灵活性
    折纸效果! Cocos Creator 3.0
    弹性跟随相机!3D入门教程!
    dotnet OpenXML 读取 PPT 主序列进入退出强调动画
    dotnet C# 调用委托的 GetInvocationList 的对象分配
    WPF 下拉框选项做鼠标 Hover 预览效果
    WPF 后台代码做 TranslateTransform 的动画
  • 原文地址:https://www.cnblogs.com/newAndHui/p/11771035.html
Copyright © 2020-2023  润新知