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() {
    }

}

  启动程序的时候

 

 调用接口

 

 

  

posted @ 2019-07-05 12:18  巴黎爱工作  阅读(1486)  评论(0编辑  收藏  举报