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() { } }
启动程序的时候
调用接口
------------------------- A little Progress a day makes you a big success... ----------------------------