三种实现日志过滤器的方式 (过滤器 (Filter)、拦截器(Interceptors)和切面(Aspect))

1.建立RequestWrapper类

import com.g2.order.server.utils.HttpHelper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Enumeration; import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest; public class HttpServletRequestWrapper extends
javax.servlet.http.HttpServletRequestWrapper { private final byte[] body; public HttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
System.out.println("-------------------------------------------------");
Enumeration e = request.getHeaderNames() ;
while(e.hasMoreElements()){
String name = (String) e.nextElement();
String value = request.getHeader(name);
System.out.println(name+" = "+value); }
body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
} @Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
} @Override
public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(body); return new ServletInputStream() {
@Override
public boolean isFinished() {
return true;
} @Override
public boolean isReady() {
return true;
} @Override
public void setReadListener(ReadListener listener) { } @Override
public int read() throws IOException {
return bais.read();
}
};
} @Override
public String getHeader(String name) {
return super.getHeader(name);
} @Override
public Enumeration<String> getHeaderNames() {
return super.getHeaderNames();
} @Override
public Enumeration<String> getHeaders(String name) {
return super.getHeaders(name);
} public String getStringBody(){
return new String(body);
}
}

2.定义ResponseWrapper

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException; import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse; public class HttpServletResponseWrapper extends javax.servlet.http.HttpServletResponseWrapper { private ByteArrayOutputStream buffer = null; private ServletOutputStream out = null; private PrintWriter writer = null; public HttpServletResponseWrapper(HttpServletResponse response) throws IOException{
super(response); buffer = new ByteArrayOutputStream();
out = new WapperedOutputStream(buffer);
writer = new PrintWriter(new OutputStreamWriter(buffer, "UTF-8"));
} //重载父类获取outputstream的方法
@Override
public ServletOutputStream getOutputStream() throws IOException {
return out;
} @Override
public PrintWriter getWriter() throws IOException {
return writer;
} @Override
public void flushBuffer() throws IOException {
if (out != null) {
out.flush();
}
if (writer != null) {
writer.flush();
}
} @Override
public void reset() {
buffer.reset();
} public String getResponseData(String charset) throws IOException {
flushBuffer();//将out、writer中的数据强制输出到WapperedResponse的buffer里面,否则取不到数据
byte[] bytes = buffer.toByteArray();
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
return "";
} } //内部类,对ServletOutputStream进行包装,指定输出流的输出端 private class WapperedOutputStream extends ServletOutputStream { private ByteArrayOutputStream bos = null; public WapperedOutputStream(ByteArrayOutputStream stream) throws IOException {
bos = stream;
} //将指定字节写入输出流bos
@Override
public void write(int b) throws IOException {
bos.write(b);
} @Override
public boolean isReady() {
return false;
} @Override
public void setWriteListener(WriteListener listener) { }
}
}

这里有三种实现方式 (过滤器 (Filter)、拦截器(Interceptors)和切面(Aspect))

3.1 建立过滤器

import com.g2.order.server.api.HttpServletRequestWrapper;
import com.g2.order.server.api.HttpServletResponseWrapper;
import com.g2.order.server.utils.HttpHelper; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.IOException; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; @WebFilter(filterName = "accessLog", urlPatterns = "/*")
public class AccessLogFilter implements Filter {
private static Logger logger = LoggerFactory.getLogger(AccessLogFilter.class); @Override
public void init(FilterConfig filterConfig) throws ServletException { } @Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequestWrapper requestWrapper;
if (request instanceof HttpServletRequestWrapper) {
requestWrapper = (HttpServletRequestWrapper) request;
} else {
requestWrapper = new HttpServletRequestWrapper((HttpServletRequest) request);
} HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper((HttpServletResponse) response);
chain.doFilter(requestWrapper, responseWrapper);
String result = responseWrapper.getResponseData(response.getCharacterEncoding());
response.getOutputStream().write(result.getBytes());
logger.info("请求值链接:{},method:{},body:{},header:{},response:{}"
, requestWrapper.getRequestURI()
, requestWrapper.getMethod()
, requestWrapper.getStringBody()
, HttpHelper.getStringHeaders(requestWrapper)
, result);
} @Override
public void destroy() { }
}

4.启动类

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.web.servlet.ServletComponentScan; /**
* 程序入口
*/
@SpringBootApplication
@ServletComponentScan
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

5.建立controller

