ハンドラインターセプタによるSpringモデルパラメータの変更

1前書き

このチュートリアルでは、Spring MVCの__HandlerInterceptorに焦点を当てます。具体的には、リクエストの処理前後にSpring MVCのモデルパラメータを変更します。

__HandlerInterceptorの基本について読みたい場合は、/spring-mvc-handlerinterceptor[article]を参照してください。

2 Mavenの依存関係

Interceptors を使用するには、 pom.xml ファイルの dependencies セクションに次のセクションを含める必要があります。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.0.6.RELEASE</version>
</dependency>

最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22spring-web%22[here]にあります。

この依存関係はSpring Webのみを対象としているので、完全なWebアプリケーションのためにs __pring-core spring-context__を追加することを忘れないでください。

3カスタム実装

HandlerInterceptor のユースケースの1つは、共通/ユーザー固有のパラメータをモデルに追加することです。これは、生成された各ビューで利用可能になります。

この例では、ログに記録されたユーザーのユーザー名をモデルパラメーターに追加するためにカスタムインターセプター実装を使用します。より複雑なシステムでは、ユーザーのアバターパス、ユーザーの場所など、より具体的な情報を追加することがあります。

新しい Interceptor クラスを定義することから始めましょう。

public class UserInterceptor extends HandlerInterceptorAdapter {

    private static Logger log = LoggerFactory.getLogger(UserInterceptor.class);

    ...
}

preHandle() および postHandle() メソッドを実装するだけなので、 HandlerInterceptorAdapter を拡張します。

前述したように、ログに記録されたユーザーの名前をモデルに追加します。

まず最初に、ユーザーがログインしているかどうかをチェックする必要があります。 SecurityContextHolder をチェックすることでこの情報を取得できます。

public static boolean isUserLogged() {
    try {
        return !SecurityContextHolder.getContext().getAuthentication()
          .getName().equals("anonymousUser");
    } catch (Exception e) {
        return false;
    }
}

HttpSession が確立されていても誰もログインしていない場合、Spring Securityコンテキストのユーザ名は anonymousUser と同じです。次に、__preHandle()の実装を進めます。

3.1. メソッド preHandle()

リクエストを処理する前に、モデルパラメータにアクセスすることはできません。ユーザー名を追加するには、 HttpSession を使用してパラメータを設定する必要があります。

@Override
public boolean preHandle(HttpServletRequest request,
  HttpServletResponse response, Object object) throws Exception {
    if (isUserLogged()) {
        addToModelUserDetails(request.getSession());
    }
    return true;
}

リクエストを処理する前にこの情報の一部を使用している場合、これは非常に重要です。ご覧のとおり、ユーザーがログインしているかどうかを確認し、そのセッションを取得してリクエストにパラメーターを追加します。

private void addToModelUserDetails(HttpSession session) {
    log.info("=============== addToModelUserDetails =========================");

    String loggedUsername
      = SecurityContextHolder.getContext().getAuthentication().getName();
    session.setAttribute("username", loggedUsername);

    log.info("user(" + loggedUsername + ") session : " + session);
    log.info("=============== addToModelUserDetails =========================");
}

loggedUsername を取得するには、 SecurityContextHolder を使用しました。標準のユーザー名の代わりにSpring SecurityのUserDetails実装をオーバーライドしてEメールを取得することができます。

3.2. メソッドp _ostHandle() _

リクエストを処理した後、私たちのモデルパラメータが利用可能になるので、値を変更したり新しいものを追加するためにそれらにアクセスすることができます。そのためには、オーバーライドされた postHandle() メソッドを使用します。

@Override
public void postHandle(
  HttpServletRequest req,
  HttpServletResponse res,
  Object o,
  ModelAndView model) throws Exception {

    if (model != null && !isRedirectView(model)) {
        if (isUserLogged()) {
        addToModelUserDetails(model);
    }
    }
}

実装の詳細を見てみましょう。

まず第一に、モデルが nullではないかどうかをチェックすることをお勧めします。 NullPointerException__が発生するのを防ぐことができます。

さらに、 View がRedirect __View . __のインスタンスではないかどうかを調べることができます

リクエストが処理されてリダイレクトされた後でパラメータを追加/変更する必要はありません。すぐに、新しいコントローラが処理を再度実行します。ビューがリダイレクトされているかどうかを確認するために、次のメソッドを導入しています。

public static boolean isRedirectView(ModelAndView mv) {
    String viewName = mv.getViewName();
    if (viewName.startsWith("redirect:/")) {
        return true;
    }
    View view = mv.getView();
    return (view != null && view instanceof SmartView
      && ((SmartView) view).isRedirectView());
}

最後に、ユーザーがログに記録されているかどうかをもう一度確認し、そうであれば、Springモデルにパラメーターを追加します。

private void addToModelUserDetails(ModelAndView model) {
    log.info("=============== addToModelUserDetails =========================");

    String loggedUsername = SecurityContextHolder.getContext()
      .getAuthentication().getName();
    model.addObject("loggedUsername", loggedUsername);

    log.trace("session : " + model.getModel());
    log.info("=============== addToModelUserDetails =========================");
}

このロジックはアプリケーションの「裏側で」機能するため、ロギングは非常に重要です。正しく記録することなく、各 View でいくつかのモデルパラメータを変更していることを忘れがちです。

4構成

新しく作成した Interceptor をSpringの設定に追加するには、 WebMvcConfigurerを実装する WebConfig クラス内の addInterceptors()__メソッドをオーバーライドする必要があります。

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new UserInterceptor());
}

XML Spring構成ファイルを編集することで同じ構成を実現できます。

<mvc:interceptors>
    <bean id="userInterceptor" class="org.baeldung.web.interceptor.UserInterceptor"/>
</mvc:interceptors>

この瞬間から、私たちはすべての生成されたビューのすべてのユーザー関連のパラメータにアクセスするかもしれません。

複数のSpring Interceptors が設定されている場合、 preHandle() メソッドは設定順に実行されますが、 postHandle() メソッドと afterCompletion() メソッドは逆の順番で呼び出されます。

5結論

このチュートリアルでは、ユーザー情報を提供するために、Spring MVCのHandlerInterceptorを使用してWeb要求を傍受する方法を説明します。

この例では、Webアプリケーションでログに記録されたユーザーの詳細をモデルパラメータに追加することに焦点を当てました。より詳細な情報を追加することで、この HandlerInterceptor 実装を拡張することができます。

例と設定はすべてhttps://github.com/eugenp/tutorials/tree/master/spring-security-mvc-custom[GitHub]から入手できます。

5.1. シリーズの記事

シリーズのすべての記事:

インターセプター]** Handler Interceptorを使ってSpringモデルのパラメータを変更する(これ)