由于最近在使用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
-
<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中参数
-
lic 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