欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解在Spring MVC或Spring Boot中使用Filter打印請求參數(shù)問題

 更新時(shí)間:2020年04月30日 10:25:07   作者:皮。。皮卡丘  
這篇文章主要介紹了詳解在Spring MVC或Spring Boot中使用Filter打印請求參數(shù)問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

使用Spring MVC或Spring Boot中打印或記錄日志一般使用AOP記錄Request請求和Response響應(yīng)參數(shù),在不使用AOP的前提下,如果在Filter中打印日志,在打印或消費(fèi)請求類型為Content-Type:application/json的請求時(shí),會(huì)出現(xiàn)嚴(yán)重的問題。

在Spring體系中,過濾器的定義我們一般采用繼承OncePerRequestFilter的方式,當(dāng)然也可以使用原始的Filter。

錯(cuò)誤寫法一:

如果不對request和response進(jìn)行處理,使用偽代碼采用如下寫法打印請求和響應(yīng)參數(shù)(注:此時(shí)request請求類型為Post,接收的是Json數(shù)據(jù))

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse       
         response, FilterChain filterChain) throws ServletException, IOException {
    filterChain.doFilter(request, response);
    printRequestLog(request);
    printResonseLog(response);
  }

運(yùn)行測試后你會(huì)發(fā)現(xiàn)拋出如下異常: 

java.io.IOException: Stream closed
 at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:359) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:132) ~[tomcat-embed-core-9.0.31.jar:9.0.31]
 at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) ~[na:1.8.0_191]
 at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) ~[na:1.8.0_191]
 at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) ~[na:1.8.0_191]
 at java.io.InputStreamReader.read(InputStreamReader.java:184) ~[na:1.8.0_191]
 at java.io.BufferedReader.fill(BufferedReader.java:161) ~[na:1.8.0_191]
 at java.io.BufferedReader.readLine(BufferedReader.java:324) ~[na:1.8.0_191]
 at java.io.BufferedReader.readLine(BufferedReader.java:389) ~[na:1.8.0_191]
 at com.micro.backend.filter.LoggingFilter.getBodyString(LoggingFilter.java:60) [classes/:na]
 at com.micro.backend.filter.LoggingFilter.doFilterInternal(LoggingFilter.java:49) [classes/:na]
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:94) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1639) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_191]
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_191]
 at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.31.jar:9.0.31]
 at java.lang.Thread.run(Thread.java:748) [na:1.8.0_191]

錯(cuò)誤寫法二:

如果不對request和response進(jìn)行處理,使用偽代碼采用如下寫法打印請求和響應(yīng)參數(shù)(注:此時(shí)request請求類型為Post,接收的是Json數(shù)據(jù))

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse 
       response, FilterChain filterChain) throws ServletException, IOException {
    printRequestLog(request);
    printResonseLog(response);
    filterChain.doFilter(request, response);
  }

運(yùn)行測試后你會(huì)發(fā)現(xiàn)拋出如下異常:  

org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing

遇到這樣的問題你是不是有坐立不安、心煩意亂、百爪撓心的痛楚,不要著急,下面我給出一個(gè)解決方案。

首先我們使用裝飾器模式,創(chuàng)建request和response兩個(gè)包裝類,如下:

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
/**
* @Description:  請求包裝器
* @Author:     liuliya
* @CreateDate:   2020/4/29 10:00
*/
public class RequestWrapper extends HttpServletRequestWrapper {
  
  private final byte[] body;
 
  public RequestWrapper(HttpServletRequest request) throws IOException {
    super(request);
    body = getRequestBodyString(request).getBytes(Charset.defaultCharset());
  }
 
  @Override
  public BufferedReader getReader() throws IOException {
    return new BufferedReader(new InputStreamReader(getInputStream()));
  }
 
  @Override
  public ServletInputStream getInputStream() throws IOException {
 
    final ByteArrayInputStream bais = new ByteArrayInputStream(body);
 
    return new ServletInputStream() {
 
      @Override
      public int read() throws IOException {
        return bais.read();
      }
 
      @Override
      public boolean isFinished() {
        return false;
      }
 
      @Override
      public boolean isReady() {
        return false;
      }
 
      @Override
      public void setReadListener(ReadListener listener) {
 
      }
    };
  }
 
