• 三种实现日志过滤器的方式 (过滤器 (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请求和响应的对象

  • 相关阅读:
    Java 线程之间的通讯,等待唤醒机制
    Java 死锁以及死锁的产生
    2018Java开发面经(持续更新)
    OpenFlow1.3协议wireshark抓包分析
    SDN核心技术剖析和实战指南---读书笔记
    Kafka常用命令
    安装kafka+zk-ui
    flink窗口
    flink架构原理
    安装Flink集群
  • 原文地址:https://www.cnblogs.com/zhshlimi/p/9671273.html
Copyright © 2020-2023  润新知