Jsp/Servlet Request getReader()/getInputStream()返回空值的解决方法

来源:互联网 发布:淘宝培训班 编辑:程序博客网 时间:2024/06/05 08:02

     因为同一次递交,request的三个方法getInputStream()/getReader()和getParameterMap(),任何一个方法使用过一次,postdata就会被清空,这三个方法再也无法使用。

     现在有一个框架的流程是先用了getParameterMap()取出参数表,后面再视情况而定调用getreader()获得post data的具体数据, 如果用原来的request则无法满足此要求 , 这时候我们可以自定义HttpServletRequestWrapper,在filter里面拦截处理。

    首先,我们定义一个可复用post data的HttpServletRequestWrapper,里面有个rebuildParams()方法,用于将POST过来的带?key1=value1&key2=value2的url参数和post data好里面的参数合并在一起, 几个getXXX获取参数的都重写了,改为从合并后的参数列表中取出参数:

package com.freestyle.common.servletsupport;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.net.URLDecoder;import java.util.ArrayList;import java.util.Arrays;import java.util.Enumeration;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Vector;import javax.servlet.ReadListener;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import org.apache.commons.io.IOUtils;public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {  private ByteArrayOutputStream cachedBytes;  private Map<String,String[]> mParams=null;  public MultiReadHttpServletRequest(HttpServletRequest request) {    super(request);  }  public void rebuildParams(){  mParams=new HashMap<String,String[]>();      String lvTmp=(String) getAttribute("_request_body");      if (lvTmp!=null){           String[] lvItems=lvTmp.split("&");      for(String item:lvItems){      String[] lvItems1=item.split("=", 2);      try {       if (lvItems1.length==2){       lvItems1[1]=URLDecoder.decode(lvItems1[1], "utf8");       }} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}      if (mParams.containsKey(lvItems1[0])){      String[] lvV=mParams.get(lvItems1[0]);      List<String> lvList=new ArrayList<String>(Arrays.asList(lvV));      if (lvItems1.length==2){      lvList.add(lvItems1[1]);      }      else{      lvList.add(null);      }      mParams.put(lvItems1[0], lvList.toArray(new String[lvList.size()]));      }      else{      String[] lvV=new String[]{lvItems1.length==2? lvItems1[1]:null};      mParams.put(lvItems1[0], lvV);      }                  }      }      Map<String,String[]> lvParams=super.getParameterMap();      for(java.util.Map.Entry<String, String[]> item:lvParams.entrySet()){      mParams.put(item.getKey(),item.getValue());      }  }  @Override  public ServletInputStream getInputStream() throws IOException {    if (cachedBytes == null){      cacheInputStream();       }      return new CachedServletInputStream();  }  public String getParameter(String pvKey){  /*if (super.getParameterMap().containsKey(pvKey)){  return super.getParameter(pvKey);  }  String[] lvRet=mParams.get(pvKey);  if (lvRet==null)return null;  return lvRet[0];*/  Object lvV = mParams.get(pvKey);          if (lvV == null) {              return null;          } else if (lvV instanceof String[]) {              String[] lvStrArr = (String[]) lvV;              if (lvStrArr.length > 0) {                  return lvStrArr[0];              } else {                  return null;              }          } else if (lvV instanceof String) {              return (String) lvV;          } else {              return lvV.toString();          }    }  public Map<String, String[]> getParameterMap(){  /*Map<String, String[]>  lvRet=super.getParameterMap();  lvRet.putAll(mParams);  return lvRet;*/    return mParams;  }  public Enumeration getParameterNames() {          Vector l = new Vector(mParams.keySet());          return l.elements();      }        public String[] getParameterValues(String name) {          Object v = mParams.get(name);          if (v == null) {              return null;          } else if (v instanceof String[]) {              return (String[]) v;          } else if (v instanceof String) {              return new String[] { (String) v };          } else {              return new String[] { v.toString() };          }      }      @Override  public BufferedReader getReader() throws IOException{    return new BufferedReader(new InputStreamReader(getInputStream()));  }  private void cacheInputStream() throws IOException {    /* Cache the inputstream in order to read it multiple times. For     * convenience, I use apache.commons IOUtils     */    cachedBytes = new ByteArrayOutputStream();    IOUtils.copy(super.getInputStream(), cachedBytes);  }  /* An inputstream which reads the cached request body */  public class CachedServletInputStream extends ServletInputStream {    private ByteArrayInputStream input;    private boolean mIsFinished=false;    public CachedServletInputStream() {      /* create a new input stream from the cached request body */      input = new ByteArrayInputStream(cachedBytes.toByteArray());      mIsFinished=false;    }    @Override    public int read() throws IOException {      int lvReaded=input.read();      mIsFinished=lvReaded==-1;      return lvReaded;    }@Overridepublic boolean isFinished() {// TODO Auto-generated method stubreturn mIsFinished;}@Overridepublic boolean isReady() {// TODO Auto-generated method stubreturn false;}@Overridepublic void setReadListener(ReadListener arg0) {// TODO Auto-generated method stub}  }}

然后我们定义一个Filter, 重写doFilter方法,在里面重新定义request, 并在POST方法&非上传文件的时候将post Data放在“_request_body"属性里面, 后面框架里面有个通用类会从“_request_body”属性里面取出此post Data解析出相应的pojo类。

package com.freestyle.common.servletsupport;import java.io.IOException;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import org.apache.commons.fileupload.servlet.ServletFileUpload;import com.alco.bms.beans.HttpBeanUtil;public class RequestFilter implements Filter {@Override  public void doFilter(ServletRequest request, ServletResponse response,        FilterChain chain) throws IOException, ServletException {    /* wrap the request in order to read the inputstream multiple times */    MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request);        /* here I read the inputstream and do my thing with it; when I pass the     * wrapped request through the filter chain, the rest of the filters, and     * request handlers may read the cached inputstream     */    boolean isMultipart = ServletFileUpload.isMultipartContent(multiReadRequest);    if (!isMultipart&&multiReadRequest.getMethod().toUpperCase().equals("POST")){    String c_request_body=HttpBeanUtil.getRequestPayload(multiReadRequest);    multiReadRequest.setAttribute("_request_body", c_request_body);    }    multiReadRequest.rebuildParams();        chain.doFilter(multiReadRequest, response);  }@Overridepublic void destroy() {// TODO Auto-generated method stub}@Overridepublic void init(FilterConfig arg0) throws ServletException {// TODO Auto-generated method stubif (arg0==null){}}}

而读出post data的方法很简单,如果用java 1.8的话,一句话就搞定了,下面写这么复杂只为了兼容性:

public static String getRequestPayload(HttpServletRequest req) {StringBuilder sb = new StringBuilder();try {BufferedReader reader = req.getReader();char[] buff = new char[1024];int len;while ((len = reader.read(buff)) != -1) {sb.append(buff, 0, len);}} catch (IOException e) {e.printStackTrace();}return sb.toString();}


现在在web.xml里面增加此filter:

<filter>    <filter-name>MultiRequestCacheFilter</filter-name>    <filter-class>com.freestyle.common.servletsupport.RequestFilter</filter-class>    </filter>  <filter-mapping>  <filter-name>MultiRequestCacheFilter</filter-name>  <url-pattern>*</url-pattern>  </filter-mapping>



0 0