Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 533|回复: 0

解决spring设置filter过滤器结合rest风格获取post请求body参数输入流问题

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-26 13:29:27 | 显示全部楼层 |阅读模式

     由于最近在使用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

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-4 17:50 , Processed in 0.065629 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表