一.前言

由于业务需要,在网上找了很久得到了这两种方式。本文代码偏少,主要讲解一下怎么传,如何接收,也记录一下,以便之后查看。

二.Spring拦截器传递参数到controller

下面是我拦截器中的代码,preHandle中设置变量,然后在controller中得到
1,变量放在request请求域中,request.setAttribute(“getAttribute”, “getAttribute”);
2,变量放在全局Servlet Context中,request.getServletContext().setAttribute(“getServletContext”, “getServletContext”);
3,变量放在request的请求头中,在controller中在到请求头header中得到数据

@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws RRException {
        //把变量放在request请求域中,仅可以被这次请求,即同一个requerst使用
        request.setAttribute("getAttribute", "getAttribute");

        //放在全局的ServletContext中,每一个web应用拥有一个ServletContext,是全局对象,具体请百度
        //把变量放在这里面,在之后什么地方都可以访问
        request.getServletContext().setAttribute("getServletContext", "getServletContext");

        //把自己的变量放在头部
        reflectSetHeader(request, "header", "header");
        return true;
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("拦截器之后输出ServletContext中保存的数据:"+request.getServletContext().getAttribute("getServletContext"));
    }

    //把自己想要的信息设置到header头部,就相当于是在request的请求头部添加一个键值对,保存自己的数据
    private void reflectSetHeader(HttpServletRequest request, String key, String value){
        Class<? extends HttpServletRequest> requestClass = request.getClass();
        try {
            Field request1 = requestClass.getDeclaredField("request");
            request1.setAccessible(true);
            Object o = request1.get(request);
            Field coyoteRequest = o.getClass().getDeclaredField("coyoteRequest");
            coyoteRequest.setAccessible(true);
            Object o1 = coyoteRequest.get(o);
            Field headers = o1.getClass().getDeclaredField("headers");
            headers.setAccessible(true);
            MimeHeaders o2 = (MimeHeaders)headers.get(o1);
            o2.removeHeader(key);
            o2.addValue(key).setString(value);
        } catch (Exception e) {
           e.printStackTrace();
        }
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

下面是我controller中的代码

@GetMapping("/hello")
    public Result hello( String hello){
        System.out.println(hello);
        //得到头部保存的信息
        System.out.println(getHeadToken((ServletRequestAttributes) RequestContextHolder.getRequestAttributes(), "header"));

        //得到servlet中的request
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        System.out.println("request.getAttribute得到数据:"+request.getAttribute("getAttribute"));
        System.out.println("request.getServletContext().getAttribute得到全局数据:"+request.getServletContext().getAttribute("getServletContext"));

        return null;
    }

     public static String getHeadToken(ServletRequestAttributes attributes, String key) {
        /**
         *
         * 功能描述: 得到头部保存的信息,通过key得到value
         *
         * @param: [attributes, key]  attribute 固定(ServletRequestAttributes) RequestContextHolder.getRequestAttributes()   key:为头部保存信息的键子key
         * @return: java.lang.String
         */
        HttpServletRequest request = attributes.getRequest();
        Map<String, String> map = new HashMap<String, String>();
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key1 = (String) headerNames.nextElement();
            String value = request.getHeader(key1);
            map.put(key1, value);
        }
        return map.get(key);
    }

java环绕切面无法获取无返回值结果 spring切面环绕controller_System


看控制台输出,第一个 null,因为controller方法上没有参数传过来

后面的都是从拦截器那边传过来的数据。于是,最后需求实现。

三.Aop切面传递参数到目标方法

切面中的环绕方法,实现切面传递参数到目标方法。

Object o[] = proceedingJoinPoint.getArgs();这句代码就是得到从前端(保存在request中的变量的值)传递到controller中的值。
比如request请求,get方式, http://www.qinjie.xyz/hello?a=1&b=2&c=3; 我controller目标方法接收a,b,c,d,e,f这6个变量值,则上面方法得到的o[]={1,2,3,null,null,null}。有兴趣可以自己测试一下试试。然后我在环绕方法执行目标方法之前替换d = 4,这在controller中就可以接收到a=1,b=2,c=3,d=4,e=null,f=null。
同理,我也可以替换掉a=11,b=22,在controller中就是a=11,b=22 了。
我把关键性代码贴出来。

@Around(value = "InterceptController()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        //得到传递给目标方法的参数值
        Object o[] = proceedingJoinPoint.getArgs();
        //得到目标方法的参数名,得到controller(目标方法)的变量的名字
        String[] paramNames = ((CodeSignature) proceedingJoinPoint
                .getSignature()).getParameterNames();

        }
        return proceedingJoinPoint.proceed(o);//返回执行目标方法,并且把转换修改后的参数值传递到controller(目标方法)
    }

四.总结

  1. aop切面确实好用,降低了代码的耦合性,可以非常方便的在后期增加功能
  2. aop和拦截器都可以进行拦截,相当于都是拦截器
  3. 这样一个需求,在我这边主要是为了降低前端和后端的交互,以前前端需要传递一个参数过来,但是现在不用传递过来了,我直接在拦截器中或aop中进行手动添加参数,传递到controller。
    好像写的有点复杂了,如果大家有没有看懂的,或是有疑问的可以私聊我哟。(_),大家一起加油!加油!(。・∀・)ノ