由於Request的getInputSteam()一旦獲取一次後,就再也無法獲取了
在實際項目中導致下面的問題:
1,多個攔截器,Filter都需要從InputStream中拿數據的情況無法處理;
2,InputStream被攔截器,Filter拿走了,Controller層無法getParameter(),也無法使用@RequestParam 注解來自動匹配設置參數。
參考了多篇處理getInputStream()相關的博文後,采取了下面的解決方案。
1,通過繼承HttpServletRequestWrapper創建自定義的Request對象,
在這個對象中,以字節數組形式長期保持Request的Stream內容,可以在攔截器,Filter,Controller中任意多次復用;
同時,重寫getParameter()相關的各個方法,確保從保持的Stream數據中,可以正常解析所有參數,並且在解析過程中,可以進行自定義的解碼操作。
package org.jiagoushi.mobile.rule.filter; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import com.mtime.mobile.utils.Encodes; public class MAPIHttpServletRequestWrapper extends HttpServletRequestWrapper { private Map<String, String[]> paramsMap; @Override public Map getParameterMap() { return paramsMap; } @Override public String getParameter(String name) {// 重寫getParameter,代表參數從當前類中的map獲取 String[] values = paramsMap.get(name); if (values == null || values.length == 0) { return null; } return values[0]; } @Override public String[] getParameterValues(String name) {// 同上 return paramsMap.get(name); } @Override public Enumeration getParameterNames() { return Collections.enumeration(paramsMap.keySet()); } private String getRequestBody(InputStream stream) { String line = ""; StringBuilder body = new StringBuilder(); int counter = 0; // 讀取POST提交的數據內容 BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); try { while ((line = reader.readLine()) != null) { if (counter > 0) { body.append("\r\n"); } body.append(line); counter++; } } catch (IOException e) { e.printStackTrace(); } return body.toString(); } private HashMap<String, String[]> getParamMapFromPost(HttpServletRequest request) { String body = ""; try { body = getRequestBody(request.getInputStream()); } catch (IOException e) { e.printStackTrace(); } HashMap<String, String[]> result = new HashMap<String, String[]>(); if (null == body || 0 == body.length()) { return result; } return parseQueryString(body); } // 自定義解碼函數 private String decodeValue(String value) { if (value.contains("%u")) { return Encodes.decodeUnicode(value); } else { try { return URLDecoder.decode(value, "UTF-8"); } catch (UnsupportedEncodingException e) { return "";// 非UTF-8編碼 } } } public HashMap<String, String[]> parseQueryString(String s) { String valArray[] = null; if (s == null) { throw new IllegalArgumentException(); } HashMap<String, String[]> ht = new HashMap<String, String[]>(); StringTokenizer st = new StringTokenizer(s, "&"); while (st.hasMoreTokens()) { String pair = (String) st.nextToken(); int pos = pair.indexOf('='); if (pos == -1) { continue; } String key = pair.substring(0, pos); String val = pair.substring(pos + 1, pair.length()); if (ht.containsKey(key)) { String oldVals[] = (String[]) ht.get(key); valArray = new String[oldVals.length + 1]; for (int i = 0; i < oldVals.length; i++) { valArray[i] = oldVals[i]; } valArray[oldVals.length] = decodeValue(val); } else { valArray = new String[1]; valArray[0] = decodeValue(val); } ht.put(key, valArray); } return ht; } private Map<String, String[]> getParamMapFromGet(HttpServletRequest request) { return parseQueryString(request.getQueryString()); } private final byte[] body; // 報文 public MAPIHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); body = readBytes(request.getInputStream()); // 首先從POST中獲取數據 if ("POST".equals(request.getMethod().toUpperCase())) { paramsMap = getParamMapFromPost(this); } else { paramsMap = getParamMapFromGet(this); } } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } }; } private static byte[] readBytes(InputStream in) throws IOException { BufferedInputStream bufin = new BufferedInputStream(in); int buffSize = 1024; ByteArrayOutputStream out = new ByteArrayOutputStream(buffSize); byte[] temp = new byte[buffSize]; int size = 0; while ((size = bufin.read(temp)) != -1) { out.write(temp, 0, size); } bufin.close(); byte[] content = out.toByteArray(); return content; } }
2,自定義一個Filter(這個Filter的配置位置放在最靠前的位置),替換掉原始的Request對象:
web.xml中最靠前的位置增加Filter
... <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/api-spring.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 下面的Filter以自定義的Request對象替換掉原有的Request,進行POST數據的保持和自定義解碼 --> <!-- 可以解決下面兩個問題: 1,CheckUrl攔截器讀取InputStream導致getParameter()方法失效; 2,POST數據由於有自定義Unicode編碼,解碼時也需要讀取InputSteam --> <filter> <filter-name>requestFilter</filter-name> <filter-class>org.jiagoushi.mobile.rule.filter.HttpServletRequestReplacedFilter</filter-class> </filter> <filter-mapping> <filter-name>requestFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ...
Filter類的代碼
package org.jiagoushi.mobile.rule.filter; 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; public class HttpServletRequestReplacedFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { ServletRequest requestWrapper = null; if(request instanceof HttpServletRequest) { HttpServletRequest httpServletRequest = (HttpServletRequest) request; if("POST".equals(httpServletRequest.getMethod().toUpperCase())){ requestWrapper = new MAPIHttpServletRequestWrapper((HttpServletRequest) request); } } if(requestWrapper == null) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); //替換! } } @Override public void init(FilterConfig arg0) throws ServletException { } }
---
參考資料:
http://ayaoxinchao.iteye.com/blog/2110902
http://my.oschina.net/tmallMoney/blog/127225
http://www.xuebuyuan.com/809435.html
http://hw1287789687.iteye.com/blog/1923085