wps控件在springMVC和spring-boot搭建的项目中,保存到后台方法获取不到流的原因分析及解决方案

问题描述:在使用wps的Active控件保存文件到服务器时候,request.getParameter()获取不到文件流。在各种百度以后得到以下结论。

WPS控件保存到远程的方法是post请求,类型是enctype="multipart/form-data"。相当于有enctype="multipart/form-data属性的form表单提交。

1.request 特性

1.1在form表单提交是默认类型的时候可以通过request.getParameter()获取请求参数。但是当请求类型不是默认类型(例如enctype="multipart/form-data"类型,上传一个文件)的时候,需调用request.getInputStream()或request.getReader()方法来获取请求内容值。

1.2 request.getParameter(),request.getInputStream(),request.getReader()三个方法是不能共存的。调用其中一个就会影响剩下两个方法的使用,会导致request中的字节流为空。导致后面再次调用的时候读取不到。

2. springMvc 分析

2.1 原理

SpringMVC 本身是支持 PUT,DELETE 等 HTTP 请求方式的,但由于某些客户端(如:浏览器)并不支持这些,所以 Spring 提供了HiddenHttpMethodFilter这个过滤器来规避这一问题.然而在HiddenHttpMethodFilter中有String paramValue = request.getParameter(this.methodParam)的代码操作导致的.详细请看2.2源码分析.

 

例:客户端提交请求时必须使用POST方式,然后再多加一个参数 (_method = "PUT")HiddenHttpMethodFilter 就会隐藏掉POST,在后续逻辑代码中获得的请求方式将都是 PUT DELETE 等其他请求方式同理。

2.2源码分析

 

@Override

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

              HttpServletRequest requestToUse = request;        if("POST".equals(request.getMethod())&&request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {

                     String paramValue = request.getParameter(this.methodParam);

                    

if (StringUtils.hasLength(paramValue)) {

                            String method = paramValue.toUpperCase(Locale.ENGLISH);

                            if (ALLOWED_METHODS.contains(method)) {

                                   requestToUse = new HttpMethodRequestWrapper(request, method);

                            }

                     }

              }

              filterChain.doFilter(requestToUse, response);

       }

正是在这个过滤器中调用了request.getParameter()方法,导致request到达controller的时候request.getInputStream()读出来是空的,获取不到文件内容。

 

  1. 解决方案

     写一个过滤器,覆盖HiddenHttpMethodFilter过滤器;再写一个requestWrapper封装类获取request中的流,将取出来的字符串放到byte[]字节流中,在重新放在request.

 

3.1过滤器

@Bean

public HiddenHttpMethodFilter hiddenHttpMethodFilter() {

return new OrderedHiddenHttpMethodFilter() {

 

@Override

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse Response, FilterChain filterChain)

throws ServletException, IOException {

RequestWrapper requestWrapper = null;

 

String url = request.getRequestURI();

String[] urlArray = url.split("/");

for (String array : urlArray) {

if("saveCurrentNew".equals(array) || "saveDraftFile".equals(array)) {

System.out.println(url);

requestWrapper = new RequestWrapper(request);

}

}

if (requestWrapper != null) {

filterChain.doFilter(requestWrapper, Response);

}else {

filterChain.doFilter(request, Response);

}

 

}

 

};

}

 

3.2 requestWrapper封装类

public class RequestWrapper extends HttpServletRequestWrapper {

 

    private byte[] bytes;

    private WrappedServletInputStream wrappedServletInputStream;

   

    public RequestWrapper(HttpServletRequest request) throws IOException{

        super(request);

        // 读取输入流里面的参数,保存到bytes里

        bytes = IOUtils.toByteArray(request.getInputStream());

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);

        this.wrappedServletInputStream = new WrappedServletInputStream(byteArrayInputStream);

        // 把参数重新写入请求流

        reWriteInputStream();

       

    }

    public void reWriteInputStream(){

        wrappedServletInputStream.setStream(new ByteArrayInputStream(bytes != null ? bytes : new byte[0]));

    }

 

    public String getRequestParams() throws IOException{

        if (bytes .length > 0){

            return new String(bytes, this.getCharacterEncoding());

        }else{

            return null;

        }

       

    }

   

    /* (non-Javadoc)

     * @see javax.servlet.ServletRequestWrapper#getInputStream()

     */

    @Override

    public ServletInputStream getInputStream() throws IOException{

        return wrappedServletInputStream;

    }

   

    /* (non-Javadoc)

     * @see javax.servlet.ServletRequestWrapper#getReader()

     */

    @Override

    public BufferedReader getReader() throws IOException{

        return new BufferedReader(new InputStreamReader(wrappedServletInputStream));

    }

   

    private class WrappedServletInputStream extends ServletInputStream{

       

        private InputStream stream;

        public void setStream(InputStream stream){

            this.stream = stream;

        }

       

        public WrappedServletInputStream(InputStream stream){

            this.stream = stream;

        }

 

        @Override

        public boolean isFinished() {

            return true;

        }

 

        @Override

        public boolean isReady() {

            return true;

        }

 

        @Override

        public void setReadListener(ReadListener arg0) {

           

        }

 

        @Override

        public int read() throws IOException {

            return stream.read();

        }

           

    }

}

 

 


这里使用了request.getParameter()方法,影响到了request.getInputStream()方法,原理看1.request特性

写一个requst封装类,对requst进行处理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值