本文已参与「新人创作礼」活动,一起开启掘金创作之路。 项目中有时需要和外部系统对接,为了便于排查接口传参是否正确,可以新增一个拦截器打印访问日志。
可以通过继承Filter接口,重写doFilter方法实现。将请求在进入Controller层前拦截下来,并打印出请求的方法、参数以及请求方IP。
package com.tct.ii.ucr.core.filter;
import com.tct.ii.ucr.common.BodyReaderHttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.springframework.util.StringUtils;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
/**
* 默认的access filter
* 主要用于调试时打印访问日志
* 可由配置文件的配置控制在filter registry生成注册
* @author wl
* @date 2021/7/26
*/
@Slf4j
public class DefaultAccessFilter implements Filter {
private static final String UNKNOWN = "unknown";
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ServletRequest requestWrapper = null;
try {
HttpServletRequest request = (HttpServletRequest) servletRequest;
String requestMethod = request.getMethod();
log.info("请求方式:" + requestMethod + " 请求地址: " + request.getRequestURI() + "; 请求来源:" + getRealIp(request));
if ("POST".equals(requestMethod)) {
if (ServletFileUpload.isMultipartContent(request)) {
log.info("请求包含文件");
}else {
requestWrapper = new BodyReaderHttpServletRequestWrapper(
(HttpServletRequest) servletRequest);
log.info("请求体: {}", ((BodyReaderHttpServletRequestWrapper) requestWrapper).getBodyStr());
}
}else {
log.info("请求参数: " + getParameterNames(request));
}
} catch (Exception e) {
e.printStackTrace();
}
if (null == requestWrapper) {
filterChain.doFilter(servletRequest, servletResponse);
}else {
filterChain.doFilter(requestWrapper, servletResponse);
}
}
private String getParameterNames(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
stringBuilder.append(entry.getKey()).append("=");
stringBuilder.append(Arrays.toString(entry.getValue())).append(", ");
}
return stringBuilder.length() > 2 ? stringBuilder.substring(0, stringBuilder.length() - 2) : "";
}
private String getRealIp(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (!StringUtils.isEmpty(ip) && !UNKNOWN.equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
if(ip.contains(",")){
ip = ip.split(",")[0];
}
}
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (StringUtils.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
package com.tct.ii.ucr.config;
import com.tct.ii.ucr.core.filter.DefaultAccessFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @author wl
* @date 2021/7/28
*/
@Configuration
@Slf4j
public class DefaultFilterRegistry {
@Bean
@Conditional(LoggingAccessCheck.class)
public FilterRegistrationBean<DefaultAccessFilter> registryAccessFilter() {
FilterRegistrationBean<DefaultAccessFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new DefaultAccessFilter());
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
private static class LoggingAccessCheck implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String loggingAccess = environment.getProperty("logging.debug.log-access");
return Boolean.parseBoolean(loggingAccess);
}
}
}
package com.tct.ii.ucr.common;
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.Charset;
/**
* 继承HttpServletRequestWrapper实现对 httpServletRequest 的装饰,用来获取 body 数据
* @author wl
* @date 2021/11/26
*/
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
private String bodyStr;
public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
String bodyString = getBodyString(request);
body = bodyString.getBytes(Charset.forName("UTF-8"));
bodyStr=bodyString;
}
public String getBodyStr() {
return bodyStr;
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
public 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")));
char[] bodyCharBuffer = new char[1024];
int len = 0;
while ((len = reader.read(bodyCharBuffer)) != -1) {
sb.append(new String(bodyCharBuffer, 0, len));
}
} 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();
}
}
logging:
config: classpath:log4j2.xml
debug:
log-access: true
log-slow-query:
enable: true
min-cost: 1000