こんにちは、@seitです。 Spring Bootで、各Controllerの共通処理を実装する機会があったので、備忘録です。
サンプルはこちらからどうぞ。
やりたいこと
HTTPリクエストに対して、どこにアクセスされたのかをログに出したい。
全てのリクエストハンドラ(Controller)に処理を入れるのは、実装の工数や保守性の観点でやりたくないので共通化したい。
利用するAPI
今回はHandlerInterceptorAdapterを使います。
Spring Bootで共通処理を挟み込む方法はいくつかあります。
名前 | 概要 |
---|---|
AdviceController | Controller専用の特殊なメソッド(initBinderやExceptionHandler、ModelAttribute)を複数のControllerで共有することが可能 |
サーブレットフィルター | DispatcherServletの呼び出し前後に共通処理を挟み込むことが可能 |
HandlerInterceptor | DispatcherServletとリクエストハンドラとの間に共通処理を挟み込むことが可能。Controllerに対してだけ共通処理を実行したい場合に利用 |
AOP | アスペクト指向プログラミング |
今回は、HTTPリクエストでハンドラが呼ばれる前に、どのコールされたハンドラを記録するログを出力したいと思います。
この場合、以下の2つの理由から、HandlerInterceptorが適していると思いました。
リクエストを受け取るControllerに対してだけ共通処理を実装すればよい
ハンドラの関数名をログに出力したいので、DispatcherServletとControllerの間に処理を挟みたい
initBinderやModelAttributeはログを出すだけという目的と用途が合致しない
AOPはそこまでする必要はなさそう
実装
まずは、HandlerInterceptorを継承したクラスを作成し、Overrideしたメソッドに共通にしたい処理を実装します。
今回は、HTTPリクエストの内容をいくつか取得してログに出力してみます。
public class LoggingInterceptor extends HandlerInterceptorAdapter { Logger logger = org.slf4j.LoggerFactory.getLogger(getClass().getPackage().getName()); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String requestUri = request.getRequestURI(); String requestMethod= request.getMethod(); String referer = request.getHeader("Referer"); HandlerMethod hm = (HandlerMethod) handler; String handlerClassName = hm.getMethod().getDeclaringClass().getSimpleName(); String handlerMethodName = hm.getMethod().getName(); String logInfo = new StringBuffer() .append(requestUri) .append(", method ") .append(requestMethod) .append(", from ") .append(referer) .append(", handlerClassName") .append(handlerClassName) .append(", handlerMethodName") .append(handlerMethodName).toString(); logger.info(logInfo); return true; } }
preHandleメソッドは、Controllerが呼ばれる前に実行されます。
Controllerの後に実行したい場合は、postHandleメソッドをOverrideします。
最後に、WebMvcConfigurerAdapterのaddInterceptorsメソッドの中で、
作成したLoggingInterceptorを登録します。
@Configuration public class SampleConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoggingInterceptor()).addPathPatterns("/**"); } }
この時、addPathPatternsでLoggingInterceptorを有効にしたいURIのパターンを指定することができます。
ここでは"/"以下全てのURIへのアクセスに対して、ログを出力するように設定しています。
2019-09-29 13:54:36.347 INFO 21072 --- [nio-8080-exec-1] com.example.HandlerInterceptordemo : /, method GET, from null, handlerClassNameSampleController, handlerMethodNametop 2019-09-29 13:54:36.353 INFO 21072 --- [nio-8080-exec-1] com.example.HandlerInterceptordemo : これはControllerのログです。
以上です。