最近有一个需要从拦截器中获取post请求的参数的需求,这里记录一下处理过程中出现的问题。
首先想到的就是request.getParameter(String )方法,但是这个方法只能在get请求中取到参数,post是不行的,后来想到了使用流的方式,调用request.getInputStream()获取流,然后从流中读取参数,如下代码所示:

  1. String body = "";
  2. StringBuilder stringBuilder = new StringBuilder();
  3. BufferedReader bufferedReader = null;
  4. InputStream inputStream = null;
  5. try {
  6. inputStream = request.getInputStream();
  7. if (inputStream != null) {
  8. bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
  9. char[] charBuffer = new char[128];
  10. int bytesRead = -1;
  11. while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
  12. stringBuilder.append(charBuffer, 0, bytesRead);
  13. }
  14. } else {
  15. stringBuilder.append("");
  16. }
  17. } catch (IOException ex) {
  18. e.printStackTrace();
  19. } finally {
  20. if (inputStream != null) {
  21. try {
  22. inputStream.close();
  23. }
  24. catch (IOException e) {
  25. e.printStackTrace();
  26. }
  27. }
  28. if (bufferedReader != null) {
  29. try {
  30. bufferedReader.close();
  31. }
  32. catch (IOException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. }
  37. body = stringBuilder.toString();

代码中的body就是request中的参数,我这里传的是JSON数据:{"page": 1, "pageSize": 10},那么body就是:body = "{"page": 1, "pageSize": 10}",一个JSON字符串。这样是可以成功获取到post请求的body,但是,经过拦截器后,参数经过@RequestBody注解赋值给controller中的方法的时候,却抛出了一个这样的异常:

org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing

在网上查找资料后发现,request的输入流只能读取一次,那么这是为什么呢?下面是答案:

那是因为流对应的是数据,数据放在内存中,有的是部分放在内存中。read 一次标记一次当前位置(mark position),第二次read就从标记位置继续读(从内存中copy)数据。 所以这就是为什么读了一次第二次是空了。 怎么让它不为空呢?只要inputstream 中的pos 变成0就可以重写读取当前内存中的数据。javaAPI中有一个方法public void reset() 这个方法就是可以重置pos为起始位置,但是不是所有的IO读取流都可以调用该方法!ServletInputStream是不能调用reset方法,这就导致了只能调用一次getInputStream()。

摘自:https://blog.csdn.net/sdut406/article/details/81369983

那么有什么办法可以用户解决呢?上面这篇博客中提到了解决方案,就是重写HttpServletRequestWrapper把request保存下来,然后通过过滤器把保存下来的request再填充进去,这样就可以多次读取request了。步骤如下所示:

①写一个类,继承HttpServletRequestWrapper

  1. import javax.servlet.ReadListener;
  2. import javax.servlet.ServletInputStream;
  3. import javax.servlet.http.HttpServletRequest;
  4. import javax.servlet.http.HttpServletRequestWrapper;
  5. import java.io.*;
  6.  
  7. public class RequestWrapper extends HttpServletRequestWrapper {
  8. private final String body;
  9.  
  10. public RequestWrapper(HttpServletRequest request) {
  11. super(request);
  12. StringBuilder stringBuilder = new StringBuilder();
  13. BufferedReader bufferedReader = null;
  14. InputStream inputStream = null;
  15. try {
  16. inputStream = request.getInputStream();
  17. if (inputStream != null) {
  18. bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
  19. char[] charBuffer = new char[128];
  20. int bytesRead = -1;
  21. while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
  22. stringBuilder.append(charBuffer, 0, bytesRead);
  23. }
  24. } else {
  25. stringBuilder.append("");
  26. }
  27. } catch (IOException ex) {
  28.  
  29. } finally {
  30. if (inputStream != null) {
  31. try {
  32. inputStream.close();
  33. }
  34. catch (IOException e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. if (bufferedReader != null) {
  39. try {
  40. bufferedReader.close();
  41. }
  42. catch (IOException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. }
  47. body = stringBuilder.toString();
  48. }
  49.  
  50. @Override
  51. public ServletInputStream getInputStream() throws IOException {
  52. final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
  53. ServletInputStream servletInputStream = new ServletInputStream() {
  54. @Override
  55. public boolean isFinished() {
  56. return false;
  57. }
  58. @Override
  59. public boolean isReady() {
  60. return false;
  61. }
  62. @Override
  63. public void setReadListener(ReadListener readListener) {
  64. }
  65. @Override
  66. public int read() throws IOException {
  67. return byteArrayInputStream.read();
  68. }
  69. };
  70. return servletInputStream;
  71.  
  72. }
  73.  
  74. @Override
  75. public BufferedReader getReader() throws IOException {
  76. return new BufferedReader(new InputStreamReader(this.getInputStream()));
  77. }
  78.  
  79. public String getBody() {
  80. return this.body;
  81. }
  82.  
  83. }

②拦截器层面

  1. import com.alibaba.fastjson.JSON;
  2. import com.miniprogram.api.douyin.user.req.DyuserReq;
  3. import com.miniprogram.common.auth.VisitLimitCount;
  4. import com.miniprogram.common.cache.RedisCache;
  5. import com.miniprogram.common.config.InterceptorConfigMap;
  6. import com.miniprogram.common.config.InterceptorUrlConfig;
  7. import com.miniprogram.common.douyin.SearchEngineMapConstants;
  8. import com.miniprogram.common.response.Response;
  9. import com.miniprogram.common.session.*;
  10. import com.miniprogram.common.utils.DateUtil;
  11. import com.miniprogram.dao.common.UserLoginEntity.Users;
  12. import com.miniprogram.service.douyin.users.UsersService;
  13. import com.miniprogram.web.douyin.config.RequestWrapper;
  14. import org.slf4j.Logger;
  15. import org.slf4j.LoggerFactory;
  16. import org.springframework.beans.BeanUtils;
  17. import org.springframework.beans.factory.annotation.Autowired;
  18. import org.springframework.stereotype.Component;
  19. import org.springframework.web.servlet.ModelAndView;
  20. import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
  21.  
  22. import javax.servlet.http.HttpServletRequest;
  23. import javax.servlet.http.HttpServletResponse;
  24. import java.io.BufferedReader;
  25. import java.io.InputStreamReader;
  26. import java.util.ArrayList;
  27. import java.util.HashMap;
  28. import java.util.List;
  29. import java.util.Map;
  30.  
  31. @Component("authSecurityInterceptor")
  32. public class AuthSecurityInterceptor extends HandlerInterceptorAdapter {
  33. private Logger logger = LoggerFactory.getLogger(AuthSecurityInterceptor.class);
  34.  
  35. @Autowired
  36. private RedisCache redisCache;
  37. @Autowired
  38. private VisitLimitCount visitLimitCount;
  39.  
  40. @Override
  41. public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
  42. try {
  43. RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest);
  44. String body = requestWrapper.getBody();
  45. System.out.println(body);
  46. return true;
  47. }catch (Exception e){
  48. logger.error("权限判断出错",e);
  49. }
  50. return false;
  51. }
  52.  
  53. @Override
  54. public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
  55.  
  56. }
  57.  
  58. @Override
  59. public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
  60. }
  61. }

③过滤器Filter,用来把request传递下去

  1. import javax.servlet.*;
  2. import javax.servlet.annotation.WebFilter;
  3. import javax.servlet.http.HttpServletRequest;
  4. import java.io.IOException;
  5.  
  6. @WebFilter(urlPatterns = "/*",filterName = "channelFilter")
  7. public class ChannelFilter implements Filter {
  8.  
  9. @Override
  10. public void init(FilterConfig filterConfig) throws ServletException {
  11.  
  12. }
  13.  
  14. @Override
  15. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  16. ServletRequest requestWrapper = null;
  17. if(servletRequest instanceof HttpServletRequest) {
  18. requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
  19. }
  20. if(requestWrapper == null) {
  21. filterChain.doFilter(servletRequest, servletResponse);
  22. } else {
  23. filterChain.doFilter(requestWrapper, servletResponse);
  24. }
  25. }
  26.  
  27. @Override
  28. public void destroy() {
  29.  
  30. }
  31. }

