Spring MVC インターセプター HandlerInterceptorAdapter、HandlerInterceptor の例
Springインターセプターは、クライアントのリクエストを intercept し、処理するために使用されます。時には、HTTPリクエストを intercept して、コントローラハンドラメソッドに渡す前に何らかの処理を行いたいことがあります。ここでSpring MVCインターセプターが便利になります。
春のインターセプター
私たちがStruts2のインターセプターを持っているように、org.springframework.web.servlet.HandlerInterceptorインターフェースを実装するか、HandlerInterceptorインターフェースの基本実装を提供する抽象クラスorg.springframework.web.servlet.handler.HandlerInterceptorAdapterをオーバーライドすることで、自分自身のSpringインターセプターを作成することができます。
スプリングインターセプター - ハンドラーインターセプター
Spring HandlerInterceptor は、HTTP リクエストをどこでインターセプトしたいかに基づいて三つのメソッドを宣言します。
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): このメソッドは、リクエストがハンドラメソッドに渡される前にそのリクエストを intercept するために使用されます。このメソッドは、他の Spring インターセプタを通じてリクエストを処理するため、または他に Spring インターセプタがない場合はハンドラメソッドに渡すために Spring に知らせるために 'true' を返す必要があります。このメソッドが 'false' を返すと、Spring フレームワークはリクエストが Spring インターセプタ自身によって処理されたと仮定し、さらに処理は必要ないと考えます。この場合、レスポンスオブジェクトを使用してクライアントリクエストに対してレスポンスを送信する必要があります。オブジェクト handler は、リクエストを処理するために選択されたハンドラオブジェクトです。このメソッドは Exception をスローすることもあり、その場合は Spring MVC 例外処理がエラーページをレスポンスとして送信するのに役立ちます。
- void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): この HandlerInterceptor インターセプターメソッドは、HandlerAdapter がハンドラーを呼び出したが、DispatcherServlet がまだビューをレンダリングしていないときに呼び出されます。このメソッドは、ビューページで使用するために ModelAndView オブジェクトに追加の属性を追加するために使用できます。この Spring インターセプターメソッドを使用して、ハンドラーメソッドがクライアントリクエストを処理するのにかかる時間を測定できます。
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): これは、ハンドラーが実行され、ビューがレンダリングされた後に呼び出されるHandlerInterceptorのコールバックメソッドです。
複数のSpringインターセプターが設定されている場合、preHandle() メソッドは設定の順序で実行され、postHandle() および afterCompletion() メソッドは逆の順序で呼び出されます。コントローラーハンドラーメソッドのタイミングを記録するためにSpringインターセプターを設定するシンプルなSpring MVCアプリケーションを作りましょう。最終的なSpringインターセプターの例プロジェクトは以下の画像のようになります。私たちが興味を持っているコンポーネントについて見ていきましょう。
スプリングインターセプター - コントローラークラス
package com.journaldev.spring;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
//adding some time lag to check interceptor execution
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
logger.info("Before returning view page");
return "home";
}
}
私は、ハンドラーメソッドの実行にいくつかの処理時間を追加して、スプリングインターセプターのメソッドが動作しているかを確認しています。
Spring MVC インターセプター - HandlerInterceptorAdapter の実装
簡単のために、私は抽象クラスHandlerInterceptorAdapterを拡張しています。HandlerInterceptorAdapterは、前処理のみまたは後処理のみのインターセプターの簡易実装のためのHandlerInterceptorインターフェースの抽象アダプタークラスです。
package com.journaldev.spring;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class RequestProcessingTimeInterceptor extends HandlerInterceptorAdapter {
private static final Logger logger = LoggerFactory
.getLogger(RequestProcessingTimeInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
long startTime = System.currentTimeMillis();
logger.info("Request URL::" + request.getRequestURL().toString()
+ ":: Start Time=" + System.currentTimeMillis());
request.setAttribute("startTime", startTime);
//if returned false, we need to make sure 'response' is sent
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("Request URL::" + request.getRequestURL().toString()
+ " Sent to Handler :: Current Time=" + System.currentTimeMillis());
//we can add attributes in the modelAndView and use that in the view page
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
long startTime = (Long) request.getAttribute("startTime");
logger.info("Request URL::" + request.getRequestURL().toString()
+ ":: End Time=" + System.currentTimeMillis());
logger.info("Request URL::" + request.getRequestURL().toString()
+ ":: Time Taken=" + (System.currentTimeMillis() - startTime));
}
}
論理は非常にシンプルです。私は、ハンドラーメソッドの実行時間と、ビューページのレンダリングを含むリクエストの処理にかかった合計時間を記録しています。
Spring MVC インターセプターの設定
リクエストにスプリングインターセプターを接続する必要があります。すべてのインターセプターを接続するために mvc:interceptors 要素を使用できます。また、リクエストのためにスプリングインターセプターを含める前に一致させるURIパターンを mapping 要素を通じて提供することもできます。最終的なスプリングBeanの設定ファイル(spring.xml)は以下のようになります。
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="https://www.springframework.org/schema/mvc"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:beans="https://www.springframework.org/schema/beans"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<!-- Configuring interceptors based on URI -->
<interceptors>
<interceptor>
<mapping path="/home" />
<beans:bean class="com.journaldev.spring.RequestProcessingTimeInterceptor"></beans:bean>
</interceptor>
</interceptors>
<context:component-scan base-package="com.journaldev.spring" />
</beans:beans>
私はウェブアプリケーションの他のすべてのコンポーネントについて説明しません。なぜなら、それらには興味がなく、特定のスプリングインターセプター関連の設定もないからです。
Spring MVC インターセプターアプリケーションテスト
単にアプリケーションをサーブレットコンテナにデプロイし、ホームコントローラーを呼び出すと、以下のようなロガー出力が表示されます。
INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: Start Time=1396906442086
INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is en_US.
INFO : com.journaldev.spring.HomeController - Before returning view page
Request URL::https://localhost:9090/SpringInterceptors/home Sent to Handler :: Current Time=1396906443098
INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: End Time=1396906443171
INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: Time Taken=1085
出力は、スプリングインターセプターメソッドが定義された順序で実行されることを確認します。スプリングインターセプターの使用はこれで終わりです。下記のリンクからスプリングインターセプターのサンプルプロジェクトをダウンロードし、複数のインターセプターを試して、異なる構成の順序で確認してみてください。
Springインターセプターズプロジェクトをダウンロードする