  public String getRequestBodyString(ServletRequest request) {
    StringBuilder sb = new StringBuilder();
    InputStream inputStream = null;
    BufferedReader reader = null;
    try {
      inputStream = request.getInputStream();
      reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset()));
      String line;
      while ((line = reader.readLine()) != null) {
        sb.append(line);
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      if (inputStream != null) {
        try {
          inputStream.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return sb.toString();
  }
}
package com.micro.backend.filter.support;
 
import org.apache.commons.io.output.TeeOutputStream; 
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
 
/**
 * @Description: 響應(yīng)包裝器
 * @Author: liuliya
 * @CreateDate: 2020/4/29 10:00
 */
public class ResponseWrapper extends HttpServletResponseWrapper {
 
  private final ByteArrayOutputStream bos = new ByteArrayOutputStream();
  private PrintWriter writer = new PrintWriter(bos);
 
  public ResponseWrapper(HttpServletResponse response) {
    super(response);
  }
 
  @Override
  public ServletResponse getResponse() {
    return this;
  }
 
  @Override
  public ServletOutputStream getOutputStream() throws IOException {
    return new ServletOutputStream() {
      @Override
      public boolean isReady() {
        return false;
      }
 
      @Override
      public void setWriteListener(WriteListener listener) {
 
      }
 
      private TeeOutputStream tee = new TeeOutputStream(ResponseWrapper.super.getOutputStream(), bos);
 
      @Override
      public void write(int b) throws IOException {
        tee.write(b);
      }
    };
  }
 
  @Override
  public PrintWriter getWriter() throws IOException {
    return new TeePrintWriter(super.getWriter(), writer);
  }
 
  public byte[] toByteArray() {
    return bos.toByteArray();
  }
}
package com.micro.backend.filter.support;
import java.io.PrintWriter;
//PrintWriter是一種寫入字符的一種操作類,可以寫入字符,TeePrintWriter繼承了他,主要功能是把原始的字符流copy到branch里面。
public class TeePrintWriter extends PrintWriter {
 
  PrintWriter branch;
 
  public TeePrintWriter(PrintWriter main, PrintWriter branch) {
    super(main, true);
    this.branch = branch;
  }
 
  public void write(char buf[], int off, int len) {
    super.write(buf, off, len);
    super.flush();
    branch.write(buf, off, len);
    branch.flush();
  }
 
  public void write(String s, int off, int len) {
    super.write(s, off, len);
    super.flush();
    branch.write(s, off, len);
    branch.flush();
  }
 
  public void write(int c) {
    super.write(c);
    super.flush();
    branch.write(c);
    branch.flush();
  }
 
  public void flush() {
    super.flush();
    branch.flush();
  }
}

接下來創(chuàng)建最重要的LoggingFilter類,繼承OncePerRequestFilter,或者直接繼承Servlet中原始的Filter。

package com.micro.backend.filter;
 
import com.micro.backend.filter.support.RequestWrapper;
import com.micro.backend.filter.support.ResponseWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.OncePerRequestFilter;
 
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
 
/**
* @Author:     liuliya
* @CreateDate:   2020/4/28 23:30
*/
@Slf4j
@Configuration
public class LoggingFilter extends OncePerRequestFilter {
  
  private static final String REQUEST_PREFIX_NAME = "Request請求: ";
  private static final String RESPONSE_PREFIX_NAME = "Response請求: ";
 
  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    request = new RequestWrapper(request);
    response = new ResponseWrapper(response);
    filterChain.doFilter(request, response);
    printRequestLog(request);
    printResponseLog((ResponseWrapper) response);
  }
 
  private void printRequestLog(final HttpServletRequest request) {
    StringBuilder msg = new StringBuilder();
    msg.append(REQUEST_PREFIX_NAME);
    HttpSession session = request.getSession(false);
    if (session != null) {
      msg.append("sessionId = ").append(session.getId()).append("; ");
    }
    if (request.getMethod() != null) {
      msg.append("method = ").append(request.getMethod()).append("; ");
    }
    if (request.getContentType() != null) {
      msg.append("contentType = ").append(request.getContentType()).append("; ");
    }
    msg.append("uri = ").append(request.getRequestURI());
    if (request.getQueryString() != null) {
      msg.append('?').append(request.getQueryString());
    }
 
    if (request instanceof RequestWrapper && !isMultipart(request) && !isBinaryContent(request)) {
      RequestWrapper requestWrapper = (RequestWrapper) request;
      msg.append("; payload = ").append(requestWrapper.getRequestBodyString(request));
    }
    log.info(msg.toString());
  }
 
  private boolean isBinaryContent(final HttpServletRequest request) {
    if (request.getContentType() == null) {
      return false;
    }
    return request.getContentType().startsWith("image")
        || request.getContentType().startsWith("video")
        || request.getContentType().startsWith("audio");
  }
 
  private boolean isMultipart(final HttpServletRequest request) {
    return request.getContentType() != null
        && request.getContentType().startsWith("multipart/form-data");
  }
 
  private void printResponseLog(final ResponseWrapper response) {
    StringBuilder msg = new StringBuilder();
    msg.append(RESPONSE_PREFIX_NAME);
    try {
      msg.append("; payload = ")
          .append(new String(response.toByteArray(), response.getCharacterEncoding()));
    } catch (UnsupportedEncodingException e) {
      log.warn("Failed to parse response payload", e);
    }
    log.info(msg.toString());
  } 
}

參考以上我整理出的代碼,你就會(huì)發(fā)現(xiàn)奇跡?。?!

為什么要這么寫呢,其本質(zhì)是把請求流拷貝了一份,一個(gè)供filterChain向下傳遞,一個(gè)來做流的消費(fèi),再有一個(gè)就是運(yùn)用裝飾器模式的精髓所在。

到此這篇關(guān)于詳解在Spring MVC或Spring Boot中使用Filter打印請求參數(shù)問題的文章就介紹到這了,更多相關(guān)SpringBoot Filter打印請求參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java面試基礎(chǔ)之TCP連接以及其優(yōu)化

