解决spring设置filter过滤器结合rest风格获取post请求body参数输入流问题
2016-07-24 14:22
1011 查看
由于最近在使用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
2.0在spring配置文件application.xml中定义自定义filterbean。
4.0基于jersey的controller中post请求处理
解决方法:
A:添加jodd支持:
在pom.xml中添加对jodd的依赖:
B:结合jodd创建自定义ServletRequestWrapper
C:用wrapper替换request修改filter
D:请求测试
请求成功................
参考文章:http://liwx2000.iteye.com/blog/1542431
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
<filter> <filter-name>DelegateFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>myFilter</param-value> <!-- 自定义拦截器--> </init-param> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>DelegateFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2.0在spring配置文件application.xml中定义自定义filterbean。
<bean id="myFilter" class="com.cybbj.action.filter.FilterPost"></bean>
PS:若是在filter中想使用springIOC容器中其他bean.如其他service类。那么可以在该bean中配置。 例如在filter中需要注入公用commonSerivce public class myFilter implements Filter{ private CommonService commonService; //需要setter ....... }
要想使用commonService而不抛出空指针异常,需要在bean中配置依赖: <bean id="myFilter" class="com.cybbj.action.filter.FilterPost"> <property name="commonService"> <ref bean="commonService"/> <!-- 其中commonService是通过注解或者xml配置到IOC容器中的类--></property></bean>
3.0 自定义filter 原始代码与运行结果如下:
public class FilterPost implements Filter{ private Log log = LogFactory.getLog(FilterPost.class); String param = ""; public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = null; if(req instanceof HttpServletRequest) { request = (HttpServletRequest)req; } if("POST".equalsIgnoreCase(request.getMethod())){ param = this.getBodyString(request.getReader()); log.info("filter读取body中的参数>>>>>>>>>"+param); chain.doFilter(request, res); } } public void init(FilterConfig config) throws ServletException { }
//获取request请求body中参数 public static String getBodyString(BufferedReader br) { String inputLine; String str = ""; try { while ((inputLine = br.readLine()) != null) { str += inputLine; } br.close(); } catch (IOException e) { System.out.println("IOException: " + e); } return str; }
4.0基于jersey的controller中post请求处理
@POST @Path("/postJson") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Map<String, String> postByJson(Map<String, Object> jsonParam) { JSONObject jo = new JSONObject(jsonParam); System.out.println(jsonParam); Map<String, String> param = new HashMap<String, String>(); param.put("name", jo.getString("name").length()==0? "" : jo.getString("name")); param.put("age", jo.getString("age").length()==0 ? "" :jo.getString("age")); param.put("status", "200"); param.put("Msg", "ok,success"); return param; }
5. 抛出异常 java.lang.IllegalStateException: getReader() has already been called for this request at org.apache.catalina.connector.Request.getInputStream(Request.java:1085)
解决方法:
结合JODD开源框架,且在Filter中将ServletRequest替换为ServletRequestWrapper 来解决该问题。
A:添加jodd支持:
在pom.xml中添加对jodd的依赖:
<!-- https://mvnrepository.com/artifact/org.jodd/jodd-core --> <dependency> </span><groupId>org.jodd</groupId> </span><artifactId>jodd-core</artifactId> </span><version>3.4.8</version> </dependency>
B:结合jodd创建自定义ServletRequestWrapper
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper{ private final byte[] body; //用于保存读取body中数据 public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); body = StreamUtil.readBytes(request.getReader(), "UTF-8"); } @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(); } @Override public boolean isFinished() { // TODO Auto-generated method stub return false; } @Override public boolean isReady() { // TODO Auto-generated method stub return false; } @Override public void setReadListener(ReadListener arg0) { // TODO Auto-generated method stub } }; } }
C:用wrapper替换request修改filter
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { String method = "GET"; ServletRequest requestWrapper = null; if(req instanceof HttpServletRequest) { method = ((HttpServletRequest) req).getMethod(); requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) req); //替换 } if("POST".equalsIgnoreCase(method)){ param = this.getBodyString(requestWrapper.getReader()); log.info("filter读取body中的参数>>>>>>>>>"+param); chain.doFilter(requestWrapper, res); }
D:请求测试
请求成功................
参考文章:http://liwx2000.iteye.com/blog/1542431
相关文章推荐
- 初学springMVC搭建框架过程及碰到的问题
- Java解决No enclosing instance of type PrintListFromTailToHead is accessible问题
- Java中split方法对结尾空字符串不正确处理的解决方案
- Java 多线程中。两个线程交替执行,一个输出偶数,一个输出奇数
- SpringBoot学习笔记(4) Spring Boot 集成 Mybatis
- Java 反射
- JavaWeb之Servlet
- 二叉树的循环遍历方法,Java实现。利用栈和arraylist
- 精选30道Java笔试题解答
- JavaSE基础(六)
- 链表分析笔记
- javaIO流总结
- 性能分析系列——小命令保证大性能
- Spring 框架的设计理念与设计模式分析
- Java获取客户端IP地址-转
- SpringBoot学习笔记(3) Spring Boot 运行原理,自动配置
- Spring 框架简介
- Spring面试题
- Java通过反射机制动态设置对象属性值的方法
- Java 项目的命名规范