先说下为啥有这个需求,在基于spring的web应用中,一般会在<代码>控制器> 代码层获取http方法中身体的数据。
<强>方式1:强>
比如http请求的<代码> - type> 代码为application/json <代码> 代码>的情况下,直接用<代码> @RequestBody 代码>接收。
<强>方式2:强>
也有像目前我们在做的这个项目,比较原始,是直接手动读取流。(不要问我为啥这么原始,第一版也不是我写的。)
@RequestMapping ("/XXX.do”) 公共空XXX (HttpServletRequest请求,HttpServletResponse响应)抛出IOException { JSONObject JSONObject=WebUtils.getParameters(请求);//业务处理 ResponseUtil。setResponse(响应,MessageFactory.createSuccessMsg ()); }
WebUtils。getparameter如下:
公共静态JSONObject getparameter (HttpServletRequest请求)抛出IOException { InputStream是=零;=new BufferedInputStream (request.getInputStream (), BUFFER_SIZE); 内容长度int contentLength=Integer.valueOf (request.getHeader (“”)); byte[]字节=新字节(contentLength); int readCount=0; 而(readCount & lt;contentLength) { readCount +=6?字节,readCount contentLength - readCount); } 字符串requestJson=新的字符串(字节,AppConstants.UTF8); 如果(StringUtils.isBlank (requestJson)) { 返回新JSONObject (); } JSONObject jsonObj=JsonUtils.toJSONObject (requestJson); 返回jsonObj; }
当然,不管怎么说,都是对流进行读取。
问题是,假如我想在控制器前面加一层aop, aop里面对进入控制器层的方法进行日志记录,记录方法参数,应该怎么办呢。
如果是采用了方式1的话,简单.spring已经帮我们把参数从流里取出来,给我们提供好了,我们拿着打印一下日志即可。
如果是比较悲剧地采用了我们这种方式,参数里只有个httpServletRequest,那就只有自己去读取流了,然而,在aop中我们把流读了的话,
在控制器层就读不到了。
毕竟,流只能读一次啊。
说一千道一,万流来自哪里,来自
javax.servlet.ServletRequest # getInputStream
所以,我们的思路,是不是可以这样,定义一个过滤器,在过滤器中将请求替换为我们自定义的请求。
下面标红的为自定义的请求。
/* * * */包com.ckl.filter; 进口com.ckl.utils.BaseWebUtils; 进口com.ckl.utils.MultiReadHttpServletRequest; 进口org.slf4j.Logger; 进口org.slf4j.LoggerFactory; 进口org.springframework.core.annotation.Order; 进口org.springframework.http.HttpMethod; 进口org.springframework.http.MediaType; 进口javax.servlet。*; 进口javax.servlet.annotation.WebFilter; 进口javax.servlet.http.HttpServletRequest; 进口java.io.IOException;/* * * Web流多次读写过滤器 * *拦截所有请求,主要是针对第三方提交过来的请求。 *为什么要做成可多次读写的流,因为可以在aop层打印日志。 *但是不影响控制器层继续读取该流 * *该滤波器的原理:https://stackoverflow.com/questions/10210645/http-servlet-request-lose-params-from-post-body-after-read-it-once/17129256 # 17129256 * @author ckl */@Order (1) @WebFilter (filterName=癱acheRequestFilter urlpattern=?,”) 公共类CacheRequestFilter实现滤波器{ 私有静态最终日志记录器=LoggerFactory.getLogger (CacheRequestFilter.class); @Override FilterConfig FilterConfig公共空init()抛出ServletException {//TODO自动生成方法存根 } @Override doFilter (ServletRequest公共无效请求,ServletResponse响应, FilterChain链)抛出IOException ServletException { HttpServletRequest HttpServletRequest=(HttpServletRequest)请求; logger.info(“请求uri: {}”, httpServletRequest.getRequestURI ()); 如果(BaseWebUtils.isFormPost (httpServletRequest)) { httpServletRequest=new MultiReadHttpServletRequest (httpServletRequest); 字符串参数=BaseWebUtils.getParameters (httpServletRequest); logger.info (“CacheRequestFilter接受post请求。身体是{}”,参数); }else if (isPost (httpServletRequest)) {//文件上传请求,没必要缓存请求 如果(request.getContentType () .contains (MediaType.MULTIPART_FORM_DATA_VALUE)) { 其他}{ httpServletRequest=new MultiReadHttpServletRequest (httpServletRequest); 字符串参数=BaseWebUtils.getParameters (httpServletRequest); logger.info (“CacheRequestFilter接受post请求。身体是{}”,参数); } } 链。doFilter (httpServletRequest、响应); } @Override 公共空间摧毁(){//TODO自动生成方法存根 } 公共静态布尔isPost (HttpServletRequest请求){ 返回HttpMethod.POST.matches (request.getMethod ()); } } MultiReadHttpServletRequest.java: 进口org.apache.commons.io.IOUtils; 进口javax.servlet.ServletInputStream; 进口javax.servlet.http.HttpServletRequest; 进口javax.servlet.http.HttpServletRequestWrapper; 进口java.io.BufferedReader; 进口java.io.ByteArrayOutputStream; 进口java.io.IOException; 进口java.io.InputStreamReader;/* * *描述: * https://stackoverflow.com/questions/10210645/http-servlet-request-lose-params-from-post-body-after-read-it-once/17129256 # 17129256 * @author: ckl * creat_date: 2018/8/2 0002 * creat_time: 13:46 * */公开课MultiReadHttpServletRequest延伸HttpServletRequestWrapper { 私人ByteArrayOutputStream cachedBytes; 公共MultiReadHttpServletRequest (HttpServletRequest请求){ 超级(请求); cachedBytes=new ByteArrayOutputStream (); ServletInputStream inputStream=零; 尝试{ inputStream=super.getInputStream (); IOUtils。复制(inputStream, cachedBytes); }捕捉(IOException e) { e.printStackTrace (); } } @Override 公共ServletInputStream getInputStream()抛出IOException { 返回新CachedServletInputStream (cachedBytes); } @Override null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null null春季应用中多次读取http post方法中的流遇到的问题