    Java面試基礎(chǔ)之TCP連接以及其優(yōu)化

    這篇文章主要給大家介紹了關(guān)于Java面試基礎(chǔ)之TCP連接以及其優(yōu)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java實(shí)現(xiàn)的簡單網(wǎng)頁截屏功能示例

    Java實(shí)現(xiàn)的簡單網(wǎng)頁截屏功能示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的簡單網(wǎng)頁截屏功能,涉及java網(wǎng)頁打開及屏幕截圖功能相關(guān)操作技巧,需要的朋友可以參考下
    2017-12-12
  • Java開發(fā)完整短信驗(yàn)證碼功能的全過程

    Java開發(fā)完整短信驗(yàn)證碼功能的全過程

    利用短信驗(yàn)證碼進(jìn)行身份驗(yàn)證是目前互聯(lián)網(wǎng)眾多產(chǎn)品常用的一種方式,那么這種短信驗(yàn)證功能是如何實(shí)現(xiàn)的呢,下面這篇文章主要給大家介紹了關(guān)于Java開發(fā)完整短信驗(yàn)證碼功能的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • java虛擬機(jī)之JVM調(diào)優(yōu)詳解

    java虛擬機(jī)之JVM調(diào)優(yōu)詳解

    這篇文章主要介紹了java虛擬機(jī)之JVM調(diào)優(yōu)詳解,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)Java虛擬機(jī)的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • SpringBoot AOP處理請求日志打印功能代碼實(shí)例

    SpringBoot AOP處理請求日志打印功能代碼實(shí)例

    這篇文章主要介紹了SpringBoot AOP處理請求日志打印功能代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • 學(xué)習(xí)java一定要知道的垃圾收集器

    學(xué)習(xí)java一定要知道的垃圾收集器

    這篇文章主要介紹了學(xué)習(xí)java一定要知道的垃圾收集器,垃圾收集器的發(fā)展路線,簡單來說是隨著內(nèi)存越來越大而發(fā)生變化,更多相關(guān)介紹需要的朋友可以參考一下
    2022-07-07
  • Java獲取網(wǎng)頁數(shù)據(jù)步驟方法詳解

    Java獲取網(wǎng)頁數(shù)據(jù)步驟方法詳解

    這篇文章主要介紹了Java獲取網(wǎng)頁數(shù)據(jù)步驟方法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • java Spring MVC4環(huán)境搭建實(shí)例詳解(步驟)

    java Spring MVC4環(huán)境搭建實(shí)例詳解(步驟)

    spring WEB MVC框架提供了一個(gè)MVC(model-view-controller)模型-視圖-控制器的結(jié)構(gòu)和組件,利用它可以開發(fā)更靈活、松耦合的web應(yīng)用。MVC模式使得整個(gè)服務(wù)應(yīng)用的各部分(控制邏輯、業(yè)務(wù)邏輯、UI界面展示)分離開來,使它們之間的耦合性更低
    2017-08-08
  • Spring使用RestTemplate模擬form提交示例

    Spring使用RestTemplate模擬form提交示例

    本篇文章主要介紹了Spring使用RestTemplate模擬form提交示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-03-03
  • IDEA如何在當(dāng)前類中查找方法快捷鍵

    IDEA如何在當(dāng)前類中查找方法快捷鍵

    這篇文章主要介紹了IDEA如何在當(dāng)前類中查找方法快捷鍵問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11

最新評論