拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.
来源:互联网 发布:下载青岛网络干部app 编辑:程序博客网 时间:2024/05/21 09:37
由于 request中getReader()和getInputStream()只能调用一次
在项目中,可能会出现需要针对接口参数进行校验等问题。
因此,针对这问题,给出一下解决方案
step 1:
添加RepeatedlyReadRequestWrapper 类并继承 HttpServletRequestWrapper 包装类
package com.config;import org.apache.commons.lang3.StringUtils;import javax.servlet.ReadListener;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.nio.charset.Charset;/** * @author zhangmz * @version 1.0.0 * @date 2017/09/21 */public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public RepeatedlyReadRequestWrapper(HttpServletRequest request) throws IOException { super(request); body = 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 boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener listener) { } @Override public int read() throws IOException { return bais.read(); } }; } /** * 通过BufferedReader和字符编码集转换成byte数组 * @param br * @param encoding * @return * @throws IOException */ private byte[] readBytes(BufferedReader br,String encoding) throws IOException{ String str = null,retStr=""; while ((str = br.readLine()) != null) { retStr += str; } if (StringUtils.isNotBlank(retStr)) { return retStr.getBytes(Charset.forName(encoding)); } return null; }}
step 2:
添加 RepeatedlyReadFilter 实现 filter 过滤器接口方法,当客户端的请求先 过滤 进入SpringMvc Dispatch 路由前先包装下
package com.filter;import com.config.RepeatedlyReadRequestWrapper;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import java.io.IOException;/** * 复制请求数据包body * 以提供 拦截器下 可数次获取Body数据包 * @author zhangmz * @version 1.0.0 * @date 2017/09/21 */public class RepeatedlyReadFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(RepeatedlyReadFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { logger.debug("复制request.getInputStream流"); ServletRequest requestWrapper = null; if (request instanceof HttpServletRequest) { requestWrapper = new RepeatedlyReadRequestWrapper((HttpServletRequest) request); } if (null == requestWrapper) { chain.doFilter(request, response); } else { chain.doFilter(requestWrapper, response); } } @Override public void destroy() { }}
step 3:
添加拦截器 RepeatedlyReadInterceptor 继承 HandlerInterceptorAdapter 拦截适配器
package com.interceptor;import com.config.RepeatedlyReadRequestWrapper;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.ServletInputStream;import javax.servlet.ServletRequest;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.*;import java.nio.charset.Charset;/** * @author zhangmz * @version 1.0.0 * @date 2017/09/21 */public class RepeatedlyReadInterceptor extends HandlerInterceptorAdapter { private static final Logger logger = LoggerFactory.getLogger(RepeatedlyReadInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { /** * 对来自后台的请求统一进行日志处理 */ RepeatedlyReadRequestWrapper requestWrapper; if (request instanceof RepeatedlyReadRequestWrapper) { // 签名处理过程 start.... requestWrapper = (RepeatedlyReadRequestWrapper) request; logger.info("请求Body: {} ", getBodyString(requestWrapper)); // 签名处理过程 end.... } // 默认记录后台接口请求日志记录 String url = request.getRequestURL().toString(); String method = request.getMethod(); String uri = request.getRequestURI(); String queryString = request.getQueryString(); logger.info(String.format("请求参数, url: %s, method: %s, uri: %s, params: %s ", url, method, uri, queryString)); return super.preHandle(request, response, handler); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { RepeatedlyReadRequestWrapper requestWrapper; if (request instanceof RepeatedlyReadRequestWrapper) { // 测试再次获取Body start.... requestWrapper = (RepeatedlyReadRequestWrapper) request; logger.info("请求Body: {} ", getBodyString(requestWrapper)); // 测试再次获取Body end.... } } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } /** * 获取请求Body * * @param request * * @return */ public static String getBodyString(final ServletRequest request) { StringBuilder sb = new StringBuilder(); InputStream inputStream = null; BufferedReader reader = null; try { inputStream = cloneInputStream(request.getInputStream()); reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); String line = ""; while ((line = reader.readLine()) != null) { sb.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return sb.toString(); } /** * Description: 复制输入流</br> * * @param inputStream * * @return</br> */ public static InputStream cloneInputStream(ServletInputStream inputStream) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; try { while ((len = inputStream.read(buffer)) > -1) { byteArrayOutputStream.write(buffer, 0, len); } byteArrayOutputStream.flush(); } catch (IOException e) { e.printStackTrace(); } InputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); return byteArrayInputStream; }}
step 4:
配置过滤器与拦截器 WebMvcConfig
package com.config;import com.filter.RepeatedlyReadFilter;import com.interceptor.MyInterceptor;import org.springframework.boot.web.servlet.FilterRegistrationBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.*;/** * SpringMVC 配置类 * * @author zhangmz * @create 2017/6/20 */@Configurationpublic class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RepeatedlyReadInterceptor()).addPathPatterns("/**"); super.addInterceptors(registry); } @Bean public FilterRegistrationBean repeatedlyReadFilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); RepeatedlyReadFilter repeatedlyReadFilter = new RepeatedlyReadFilter(); registration.setFilter(repeatedlyReadFilter); registration.addUrlPatterns("/*"); return registration; }}
step 5:
添加测试Controller类 TestController
package com.controller;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.MediaType;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;/** * @author zhangmz * @version 1.0.0 * @date 2017/09/21 */@Controller@RequestMapping( "/test" )public class TestController { private static final Logger logger = LoggerFactory.getLogger(TestController.class); @ResponseBody @RequestMapping( value = "/str", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE ) public String queryStr(@RequestBody String json) { logger.info("json : {}", json); return "ok"; }}
控制台结果:
2017-09-21 15:48:30.582 DEBUG 35564 -- [nio-8080-exec-1] c.filter.RepeatedlyReadFilter : 复制request.getInputStream流2017-09-21 15:48:30.591 INFO 35564 -- [nio-8080-exec-1] com.interceptor.RepeatedlyReadInterceptor : 请求Body: {"aa":"bb"} 2017-09-21 15:48:30.592 INFO 35564 -- [nio-8080-exec-1] com.interceptor.RepeatedlyReadInterceptor : 请求参数, url: http://localhost:8080/test/str, method: POST, uri: /test/str, params: null 2017-09-21 15:48:30.602 INFO 35564 -- [nio-8080-exec-1] com.controller.TestController : json : {"aa":"bb"}2017-09-21 15:48:30.609 INFO 35564 -- [nio-8080-exec-1] com.interceptor.RepeatedlyReadInterceptor : 请求Body: {"aa":"bb"}
参考资料:
构建可重复读取inputStream的request
ServletRequest中getReader()和getInputStream()只能调用一次的解决办法-续网友
解决request.getParameter() 、 request.getInputStream()和request.getReader()只能使用一次的问题
阅读全文
0 0
- 拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.
- ServletRequest中getReader()和getInputStream()只能调用一次的解决办法
- 解决request.getParameter() 、 request.getInputStream()和request.getReader()只能使用一次的问题
- 构建可重复读取inputStream的request
- 构建可重复读取inputStream的request
- ServletRequest中getReader()和getInputStream()只能调用一次的解决办法-续网友
- Servlet的Request.getInputStream()只能读取一次
- request.getinputstream只能读取一次
- request.getParameter()、request.getInputStream()和request.getReader()
- request.getParameter()、request.getInputStream()和request.getReader()
- request.getParameter()、request.getInputStream()和request.getReader()
- request.getParameter()、request.getInputStream()和request.getReader()
- request.getParameter()、request.getInputStream()和request.getReader()
- request.getParameter()、request.getInputStream()和request.getReader()
- request.getParameter()、request.getInputStream()和request.getReader()
- request.getParameter() 、 request.getInputStream()和request.getReader()
- request.getParameter()、request.getInputStream()和request.getReader()
- (转)servlet/jsp中得到表单数据的3种方法request.getParameter()、request.getInputStream()和request.getReader()
- ajax规范
- Redis系列-5.列表(List)结构
- NoSql简介(-)
- lua学习笔记_metatable,__index,__newindex
- thinkphp 实现查询重复的值,
- 拦截器中,request中getReader()和getInputStream()只能调用一次,构建可重复读取inputStream的request.
- pdf导出功能
- ansible 效率优化
- 51nod 1264 线段相交
- linux(centos)服务器部署web项目
- spring文件上传
- netty实现TimeServer服务
- 无限轮播加小圆点(从网络获取图片)
- Activiti入门之环境搭建