SpringBoot拦截器或过滤器中使用流读取参数后,controller中注解读取不到参数
来源:互联网 发布:ip地址显示杭州阿里云 编辑:程序博客网 时间:2024/06/10 22:28
今天出现这样一个问题:
现在开发的项目是基于SpringBoot的maven项目,有个需求就是要加一个拦截器和过滤器,在拦截器中我需要获取到前端传过来的json数据,按照常理来说,获取请求参数使用request.getParameter()方法就可以,但是不知道为什么在这个项目里面获取不到。这时候我想到了使用流的方法从request对象中直接读出来。
当然,方法写好后,在拦截器中也读取到了请求参数,但是出现一个问题。就是后面的controller中使用了@RequestBody注解获取参数,但是拦截器执行过后,controller获取不到参数,甚至是方法都没有进入对应的方法中就报错了(注:拦截器中不使用流,controller中是能获取到参数的)。
在debug过程中,发现拦截器使用流和不适用流到了一个获取字符集解析器的方法里面就有差别了。一个是能获取到字符集解析器。另一个获取不到。但是看了执行过程也没发现什么问题。就百度了一下,发现了Spring有一个问题就是: ServletRequest中getReader()和getInputStream()只能调用一次。而又由于@RequestBody注解获取输出参数的方式也是根据流的方式获取的。所以我们前面使用流获取后,后面的@RequestBody就获取不到对应的输入流了。
那么问题找到之后。想着解决。从网上查找了一下,有一个方法就是。先读取流,然后在将流写进去就行了,下面是我的一些解决代码:
过滤器:
package com.***;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import java.io.*;/** * Created by yefuliang on 2017/10/25. */@WebFilter(filterName="myFilter",urlPatterns="/*")public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("--------------过滤器初始化------------"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("--------------执行过滤操作------------"); // 防止流读取一次后就没有了, 所以需要将流继续写出去 HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest); filterChain.doFilter(requestWrapper, servletResponse); } @Override public void destroy() { System.out.println("--------------过滤器销毁------------"); }}
在代码中我们可以看到我们为了方式流的丢失,我们新建了一个类的对象,注意filterChain.doFilter(requestWrapper, servletResponse);这句代码的requestWrapper参数,和原生的不一致哦,是我们处理过后的ServletRequest。下面是BodyReaderHttpServletRequestWrapper的实现:
package com.***;/** * Created by yefuliang on 2017/10/25. */import javax.servlet.ReadListener;import javax.servlet.ServletInputStream;import javax.servlet.ServletRequest;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import java.io.*;import java.nio.charset.Charset;/** * 保存流 * * @author yefuliang 2017年10月25日 */public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper { private final byte[] body; public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); String sessionStream = getBodyString(request); body = sessionStream.getBytes(Charset.forName("UTF-8")); } /** * 获取请求Body * * @param request * @return */ public 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 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; } @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() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; }}
代码逻辑大家可以自己看下,很简单的一个逻辑。
下面是我的拦截器获取参数代码:
package com.***;import com.alibaba.dubbo.config.annotation.Reference;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Arrays;import java.util.UUID;/** * 自定义拦截器 * 拦截时机 Filter pre -> service -> dispatcher -> preHandle ->controller * ->postHandle - > afterCompletion -> FilterAfter * Created by yefuliang on 2017/10/23. */public class bgqCommonInterceptorl implements HandlerInterceptor { /** * 在controller处理之前首先对请求参数进行处理,以及对公共参数的保存 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("---------------拦截器开始------------------"); try{ response.setHeader("Content-type", "application/json;charset=UTF-8"); String requestMethord = request.getRequestURI();//请求方法 if(requestMethord==null){ return false; } //获取请求参数 JSONObject parameterMap = JSON.parseObject(new BodyReaderHttpServletRequestWrapper(request).getBodyString(request)); String dataFrom = String.valueOf(parameterMap.get("dataFrom")); }catch (Exception e){ e.printStackTrace(); } System.out.println("拦截器拦截完成"); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("---------------拦截器方法二开始------------------"); } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("---------------拦截器方法三开始------------------"); }
parameterMap 就是获取的请求参数json对象。
问题解决。
- SpringBoot拦截器或过滤器中使用流读取参数后,controller中注解读取不到参数
- 拦截器中读取request中的流后,controller 无法获取到数据解决方案
- Controller中获取输入参数注解使用总结
- JFinal中的Controller读取参数
- 解决在Filter中读取Request中的流后,后续controller或restful接口中无法获取流的问题
- js中读取url参数
- 从配置文件中读取参数
- 使用参数拦截器通过注解直接从JSON对象中获取数据
- 关于过滤器使用了参数后,接口获取不到参数问题
- web拦截器中读取request中流导致跳转controller失败问题解决方案
- Java中nextInt()后接nextLine()读取不到数据
- 解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法
- 解决在Filter中读取Request中的流后, 然后再Control中读取不到的做法
- Spring mvc中Controller参数绑定注解详解
- 批处理中读取文本文件作为参数
- java中从命令行读取参数+代码
- 数据库连接参数从配置文件中读取
- c语言中读取命令行参数
- windows Server 2008 r2部署JSP项目
- Red and Black (POJ 1979,深度优先搜索)
- larvael学习之Eloquent
- Thinkphp 结合kibana 来监测设备(监测车辆情况的设备)是否还在正常运行
- C#中的GUID生成格式
- SpringBoot拦截器或过滤器中使用流读取参数后,controller中注解读取不到参数
- 广度、深度、易用性,详解6大机器学习云
- matlab中控制并口打标Failure to find requested data acquisition device: parallel.解决方案
- 三阶幻方
- ubuntu 安装搜狗输入法后,皮肤错乱解决办法【ubuntu16.04 x64】
- kubernetes minikube kubectl的安装 绝对良心
- JVM线程测试与java原子操作
- 语义分割学习笔记(三)——SegNet Upsample层解析
- @ResponseBody与response.getWriter .write()区别