SpringBoot下,@WebFilter配置获取日志

Posted qianjinyan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot下,@WebFilter配置获取日志相关的知识,希望对你有一定的参考价值。


CREATE TABLE [dbo].[SWEBSERVICELOG]( [WLG_ID] [varchar](100) NOT NULL, [WLG_SESSIONID] [varchar](100) NULL, [WLG_REMOTEIPADDR] [varchar](20) NULL, [WLG_REQUESTURL] [varchar](100) NULL, [WLG_START_DT] [datetime2](7) NULL, [WLG_END_DT] [datetime2](7) NULL, [WLG_CLIENTHOST] [varchar](200) NULL, [WLG_USERAGENT] [varchar](500) NULL, [WLG_METHOD] [nvarchar](20) NULL, [WLG_PARAMS] [varchar](500) NULL, [WLG_PARAMSVALUE] [varchar](4000) NULL, [WLG_RETURN_MSG] [text] NULL, [WLG_EXCEPTION] [varchar](500) NULL, [WLG_CREATION_DT] [datetime] NULL, [WLG_UPDATE_DT] [datetime] NULL, [WLG_CREATIONUID] [varchar](50) NULL, [WLG_UPDATEUID] [varchar](50) NULL, [WLG_NAME] [varchar](100) NULL, [WLG_RETURN_CODE] [varchar](20) NULL, [WLG_RETURN_MESSAGE] [varchar](200) NULL, [WLG_SOURCE] [varchar](20) NULL, CONSTRAINT [SWEBSERVICELOG_WECHAT_WLG_ID_pk_4] PRIMARY KEY CLUSTERED ( [WLG_ID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO

  

package cn.com.acxiom.coty.wechat.ws.filter;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.UUID;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ReadListener;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.WriteListener;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

import cn.com.acxiom.coty.wechat.ws.bean.po.WebserviceLogWechat;
import cn.com.acxiom.coty.wechat.ws.common.CONST;
import cn.com.acxiom.coty.wechat.ws.common.ResponseBean;
import cn.com.acxiom.coty.wechat.ws.common.UUID16;
import cn.com.acxiom.coty.wechat.ws.mapper.WebserviceLogWechatMapper;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;


import org.springframework.util.StringUtils;



@SuppressWarnings("ALL")
@WebFilter
@Component("logFilter")
public class LogFilter implements Filter 


    static InetAddress ia = null;

    static 
        try 
            ia = InetAddress.getLocalHost();
         catch (UnknownHostException e) 
            e.printStackTrace();
        
    

    private static final Logger logger = LoggerFactory.getLogger(LogFilter.class);
    private static final String NOTLOGIN = "NOT LOGIN";
    private static final String LOGIN_PATH = "/account";

    @Autowired
    private WebserviceLogWechatMapper webLogMapper;

    @Value("$sys.name")
    private String sysName;

    private Pattern ignore = Pattern.compile(".*/webjars/.*$|.*/v2/.*$|.*/swagger.*$|.*/configuration/.*$|.*/images/.*|.*/farvirate.ico|.*/actuator.*");

    static final Pattern BLANK = Pattern.compile("\\\\t|\\r|\\n");

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 

        long startTime = System.currentTimeMillis();


        /* 判断如果是swagger界面请求的一些资源就不会走日志 */
        HttpServletRequest request = (HttpServletRequest) req;

        if ("option".equalsIgnoreCase(request.getMethod()))
            System.out.println("OPTION");
        

        HttpServletResponse response = (HttpServletResponse) res;
        String requestId = null;

        if (StringUtils.isEmpty(request.getHeader("sid"))) 
            requestId = UUID.randomUUID().toString().replace("-", "");
            request.setAttribute("sid", requestId);
         else 
            requestId = request.getHeader("sid");
            request.setAttribute("sid", request.getHeader("sid"));
        
        response.addHeader("sid", requestId);


        String requestURL = request.getRequestURI();
        if (ignore.matcher(requestURL).matches()) 
            chain.doFilter(req, res);
            return;
        


        // 2、RequestBody读取
        // 创建包装对象
        LoggerHttpServletRequest wrappedRequest = new LoggerHttpServletRequest(request);
        // 读取参数
        String content = IOUtils.toString(wrappedRequest.getInputStream());
        // 重设参数
        wrappedRequest.resetServletInputStream();
        // 返回输出值
        wrappedRequest.setAttribute("sid", requestId);
        OutputStream outputStream = res.getOutputStream();

        LoggerHttpServletResponse wrapperResponse = new LoggerHttpServletResponse(response);

        chain.doFilter(wrappedRequest, wrapperResponse);

        long endTime = System.currentTimeMillis();
        byte[] responseContent = wrapperResponse.getData();
        String responseContext = null;
        String responseContentType = wrapperResponse.getContentType();
        if (!StringUtils.isEmpty(responseContentType) && responseContentType.contains("image")) 
            responseContext = "[image]";
         else 
            responseContext = new String(wrapperResponse.getData(), "UTF-8");
        

        outputStream.write(responseContent);

        /* 插入接口参数捕获日志 */
        try 
            insertWebServiceInvokeLog(wrappedRequest, wrapperResponse, responseContext, content, startTime, endTime, requestId);
         catch (Exception e) 
            // TODO Auto-generated catch block
            e.printStackTrace();
        

    


    private void insertWebServiceInvokeLog(LoggerHttpServletRequest wrappedRequest, LoggerHttpServletResponse wrapperResponse, String responseBody, String requestBody, long beginTime,
                                           long endTime, String requestId) 
        String httpMethod = wrappedRequest.getMethod();
        String remoteHost = wrappedRequest.getRemoteHost();
        String params = wrappedRequest.getQueryString();
        String userAgent = wrappedRequest.getHeader("user-agent");
        String requestPath = wrappedRequest.getServletPath();
        String responseContentType = wrapperResponse.getContentType();
        String apiName =wrapperResponse.getHeader(CONST.RESPONS_API_NAME_KEY);


        // 创建系统日志
        WebserviceLogWechat webLog = new WebserviceLogWechat();

        webLog.setWlgId(UUID16.uuid());
        webLog.setWlgCreationuid(sysName);
        webLog.setWlgCreationDt(new Date());
        webLog.setWlgUpdateDt(new Date());
        webLog.setWlgUpdateuid(sysName);
        webLog.setWlgRemoteipaddr(remoteHost);
        webLog.setWlgRequesturl(requestPath);

        webLog.setWlgStartDt(new Date(beginTime));
        webLog.setWlgEndDt(new Date(endTime));
        webLog.setWlgMethod(httpMethod);
        webLog.setWlgName(apiName);
        webLog.setWlgParams(params);
        webLog.setWlgParamsvalue(requestBody);

        webLog.setWlgReturnMsg(responseBody);

        try 
            if (!StringUtils.isEmpty(responseContentType) && !responseContentType.contains("image")) 
                ResponseBean responseBean = JSONObject.parseObject(responseBody, ResponseBean.class);
                webLog.setWlgReturnMessage(responseBean.getMessage());
                webLog.setWlgReturnCode(responseBean.getCode());
            
         catch (Exception e) 
            e.printStackTrace();
        


        webLog.setWlgUseragent(userAgent);
        webLog.setWlgClienthost(String.format("%s:%s", ia.getHostName(), ia.getHostAddress()));
        webLog.setWlgSessionid(requestId);
        webLog.setWlgSource(sysName);

        try 
            webLogMapper.insertSelective(webLog);
         catch (Exception e) 
            e.printStackTrace();
            logger.error("requestId:[] Save log to db with some error",requestId);
            logger.error("requestId:[] Save log to file, Log Data: ",requestId, JSONObject.toJSONString(webLog));
        


    


    /**
     * 包装HttpServletRequest
     */
    private static class LoggerHttpServletRequest extends HttpServletRequestWrapper 

        private byte[] data;
        private HttpServletRequest request;
        private LoggerServletInputStream servletInputStream;

        public LoggerHttpServletRequest(HttpServletRequest request) 
            super(request);
            this.request = request;
            servletInputStream = new LoggerServletInputStream();
        

        public void resetServletInputStream() 
            try 
                servletInputStream.inputStream = new ByteArrayInputStream(new String(data).getBytes("UTF-8"));
             catch (UnsupportedEncodingException e) 

                logger.error(e.getMessage());

            
        

        @Override
        public ServletInputStream getInputStream() throws IOException 
            if (data == null) 
                data = IOUtils.toByteArray(this.request.getReader());
                servletInputStream.inputStream = new ByteArrayInputStream(data);
            
            return servletInputStream;
        

        private class LoggerServletInputStream extends ServletInputStream 

            private InputStream inputStream;

            @Override
            public int read() throws IOException 
                return inputStream.read();
            

            @Override
            public boolean isFinished() 
                return false;
            

            @Override
            public boolean isReady() 
                return false;
            

            @Override
            public void setReadListener(ReadListener listener) 

            

        
    

    /**
     * 包装的HttpServletResponse类
     *
     * @author jacwan
     */
    private static class LoggerHttpServletResponse extends HttpServletResponseWrapper 

        private ByteArrayOutputStream byteStream;

        public LoggerHttpServletResponse(HttpServletResponse response) 
            super(response);
            byteStream = new ByteArrayOutputStream();
        

        @Override
        public ServletOutputStream getOutputStream() 
            return new LoggerServletOutputStream(byteStream);
        

        @Override
        public PrintWriter getWriter() throws IOException 
            return new PrintWriter(getOutputStream(), false);
        

        public byte[] getData() 
            return byteStream.toByteArray();
        

        public class LoggerServletOutputStream extends ServletOutputStream 

            private DataOutputStream dataOutputStream;

            public LoggerServletOutputStream(OutputStream output) 
                dataOutputStream = new DataOutputStream(output);
            

            @Override
            public void write(int b) throws IOException 
                dataOutputStream.write(b);
            

            @Override
            public void write(byte[] b) throws IOException 
                dataOutputStream.write(b);
            

            @Override
            public void write(byte[] b, int off, int len) throws IOException 
                dataOutputStream.write(b, off, len);
            

            @Override
            public boolean isReady() 
                return false;
            

            @Override
            public void setWriteListener(WriteListener listener) 

            
        
    

    @Override
    public void init(FilterConfig filterConfig) throws ServletException 
    

    @Override
    public void destroy() 
    

  1. 需要注意的是: 实现的接口Filter是javax.servlet包中的,不是util.logger中的

  2. 有时候需要在运行的main函数头上加上@ServletComponentScan,有时候不需要添加, @WebFilter的使用还要深入看下,如果在filter类的头上加上@Component("小写的filter类名"),就可以不用添加@ServletComponentScan

 

 

直接上测试代码

技术图片

DemoApplication中

package com.example.demo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableCaching
@EnableTransactionManagement
@EnableAsync
public class DemoApplication implements CommandLineRunner 

    private static Logger logger = LoggerFactory.getLogger(DemoApplication.class);


    public static void main(String[] args) 
        SpringApplication.run(DemoApplication.class, args);
    

    @Override
    public void run(String... args) throws Exception 
        logger.info("started");
        System.out.println("startedstartedstartedstartedstarted====");
    

  

ResponseBean
package com.example.demo.pojo;

import com.example.demo.common.Message;
import com.fasterxml.jackson.annotation.JsonIgnore;

public class ResponseBean<T> 

    @JsonIgnore
    public boolean ok() 
        return this.code.equalsIgnoreCase(Message.SUCCESS_CODE);
    

    public ResponseBean() 
        this.code = Message.SUCCESS_CODE;
        this.message = Message.SUCCESS_MESSAGE;
    

    public ResponseBean(T data) 
        this.code = Message.SUCCESS_CODE;
        this.message = Message.SUCCESS_MESSAGE;
        this.data = data;
    

    private T data;
    private String code;
    private String message;

    public T getData() 
        return data;
    

    public void setData(T data) 
        this.data = data;
    

    public String getCode() 
        return code;
    

    public void setCode(String code) 
        this.code = code;
    

    public String getMessage() 
        return message;
    

    public void setMessage(String message) 
        this.message = message;
    

  

IndexController
package com.example.demo.controller;


import com.example.demo.pojo.ResponseBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class IndexController 

    @GetMapping("/index")
    public ResponseBean index()
        ResponseBean responseBean = new ResponseBean();
        String info = "=========Welcome===========";
        responseBean.setData(info);
        return responseBean;
    



Message
package com.example.demo.common;

public class Message 

    public static final String SUCCESS_CODE = "0000";
    public static final String SUCCESS_MESSAGE = "success";


 

FilterDemo01
package com.example.demo.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;


@WebFilter
@Component("filterDemo01")
public class FilterDemo01 implements Filter 


    public void init(FilterConfig filterConfig) throws ServletException 
        System.out.println("----FilterDemo01过滤器初始化----");
    


    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 

        // 对request和response进行一些预处理
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        System.out.println("FilterDemo01执行前!!!");
        chain.doFilter(request, response); // 让目标资源执行,放行
        System.out.println("FilterDemo01执行后!!!");
    


    public void destroy() 
        System.out.println("----过滤器销毁----");
    



 

Rest0PubFilter
package com.example.demo.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter
@Component
//(urlPatterns = "/*", filterName = "rest0PubFilter")
//@Order(1)//指定过滤器的执行顺序,值越大越靠后执行
public class Rest0PubFilter implements Filter 


    @Override
    public void init(FilterConfig filterConfig) //初始化过滤器
        System.out.println("getFilterName:"+filterConfig.getFilterName());//返回<filter-name>元素的设置值。
        System.out.println("getServletContext:"+filterConfig.getServletContext());//返回FilterConfig对象中所包装的ServletContext对象的引用。
        System.out.println("getInitParameter:"+filterConfig.getInitParameter("cacheTimeout"));//用于返回在web.xml文件中为Filter所设置的某个名称的初始化的参数值
        System.out.println("getInitParameterNames:"+filterConfig.getInitParameterNames());//返回一个Enumeration集合对象。
    

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
                         FilterChain filterChain) throws IOException, ServletException 
        if(false)
            //response.sendRedirect("http://localhost:8081/demo/test/login");//重定向
            System.out.println("==========");
        
        filterChain.doFilter(servletRequest, servletResponse);//doFilter将请求转发给过滤器链下一个filter , 如果没有filter那就是你请求的资源

    

    @Override
    public void destroy() 
    


  启动程序的时候

技术图片

 

 调用接口

技术图片

 

 

  

以上是关于SpringBoot下,@WebFilter配置获取日志的主要内容,如果未能解决你的问题,请参考以下文章

springboot + webFilter

springboot + webFilter

springboot的注解声明过滤器配置错误导致拦截所有请求。

@WebFilter注解

@WebFilter注解

Spring Boot配置过滤器的两种方式