转: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框架中,拦截器(Interceptor)是一种强大的工具,它允许开发者在请求处理前后执行自定义逻辑,例如日志记录、权限检查等。Spring MVC中的拦截器是基于AOP(面向切面编程)原理实现的,可以理解为对...
在Spring Boot中,处理POST请求时,通常可以方便地通过控制器方法的参数直接获取请求参数。然而,当遇到无法获取POST请求参数的情况,这可能是由于客户端发送请求的方式与服务器端期望的数据格式不匹配导致的。在...
本文将详细介绍如何在Spring Boot中设置拦截器,并通过四个基本的HTTP请求方法(PUT、DELETE、POST和GET)来展示其工作原理。 首先,我们需要创建一个自定义的拦截器类,它需要继承Spring MVC的`HandlerInterceptor...
在Spring MVC中,我们可以使用@RequestBody注解来处理请求参数,并使用 EncryptUtils 工具类来进行加密和解密。EncryptUtils 工具类提供了sha()方法来生成签名,createAesCipher()方法来创建AES加密器。 在控制器...
然而,如果在处理JSON类型的POST请求时,直接在Filter中打印请求参数,可能会遇到一些问题,如上述描述中的`IOException: Stream closed`异常。这是因为当我们读取请求体时,如果没有正确地管理流,流可能在我们尝试...
可以创建一个过滤器(Filter),在Spring Boot中通过`@WebFilter`注解注册,实现请求和响应的拦截。 ```java @WebFilter(filterName = "MyFilter", urlPatterns = "/*") public class MyFilter implements Filter {...
本教程将详细讲解如何在Spring Boot项目中设置一个简单的登录拦截器。 首先,我们需要理解Spring Security是Spring Boot推荐用于安全控制的框架。它提供了丰富的功能,包括认证、授权、CSRF防护、会话管理等。我们...
本示例将指导你如何在Spring Boot中自定义国际化实现,包括从文件夹中动态加载多个国际化文件、根据用户请求动态设置前端显示的语言,并通过拦截器和注解自动化处理。 首先,让我们回顾一下项目的初始化步骤。在...
在Spring Boot框架中,拦截器是实现诸如日志记录、权限检查、性能监控等通用功能的有效手段。拦截器可以在请求到达控制器之前和之后执行特定操作。同时,由于前端与后端的分离开发模式越来越流行,跨域访问问题也...
1. 它可以绕过拦截器,如果你的项目使用了spring boot security,他可以无视spring boot security的认证,并且你不需要配置什么 2. 它支持前后置脚本,并且使用java编写,可以调用任意第三方库,和项目自身的clas ...
本文将详细介绍如何在Spring Boot项目中使用拦截器,包括自定义拦截器的创建、配置以及应用。拦截器在Spring框架中是一种用于扩展和定制Spring MVC框架行为的组件,可以拦截进入的请求,并进行相关处理,例如:权限...
在本文中,我们将深入探讨Spring Boot Web请求响应的案例,这是一个关于如何使用Spring Boot构建Web应用程序的基本教程。Spring Boot简化了Java开发,尤其是对于构建基于Web的服务,它提供了开箱即用的功能,使得...
在本教程中,我们将深入探讨如何使用SpringBoot构建RESTful Web服务,并结合拦截器实现更高效、可控的服务。首先,让我们理解REST(Representational State Transfer)的核心概念,它是一种架构风格,用于设计网络...
在Spring Boot项目中,我们也可以使用拦截器来实现CORS机制。拦截器可以根据不同的路径配置不同的拦截器。例如,我们可以配置拦截器来允许某些路径下的资源访问。 以下是一个简单的拦截器示例: ```java public ...
- `@PathVariable`,`@RequestParam`,`@ModelAttribute`:用于获取请求参数。 4. **拦截器(Interceptor)**: - 自定义拦截器可以实现HandlerInterceptor接口,处理预处理和后处理逻辑。 - 拦截器链中的顺序由...
- **servlet-context.xml**:Spring MVC的核心配置文件,声明拦截器、视图解析器、bean等。 3. **处理器映射器与适配器** - **HandlerMapping**:负责将URL映射到对应的处理器(Controller)方法。 - **...
虽然这个示例是注解驱动的,但通常还需要一个配置类来启用Spring MVC,如`WebMvcConfigurerAdapter`的子类,配置拦截器、视图解析器等。然而,Spring Boot项目通常不再需要显式配置。 8. **依赖注入**: Spring ...
- 用于从请求参数中获取值,将其绑定到方法参数上。 - 示例: ```java @GetMapping("/search") public String search(@RequestParam("keyword") String keyword) { // ... } ``` 7. **@PathVariable** - ...
- **Java配置**:使用Java配置来声明式地定义Spring MVC的组件,例如控制器、过滤器、拦截器等。 - **控制器**:通过`@RestController`注解的类来定义HTTP端点,使用`@RequestMapping`、`@GetMapping`、`@...