前言: 在使用自定义注解获取接口中形参中的参数或者实体类对象数据的时候,需要用到拦截器去拦截每次请求,但在拦截器使用getInputStream()或者getReader()方法后会导致后面的执行无法获取到数据(也就是使用@RequestBody注解),这是因为这两个方法只能读一次数据流之后会失效,本人亲测在HandlerMethod对象中能获取到方法入参参数,但无法获取到实体类数据,整了有点时间查询相关文章解决后分享
新建Demo项目 引入Maven依赖引入SpringBoot启动类org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE UTF-8 UTF-8 1.8 true org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test org.apache.commons commons-lang3 3.5 commons-io commons-io 2.5
@SpringBootApplication
public class RequestStreamApplication {
public static void main(String[] args) {
SpringApplication.run(RequestStreamApplication.class);
}
}
创建实体类和Controller类
public class Student {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + ''' +
'}';
}
}
@RestController
public class RequestStreamController {
private static final Logger log = LoggerFactory.getLogger(RequestStreamController.class);
@PostMapping(value = "/requestDemo")
@Permission
public String requestDemo(@RequestBody Student student){
log.info(student.toString());
return student.toString();
}
}
创建自定义注解类
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
boolean isOpen() default true;
}
配置文件
server:
port: 8085
servlet:
context-path: /requestStream
创建自定义RequestWrapper装饰类
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 byte[] requestBody;
private HttpServletRequest request;
public RequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public ServletInputStream getInputStream() throws IOException {
if(null == requestBody){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(request.getInputStream(),baos);
this.requestBody = baos.toByteArray();
}
final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
return 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 bais.read();
}
};
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}
创建自定义过滤器
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
@Component
@WebFilter(filterName = "channelFilter",urlPatterns = {"
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
ServletRequest requestWrapper = null;
if(request instanceof HttpServletRequest){
requestWrapper = new RequestWrapper((HttpServletRequest) request);
}
if (null == requestWrapper) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
} catch (IOException e) {
e.printStackTrace();
} catch (ServletException e) {
e.printStackTrace();
}
}
@Override
public void destroy() {
}
}
创建自定义拦截器
说明:这里是利用@Permission注解判断,如果学生名为alice则被拦截无法进入接口,否则就放行
import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.edward.annotation.Permission;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.util.HashMap;
import java.util.Map;
@Component
public class MyInterceptor implements HandlerInterceptor {
private static final Logger log = LoggerFactory.getLogger(MyInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(handler instanceof HandlerMethod){
HandlerMethod handlerMethod = (HandlerMethod) handler;
boolean isAnnotation = handlerMethod.hasMethodAnnotation(Permission.class);
if(isAnnotation){
Permission perm = handlerMethod.getMethodAnnotation(Permission.class);
boolean open = perm.isOpen();
if(open){
BufferedReader reader = request.getReader();
String str = "";
StringBuilder stringBuilder = new StringBuilder();
while((str = reader.readLine())!= null){
stringBuilder.append(str);
}
ObjectMapper objectMapper = new ObjectMapper();
Map map = objectMapper.readValue(stringBuilder.toString(), Map.class);
if("alice".equals(map.get("name"))){
response.setContentType("application/json;charset=utf-8");
HashMap returnMap = new HashMap<>();
returnMap.put("message","学生名为alice被拦截");
String value = objectMapper.writeValueAsString(returnMap);
response.getWriter().print(value);
return false;
}
}
}
}
return true;
}
}
创建WebMvc配置类,用于添加自定义拦截器
说明:这里实现WebMvcConfigurer或继承WebMvcConfigurationSupport,两种只能选择其中一种,同时配置会导致其中一个失效
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
}
}
测试结果
这里字段名为name的alice被拦截了
字段名为name的edward不会拦截
参考文章:https://blog.csdn.net/qq_33548675/article/details/121015317



