1.创建自定义过滤器
import com.jdcloud.apim.openapi.util.RequestWrapper;
import org.springframework.core.annotation.Order;
import javax.servlet.*;
import java.io.IOException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
//将过滤器注册到springboot的启动项中,顺序为第一个。这里有两种方法
//方法一:通过注解的方式
@Order(1)
@WebFilter(filterName = "httpServletRequestFilter", urlPatterns = "/*")
public class RequestReplacedFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
// logger.debug("复制request.getInputStream流");
if (request instanceof HttpServletRequest) {
requestWrapper = new RequestWrapper((HttpServletRequest) request);
}
//获取request请求中的流,将取出来的字符串保存在缓存中,同时再将该字符串再次转换成流,然后把它放入到新request对象中。
if (requestWrapper == null) {
chain.doFilter(request, response);
} else {
chain.doFilter(requestWrapper, response);
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
//方法二:在springboot的启动类中,添加如下代码:
@Bean
public FilterRegistrationBean httpServletRequestReplacedRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new HttpServletRequestReplacedFilter());
registration.addUrlPatterns("/*");
registration.addInitParameter("paramName", "paramValue");
registration.setName("httpServletRequestReplacedFilter");
registration.setOrder(1);
return registration;
}
2.创建request请求的包装类,获取到body信息的同时,将该body信息在放入到新的request对象中,并返回。
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
public class RequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = readBytes(request.getReader(), "utf-8");
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream(),"utf-8"));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() throws IOException {
return bais.read();
}
};
}
/**
* 通过BufferedReader和字符编码集转换成byte数组
* @param br
* @param encoding
* @return
* @throws IOException
*/
private byte[] readBytes(BufferedReader br, String encoding) throws IOException {
String str = null;
StringBuilder sb=new StringBuilder();
while ((str = br.readLine()) != null) {
sb.append(str);
}
return sb.toString().getBytes(Charset.forName(encoding));
}
}
3.在日志的拦截器中,获取request中的body信息
public class LoggerInterceptor implements HandlerInterceptor {
private static Logger LOGGER = LoggerFactory.getLogger(LoggerInterceptor.class);
//拦截器处理之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if(method.equals(HttpGet.METHOD_NAME)||method.equals(HttpDelete.METHOD_NAME)){
requestParam=request.getQueryString();
}else if(method.equals(HttpPost.METHOD_NAME)||method.equals(HttpPatch.METHOD_NAME)||method.equals(HttpPut.METHOD_NAME)){
/**
* 对来自后台的请求统一进行日志处理
*/
RequestWrapper requestWrapper;
if (request instanceof RequestWrapper) {
// 签名处理过程 start....
requestWrapper = (RequestWrapper) request;
requestParam=getBodyString(requestWrapper);
LOGGER.info("请求Body: {} ", requestParam);
// 签名处理过程 end....
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
RequestWrapper requestWrapper;
if (request instanceof RequestWrapper) {
// 测试再次获取Body start....
requestWrapper = (RequestWrapper) request;
LOGGER.info("请求Body: {} ", getBodyString(requestWrapper)); // 测试再次获取Body end....
}
}
private String getBodyString(HttpServletRequest request) throws IOException {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString().trim();
}
}
至此,通过以上两篇文章即可实现获取request中的参数,实现在生产环境中日志可追溯的场景。以上是个人项目中的总结,有更好的方法欢迎大家留言。