SpringMVC框架中使用Filter实现请求日志打印方式

目录
  • 查找资料后确定两种技术方案

    1. 使用AOP对所有Controller的方法进行环绕通知处理;

    2. 使用Filter拦截所有的Request和Response,并获取body。

    最后选择了第二种方式,具体实现记录如下。

    具体实现

    日志记录过滤器

    public class RequestFilter implements Filter{private static final String LOG_FORMATTER_IN = "请求路径:{%s},请求方法:{%s},参数:{%s},来源IP:{%s},请求开始时间{%s},返回:{%s},请求结束时间{%s},用时:{%s}ms,操作类型:{%s},操作人:{%s}";public static final String USER_TOKEN_REDIS_PREFIX = "token_prefix";private static final Logger log = LoggerFactory.getLogger(RequestFilter.class);//request拦截的conten-type列表private List<String> contentTypes;@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {    HttpServletRequest httpServletRequest = (HttpServletRequest) request;    HttpServletResponse httpServletResponse = (HttpServletResponse) response;    //请求路径    String path = httpServletRequest.getRequestURI();    String method = httpServletRequest.getMethod();    //所有请求参数的Map    Map<String,String> paramMap = new HashMap<>();    //请求的真实IP    String requestedIP = RequestUtils.getRealIP(httpServletRequest);    //是否拦截并包装请求,如果需要拦截则会获取RequestBody,一般为application/json才拦截    boolean filterRequestFlag = checkFilter(request.getContentType());    if (filterRequestFlag) {        httpServletRequest = new MyRequestBodyReaderWrapper(httpServletRequest);    }    //获取所有queryString和requestBody    Map<String, String> requestParamMap = RequestUtils.getRequestParamMap(httpServletRequest);    if (requestParamMap != null && !requestParamMap.isEmpty()){        paramMap.putAll(requestParamMap);    }    //获取header参数    Map<String, String> headerMap = RequestUtils.getHeaders(httpServletRequest);    if (headerMap != null && !headerMap.isEmpty()){       paramMap.putAll(headerMap);    }    //获取路径参数    Map<String,String> uriTemplateMap = RequestUtils.getUriTemplateVar(httpServletRequest);    if (uriTemplateMap != null && !uriTemplateMap.isEmpty()){        paramMap.putAll(uriTemplateMap);    }    //包装Response,重写getOutputStream()和getWriter()方法,并用自定义的OutputStream和Writer来拦截和保存ResponseBody    MyResponseWrapper responseWrapper = new MyResponseWrapper(httpServletResponse);    //请求开始时间    Long dateStart = System.currentTimeMillis();    //Spring通过DispatchServlet处理请求    chain.doFilter(httpServletRequest, responseWrapper);    //请求结束时间    Long dateEnd = System.currentTimeMillis();    String responseBody;    if (responseWrapper.getMyOutputStream() == null){            if (responseWrapper.getMyWriter() != null){                responseBody = responseWrapper.getMyWriter().getContent();                //一定要flush,responseBody会被复用                responseWrapper.getMyWriter().myFlush();            }        }else {            responseBody = responseWrapper.getMyOutputStream().getBuffer();            //一定要flush,responseBody会被复用            responseWrapper.getMyOutputStream().myFlush();    }    String params = JSONObject.toJSONString(paramMap);    log.info(String.format(LOG_FORMATTER_IN, path, method, params, requestedIP, dateStart, responseBody, dateEnd,(dateEnd - dateStart));}/** * 判断请求/返回是否为application/json * 是则进行拦截, * 否则退出 * @param contentType 请求/响应类型 */private boolean checkFilter(String contentType) {    boolean filterFlag = false;//是否继续拦截    for (String p : getContentTypes()) {        if (StringUtils.contains(contentType, p)){            filterFlag = true;        }    }    if (StringUtils.isEmpty(contentType)){        filterFlag = true;    }    return filterFlag;}}

    Request包装器

    /*** HttpServletRequest的包装器,为了在拦截器阶段获取requestBody且不妨碍SpringMVC再次获取requestBody*/@Slf4jpublic class MyRequestBodyReaderWrapper extends HttpServletRequestWrapper {//存放JSON数据主体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() {        @Override        public int read() throws IOException {            return byteArrayInputStream.read();        }    };}@Overridepublic BufferedReader getReader() throws IOException {    return new BufferedReader(new InputStreamReader(this.getInputStream()));}/** * 获取请求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()异常-->",e);    } finally {        if (inputStream != null) {            try {                inputStream.close();            } catch (IOException e) {                log.error("MyRequestBodyReaderWrapper.getBody()异常-->",e);            }        }        if (reader != null) {            try {                reader.close();            } catch (IOException e) {                log.error("MyRequestBodyReaderWrapper.getBody()异常-->",e);            }        }    }    return sb.toString();}}

    RequestUtils

    /*** 请求工具类*/public class RequestUtils {private static final Logger logger = LoggerFactory.getLogger(RequestUtils.class);/** * 获取所有的请求头 * @param request * @return */public static Map<String,String> getHeaders(HttpServletRequest request){    Map<String,String> headerMap = new HashMap<>();    List<String> headers = getCommonHeaders();    headers.add("Postman-Token");    headers.add("Proxy-Connection");    headers.add("X-Lantern-Version");    headers.add("Cookie");    Enumeration<String> headerNames = request.getHeaderNames();    while (headerNames.hasMoreElements()){        String headerName = headerNames.nextElement();        if (headers.contains(headerName)){            continue;        }        headerMap.put(headerName,request.getHeader(headerName));    }    return headerMap;}/** * 获取请求的路径参数 * @param request * @return */public static Map<String, String> getUriTemplateVar(HttpServletRequest request) {    NativeWebRequest webRequest = new ServletWebRequest(request);    Map<String, String> uriTemplateVars = (Map<String, String>) webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);    return uriTemplateVars;}/** * 获取请求的真实IP * @param request * @return */public static String getRealIP(HttpServletRequest request) {    String ip = request.getHeader("X-Forwarded-For");    if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {        //多次反向代理后会有多个ip值,第一个ip才是真实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();}/** * 从Request中获取所有的请求参数,包括GET/POST/PATCH等请求,不包括路径参数 * @param request * @return */public static Map<String,String> getRequestParamMap(HttpServletRequest request) {    Map<String,String> paramMap = new HashMap<>();    //获取QueryString中的参数,GET方式 或application/x-www-form-urlencoded    Map<String, String> queryParamMap = RequestUtils.getUriQueryVar(request);    if (queryParamMap != null){        paramMap.putAll(queryParamMap);    }    //获取Body中的参数,POST/PATCH等方式,application/json    Map<String,String> bodyParamMap = null;    try {        //当为POST请求且 application/json时,request被RequestFilter处理为wrapper类        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)){            /**             * 该方法为了避免 fastJson在 反序列化多层json时,改变对象顺序             */            bodyParamMap = JSONObject.parseObject(requestBody, new TypeReference<LinkedHashMap<String,String>>(){}, Feature.OrderedField);        }    } catch (Exception e) {        logger.error("获取请求Body异常-->",e);    }    if (bodyParamMap != null){        paramMap.putAll(bodyParamMap);    }    return paramMap;}private static List<String> getCommonHeaders(){    List<String> headers = new ArrayList<>();    Class<HttpHeaders> 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("反射获取属性值异常-->",e);            }        }    }    return headers;}}

    Response包装器

    /***该包装器主要是重写getOutputStream()和getWriter()方法,给调用者返回自定义的OutputStream和Writer,以便参与输出的过程并记录保存responseBody。*/public class MyResponseWrapper extends HttpServletResponseWrapper {private ResponsePrintWriter writer;private MyServletOutputStream out;public MyResponseWrapper(HttpServletResponse response) {    super(response);}@Overridepublic ServletOutputStream getOutputStream() throws IOException {    //一定要先判断当前out为空才能去新建out对象,否则一次请求会出现多个out对象    if (out == null){        out = new MyServletOutputStream(super.getOutputStream());    }    return out;}@Overridepublic PrintWriter getWriter() throws IOException {    //一定要先判断当前writer为空才能去新建writer对象,否则一次请求会出现多个writer对象    if (writer == null){        writer = new ResponsePrintWriter(super.getWriter());    }    return writer;}public ResponsePrintWriter getMyWriter() {    return writer;}public MyServletOutputStream getMyOutputStream(){    return out;}}

    自定义Writer

    /***自定义Writer,重写write方法,并记录保存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();}//清空buffer,以便下一次重新使用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);}}

    自定义OutputStream

    /*** 自定义输出流包装器,重写write方法,并记录保存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();}//清空buffer,以便下一次重新使用public void myFlush(){    outputStream = null;    buffer = null;}public String getBuffer() {    if (buffer != null){        return buffer.toString();    }    return null;}}

    总结

之前利用HttpServletRequest.getInputStream()和RequestWrapper实现了请求的requestBody获取,现在提出将一个请求的RequestBody和ResponseBody都提出来并打印日志&落入数据库,以便统计和查找问题。

查找资料后确定两种技术方案

1. 使用AOP对所有Controller的方法进行环绕通知处理;

2. 使用Filter拦截所有的Request和Response,并获取body。

最后选择了第二种方式,具体实现记录如下。

具体实现

日志记录过滤器

public class RequestFilter implements Filter{private static final String LOG_FORMATTER_IN = "请求路径:{%s},请求方法:{%s},参数:{%s},来源IP:{%s},请求开始时间{%s},返回:{%s},请求结束时间{%s},用时:{%s}ms,操作类型:{%s},操作人:{%s}";public static final String USER_TOKEN_REDIS_PREFIX = "token_prefix";private static final Logger log = LoggerFactory.getLogger(RequestFilter.class);//request拦截的conten-type列表private List<String> contentTypes;@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {    HttpServletRequest httpServletRequest = (HttpServletRequest) request;    HttpServletResponse httpServletResponse = (HttpServletResponse) response;    //请求路径    String path = httpServletRequest.getRequestURI();    String method = httpServletRequest.getMethod();    //所有请求参数的Map    Map<String,String> paramMap = new HashMap<>();    //请求的真实IP    String requestedIP = RequestUtils.getRealIP(httpServletRequest);    //是否拦截并包装请求,如果需要拦截则会获取RequestBody,一般为application/json才拦截    boolean filterRequestFlag = checkFilter(request.getContentType());    if (filterRequestFlag) {        httpServletRequest = new MyRequestBodyReaderWrapper(httpServletRequest);    }    //获取所有queryString和requestBody    Map<String, String> requestParamMap = RequestUtils.getRequestParamMap(httpServletRequest);    if (requestParamMap != null && !requestParamMap.isEmpty()){        paramMap.putAll(requestParamMap);    }    //获取header参数    Map<String, String> headerMap = RequestUtils.getHeaders(httpServletRequest);    if (headerMap != null && !headerMap.isEmpty()){       paramMap.putAll(headerMap);    }    //获取路径参数    Map<String,String> uriTemplateMap = RequestUtils.getUriTemplateVar(httpServletRequest);    if (uriTemplateMap != null && !uriTemplateMap.isEmpty()){        paramMap.putAll(uriTemplateMap);    }    //包装Response,重写getOutputStream()和getWriter()方法,并用自定义的OutputStream和Writer来拦截和保存ResponseBody    MyResponseWrapper responseWrapper = new MyResponseWrapper(httpServletResponse);    //请求开始时间    Long dateStart = System.currentTimeMillis();    //Spring通过DispatchServlet处理请求    chain.doFilter(httpServletRequest, responseWrapper);    //请求结束时间    Long dateEnd = System.currentTimeMillis();    String responseBody;    if (responseWrapper.getMyOutputStream() == null){            if (responseWrapper.getMyWriter() != null){                responseBody = responseWrapper.getMyWriter().getContent();                //一定要flush,responseBody会被复用                responseWrapper.getMyWriter().myFlush();            }        }else {            responseBody = responseWrapper.getMyOutputStream().getBuffer();            //一定要flush,responseBody会被复用            responseWrapper.getMyOutputStream().myFlush();    }    String params = JSONObject.toJSONString(paramMap);    log.info(String.format(LOG_FORMATTER_IN, path, method, params, requestedIP, dateStart, responseBody, dateEnd,(dateEnd - dateStart));}/** * 判断请求/返回是否为application/json * 是则进行拦截, * 否则退出 * @param contentType 请求/响应类型 */private boolean checkFilter(String contentType) {    boolean filterFlag = false;//是否继续拦截    for (String p : getContentTypes()) {        if (StringUtils.contains(contentType, p)){            filterFlag = true;        }    }    if (StringUtils.isEmpty(contentType)){        filterFlag = true;    }    return filterFlag;}}

Request包装器

/*** HttpServletRequest的包装器,为了在拦截器阶段获取requestBody且不妨碍SpringMVC再次获取requestBody*/@Slf4jpublic class MyRequestBodyReaderWrapper extends HttpServletRequestWrapper {//存放JSON数据主体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() {        @Override        public int read() throws IOException {            return byteArrayInputStream.read();        }    };}@Overridepublic BufferedReader getReader() throws IOException {    return new BufferedReader(new InputStreamReader(this.getInputStream()));}/** * 获取请求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()异常-->",e);    } finally {        if (inputStream != null) {            try {                inputStream.close();            } catch (IOException e) {                log.error("MyRequestBodyReaderWrapper.getBody()异常-->",e);            }        }        if (reader != null) {            try {                reader.close();            } catch (IOException e) {                log.error("MyRequestBodyReaderWrapper.getBody()异常-->",e);            }        }    }    return sb.toString();}}

RequestUtils

/*** 请求工具类*/public class RequestUtils {private static final Logger logger = LoggerFactory.getLogger(RequestUtils.class);/** * 获取所有的请求头 * @param request * @return */public static Map<String,String> getHeaders(HttpServletRequest request){    Map<String,String> headerMap = new HashMap<>();    List<String> headers = getCommonHeaders();    headers.add("Postman-Token");    headers.add("Proxy-Connection");    headers.add("X-Lantern-Version");    headers.add("Cookie");    Enumeration<String> headerNames = request.getHeaderNames();    while (headerNames.hasMoreElements()){        String headerName = headerNames.nextElement();        if (headers.contains(headerName)){            continue;        }        headerMap.put(headerName,request.getHeader(headerName));    }    return headerMap;}/** * 获取请求的路径参数 * @param request * @return */public static Map<String, String> getUriTemplateVar(HttpServletRequest request) {    NativeWebRequest webRequest = new ServletWebRequest(request);    Map<String, String> uriTemplateVars = (Map<String, String>) webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);    return uriTemplateVars;}/** * 获取请求的真实IP * @param request * @return */public static String getRealIP(HttpServletRequest request) {    String ip = request.getHeader("X-Forwarded-For");    if (StringUtils.isNotEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {        //多次反向代理后会有多个ip值,第一个ip才是真实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();}/** * 从Request中获取所有的请求参数,包括GET/POST/PATCH等请求,不包括路径参数 * @param request * @return */public static Map<String,String> getRequestParamMap(HttpServletRequest request) {    Map<String,String> paramMap = new HashMap<>();    //获取QueryString中的参数,GET方式 或application/x-www-form-urlencoded    Map<String, String> queryParamMap = RequestUtils.getUriQueryVar(request);    if (queryParamMap != null){        paramMap.putAll(queryParamMap);    }    //获取Body中的参数,POST/PATCH等方式,application/json    Map<String,String> bodyParamMap = null;    try {        //当为POST请求且 application/json时,request被RequestFilter处理为wrapper类        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)){            /**             * 该方法为了避免 fastJson在 反序列化多层json时,改变对象顺序             */            bodyParamMap = JSONObject.parseObject(requestBody, new TypeReference<LinkedHashMap<String,String>>(){}, Feature.OrderedField);        }    } catch (Exception e) {        logger.error("获取请求Body异常-->",e);    }    if (bodyParamMap != null){        paramMap.putAll(bodyParamMap);    }    return paramMap;}private static List<String> getCommonHeaders(){    List<String> headers = new ArrayList<>();    Class<HttpHeaders> 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("反射获取属性值异常-->",e);            }        }    }    return headers;}}

Response包装器

/***该包装器主要是重写getOutputStream()和getWriter()方法,给调用者返回自定义的OutputStream和Writer,以便参与输出的过程并记录保存responseBody。*/public class MyResponseWrapper extends HttpServletResponseWrapper {private ResponsePrintWriter writer;private MyServletOutputStream out;public MyResponseWrapper(HttpServletResponse response) {    super(response);}@Overridepublic ServletOutputStream getOutputStream() throws IOException {    //一定要先判断当前out为空才能去新建out对象,否则一次请求会出现多个out对象    if (out == null){        out = new MyServletOutputStream(super.getOutputStream());    }    return out;}@Overridepublic PrintWriter getWriter() throws IOException {    //一定要先判断当前writer为空才能去新建writer对象,否则一次请求会出现多个writer对象    if (writer == null){        writer = new ResponsePrintWriter(super.getWriter());    }    return writer;}public ResponsePrintWriter getMyWriter() {    return writer;}public MyServletOutputStream getMyOutputStream(){    return out;}}

自定义Writer

/***自定义Writer,重写write方法,并记录保存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();}//清空buffer,以便下一次重新使用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);}}

自定义OutputStream

/*** 自定义输出流包装器,重写write方法,并记录保存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();}//清空buffer,以便下一次重新使用public void myFlush(){    outputStream = null;    buffer = null;}public String getBuffer() {    if (buffer != null){        return buffer.toString();    }    return null;}}

总结

  • Request.getInputStream一次请求中只能被调用一次;
  • Response.getOutputStream()无法获取ResponseBody;
  • Response的输出有两种方式,都需要考虑到并重写

getOutputStream().write()

getWrite().write()

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 详解在Spring MVC或Spring Boot中使用Filter打印请求参数问题

    使用Spring MVC或Spring Boot中打印或记录日志一般使用AOP记录Request请求和Response响应参数,在不使用AOP的前提下,如果在Filter中打印日志,在打印或消费请求类型为Content-Type:application/json的请求时,会出现严重的问题. 在Spring体系中,过滤器的定义我们一般采用继承OncePerRequestFilter的方式,当然也可以使用原始的Filter. 错误写法一: 如果不对request和response进行处理,使用伪代码

  • 详解AOP与Filter拦截请求打印日志实用例子

    相信各位同道在写代码的时候,肯定会写一些日志打印,因为这对往后的运维而言,至关重要的. 那么我们请求一个restfull接口的时候,哪些信息是应该被日志记录的呢? 以下做了一个基本的简单例子,这里只是示例说明基本常规实现记录的信息,根据项目的真实情况选用: 1 . Http请求拦截器(Filter) : 从HttpServletRequest获取基本的请求信息 import name.ealen.util.HttpUtil; import org.slf4j.Logger; import org

  • Spring MVC打印@RequestBody、@Response日志的方法

    问题描述: 使用JSON接收前端参数时, SpringMVC默认输出日志如下: o.s.web.servlet.DispatcherServlet : POST "/example_project/app/login", parameters={} parameters={}无法打印出JSON消息内容. 如果自己实现参数打印, 则需要从reqeust.getInputStream中获取JSON内容, 但是由于流只能读取一次, 所以会导致后续SpringMVC解析参数异常. 网上找到一种

  • SpringBoot之自定义Filter获取请求参数与响应结果案例详解

    一个系统上线,肯定会或多或少的存在异常情况.为了更快更好的排雷,记录请求参数和响应结果是非常必要的.所以,Nginx 和 Tomcat 之类的 web 服务器,都提供了访问日志,可以帮助我们记录一些请求信息. 本文是在我们的应用中,定义一个Filter来实现记录请求参数和响应结果的功能. 有一定经验的都知道,如果我们在Filter中读取了HttpServletRequest或者HttpServletResponse的流,就没有办法再次读取了,这样就会造成请求异常.所以,我们需要借助 Spring

  • SpringMVC框架中使用Filter实现请求日志打印方式

    目录 查找资料后确定两种技术方案 1. 使用AOP对所有Controller的方法进行环绕通知处理: 2. 使用Filter拦截所有的Request和Response,并获取body. 最后选择了第二种方式,具体实现记录如下. 具体实现 日志记录过滤器 public class RequestFilter implements Filter{private static final String LOG_FORMATTER_IN = "请求路径:{%s},请求方法:{%s},参数:{%s},来源

  • SpringCloud Gateway之请求应答日志打印方式

    目录 Gateway请求应答日志打印 第一步 第二步 Gateway全局请求日志打印 把请求体的数据存入exchange 编写全局日志拦截器代码 在代码中配置全局拦截器 Gateway请求应答日志打印 请求应答日志时在日常开发调试问题的重要手段之一,那么如何基于Spring Cloud Gateway做呢,请看我上代码. 第一步 创建RecorderServerHttpRequestDecorator,缓存请求参数,解决body只能读一次问题. public class RecorderServ

  • Python中的logging模块实现日志打印

    目录 方法1:配置并输出日志到标准输出 方法2:配置输出到日志文件 前言: 大家在写代码的时候,经常会使用print打印日志方便排查问题,然而print的问题就是太过简单,缺少时间.日志级别等格式化信息. Python自带的logging模块,很简单就能实现日志的配置和打印,它有两种用法,方法1是把日志输出到标准输出,其实就是命令行界面,方法2则是输出日志到文件,更加方便. 方法1:配置并输出日志到标准输出 import logging   LOG_FORMAT = "%(asctime)s -

  • 使用springmvc的controller层获取到请求的数据方式

    目录 content-type 1.application/x-www-form-urlencoded 1.1 String 参数值=reqeust.getParameter("参数名"); 1.2 Map<String,String[]> paramMap=request.getParameterMap(); 2.multipart/form-data 3.text/xml 4.application/json 4.1 页面请求的数据获取 4.1.1 页面js请求如下 4

  • gateway、webflux、reactor-netty请求日志输出方式

    目录 gateway.webflux.reactor-netty请求日志输出 场景 思路 解决方案 spring-webflux.gateway.springboot-start-web问题 Spring-webflux Spring-gateway gateway.webflux.reactor-netty请求日志输出 场景 在使用spring cloud gateway时想要输出请求日志,考虑到两种实现方案 方案一 官网中使用Reactor Netty Access Logs方案,配置“-D

  • Log4j关闭Spring和Hibernate日志打印方式

    目录 Log4j关闭Spring和Hibernate日志打印 Log4j关闭Hibernate日志输出 Log4j关闭Spring和Hibernate日志打印 这里所说的关闭不是全部不打印,只需要修改一下log级别就好了. 普通的info信息其实我们是不看的,所以直接设置成warn或error级别就好了. #close java-jdbc log out log4j.logger.java.sql.Connection=ERROR log4j.logger.java.sql.Statement=

  • Python的Django REST框架中的序列化及请求和返回

    序列化Serialization 1. 设置一个新的环境 在我们开始之前, 我们首先使用virtualenv要创建一个新的虚拟环境,以使我们的配置和我们的其他项目配置彻底分开. $mkdir ~/env $virtualenv ~/env/tutorial $source ~/env/tutorial/bin/avtivate 现在我们处在一个虚拟的环境中,开始安装我们的依赖包 $pip install django $pip install djangorestframework $pip i

  • SpringBoot AOP处理请求日志打印功能代码实例

    设计原则和思路: 元注解方式结合AOP,灵活记录操作日志 能够记录详细错误日志为运营以及审计提供支持 日志记录尽可能减少性能影响 操作描述参数支持动态获取,其他参数自动记录. 代码实例如下 @Slf4j @Aspect @Configuration public class RequestAopConfig { @Autowired private HttpServletRequest request; private static final ThreadLocal<Long> START_

  • php ci框架中加载css和js文件失败的解决方法

    在将html页面整合到ci框架里面的时候,加载css和js失败,弄了半天发现ci框架是入口的框架,对框架中文件的所有请求都需要经过index.php处理完成,当加载外部的css和js文件的时候要使用base_url()函数处理外部的链接. 比如: 在config配置文件中的base_url为:" localhost:8080/项目名称/ " 在控制器中访问application/resource/aaa.js文件 相对路径<script src= "resource/a

  • php ci框架中加载css和js文件失败的原因及解决方法

    在将html页面整合到ci框架里面的时候,加载css和js失败,弄了半天发现ci框架是入口的框架, 对框架中文件的所有请求都需要经过index.php处理完成,当加载外部的css和js文件的时候要使 用base_url()函数处理外部的链接. 比如: 在config配置文件中的base_url为:" localhost:8080/项目名称/ " 在控制器中访问application/resource/aaa.js文件 相对路径<script src= "resource

随机推荐