springmvcの場合requestのgetReader()とgetInputStream()は一度しか呼び出せない解決策について

8991 ワード

最近、既存のSSMプロジェクトに基づいて完全なログ分析を追加する予定ですが、アプリのバックグラウンドシステムなので、これまでアプリを計画していたときは、アプリに埋め込み処理をしていませんでしたが、埋め込み処理をしようとすると、新しくアップグレードできなかったアプリのユーザーにとっては、意味があります.ユーザーがアップグレードしない限り、埋め込みは彼のアプリで実行できないからです.そこで,バックグラウンドのエントリにログのモニタリングを追加することを考慮した.
考えはいつも簡単だが、実際に実現する過程で問題に直面した.APPは基本的に共通パラメータの暗号化チェックを採用しているため、POST要求でJSONデータを転送します.一般的なリクエスト分析、例えば各期間のアクセス量、または各メソッドの各ブロックの統計は、ブロッカーにデータをメッセージキューに追加し、消費者側でログの分析と処理を行うだけで簡単です.そして、各ユーザがどの時間帯に、どのような処理をしたかについて、postのjsonパラメータを取得しなければならないため、問題が発生します.
一部の学生は、これは簡単ではないかと言って、直接request.getParameter()でいいんじゃないですか?NO,postのjsonデータはストリームによって伝達され,直接読み取ることはできない.じゃあrequestを使いますgetReader()ストリームを手に入れて文字列に変換すればいいのではないでしょうか.それでは問題が来て、流れは1回しか流れないので、いったん読んだらもうありません.具体的な方法では取れません.ここまで言うと、springmvcのDispatcherServiceletが異常getReader()has already been called forを投げ出すので、アクセスはメソッドには入りません....
これだけ言ったら、次がポイントですが、実は簡単です.フィルタでrequestを処理します(フィルタがなければ、もう一つ追加すればいいです)
実装方法:RequestBodyをbyte配列として保存した後、getReader()メソッドとgetInputStream()メソッドをサーブレットが所有するH t pサーブレットRequestWrapperクラスで上書きし、保存したbyte配列からストリームを読み出す.その後、FilterでサーブレットRequestをサーブレットRequestWrapperに置き換えます.コードは次のとおりです.BodyReader HttpServeretRequestWrapperクラスは、ServeretRequestをパッケージ化し、ストリームをbyte[]に保存し、getReader()メソッドとgetInputStream()メソッドのストリームの読み取りをbyte[]に指します.
import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class AuthFilter implements Filter{
    
    public void destroy() {
        
    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;  
        if(request instanceof HttpServletRequest) {  
            requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);  
        }
        if(null == requestWrapper) {  
            chain.doFilter(request, response);  
        } else {  
            chain.doFilter(requestWrapper, response);  
        }
    }
    
    /**
     *       ,         url
     */
    public void init(FilterConfig config) throws ServletException {
    
    }
}
参照クラス
 1 import java.io.BufferedReader;
 2 import java.io.ByteArrayInputStream;
 3 import java.io.IOException;
 4 import java.io.InputStreamReader;
 5 
 6 import javax.servlet.ServletInputStream;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletRequestWrapper;
 9 
10 import jodd.JoddDefault;
11 import jodd.io.StreamUtil;
12 
13 public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
14     
15     private final byte[] body;  
16     
17     public BodyReaderHttpServletRequestWrapper(HttpServletRequest request)throws IOException {  
18         super(request);  
19         body = StreamUtil.readBytes(request.getReader(), JoddDefault.encoding);  
20     }  
21   
22     @Override  
23     public BufferedReader getReader() throws IOException {  
24         return new BufferedReader(new InputStreamReader(getInputStream()));  
25     }  
26   
27     @Override  
28     public ServletInputStream getInputStream() throws IOException {  
29         final ByteArrayInputStream bais = new ByteArrayInputStream(body);  
30         return new ServletInputStream() {  
31   
32             @Override  
33             public int read() throws IOException {  
34                 return bais.read();  
35             }  
36         };  
37     }  
38 }
 
転載先:https://www.cnblogs.com/ocean-sky/p/6899613.html