为了 重写 ServletInputStream 的 getInputStream()方法,我们需要自定义一个 HttpServletRequestWrapper
package com.xxx.emes.dc.server.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StreamUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: xxx
* @Decription: post请求参数缓存
* @Date: 2021/12/28
*<dependency>
* <groupId>com.alibaba</groupId>
* <artifactId>fastjson</artifactId>
* <version>1.2.73</version>
*</dependency>
*/
@Slf4j
public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper
{
/**
* 缓存下来的HTTP body
* 原因是执行request.getInputStream(),读取参数后inputStream中的值会消失
* 所以需要把读取过的内容存下来,然后需要的时候对外提供可被重复读取的ByteArrayInputStream
* 对于MVC的过滤器来说,我们就需要重写 ServletInputStream 的 getInputStream()方法
*/
private byte[] body;
/**
* 需要处理参数的地址 key=地址 value=参数名称 的map
* initMap说明 key=参数名称 value=参数名称
*/
//private Map<String,Map<String,String>> initMap = new HashMap<>();
public MyHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
//初始化需要处理的链接和参数名称
//initMap();
body = StreamUtils.copyToByteArray(request.getInputStream());
// if(initMap.containsKey(request.getRequestURI())){
// body = StreamUtils.copyToByteArray(request.getInputStream());
String bodyStr = new String(body, request.getCharacterEncoding());
log.info("原始参数:"+bodyStr);
JSONObject json = JSON.parseObject(bodyStr);
JSONObject requestJson = json.getJSONObject("request");
body = requestJson.getString("body").getBytes(StandardCharsets.UTF_8);
log.info("原始参数内的请求体body:"+ new String(body, request.getCharacterEncoding()));
// initMap.get(request.getRequestURI()).forEach((key,value)->{
// if(StringUtils.notBlank(json.getString(key))){
// json.put(key,json.getString(key) + value);
// }
// });
// bodyStr = json.toJSONString();
// body = bodyStr.getBytes();
// }
}
/**
* @Author: xxx
* @Decription: 需要特殊处理的请求地址-初始化地址和参数名称
* @Date: 2021/12/9
*/
/*private Map<String,Map<String,String>> initMap(){
//xxx请求说明
Map<String,String> newValue = new HashMap<>();
newValue.put("searchStartTime"," 00:00:00");
newValue.put("searchEndTime"," 23:59:59");
initMap.put("/xxx/xxx/xxx",newValue);
return initMap;
}*/
/**
* 重新包装输入流
* @return
* @throws IOException
*/
@Override
public ServletInputStream getInputStream() throws IOException {
InputStream bodyStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bodyStream.read();
}
/**
* 下面的方法一般情况下不会被使用,如果你引入了一些需要使用ServletInputStream的外部组件,可以重点关注一下。
* @return
*/
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
@Override
public BufferedReader getReader() throws IOException {
InputStream bodyStream = new ByteArrayInputStream(body);
return new BufferedReader(new InputStreamReader(getInputStream()));
}
}
然后定义一个 DispatcherServlet子类来分派 上面自定义的 HttpServletRequestWrapper
package com.xxx.emes.dc.server.config;
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Author: xxx
* @Decription: 自定义 DispatcherServlet 来分派 MyHttpServletRequestWrapper
* @Date: 2021/12/28
*/
public class MyDispatcherServlet extends DispatcherServlet
{
/**
* 包装成我们自定义的request
* @param request
* @param response
* @throws Exception
*/
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
super.doDispatch(new MyHttpServletRequestWrapper(request), response);
}
}
然后配置一下
package com.xxx.emes.dc.server.config;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author xxx
* @summary HTTP请求拦截器
*/
@Slf4j
public class RequestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/*
//获取请求参数(请求URL问号后拼接的参数)
String queryString = request.getQueryString();
log.info("请求参数:{}", queryString);
//获取请求body(JSON请求参数)
byte[] bodyBytes = StreamUtils.copyToByteArray(request.getInputStream());
byte[] bodyBytesNew = StreamUtils.copyToByteArray(request.getInputStream());
//通过两次getInputStream()发现,第二遍getInputStream() bodyBytesNew是NULL,原因是读取参数后inputStream中的值会消失,导致controller接口没有请求参数报错400
//所以需要把读取过的内容存下来,然后需要的时候对外提供可被重复读取的ByteArrayInputStream。
//对于MVC的过滤器来说,我们就需要重写 ServletInputStream 的 getInputStream()方法。
String body = new String(bodyBytes, request.getCharacterEncoding());
//log.info("请求体:{}", body);
JSONObject object = JSONObject.parseObject(body);
//log.info("JSON格式请求体:{}", object);
*/
return true;
}
}
package com.penghai.emes.dc.server.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* WebMVC配置,你可以集中在这里配置拦截器、过滤器、静态资源缓存等
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RequestInterceptor())
//.addPathPatterns("/**")//不做过滤
.addPathPatterns("/agvLiKu/agvLiKuTaskCallBack");
}
@Bean
@Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
return new MyDispatcherServlet();
}
}
最后把需要过滤的请求Controller接口地址配置到.addPathPatterns处,即可实现对接口请求参数的拦截。