您的位置:首页 > 产品设计 > UI/UE

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

2016-12-27 17:04 633 查看
     因为同一次递交,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 block
e.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;
}

@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:

<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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