spring 日志拦截器
为了方便追踪业务调用过程,记录一种日志实现方法
简单版
日志拦截器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StreamUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
/**
* LogInterceptor
* 日志拦截器
*
* @author Kuzer
* @version 0.0.1
* @since 2022/7/16
*/
public class LogInterceptor implements HandlerInterceptor {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String logId = ThreadLogId.setAndGet();
response.setHeader("logId", logId);
info(logId, handler, "α ", "");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
String logId = ThreadLogId.remove();
if (ex == null) {
info(logId, handler, "Ω ", "");
} else {
error(logId, handler, ex);
}
}
private void info(String logId, Object handler, String prefix, String args) {
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
logger.info(prefix + "调用: {} {}", hm.getMethod().getName() , logId);
}
}
private void error(String logId, Object handler, Exception e) {
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
logger.error("异常处理:{}",logId , e);
}
}
}
ThreadLogId.java 大概长这样子
/**
* ThreadLogId
*
* @author Kuzer
* @version 0.0.1
* @since 2022/7/16
*/
public class ThreadLogId {
private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static String setAndGet() {
String logId = UUID.randomUID().toString();
threadLocal.set(logId);
return logId;
}
public static String get() {
return threadLocal.get();
}
public static String remove() {
String logId = get();
if(logId != null){
threadLocal.remove();
}
return logId;
}
}
注册拦截器
import com.xinyuan.yzy.usersystem.config.interceptor.LogInterceptor;
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;
/**
* WebConfig
*
* @author Kuzer
* @version 0.0.1
* @since 2022/7/15
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
}
}
需要记录请求参数
自己封装 HttpServletRequest
多次字符流读取
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.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* MultiReadRequest
*
* @author Kuzer
* @version 0.0.1
* @since 2022/7/16
*/
public class MultiReadRequest extends HttpServletRequestWrapper {
/**
* inputStream 缓存
*/
private byte[] buf;
/**
* 读取剩余次数,读取完后清除buf缓存
*/
private int count;
public MultiReadRequest(HttpServletRequest request) throws IOException {
this(request, 2);
}
public MultiReadRequest(HttpServletRequest request, int count) throws IOException {
super(request);
this.count = count;
this.buf = StreamUtils.copyToByteArray(request.getInputStream());
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (buf == null) {
throw new IOException("the input stream is over than count");
}
count--;
InputStream stream = new ByteArrayInputStream(buf);
if (count <= 0) {
buf = null;
}
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return buf != null;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() throws IOException {
return stream.read();
}
};
}
}
自定义dispatcher
import org.springframework.web.servlet.DispatcherServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* MultiReadDispatcher
* 为了解决多次读取 request InputStream
*
* @author Kuzer
* @version 0.0.1
* @since 2022/7/16
*/
public class MultiReadDispatcher extends DispatcherServlet {
@Override
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
super.doDispatch(new MultiReadRequest(request, 2), response);
}
}
注册dispatcherServlet
public class WebConfig {
// ... 拦截器注册
@Bean(name = DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet() {
return new MultiReadDispatcher();
}
}