Поиск по сайту:

Spring MVC Interceptor HandlerInterceptorAdapter, пример HandlerInterceptor


Spring Interceptor используются для перехвата клиентских запросов и их обработки. Иногда мы хотим перехватить HTTP-запрос и выполнить некоторую обработку, прежде чем передать его методам обработчика контроллера. Вот где Spring MVC Interceptor пригодится.

Весенний перехватчик

Весенний перехватчик — HandlerInterceptor

Spring HandlerInterceptor объявляет три метода в зависимости от того, где мы хотим перехватить HTTP-запрос.

  1. boolean preHandle (запрос HttpServletRequest, ответ HttpServletResponse, обработчик объекта): этот метод используется для перехвата запроса до того, как он будет передан методу обработчика. Этот метод должен возвращать «true», чтобы сообщить Spring об обработке запроса через другой перехватчик Spring или отправить его методу обработчика, если других перехватчиков Spring нет. Если этот метод возвращает «false», среда Spring предполагает, что запрос был обработан самим перехватчиком Spring, и дальнейшая обработка не требуется. В этом случае мы должны использовать объект ответа для отправки ответа на запрос клиента. Объект handler — это выбранный объект-обработчик для обработки запроса. Этот метод также может вызывать исключение, в этом случае Spring MVC Exception Handling должен быть полезен для отправки страницы с ошибкой в качестве ответа.
  2. void postHandle (запрос HttpServletRequest, ответ HttpServletResponse, обработчик объекта, ModelAndView modelAndView): этот метод перехватчика HandlerInterceptor вызывается, когда HandlerAdapter вызвал обработчик, но DispatcherServlet еще не отобразил представление. Этот метод можно использовать для добавления дополнительного атрибута к объекту ModelAndView, который будет использоваться на страницах просмотра. Мы можем использовать этот метод перехватчика spring, чтобы определить время, необходимое методу обработчика для обработки запроса клиента.
  3. void afterCompletion (запрос HttpServletRequest, ответ HttpServletResponse, обработчик объекта, исключение ex): это метод обратного вызова HandlerInterceptor, который вызывается после выполнения обработчика и отображения представления.

Spring Interceptor — класс контроллера

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 в действии.

Spring MVC Interceptor — реализация HandlerInterceptorAdapter

Для простоты я расширяю абстрактный класс HandlerInterceptorAdapter. HandlerInterceptorAdapter — это абстрактный класс адаптера для интерфейса HandlerInterceptor для упрощенной реализации перехватчиков pre-only/post-only.

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

Мы должны подключить перехватчик spring к запросам, мы можем использовать элемент mvc:interceptors для подключения всех перехватчиков. Мы также можем предоставить шаблон URI для сопоставления перед включением перехватчика spring для запроса через элемент сопоставления. Наш окончательный файл конфигурации bean-компонента Spring (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.

Тестирование приложений Spring MVC Interceptor

Просто разверните приложение в контейнере сервлетов и вызовите домашний контроллер, вы увидите вывод логера примерно так, как показано ниже.

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 выполняются в указанном порядке. Это все, что касается использования перехватчиков Spring, вы можете загрузить пример проекта Spring Interceptor по ссылке ниже и попробовать использовать несколько перехватчиков и проверить их в другом порядке конфигурации.

Скачать проект весенних перехватчиков