由於最近在使用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
原文地址:https://blog.csdn.net/xiansky2015/article/details/52013690