频道栏目
首页 > 资讯 > 其他 > 正文

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

17-01-02        来源:[db:作者]  
收藏   我要投稿

Jsp/Servlet Request getReader()/getInputStream()返回空值的解决方法:因为同一次递交,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 mParams=null;
	  public MultiReadHttpServletRequest(HttpServletRequest request) {
	    super(request);
	  }
	  public void rebuildParams(){
		  mParams=new HashMap();
	      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 block
						e.printStackTrace();
					}
		    	  if (mParams.containsKey(lvItems1[0])){
		    		  String[] lvV=mParams.get(lvItems1[0]);
		    		  List lvList=new ArrayList(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 lvParams=super.getParameterMap();
	      for(java.util.Map.Entry 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 getParameterMap(){
		  /*Map  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;
	    }

		@Override
		public boolean isFinished() {
			// TODO Auto-generated method stub
			return mIsFinished;
		}

		@Override
		public boolean isReady() {
			// TODO Auto-generated method stub
			return false;
		}

		@Override
		public 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);
	  }

	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
		if (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:


    MultiRequestCacheFilter
    com.freestyle.common.servletsupport.RequestFilter  
  
  
  	MultiRequestCacheFilter
  	*
  
相关TAG标签
上一篇:建造者模式(创建型)
下一篇:shiro初识
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站