import com.g2.order.dao.mapper.user.UserMapper;
import com.g2.order.server.vo.user.UserLoginReq;
import com.g2.order.dao.model.user.UserDao;
import com.g2.order.server.vo.user.UserLoginResp;
import com.g2.order.server.vo.user.UserModel; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; @Api(value = "HomeController", description = "用户登录登出接口")
@RestController
@RequestMapping("/home")
public class HomeController { @Autowired
private UserMapper userMapper; @ApiOperation(value = "用户登录", notes = "用户登录接口")
@RequestMapping(value = "/login",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public UserLoginResp login(@RequestBody UserLoginReq req) {
UserDao userDao = userMapper.getById(1);
UserModel userModel = new UserModel();
userModel.setUserId(Integer.toString(userDao.getUserId()));
return new UserLoginResp(userModel);
}
}

6.请求后的日志

请求值链接:/home/login,method:POST,body:{ "userId":"123","password":"123444"},header:cache-control:no-cache
postman-token:a75b1ed5-27d4-47ea-ba21-ee368b463fc5
content-type:application/json
user-agent:PostmanRuntime/2.3.2
host:127.0.0.1:88
accept-encoding:gzip, deflate
content-length:42
connection:keep-alive

返回值:{"success":true,"errorMessage":"","payload":{"userId":"1","roleName":null,"roleId":null}}

如果使用 拦截器(Interceptors)代码会更加简单

import com.google.common.base.Strings;

import com.g2.order.server.api.HttpServletRequestWrapper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import static java.util.stream.Collectors.joining; public class AccessLogInterceptor extends HandlerInterceptorAdapter {
private static Logger logger = LoggerFactory.getLogger(AccessLogInterceptor.class); @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String body = "";
logger.debug("Access Auth Interceptor - 进入拦截器");
if (request instanceof HttpServletRequestWrapper) {
HttpServletRequestWrapper requestWrapper = (HttpServletRequestWrapper) request;
body = requestWrapper.getStringBody();
}
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
Class[] paramTypes = method.getParameterTypes();
String paramTypesString = Arrays.stream(paramTypes).map(p -> p.getName()).collect(joining(",")); Parameter[] methodParameters = method.getParameters();
if (methodParameters.length == 0) {
return false;
}
Parameter methodParameter = methodParameters[0];
String parameterName = methodParameter.getName();
String parameterClass = methodParameter.getType().getCanonicalName();
String parameterVelue = request.getParameter(parameterName);
if (Strings.isNullOrEmpty(parameterVelue)) {
parameterVelue = body;
}
logger.info("请求方法:{},请求参数类型:{},请求值:{}", method.getName(), parameterClass, parameterVelue);
}
return true;
} /**
* This implementation is empty.
*/
@Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
} /**
* This implementation is empty.
*/
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
} /**
* This implementation is empty.
*/
@Override
public void afterConcurrentHandlingStarted(
HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
}
}

再建立Config 类

import com.g2.order.server.interceptor.AccessLogInterceptor;

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Component
public class LogInterceptorConfig extends WebMvcConfigurerAdapter {
@Bean
public AccessLogInterceptor getAccessLogInterceptor() {
return new AccessLogInterceptor();
} @Override
public void addInterceptors(InterceptorRegistry registry) {
InterceptorRegistration addInterceptor = registry.addInterceptor(getAccessLogInterceptor()); // 排除配置
addInterceptor.excludePathPatterns("/error"); // 拦截配置
addInterceptor.addPathPatterns("/**");
}
}

3.3 对controller层使用切面(Aspect)(代码最简单,功能最强大)


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component; import java.lang.reflect.Method; import javax.annotation.Resource; //开启AspectJ 自动代理模式,如果不填proxyTargetClass=true,默认为false,
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Component
@Aspect
public class ControllerAspectConfig {
@Around("execution(* com.g2.order.server.controller.*.*(..))")
public Object handleControllerMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("进入切面,执行before.."); //获取controller对应的方法.
org.aspectj.lang.reflect.MethodSignature methodSignature = (org.aspectj.lang.reflect.MethodSignature) proceedingJoinPoint.getSignature();
//获取方法所在的类(controller)
Class beanType = methodSignature.getDeclaringType();
//获取方法
Method method = methodSignature.getMethod(); //获取方法参数列表(无需处理讨厌的流了)
Object[] args = proceedingJoinPoint.getArgs();
for (Object arg : args) {
//获取参数的类型与值
System.out.println(arg.getClass().getName());
System.out.println("arg is " + arg);
} long startTime = System.currentTimeMillis();
System.out.println("进入其他切面或业务执行..");
Object obj = proceedingJoinPoint.proceed();
     System.out.println("业务完成,执行after..");
        //获取返回值的类型,与 Method.getReturnType()一致
Class responseClass=obj.getClass();
System.out.println("time aspect 耗时" + (System.currentTimeMillis() - startTime)); //方法的返回值是:
System.out.println("response is " + obj); return obj;
}
}
 

拦截器和过滤器的区别

spring boot RESTFul API拦截 以及Filter和interceptor 、Aspect区别

拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。

过滤器(Filter)         :可以拿到原始的http请求,但是拿不到你请求的控制器和请求控制器中的方法的信息。

拦截器(Interceptor):可以拿到你请求的控制器和方法,却拿不到请求方法的参数。

切片   (Aspect)       :  可以拿到方法的参数,但是却拿不到http请求和响应的对象

上一篇:(转)Linux下设置和查看环境变量


下一篇:Spring filter和拦截器(Interceptor)的区别和执行顺序