Exemplo de HandlerInterceptorAdapter do Spring MVC, HandlerInterceptor

Primavera Interceptors são utilizados para interceptar solicitações do cliente e processá-las. Às vezes, queremos interceptar a solicitação HTTP e realizar algum processamento antes de entregá-la aos métodos do manipulador do controlador. É aí que os Interceptors do Spring MVC são úteis.

Interceptores do Spring

Assim como temos os Interceptors do Struts2, podemos criar nosso próprio interceptor do Spring, seja implementando a interface org.springframework.web.servlet.HandlerInterceptor ou substituindo a classe abstrata org.springframework.web.servlet.handler.HandlerInterceptorAdapter, que fornece a implementação base da interface HandlerInterceptor.

Interceptor do Spring – HandlerInterceptor

O HandlerInterceptor do Spring declara três métodos com base onde queremos interceptar a solicitação HTTP.

  1. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): Este método é usado para interceptar a solicitação antes de ser entregue ao método handler. Este método deve retornar ‘true’ para permitir que o Spring saiba que deve processar a solicitação por meio de outro interceptor do Spring ou enviá-la ao método handler se não houver mais interceptadores do Spring. Se este método retornar ‘false’, o framework Spring assumirá que a solicitação foi tratada pelo próprio interceptor do Spring e nenhum processamento adicional será necessário. Devemos usar o objeto de resposta para enviar a resposta à solicitação do cliente neste caso. O objeto handler é o objeto de manipulador escolhido para lidar com a solicitação. Este método também pode lançar uma exceção, nesse caso o tratamento de exceções do Spring MVC deve ser útil para enviar uma página de erro como resposta.
  2. void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): Este método interceptor HandlerInterceptor é chamado quando o HandlerAdapter invocou o manipulador, mas DispatcherServlet ainda não renderizou a visualização. Este método pode ser usado para adicionar um atributo adicional ao objeto ModelAndView a ser usado nas páginas de visualização. Podemos usar este método interceptor do Spring para determinar o tempo necessário pelo método handler para processar a solicitação do cliente.
  3. void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): Este é um método de retorno de chamada HandlerInterceptor que é chamado uma vez que o manipulador é executado e a visualização é renderizada.

Se houverem múltiplos interceptadores Spring configurados, o método preHandle() é executado na ordem de configuração, enquanto os métodos postHandle() e afterCompletion() são invocados na ordem inversa. Vamos criar uma aplicação Spring MVC simples onde configuraremos um Interceptor Spring para registrar os tempos dos métodos manipuladores do controlador. Nosso projeto final de exemplo de Interceptor Spring ficará como na imagem abaixo, vamos analisar os componentes nos quais estamos interessados.

Interceptor Spring – Classe do Controlador

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);
		//adicionando algum atraso de tempo para verificar a execução do interceptor
		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";
	}
	
}

I am just adding some processing time in the execution of the handler method to check our spring interceptor methods in action.

Interceptor Spring MVC – Implementação do HandlerInterceptorAdapter

Para simplificar, estou estendendo a classe abstrata HandlerInterceptorAdapter. HandlerInterceptorAdapter é uma classe adaptadora abstrata para a interface HandlerInterceptor, para implementação simplificada de interceptadores apenas de pré ou pós-execução.

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);
		// se retornar false, precisamos garantir que 'response' seja enviado
		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());
		// podemos adicionar atributos no modelAndView e usá-los na página de visualização
	}

	@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));
	}

}

A lógica é realmente simples, estou apenas registrando os tempos de execução do método handler e o tempo total necessário para processar a solicitação, incluindo a renderização da página de visualização.

Configuração do Interceptor do Spring MVC

Temos que vincular o interceptor do Spring às solicitações, podemos usar o elemento mvc:interceptors para vincular todos os interceptadores. Também podemos fornecer um padrão de URI para corresponder antes de incluir o interceptor do Spring para a solicitação por meio do elemento mapping. Nosso arquivo de configuração final do bean do Spring (spring.xml) parece com o seguinte.

<?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>

I will not explain all other components of the web application, because we are not interested in them and they don’t have any specific spring interceptor related configuration.

Teste de Aplicação do Interceptor do Spring MVC

Apenas implante a aplicação no contêiner de servlet e invoque o controlador principal, você verá a saída do logger algo como abaixo.

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

A saída confirma que os métodos interceptores de spring são executados na ordem definida. Isso é tudo para usar interceptadores de spring, você pode baixar o projeto de exemplo de Interceptor Spring no link abaixo e tentar ter múltiplos interceptadores e verificar por diferentes ordens de configuração.

Baixar Projeto de Interceptors Spring

Source:
https://www.digitalocean.com/community/tutorials/spring-mvc-interceptor-example-handlerinterceptor-handlerinterceptoradapter