解決spring設置filter過濾器結合rest風格獲取post請求body參數輸入流問題


 由於最近在使用spring+jersey開發要設置基於servlet的filter。當在filter中通過request.getReader或者getInputStream讀取body中的json參數處理時,由於rest風格的jersey框架底層亦是基於同樣原理讀取post請求body中參數。因為request自身的原則:getReader或者getInputStream只能調用其中一個且只有一次可以正常獲取body中內容,導致在filter中通過getReader第一次讀取body中參數成功,當放行時,jersey中控制器執行時候,會出現異常:

java.lang.IllegalStateException: getReader() has already been called for this request。

 

############################

###           運行系統:windows8

###          JDK版本 : JDK1.7

###          框架:spring3x + jersey2.x

###          開發IDE:MyEclipse

############################

1.0 在web.xml中配置spring過濾器filter,集成自定義filter

 

[html]  view plain  copy
 
  1. <filter>  
  2.         <filter-name>DelegateFilter</filter-name>  
  3.         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  4.         <init-param>  
  5.             <param-name>targetBeanName</param-name>  
  6.             <param-value>myFilter</param-value<!-- 自定義攔截器-->  
  7.         </init-param>  
  8.         <init-param>  
  9.             <param-name>targetFilterLifecycle</param-name>  
  10.             <param-value>true</param-value>  
  11.         </init-param>  
  12.     </filter>  
  13.     <filter-mapping>  
  14.         <filter-name>DelegateFilter</filter-name>  
  15.         <url-pattern>/*</url-pattern>  
  16.     </filter-mapping>  


2.0在spring配置文件application.xml中定義自定義filterbean。

 

 

[html]  view plain  copy
 
  1. <bean id="myFilter" class="com.cybbj.action.filter.FilterPost"></bean>  
[html]  view plain  copy
 
  1. PS:若是在filter中想使用springIOC容器中其他bean.如其他service類。那么可以在該bean中配置。  
  2. 例如在filter中需要注入公用commonSerivce  
  3. public class myFilter implements Filter{  
  4.     private CommonService commonService;  
  5.   
  6. //需要setter  
  7.    .......  
  8. }  
[plain]  view plain  copy
 
  1. 要想使用commonService而不拋出空指針異常,需要在bean中配置依賴:  
  2. <bean id="myFilter" class="com.cybbj.action.filter.FilterPost">  
  3. <property name="commonService"> <ref bean="commonService"/> <!-- 其中commonService是通過注解或者xml配置到IOC容器中的類--></property></bean>  
 
        

 

[plain]  view plain  copy
 
  1. 3.0 自定義filter  
  2. 原始代碼與運行結果如下:  
 
        

 

[java]  view plain  copy
 
  1. public class FilterPost implements Filter{  
  2.       
  3.     private Log log = LogFactory.getLog(FilterPost.class);  
  4.   
  5.     String param = "";  
  6.       
  7.     public void destroy() {  
  8.         // TODO Auto-generated method stub  
  9.           
  10.     }  
  11.   
  12.     public void doFilter(ServletRequest req, ServletResponse res,  
  13.             FilterChain chain) throws IOException, ServletException {  
  14.            HttpServletRequest request = null;  
  15.             if(req instanceof HttpServletRequest) {   
  16.                request = (HttpServletRequest)req;  
  17.             }  
  18.               
  19.             if("POST".equalsIgnoreCase(request.getMethod())){  
  20.                 param = this.getBodyString(request.getReader());  
  21.                 log.info("filter讀取body中的參數>>>>>>>>>"+param);  
  22.                 chain.doFilter(request, res);  
  23.     }  
  24.           
  25.     }  
  26.   
  27.     public void init(FilterConfig config) throws ServletException {  
  28.           
  29.     }  
[java]  view plain  copy
 
  1.     //獲取request請求body中參數  
  2. lic static String getBodyString(BufferedReader br) {  
  3. String inputLine;  
  4.      String str = "";  
  5.    try {  
  6.      while ((inputLine = br.readLine()) != null) {  
  7.       str += inputLine;  
  8.      }  
  9.      br.close();  
  10.    } catch (IOException e) {  
  11.      System.out.println("IOException: " + e);  
  12.    }  
  13.    return str;  

 

4.0基於jersey的controller中post請求處理

 

[html]  view plain  copy
 
  1. @POST  
  2. @Path("/postJson")  
  3. @Produces(MediaType.APPLICATION_JSON)  
  4. @Consumes(MediaType.APPLICATION_JSON)  
  5. public Map<String, String> postByJson(Map<String, Object> jsonParam) {  
  6.   
  7.     JSONObject jo = new JSONObject(jsonParam);  
  8.     System.out.println(jsonParam);  
  9.     Map<String, Stringparam = new HashMap<String, String>();  
  10.     param.put("name", jo.getString("name").length()==0? "" : jo.getString("name"));  
  11.     param.put("age", jo.getString("age").length()==0  ? "" :jo.getString("age"));  
  12.     param.put("status", "200");  
  13.     param.put("Msg", "ok,success");  
  14.     return param;  
  15. }  

 

 

[html]  view plain  copy
 
  1. 5. 拋出異常  
  2. java.lang.IllegalStateException: getReader() has already been called for this request  
  3.     at org.apache.catalina.connector.Request.getInputStream(Request.java:1085)  


解決方法:

 

[html]  view plain  copy
 
  1. 結合JODD開源框架,且在Filter中將ServletRequest替換為ServletRequestWrapper 來解決該問題。  

 

 

A:添加jodd支持:

在pom.xml中添加對jodd的依賴:

 

[html]  view plain  copy
 
  1. <!-- https://mvnrepository.com/artifact/org.jodd/jodd-core -->  
  2. <dependency>  
  3. </span><groupId>org.jodd</groupId>  
  4. </span><artifactId>jodd-core</artifactId>  
  5. </span><version>3.4.8</version>  
  6. </dependency>  

 

 

B:結合jodd創建自定義ServletRequestWrapper

 

[html]  view plain  copy
 
  1. public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper{  
  2.   
  3.      private final byte[] body; //用於保存讀取body中數據   
  4.        
  5.         public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)     
  6.     throws IOException {    
  7.             super(request);    
  8.             body = StreamUtil.readBytes(request.getReader(), "UTF-8");    
  9.         }    
  10.         
  11.         @Override    
  12.         public BufferedReader getReader() throws IOException {    
  13.             return new BufferedReader(new InputStreamReader(getInputStream()));    
  14.         }    
  15.         
  16.         @Override    
  17.         public ServletInputStream getInputStream() throws IOException {    
  18.             final ByteArrayInputStream bais = new ByteArrayInputStream(body);    
  19.             return new ServletInputStream() {    
  20.         
  21.                 @Override    
  22.                 public int read() throws IOException {    
  23.                     return bais.read();    
  24.                 }  
  25.   
  26.                 @Override  
  27.                 public boolean isFinished() {  
  28.                     // TODO Auto-generated method stub  
  29.                     return false;  
  30.                 }  
  31.   
  32.                 @Override  
  33.                 public boolean isReady() {  
  34.                     // TODO Auto-generated method stub  
  35.                     return false;  
  36.                 }  
  37.   
  38.                 @Override  
  39.                 public void setReadListener(ReadListener arg0) {  
  40.                     // TODO Auto-generated method stub  
  41.                       
  42.                 }    
  43.             };    
  44.         }    
  45. }  


C:用wrapper替換request修改filter

 

 

[html]  view plain  copy
 
  1. public void doFilter(ServletRequest req, ServletResponse res,  
  2.             FilterChain chain) throws IOException, ServletException {  
  3.           String method = "GET";  
  4.            ServletRequest requestWrapper = null;    
  5.             if(req instanceof HttpServletRequest) {    
  6.                 method = ((HttpServletRequest) req).getMethod();  
  7.                 requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) req);  //替換  
  8.             }    
  9.               
  10.             if("POST".equalsIgnoreCase(method)){  
  11.                 param = this.getBodyString(requestWrapper.getReader());  
  12.                 log.info("filter讀取body中的參數>>>>>>>>>"+param);  
  13.                 chain.doFilter(requestWrapper, res);  
  14.     }  
  15.           



D:請求測試

 

請求成功................

 

參考文章:http://liwx2000.iteye.com/blog/1542431

 

原文地址:https://blog.csdn.net/xiansky2015/article/details/52013690


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM