• HttpServletRequest请求流只能读取一次的问题


    问题当使用拦截器Interceptor的时候在中从request.getInputStream()后,controller将接收不到对应的参数,因为 请求流只能读取一次

    下面介绍处理方式

    我们可以利用HttpServletRequestWrapper来包装HttpServletRequest,将请求体中的流copy一份,覆写getInputStream()和getReader()方法供外部使用,同时自己定义一个getRequestBody()方法,用于直接获取Json参数。每次调用覆写后的getInputStream()方法都是从复制出来的二进制数组中进行获取,这个二进制数组在对象存在期间一直存在,这样就实现了流的重复读取。
     1、增强 requestwrapper

    package com.multiplethread.multiplethread.selffilter;
    
    import org.springframework.util.StreamUtils;
    
    import javax.servlet.ReadListener;
    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletRequestWrapper;
    import java.io.BufferedReader;
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    public class RequestWrapper extends HttpServletRequestWrapper {
        private final byte[] requestBody;
    
    
        /**
         * Constructs a request object wrapping the given request.
         *
         * @param request The request to wrap
         * @throws IllegalArgumentException if the request is null
         */
        public RequestWrapper(HttpServletRequest request)  throws IOException {
            super(request);
            requestBody =  StreamUtils.copyToByteArray(request.getInputStream());
        }
    
        @Override
        public ServletInputStream getInputStream() throws IOException {
            final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(requestBody);
            return new ServletInputStream() {
                public boolean isFinished() {
                    return false;
                }
                public boolean isReady() {
                    return false;
                }
                public void setReadListener(ReadListener readListener) {}
                public int read() {
                    return byteArrayInputStream.read();
                }
            };
    
        }
    
        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(this.getInputStream()));
        }
    
    
        public String getRequestBody() {
            return new String(this.requestBody);
        }
    
    }

    2、定义fitler

    package com.multiplethread.multiplethread.selffilter;

    import org.springframework.stereotype.Component;

    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;

    @Component
    @WebFilter
    public class JsonFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    //请求参数为JSON类型,则使用自定义包装
    if(request instanceof HttpServletRequest
    && "application/json".equals(((HttpServletRequest)request).getHeader("Content-Type"))) {
    chain.doFilter(new RequestWrapper((HttpServletRequest) request), response);
    // chain.doFilter(request, response); // 直接传有问题
    } else {
    chain.doFilter(request, response);
    }

    }

    @Override
    public void destroy() {

    }
    }
    3、定义拦截器FirstInterceptor
    package com.multiplethread.multiplethread.selffilter;

    import com.alibaba.fastjson.JSONObject;
    import org.springframework.lang.Nullable;
    import org.springframework.util.StreamUtils;
    import org.springframework.util.StringUtils;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;

    import javax.servlet.ServletInputStream;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    public class FirstInterceptor implements HandlerInterceptor {
    /**
    * 控制器 请求执行前进入
    * @param request
    * @param response
    * @param handler
    * @return true:继续向下执行, false:不向下执行
    *
    * @throws Exception
    */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {
    String params = "";
    if("application/json".equals(request.getHeader("Content-Type"))){
    //通过方法直接获取JSON参数
    ServletInputStream servletInputStream=request.getInputStream();
    byte[] requestBody = StreamUtils.copyToByteArray(request.getInputStream());
    System.out.println("requestBody.toString() = " + requestBody.toString());
    System.out.println("new String(requestBody) = " + new String(requestBody));

    }else {
    params = JSONObject.toJSONString(request.getParameterMap());
    }

    if(!StringUtils.isEmpty(params)){
    System.out.println("params = " + params);
    }

    return true;
    }


    /**
    * 执行action
    * @param request
    * @param response
    * @param handler
    * @param modelAndView
    * @throws Exception
    */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    @Nullable ModelAndView modelAndView) throws Exception {
    }

    }
    4、注册拦截器
    package com.multiplethread.multiplethread.selffilter;

    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

    import java.util.Arrays;
    import java.util.List;

    /**
    * 用于注册 FirstInterceptor 拦截器
    */
    @Component
    public class MyWEbMvcConfigurer implements WebMvcConfigurer {
    // 静态资源不进拦截器
    static List<String> ListStaticResuource= Arrays.asList("/","/css/**","/img/**","/script/**","/pages/**");
    @Override
    public void addInterceptors(InterceptorRegistry registry){
    registry.addInterceptor(getHandlerInterceptor()).excludePathPatterns(ListStaticResuource);
    }


    public HandlerInterceptor getHandlerInterceptor(){
    return new FirstInterceptor();
    }
    }
    5、定义controller 测试
    package com.multiplethread.multiplethread.controller;

    import com.multiplethread.multiplethread.Model.Questionnaire;
    import com.multiplethread.multiplethread.Model.dataEnum.QuestionSwitchEnum;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RestController;

    @RequestMapping("dianCaiBao")
    @RestController
    public class DianCaiBaoController {

    @RequestMapping("getQuestionnaire")
    public Questionnaire getQuestionnaire() {
    Questionnaire questionnaire=new Questionnaire();
    questionnaire.setQuestionSwitch(QuestionSwitchEnum.Open.getValue());
    questionnaire.setQuestionUrl("https://www.baidu.com");
    return questionnaire;
    }
    //{"questionSwitch":1,"questionUrl":"https://www.baidu.com"}


    @RequestMapping(value = "saveQuestionnaire",method = {RequestMethod.POST,RequestMethod.GET})
    public int getQuestionnaire(@RequestBody Questionnaire questionnaire) {
    System.out.println("questionnaire = " + questionnaire);
    // Questionnaire questionnaire=new Questionnaire();
    // questionnaire.setQuestionSwitch(QuestionSwitchEnum.Open.getValue());
    // questionnaire.setQuestionUrl("https://www.baidu.com");
    return 1;
    }
    }

    总结概述:RequestWrapper 实现将 request.getInputStream() 读取后放到requestBody 对象属性中
    ,后续操作都是从requestBody 对象属性中读取,这样就实现了可以多次读取的场景
    参考:https://wenku.baidu.com/view/98adf15f8d9951e79b89680203d8ce2f01666559.html
  • 相关阅读:
    tensorflow2.0——动量,动态学习率,Dropout
    tensorflow2.0——过拟合优化regularization(简化参数结构,添加参数代价变量)
    tensorflow2.0——自定义全连接层实现并保存
    关于生成器的问题
    端午节大礼包(投票系统)
    写一个函数完成三次登陆功能,再写一个函数完成注册功能
    例题练习
    文件操作
    解决列表中增加字典覆盖之前相同key的字典
    字符串操作,列表,元组,字典操作
  • 原文地址:https://www.cnblogs.com/liyanbofly/p/16357933.html
Copyright © 2020-2023  润新知