解决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

猜你喜欢

转载自www.cnblogs.com/yucongblog/p/9122342.html