Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use Filter to print request Log in SpringMVC Framework

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly shows you the "SpringMVC framework how to use Filter to achieve request log printing", the content is easy to understand, well-organized, hope to help you solve your doubts, the following let Xiaobian lead you to study and learn "SpringMVC framework how to use Filter to achieve request log printing" this article.

Concrete realization

Logging filter

Public class RequestFilter implements Filter {private static final String LOG_FORMATTER_IN = "request path: {% s}, request method: {% s}, parameter: {% s}, source IP: {% s}, request start time {% s}, return: {% s}, request end time {% s}, time: {% s} ms, operation type: {% s}, operator: {% s}"; public static final String USER_TOKEN_REDIS_PREFIX = "token_prefix" Private static final Logger log = LoggerFactory.getLogger (RequestFilter.class); / / conten-type list intercepted by request private List contentTypes;@Overridepublic void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; / / request path String path = httpServletRequest.getRequestURI (); String method = httpServletRequest.getMethod (); / / Map Map paramMap = new HashMap () for all request parameters / / the real IP String requestedIP of the request = RequestUtils.getRealIP (httpServletRequest); / / whether to intercept and wrap the request. If you need to intercept, you will get RequestBody. Generally, application/json is used to intercept boolean filterRequestFlag = checkFilter (request.getContentType ()); if (filterRequestFlag) {httpServletRequest = new MyRequestBodyReaderWrapper (httpServletRequest);} / / get all queryString and requestBody Map requestParamMap = RequestUtils.getRequestParamMap (httpServletRequest) If (requestParamMap! = null & &! requestParamMap.isEmpty ()) {paramMap.putAll (requestParamMap);} / / get header parameter Map headerMap = RequestUtils.getHeaders (httpServletRequest); if (headerMap! = null & &! headerMap.isEmpty ()) {paramMap.putAll (headerMap);} / / get path parameter Map uriTemplateMap = RequestUtils.getUriTemplateVar (httpServletRequest) If (uriTemplateMap! = null & &! uriTemplateMap.isEmpty ()) {paramMap.putAll (uriTemplateMap);} / / wraps Response, overrides the getOutputStream () and getWriter () methods, and uses custom OutputStream and Writer to intercept and save ResponseBody MyResponseWrapper responseWrapper = new MyResponseWrapper (httpServletResponse); / / request start time Long dateStart = System.currentTimeMillis (); / / Spring handles requests chain.doFilter (httpServletRequest, responseWrapper) through DispatchServlet / / request end time Long dateEnd = System.currentTimeMillis (); String responseBody; if (responseWrapper.getMyOutputStream () = = null) {if (responseWrapper.getMyWriter ()! = null) {responseBody = responseWrapper.getMyWriter () .getContent (); / must flush,responseBody be reused responseWrapper.getMyWriter () .myFlush () }} else {responseBody = responseWrapper.getMyOutputStream (). GetBuffer (); / / make sure that flush,responseBody will be reused responseWrapper.getMyOutputStream (). MyFlush ();} String params = JSONObject.toJSONString (paramMap); log.info (LOG_FORMATTER_IN, path, method, params, requestedIP, dateStart, responseBody, dateEnd, (dateEnd-dateStart)) } / * determine whether the request / return is application/json * Yes, * otherwise exit * @ param contentType request / response type * / private boolean checkFilter (String contentType) {boolean filterFlag = false;// whether to continue to intercept for (String p: getContentTypes ()) {if (StringUtils.contains (contentType, p)) {filterFlag = true } if (StringUtils.isEmpty (contentType)) {filterFlag = true;} return filterFlag;}}

Request wrapper

/ * wrapper for HttpServletRequest, in order to obtain requestBody during interceptor phase without preventing SpringMVC from getting requestBody*/@Slf4jpublic class MyRequestBodyReaderWrapper extends HttpServletRequestWrapper again {/ / storing JSON data body private final byte [] body;public MyRequestBodyReaderWrapper (HttpServletRequest request) throws IOException {super (request); body = getBody (request) .getBytes (Charset.forName ("UTF-8"));} @ Overridepublic ServletInputStream getInputStream () throws IOException {final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream (body) Return new ServletInputStream () {@ Overridepublic int read () throws IOException {return byteArrayInputStream.read ();}};} @ Overridepublic BufferedReader getReader () throws IOException {return new BufferedReader (new InputStreamReader (this.getInputStream ());} / * get request Body * / public static String getBody (ServletRequest request) {StringBuilder sb = new StringBuilder (); InputStream inputStream = null; BufferedReader reader = null Try {inputStream = request.getInputStream (); reader = new BufferedReader (new InputStreamReader (inputStream, Charset.forName ("UTF-8")); String line; while ((line = reader.readLine ())! = null) {sb.append (line);} catch (IOException e) {log.error ("MyRequestBodyReaderWrapper.getBody () exception-- >", e) } finally {if (inputStream! = null) {try {inputStream.close ();} catch (IOException e) {log.error ("MyRequestBodyReaderWrapper.getBody () exception-- >", e);}} if (reader! = null) {try {reader.close () } catch (IOException e) {log.error ("MyRequestBodyReaderWrapper.getBody () exception->", e);} return sb.toString ();}}

RequestUtils

/ * request tool class * / public class RequestUtils {private static final Logger logger = LoggerFactory.getLogger (RequestUtils.class); / * get all request headers * @ param request * @ return * / public static Map getHeaders (HttpServletRequest request) {Map headerMap = new HashMap (); List headers = getCommonHeaders (); headers.add ("Postman-Token"); headers.add ("Proxy-Connection"); headers.add ("X-Lantern-Version") Headers.add ("Cookie"); Enumeration headerNames = request.getHeaderNames (); while (headerNames.hasMoreElements ()) {String headerName = headerNames.nextElement (); if (headers.contains (headerName)) {continue;} headerMap.put (headerName,request.getHeader (headerName));} return headerMap } / * get the path parameter of the request * @ param request * @ return * / public static Map getUriTemplateVar (HttpServletRequest request) {NativeWebRequest webRequest = new ServletWebRequest (request); Map uriTemplateVars = (Map) webRequest.getAttribute (HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); return uriTemplateVars } / * get the real IP * @ param request * @ return * / public static String getRealIP (HttpServletRequest request) {String ip = request.getHeader ("X-Forwarded-For"); if (StringUtils.isNotEmpty (ip) & &! "unKnown" .equalsIgnoreCase (ip)) {/ / multiple reverse proxies will have multiple IP values, and the first ip is the real ip int index = ip.indexOf (",") If (index! =-1) {return ip.substring (0, index);} else {return ip;}} ip = request.getHeader ("X-Real-IP"); if (StringUtils.isNotEmpty (ip) & &! "unKnown" .equalsIgnoreCase (ip)) {return ip;} return request.getRemoteAddr () } / * get all request parameters from Request, including requests such as GET/POST/PATCH, excluding path parameters * @ param request * @ return * / public static Map getRequestParamMap (HttpServletRequest request) {Map paramMap = new HashMap (); / / get parameters in QueryString, GET or application/x-www-form-urlencoded Map queryParamMap = RequestUtils.getUriQueryVar (request); if (queryParamMap! = null) {paramMap.putAll (queryParamMap) } / / get the parameters in Body, POST/PATCH, etc., application/json Map bodyParamMap = null; try {/ / when it is a POST request and application/json, request is processed by RequestFilter as wrapper class if (! (request instanceof MyRequestBodyReaderWrapper)) {return paramMap;} MyRequestBodyReaderWrapper readerWrapper = (MyRequestBodyReaderWrapper) request; String requestBody = new String (readerWrapper.getBody (), "UTF-8") If (com.zhongan.health.common.utils.StringUtils.isNotBlank (requestBody)) {/ * this method is to prevent fastJson from changing the object order * / bodyParamMap = JSONObject.parseObject (requestBody, new TypeReference () {}, Feature.OrderedField) when deserializing multi-layer json. } catch (Exception e) {logger.error ("get request Body exception-- >", e);} if (bodyParamMap! = null) {paramMap.putAll (bodyParamMap);} return paramMap;} private static List getCommonHeaders () {List headers = new ArrayList (); Class clazz = HttpHeaders.class; Field [] fields = clazz.getFields () For (Field field: fields) {field.setAccessible (true); if (field.getType (). ToString (). EndsWith ("java.lang.String") & & Modifier.isStatic (field.getModifiers ()) {try {headers.add ((String) field.get (HttpHeaders.class) } catch (IllegalAccessException e) {logger.error ("reflection acquisition property value exception->", e);} return headers;}}

Response wrapper

/ * this wrapper mainly overrides the getOutputStream () and getWriter () methods to return custom OutputStream and Writer to the caller in order to participate in the output process and record and save the responseBody. * / public class MyResponseWrapper extends HttpServletResponseWrapper {private ResponsePrintWriter writer;private MyServletOutputStream out;public MyResponseWrapper (HttpServletResponse response) {super (response);} @ Overridepublic ServletOutputStream getOutputStream () throws IOException {/ / you must determine that the current out is empty before you can create a new out object, otherwise multiple out objects if (out = = null) {out = new MyServletOutputStream (super.getOutputStream ());} return out will appear in one request. } @ Overridepublic PrintWriter getWriter () throws IOException {/ / you must judge that the current writer is empty before you can create a new writer object, otherwise multiple writer objects will appear in one request: if (writer = = null) {writer = new ResponsePrintWriter (super.getWriter ());} return writer;} public ResponsePrintWriter getMyWriter () {return writer;} public MyServletOutputStream getMyOutputStream () {return out;}}

Custom Writer

/ * customize Writer, override the write method, and record and save ResponseBody*/public class ResponsePrintWriter extends PrintWriter {private StringBuffer buffer;public ResponsePrintWriter (PrintWriter out) {super (out); buffer = new StringBuffer ();} public String getContent () {return buffer = = null? Null: buffer.toString ();} @ Overridepublic void flush () {super.flush ();} / / clear buffer so that public void myFlush () {buffer = null;} @ Overridepublic void write (char [] buf, int off, int len) {super.write (buf,off, len); char [] destination = new char [len]; System.arraycopy (buf,off,destination,0,len); buffer.append (destination) } @ Overridepublic void write (String s) {super.write (s); buffer.append (s);}}

Custom OutputStream

/ * Custom output stream wrapper, override the write method, and record and save ResponseBody*/public class MyServletOutputStream extends ServletOutputStream {private ServletOutputStream outputStream;private StringBuffer buffer;public MyServletOutputStream (ServletOutputStream outputStream) {this.outputStream = outputStream; buffer = new StringBuffer ();} @ Overridepublic void write (int b) throws IOException {outputStream.write (b);} @ Overridepublic void write (byte [] b, int off, int len) throws IOException {outputStream.write (b, off, len) Byte [] bytes = new byte [len]; System.arraycopy (b, off, bytes, 0, len); buffer.append (new String (bytes, "UTF-8"));} @ Overridepublic void write (byte [] b) throws IOException {outputStream.write (b);} @ Overridepublic void flush () throws IOException {super.flush ();} / / clear buffer for next reuse of public void myFlush () {outputStream = null; buffer = null } public String getBuffer () {if (buffer! = null) {return buffer.toString ();} return null;}} Summary

Previously, we used HttpServletRequest.getInputStream () and RequestWrapper to obtain the requested requestBody, but now we propose to bring up both the RequestBody and ResponseBody of a request and print the log & drop it into the database to count and find the problem.

Two technical schemes are determined after looking up the data.

1. Surround notification processing for all Controller methods using AOP

two。 Use Filter to intercept all Request and Response and get body.

Finally, the second way is chosen, and the specific implementation record is as follows.

Concrete realization

Logging filter

Public class RequestFilter implements Filter {private static final String LOG_FORMATTER_IN = "request path: {% s}, request method: {% s}, parameter: {% s}, source IP: {% s}, request start time {% s}, return: {% s}, request end time {% s}, time: {% s} ms, operation type: {% s}, operator: {% s}"; public static final String USER_TOKEN_REDIS_PREFIX = "token_prefix" Private static final Logger log = LoggerFactory.getLogger (RequestFilter.class); / / conten-type list intercepted by request private List contentTypes;@Overridepublic void doFilter (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest httpServletRequest = (HttpServletRequest) request; HttpServletResponse httpServletResponse = (HttpServletResponse) response; / / request path String path = httpServletRequest.getRequestURI (); String method = httpServletRequest.getMethod (); / / Map Map paramMap = new HashMap () for all request parameters / / the real IP String requestedIP of the request = RequestUtils.getRealIP (httpServletRequest); / / whether to intercept and wrap the request. If you need to intercept, you will get RequestBody. Generally, application/json is used to intercept boolean filterRequestFlag = checkFilter (request.getContentType ()); if (filterRequestFlag) {httpServletRequest = new MyRequestBodyReaderWrapper (httpServletRequest);} / / get all queryString and requestBody Map requestParamMap = RequestUtils.getRequestParamMap (httpServletRequest) If (requestParamMap! = null & &! requestParamMap.isEmpty ()) {paramMap.putAll (requestParamMap);} / / get header parameter Map headerMap = RequestUtils.getHeaders (httpServletRequest); if (headerMap! = null & &! headerMap.isEmpty ()) {paramMap.putAll (headerMap);} / / get path parameter Map uriTemplateMap = RequestUtils.getUriTemplateVar (httpServletRequest) If (uriTemplateMap! = null & &! uriTemplateMap.isEmpty ()) {paramMap.putAll (uriTemplateMap);} / / wraps Response, overrides the getOutputStream () and getWriter () methods, and uses custom OutputStream and Writer to intercept and save ResponseBody MyResponseWrapper responseWrapper = new MyResponseWrapper (httpServletResponse); / / request start time Long dateStart = System.currentTimeMillis (); / / Spring handles requests chain.doFilter (httpServletRequest, responseWrapper) through DispatchServlet / / request end time Long dateEnd = System.currentTimeMillis (); String responseBody; if (responseWrapper.getMyOutputStream () = = null) {if (responseWrapper.getMyWriter ()! = null) {responseBody = responseWrapper.getMyWriter () .getContent (); / must flush,responseBody be reused responseWrapper.getMyWriter () .myFlush () }} else {responseBody = responseWrapper.getMyOutputStream (). GetBuffer (); / / make sure that flush,responseBody will be reused responseWrapper.getMyOutputStream (). MyFlush ();} String params = JSONObject.toJSONString (paramMap); log.info (LOG_FORMATTER_IN, path, method, params, requestedIP, dateStart, responseBody, dateEnd, (dateEnd-dateStart)) } / * determine whether the request / return is application/json * Yes, * otherwise exit * @ param contentType request / response type * / private boolean checkFilter (String contentType) {boolean filterFlag = false;// whether to continue to intercept for (String p: getContentTypes ()) {if (StringUtils.contains (contentType, p)) {filterFlag = true } if (StringUtils.isEmpty (contentType)) {filterFlag = true;} return filterFlag;}}

Request wrapper

/ * wrapper for HttpServletRequest, in order to obtain requestBody during interceptor phase without preventing SpringMVC from getting requestBody*/@Slf4jpublic class MyRequestBodyReaderWrapper extends HttpServletRequestWrapper again {/ / storing JSON data body private final byte [] body;public MyRequestBodyReaderWrapper (HttpServletRequest request) throws IOException {super (request); body = getBody (request) .getBytes (Charset.forName ("UTF-8"));} @ Overridepublic ServletInputStream getInputStream () throws IOException {final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream (body) Return new ServletInputStream () {@ Overridepublic int read () throws IOException {return byteArrayInputStream.read ();}};} @ Overridepublic BufferedReader getReader () throws IOException {return new BufferedReader (new InputStreamReader (this.getInputStream ());} / * get request Body * / public static String getBody (ServletRequest request) {StringBuilder sb = new StringBuilder (); InputStream inputStream = null; BufferedReader reader = null Try {inputStream = request.getInputStream (); reader = new BufferedReader (new InputStreamReader (inputStream, Charset.forName ("UTF-8")); String line; while ((line = reader.readLine ())! = null) {sb.append (line);} catch (IOException e) {log.error ("MyRequestBodyReaderWrapper.getBody () exception-- >", e) } finally {if (inputStream! = null) {try {inputStream.close ();} catch (IOException e) {log.error ("MyRequestBodyReaderWrapper.getBody () exception-- >", e);}} if (reader! = null) {try {reader.close () } catch (IOException e) {log.error ("MyRequestBodyReaderWrapper.getBody () exception->", e);} return sb.toString ();}}

RequestUtils

/ * request tool class * / public class RequestUtils {private static final Logger logger = LoggerFactory.getLogger (RequestUtils.class); / * get all request headers * @ param request * @ return * / public static Map getHeaders (HttpServletRequest request) {Map headerMap = new HashMap (); List headers = getCommonHeaders (); headers.add ("Postman-Token"); headers.add ("Proxy-Connection"); headers.add ("X-Lantern-Version") Headers.add ("Cookie"); Enumeration headerNames = request.getHeaderNames (); while (headerNames.hasMoreElements ()) {String headerName = headerNames.nextElement (); if (headers.contains (headerName)) {continue;} headerMap.put (headerName,request.getHeader (headerName));} return headerMap } / * get the path parameter of the request * @ param request * @ return * / public static Map getUriTemplateVar (HttpServletRequest request) {NativeWebRequest webRequest = new ServletWebRequest (request); Map uriTemplateVars = (Map) webRequest.getAttribute (HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); return uriTemplateVars } / * get the real IP * @ param request * @ return * / public static String getRealIP (HttpServletRequest request) {String ip = request.getHeader ("X-Forwarded-For"); if (StringUtils.isNotEmpty (ip) & &! "unKnown" .equalsIgnoreCase (ip)) {/ / multiple reverse proxies will have multiple IP values, and the first ip is the real ip int index = ip.indexOf (",") If (index! =-1) {return ip.substring (0, index);} else {return ip;}} ip = request.getHeader ("X-Real-IP"); if (StringUtils.isNotEmpty (ip) & &! "unKnown" .equalsIgnoreCase (ip)) {return ip;} return request.getRemoteAddr () } / * get all request parameters from Request, including requests such as GET/POST/PATCH, excluding path parameters * @ param request * @ return * / public static Map getRequestParamMap (HttpServletRequest request) {Map paramMap = new HashMap (); / / get parameters in QueryString, GET or application/x-www-form-urlencoded Map queryParamMap = RequestUtils.getUriQueryVar (request); if (queryParamMap! = null) {paramMap.putAll (queryParamMap) } / / get the parameters in Body, POST/PATCH, etc., application/json Map bodyParamMap = null; try {/ / when it is a POST request and application/json, request is processed by RequestFilter as wrapper class if (! (request instanceof MyRequestBodyReaderWrapper)) {return paramMap;} MyRequestBodyReaderWrapper readerWrapper = (MyRequestBodyReaderWrapper) request; String requestBody = new String (readerWrapper.getBody (), "UTF-8") If (com.zhongan.health.common.utils.StringUtils.isNotBlank (requestBody)) {/ * this method is to prevent fastJson from changing the object order * / bodyParamMap = JSONObject.parseObject (requestBody, new TypeReference () {}, Feature.OrderedField) when deserializing multi-layer json. } catch (Exception e) {logger.error ("get request Body exception-- >", e);} if (bodyParamMap! = null) {paramMap.putAll (bodyParamMap);} return paramMap;} private static List getCommonHeaders () {List headers = new ArrayList (); Class clazz = HttpHeaders.class; Field [] fields = clazz.getFields () For (Field field: fields) {field.setAccessible (true); if (field.getType (). ToString (). EndsWith ("java.lang.String") & & Modifier.isStatic (field.getModifiers ()) {try {headers.add ((String) field.get (HttpHeaders.class) } catch (IllegalAccessException e) {logger.error ("reflection acquisition property value exception->", e);} return headers;}}

Response wrapper

/ * this wrapper mainly overrides the getOutputStream () and getWriter () methods to return custom OutputStream and Writer to the caller in order to participate in the output process and record and save the responseBody. * / public class MyResponseWrapper extends HttpServletResponseWrapper {private ResponsePrintWriter writer;private MyServletOutputStream out;public MyResponseWrapper (HttpServletResponse response) {super (response);} @ Overridepublic ServletOutputStream getOutputStream () throws IOException {/ / you must determine that the current out is empty before you can create a new out object, otherwise multiple out objects if (out = = null) {out = new MyServletOutputStream (super.getOutputStream ());} return out will appear in one request. } @ Overridepublic PrintWriter getWriter () throws IOException {/ / you must judge that the current writer is empty before you can create a new writer object, otherwise multiple writer objects will appear in one request: if (writer = = null) {writer = new ResponsePrintWriter (super.getWriter ());} return writer;} public ResponsePrintWriter getMyWriter () {return writer;} public MyServletOutputStream getMyOutputStream () {return out;}}

Custom Writer

/ * customize Writer, override the write method, and record and save ResponseBody*/public class ResponsePrintWriter extends PrintWriter {private StringBuffer buffer;public ResponsePrintWriter (PrintWriter out) {super (out); buffer = new StringBuffer ();} public String getContent () {return buffer = = null? Null: buffer.toString ();} @ Overridepublic void flush () {super.flush ();} / / clear buffer so that public void myFlush () {buffer = null;} @ Overridepublic void write (char [] buf, int off, int len) {super.write (buf,off, len); char [] destination = new char [len]; System.arraycopy (buf,off,destination,0,len); buffer.append (destination) } @ Overridepublic void write (String s) {super.write (s); buffer.append (s);}}

Custom OutputStream

/ * Custom output stream wrapper, override the write method, and record and save ResponseBody*/public class MyServletOutputStream extends ServletOutputStream {private ServletOutputStream outputStream;private StringBuffer buffer;public MyServletOutputStream (ServletOutputStream outputStream) {this.outputStream = outputStream; buffer = new StringBuffer ();} @ Overridepublic void write (int b) throws IOException {outputStream.write (b);} @ Overridepublic void write (byte [] b, int off, int len) throws IOException {outputStream.write (b, off, len) Byte [] bytes = new byte [len]; System.arraycopy (b, off, bytes, 0, len); buffer.append (new String (bytes, "UTF-8"));} @ Overridepublic void write (byte [] b) throws IOException {outputStream.write (b);} @ Overridepublic void flush () throws IOException {super.flush ();} / / clear buffer for next reuse of public void myFlush () {outputStream = null; buffer = null } public String getBuffer () {if (buffer! = null) {return buffer.toString ();} return null;}} these are all the contents of the article "how to use Filter to print request logs in the SpringMVC framework". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report