问题描述:在使用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()读出来是空的,获取不到文件内容。
- 解决方案
写一个过滤器,覆盖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进行处理