④在启动类中注册拦截器

  1. import org.springframework.boot.SpringApplication;
  2. import org.springframework.boot.autoconfigure.SpringBootApplication;
  3. import org.springframework.boot.web.servlet.MultipartConfigFactory;
  4. import org.springframework.boot.web.servlet.ServletComponentScan;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.ComponentScan;
  7. import org.springframework.context.annotation.Configuration;
  8.  
  9. @SpringBootApplication
  10. // @ServletComponentScan //注册过滤器注解
  11. @Configuration
  12. public class WebApplication {
  13.  
  14. public static void main(String[] args) {
  15. SpringApplication.run(WebApplication.class, args);
  16. }
  17. }

经测试,问题解决

spring boot拦截器中获取request post请求中的参数的更多相关文章

  1. spring boot拦截器中获取request post请求中的参数(转)

    文章转自 https://www.jianshu.com/p/69c6fba08c92

  2. Spring boot拦截器的实现

    Spring boot拦截器的实现 Spring boot自带HandlerInterceptor,可通过继承它来实现拦截功能,其的功能跟过滤器类似,但是提供更精细的的控制能力. 1.注册拦截器 @C ...

  3. 【spring boot】spring boot 拦截器

    今日份代码: 1.定义拦截器 import com.alibaba.fastjson.JSON; import org.apache.commons.collections.CollectionUti ...

  4. spring boot拦截器配置

    1.在spring boot配置文件application.properties中添加要拦截的链接 com.url.interceptor=/user/test 2.编写拦截器代码 ,创建UrlInt ...

  5. Spring boot 拦截器和过滤器

    1. 过滤器 Filter介绍 Filter可以认为是Servlet的一种“加强版”,是对Servlet的扩展(既可以对请求进行预处理,又可以对处理结果进行后续处理.使用Filter完整的一般流程是: ...

  6. (22)Spring Boot 拦截器HandlerInterceptor【从零开始学Spring Boot】

    上一篇对过滤器的定义做了说明,也比较简单.过滤器属于Servlet范畴的API,与Spring 没什么关系.     Web开发中,我们除了使用 Filter 来过滤请web求外,还可以使用Sprin ...

  7. spring boot拦截器WebMvcConfigurerAdapter,以及高版本的替换方案

    Springboot中静态资源和拦截器处理(踩了坑)   背景: 在项目中我使用了自定义的Filter 这时候过滤了很多路径,当然对静态资源我是直接放过去的,但是,还是出现了静态资源没办法访问到spr ...

  8. spring boot拦截器

    实现自定义拦截器只需要3步: 1.创建我们自己的拦截器类并实现 HandlerInterceptor 接口. 2.创建一个Java类继承WebMvcConfigurerAdapter,并重写 addI ...

  9. 九、 Spring Boot 拦截器

    过滤器属于Servlet范畴的API,与spring 没什么关系. Web开发中,我们除了使用 Filter 来过滤请web求外,还可以使用Spring提供的HandlerInterceptor(拦截 ...

随机推荐

  1. 安卓开发常用icon/png图样

    平时开发当中会用到很多png图样,但是自己又不太会做,因此做好的办法就是直接在网上下载下来用了,这里给大家推荐一个比较好用的网站,免费的,有很多好的png可以直接下载下来使用. http://www. ...

  2. 启动VMware虚拟机时总是出现许可证到期提示怎么办?

    不知道大家有没有遇到过这个问题,每次当你打开VMware虚拟机时它总是会提示许可证到期,需要注册,还会出现许多报红的代码,下面就让小编带大家解决一下吧~ VMware教程 如果Fusion本身无法启动 ...

  3. 微服务架构 - CentOS7离线部署docker

    1.环境准备 系统环境为: CentOS Linux release 7.5.1804 (Core) 安装docker版本为: 17.12.0-ce 2.准备部署文件 在http://mirrors. ...

  4. 用node探究http缓存

    用node搞web服务和直接用tomcat.Apache做服务器不太一样, 很多工作都需要自己做.缓存策略也要自己选择,虽然有像koa-static,express.static这些东西可以用来管理静 ...

  5. KnockoutJS-与服务端交互

    几乎所有Web应用程序都要和服务器端交换数据,交换数据时最方便的就是使用JSON格式.Knockout可以实现很复杂的客户端交互,对于前后端交互使用的技术最为基本且常用的是Ajax,本次利用Ajax和 ...

  6. java中如何从一行数据中读取数据

    目录 @(如何从一行数据中切割数据) 例如我要从一行学生信息中分割出学号.姓名.年龄.学历等等 ==主要使用split方法,split方法在API中定义如下:== public String[] sp ...

  7. JDBC mysql 相关内容笔记

    解决乱码: url字符串加上?useUnicode=true&characterEncoding=utf-8; mysql数据库无法插入中文数据问题:将mysql数据库的编码改为utf-8; ...

  8. HIVE扩展GIS函数

        按项目日益增长的gis数据量要求,需要在大数据集群中部署HIVE的扩展函数.     Apache Hive是一个建立在Hadoop架构之上的数据仓库.它能够提供数据的精炼,查询和分析.([引 ...

  9. Sql Server 本地(客户端)连接服务器端操作

    网有很多相关内容,我在此做记录和总结 1.主要是sql server 配置管理工具的配置 在此参考 https://www.cnblogs.com/yougmi/p/4616273.html(再次感谢 ...

  10. CVE-2019-0686|Microsoft Exchange特权提升漏洞补丁已发布

    Microsoft Exchange Server中存在一个特权提升漏洞.成功利用此漏洞的攻击者可以获得与Exchange服务器的任何其他用户相同的权限.这可能允许攻击者执行诸如访问其他用户的邮箱之类 ...