Spring MVC HandlerInterceptorの概要
1. 前書き
このチュートリアルでは、Spring MVCHandlerInterceptorを理解し、それを正しく使用する方法に焦点を当てます。 __
2. Spring MVCハンドラー
そして、インターセプターを理解するために、一歩下がってHandlerMappingを見てみましょう。 これにより、メソッドがURLにマップされるため、DispatcherServletはリクエストの処理時にメソッドを呼び出すことができます。
そして、DispatcherServletはHandlerAdapterを使用して実際にメソッドを呼び出します。
これで、全体的なコンテキスト–this is where the handler interceptor comes inが理解できました。 HandlerInterceptorを使用して、リクエストの処理前、処理後、または完了後(ビューがレンダリングされるとき)にアクションを実行します。
インターセプターは、横断的な関心事に使用したり、ロギング、Springモデルでグローバルに使用されるパラメーターの変更などの繰り返しハンドラーコードを回避するために使用できます。
次のいくつかのセクションでは、まさにこれから見ていきます。さまざまなインターセプターの実装の違いです。
3. Mavenの依存関係
Interceptorsを使用するには、pom.xmlファイルのdependenciesセクションに次のセクションを含める必要があります。
org.springframework
spring-web
5.0.6.RELEASE
最新バージョンはhereで見つけることができます。
4. スプリングハンドラーインターセプター
フレームワークでHandlerMappingを操作するインターセプターは、HandlerInterceptorインターフェースを実装する必要があります。
このインターフェイスには、3つの主要なメソッドが含まれています。
-
prehandle() –実際のハンドラーが実行される前に呼び出されますが、ビューはまだ生成されていません
-
postHandle() –afterと呼ばれ、ハンドラーが実行されます
-
after the complete request has finished and view was generatedと呼ばれるafterCompletion() –
これらの3つの方法は、あらゆる種類の前処理および後処理を行う柔軟性を提供します。
簡単な注意–HandlerInterceptorとHandlerInterceptorAdapterの主な違いは、最初の方法では、preHandle()、postHandle()、afterCompletion()の3つのメソッドすべてをオーバーライドする必要があることです。 s、一方、2番目では、必要なメソッドのみを実装できます。
先に進む前の簡単なメモ–理論をスキップして例に直接ジャンプしたい場合は、セクション5に直接ジャンプしてください。
単純なpreHandle()の実装は次のようになります。
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
// your code
return true;
}
メソッドがboolean値を返すことに注意してください。これは、リクエストをハンドラーでさらに処理する必要があるか(true)、処理しないか(false)をSpringに通知します。
次に、postHandle()の実装があります。
@Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
// your code
}
このメソッドは、リクエストがHandlerAdapterによって処理された直後、ビューを生成する前に呼び出されます。
もちろん、さまざまな方法で使用できます。たとえば、ログインしたユーザーのアバターをモデルに追加できます。
カスタムHandlerInterceptor実装で実装する必要がある最後のメソッドはafterCompletion():です
@Override
public void afterCompletion(
HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) {
// your code
}
ビューが正常に生成されると、このフックを使用して、リクエストに関連する追加の統計を収集するなどのことを実行できます。
覚えておくべき最後の注意点は、HandlerInterceptorがDefaultAnnotationHandlerMapping Beanに登録されていることです。これは、@Controllerアノテーションでマークされたクラスにインターセプターを適用する役割を果たします。 さらに、Webアプリケーションで任意の数のインターセプターを指定できます。
5. カスタムロガーインターセプター
この例では、Webアプリケーションのログインに焦点を当てます。 まず、クラスはHandlerInterceptorAdapterを拡張する必要があります。
public class LoggerInterceptor extends HandlerInterceptorAdapter {
...
}
また、インターセプターでロギングを有効にする必要があります。
private static Logger log = LoggerFactory.getLogger(LoggerInterceptor.class);
これにより、Log4Jはログを表示できるだけでなく、現在どのクラスが指定された出力に情報を記録しているかを示します。
次に、カスタムインターセプターの実装に焦点を当てましょう。
5.1. メソッドpreHandle()
このメソッドは、リクエストを処理する前に呼び出されます。 true,を返し、フレームワークがリクエストをさらにハンドラーメソッド(または次のインターセプター)に送信できるようにします。 メソッドがfalseを返す場合、Springは要求が処理されたと見なし、それ以上の処理は必要ありません。
フックを使用して、リクエストのパラメータに関する情報を記録できます。リクエストの発信元など。
この例では、単純なLog4Jロガーを使用してこの情報を記録しています。
@Override
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
log.info("[preHandle][" + request + "]" + "[" + request.getMethod()
+ "]" + request.getRequestURI() + getParameters(request));
return true;
}
ご覧のとおり、リクエストに関するいくつかの基本情報をログに記録しています。
ここでパスワードに遭遇した場合は、もちろんそれをログに記録しないようにする必要があります。
簡単なオプションは、パスワードやその他の機密データを星に置き換えることです。
これを行う方法の簡単な実装は次のとおりです。
private String getParameters(HttpServletRequest request) {
StringBuffer posted = new StringBuffer();
Enumeration> e = request.getParameterNames();
if (e != null) {
posted.append("?");
}
while (e.hasMoreElements()) {
if (posted.length() > 1) {
posted.append("&");
}
String curr = (String) e.nextElement();
posted.append(curr + "=");
if (curr.contains("password")
|| curr.contains("pass")
|| curr.contains("pwd")) {
posted.append("*****");
} else {
posted.append(request.getParameter(curr));
}
}
String ip = request.getHeader("X-FORWARDED-FOR");
String ipAddr = (ip == null) ? getRemoteAddr(request) : ip;
if (ipAddr!=null && !ipAddr.equals("")) {
posted.append("&_psip=" + ipAddr);
}
return posted.toString();
}
最後に、HTTPリクエストの送信元IPアドレスを取得することを目指しています。
簡単な実装は次のとおりです。
private String getRemoteAddr(HttpServletRequest request) {
String ipFromHeader = request.getHeader("X-FORWARDED-FOR");
if (ipFromHeader != null && ipFromHeader.length() > 0) {
log.debug("ip from proxy - X-FORWARDED-FOR : " + ipFromHeader);
return ipFromHeader;
}
return request.getRemoteAddr();
}
5.2. メソッドpostHandle()
このフックは、HandlerAdapterがハンドラーを呼び出されたが、DispatcherServletがまだビューをレンダリングしていない場合に実行されます。
このメソッドを使用して、ModelAndViewに属性を追加したり、ハンドラーメソッドがクライアントのリクエストを処理するのにかかる時間を決定したりできます。
この例では、DispatcherServletがビューをレンダリングする直前にリクエストをログに記録するだけです。
@Override
public void postHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
log.info("[postHandle][" + request + "]");
}
5.3. メソッドafterCompletion()
リクエストが終了し、ビューがレンダリングされると、リクエストとレスポンスのデータ、および例外が発生した場合は例外に関する情報を取得できます。
@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response,Object handler, Exception ex)
throws Exception {
if (ex != null){
ex.printStackTrace();
}
log.info("[afterCompletion][" + request + "][exception: " + ex + "]");
}
6. 設定
インターセプターをSpring構成に追加するには、WebMvcConfigurer:を実装するWebConfigクラス内のaddInterceptors()メソッドをオーバーライドする必要があります
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggerInterceptor());
}
XML Spring構成ファイルを編集することにより、同じ構成を実現できます。
この構成をアクティブにすると、インターセプターがアクティブになり、アプリケーション内のすべての要求が適切に記録されます。
複数のSpringインターセプターが構成されている場合、preHandle()メソッドは構成の順序で実行されますが、postHandle()メソッドとafterCompletion()メソッドは逆の順序で呼び出されることに注意してください。
7. 結論
このチュートリアルは、Spring MVC Handler Interceptorを使用してHTTPリクエストをインターセプトする簡単な紹介です。
すべての例と構成は、ここGitHubで入手できます。