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 MapmParams=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 } } }
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){ } } }
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 *