转:https://www.jianshu.com/p/69c6fba08c92
最近有一个需要从拦截器中获取post请求的参数的需求,这里记录一下处理过程中出现的问题。
首先想到的就是request.getParameter(String )方法,但是这个方法只能在get请求中取到参数,post是不行的,后来想到了使用流的方式,调用request.getInputStream()获取流,然后从流中读取参数,如下代码所示:
String body = "";
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
InputStream inputStream = null;
try {
inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
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()。
那么有什么办法可以用户解决呢?上面这篇博客中提到了解决方案,就是重写HttpServletRequestWrapper把request保存下来,然后通过过滤器把保存下来的request再填充进去,这样就可以多次读取request了。步骤如下所示:
①写一个类,继承HttpServletRequestWrapper
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
public class RequestWrapper extends HttpServletRequestWrapper {
private final String body;
public RequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
InputStream inputStream = null;
try {
inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
} finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (bufferedReader != null) {
try {
bufferedReader.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
body = stringBuilder.toString();
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}
②拦截器层面
package com.miniprogram.web.douyin.interceptor;
import com.alibaba.fastjson.JSON;
import com.miniprogram.api.douyin.user.req.DyuserReq;
import com.miniprogram.common.auth.VisitLimitCount;
import com.miniprogram.common.cache.RedisCache;
import com.miniprogram.common.config.InterceptorConfigMap;
import com.miniprogram.common.config.InterceptorUrlConfig;
import com.miniprogram.common.douyin.SearchEngineMapConstants;
import com.miniprogram.common.response.Response;
import com.miniprogram.common.session.*;
import com.miniprogram.common.utils.DateUtil;
import com.miniprogram.dao.common.UserLoginEntity.Users;
import com.miniprogram.service.douyin.users.UsersService;
import com.miniprogram.web.douyin.config.RequestWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Component("authSecurityInterceptor")
public class AuthSecurityInterceptor extends HandlerInterceptorAdapter {
private Logger logger = LoggerFactory.getLogger(AuthSecurityInterceptor.class);
@Autowired
private UsersService douYinUsersService;
@Autowired
private RedisCache redisCache;
@Autowired
private VisitLimitCount visitLimitCount;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
try {
RequestWrapper requestWrapper = new RequestWrapper(httpServletRequest);
String body = requestWrapper.getBody();
System.out.println(body);
return true;
}catch (Exception e){
logger.error("权限判断出错",e);
}
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
③过滤器Filter,用来把request传递下去
import com.miniprogram.web.douyin.config.RequestWrapper;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Component
@WebFilter(urlPatterns = "/*",filterName = "channelFilter")
public class ChannelFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
if(servletRequest instanceof HttpServletRequest) {
requestWrapper = new RequestWrapper((HttpServletRequest) servletRequest);
}
if(requestWrapper == null) {
filterChain.doFilter(servletRequest, servletResponse);
} else {
filterChain.doFilter(requestWrapper, servletResponse);
}
}
@Override
public void destroy() {
}
}
④在启动类中注册拦截器
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@SpringBootApplication
@ServletComponentScan //注册过滤器注解
@Configuration
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
经测试,问题解决
相关推荐
自己spring boot 拦截器,可以自定义限制跳转路径及自定义不拦截哪些具体路径,具体设置可以看注释,一看就懂,引用哪些包已经包含了,不明白的请浏览,看到后第一时间给您回复
spring mvc 拦截器获取请求数据信息 解压之后放到项目中 直接运行就可以了 (将流多次运用)
spring-boot 拦截器 登录拦截spring-boot 拦截器 登录拦截spring-boot 拦截器 登录拦截spring-boot 拦截器 登录拦截
spring拦截器,高级参数绑定,controller返回值
常用拦截 拦截器HandlerInterceptor 拦截器MethodInterceptor 添加依赖 创建启动类 创建拦截器类 创建控制器 监控control请求耗时,提高性能
idea软件。SpringBoot的拦截器的博客所写的例子。preHandle()方法的返回值true和false的详细区别还未描述
spring boot jpa连接数据库,设置拦截器拦截指定路径下的文件。
Spring Boot 拦截器 各项日志 通过kibana具体查询分析 Advanced Settings [7.2.0] 综合分析 定时任务执行日志 数据同步日志 用户访问操作日志 异常日志 内存日志 Spring逻辑参数执行日志 SQL...
主要介绍了SpringBoot拦截器原理解析及使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
spring boot简单应用,配置yml文件,实现mysql数据库的连接,对数据进行增删改查,另有登录拦截器。
本案例中 使用maven 搭建spring boot 基本案例 其中实现了 用户登录功能,实现Filter 和 拦截器两种方式 来过滤session登录,后续会使用token方式,请大家关注
使用Spring MVC或Spring Boot中打印或记录日志一般使用AOP记录Request请求和Response响应参数,在不使用AOP的前提下,如果在Filter中打印日志,在打印或消费请求类型为Content-Type:application/json的请求时,会...
Spring Boot中文文档提供了详细的中文翻译和说明,包括了基本概念、使用方法、配置参数、代码示例等,可以帮助用户快速上手和深入理解Spring Boot的使用。该文档还提供了丰富的链接和参考资料,方便用户深入学习和...
Spring AOP 拦截器 Advisor Spring AOP 拦截器 Advisor
针对spring boot 集成jpa sql操作进行自定义分库分表逻辑
NULL 博文链接:https://412887952-qq-com.iteye.com/blog/2292476
获取Spring Boot 2微框架的可重用代码配方和代码段 了解Spring Boot 2如何与其他Spring API,工具和框架集成 访问Spring MVC和新的Spring Web Sockets,以实现更简单的Web开发 使用微服务进行Web服务开发并与Spring ...
本demo为Spring boot整合shiro,以mybatis plus做dao层交互数据,实现了读取数据库用户数据实现用户登录,权限认证,读取数据库中用户对应的url请求,实现请求的过滤。自定义了relam和过滤器来实现这些功能
spring-boot-helloWorld:spring-boot的helloWorld版本 spring-boot-mybaits-annotation:注解版本 spring-boot-mybaits-xml:xml配置版本 spring-boot-mybatis-mulidatasource:springboot+mybatis多数据源最简解决...
spring boot mybatis mysql springmvc国际化 拦截器 创建聚合项目