Spring MVC拦截器HandlerInterceptorAdapter,HandlerInterceptor示例

Spring Interceptor are used to intercept client requests and process them. Sometimes we want to intercept the HTTP Request and do some processing before handing it over to the controller handler methods. That’s where Spring MVC Interceptor come handy.

Spring Interceptor用于拦截客户端请求并进行处理。 有时我们想要截取HTTP请求并进行一些处理,然后再将其移交给控制器处理程序方法。 这就是Spring MVC拦截器派上用场的地方。

弹簧拦截器 (Spring Interceptor)

Just like we have Struts2 Interceptors, we can create our own Spring interceptor by either implementing org.springframework.web.servlet.HandlerInterceptor interface or by overriding abstract class org.springframework.web.servlet.handler.HandlerInterceptorAdapter that provides the base implementation of HandlerInterceptor interface.

就像拥有Struts2 Interceptor一样 ,我们可以通过实现org.springframework.web.servlet.HandlerInterceptor接口或重写抽象类org.springframework.web.servlet.handler.HandlerInterceptorAdapter来创建自己的Spring拦截器,该抽象类提供HandlerInterceptor的基本实现接口。

弹簧拦截器– HandlerInterceptor (Spring Interceptor – HandlerInterceptor)

Spring HandlerInterceptor declares three methods based on where we want to intercept the HTTP request.

Spring HandlerInterceptor根据我们想要拦截HTTP请求的位置声明了三个方法。

  1. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): This method is used to intercept the request before it’s handed over to the handler method. This method should return ‘true’ to let Spring know to process the request through another spring interceptor or to send it to handler method if there are no further spring interceptors.

    If this method returns ‘false’ Spring framework assumes that request has been handled by the spring interceptor itself and no further processing is needed. We should use response object to send response to the client request in this case.

    Object handler is the chosen handler object to handle the request. This method can throw Exception also, in that case Spring MVC Exception Handling should be useful to send error page as response.

    boolean preHandle(HttpServletRequest请求,HttpServletResponse响应,对象处理程序) :此方法用于在将请求移交给处理程序方法之前对其进行拦截。 该方法应返回“ true”,以让Spring知道通过另一个Spring拦截器处理请求,或者在没有其他Spring拦截器的情况下将其发送到处理程序方法。

    如果此方法返回“ false”,Spring框架将假定该请求已由Spring拦截器本身处理,并且不需要进一步的处理。 在这种情况下,我们应该使用response对象将响应发送到客户端请求。

    对象处理程序是选择的处理程序对象来处理请求。 这个方法也可以抛出Exception,在这种情况下, Spring MVC Exception Handling对于发送错误页面作为响应应该很有用。

  2. void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): This HandlerInterceptor interceptor method is called when HandlerAdapter has invoked the handler but DispatcherServlet is yet to render the view. This method can be used to add additional attribute to the ModelAndView object to be used in the view pages. We can use this spring interceptor method to determine the time taken by handler method to process the client request.

    void postHandle(HttpServletRequest请求,HttpServletResponse响应,对象处理程序,ModelAndView modelAndView) :当HandlerAdapter调用处理程序但DispatcherServlet尚未呈现视图时,将调用此HandlerInterceptor拦截器方法。 此方法可用于将附加属性添加到要在视图页面中使用的ModelAndView对象。 我们可以使用这种Spring拦截器方法来确定处理程序方法处理客户端请求所花费的时间。
  3. void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): This is a HandlerInterceptor callback method that is called once the handler is executed and view is rendered.

    afterCompletion(HttpServletRequest请求,HttpServletResponse响应,对象处理程序,异常Exception) :这是一个HandlerInterceptor回调方法,该方法在执行处理程序并呈现视图后立即被调用。

If there are multiple spring interceptors configured, preHandle() method is executed in the order of configuration whereas postHandle() and afterCompletion() methods are invoked in the reverse order.

如果配置了多个弹簧拦截器,则preHandle()方法将按照配置顺序执行,而postHandle()afterCompletion()方法将以相反的顺序调用。

Let’s create a simple Spring MVC application where we will configure an Spring Interceptor to log timings of controller handler method.

让我们创建一个简单的Spring MVC应用程序,在其中我们将配置一个Spring Interceptor来记录控制器处理程序方法的计时。

Our final Spring Interceptor example project will look like below image, we will look into the components that we are interested in.

我们最终的Spring Interceptor示例项目将如下图所示,我们将研究我们感兴趣的组件。

弹簧拦截器–控制器类 (Spring Interceptor – Controller Class)

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";
	}
	
}

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

我只是在处理程序方法的执行中添加了一些处理时间,以检查我们的spring拦截器方法是否有效。

Spring MVC拦截器– HandlerInterceptorAdapter实现 (Spring MVC Interceptor – HandlerInterceptorAdapter Implementation)

For simplicity, I am extending abstract class HandlerInterceptorAdapter. HandlerInterceptorAdapter is abstract adapter class for the HandlerInterceptor interface, for simplified implementation of pre-only/post-only interceptors.

为简单起见,我扩展了抽象类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));
	}

}

The logic is really simple, I am just logging the timings of handler method execution and total time taken in processing the request including rendering view page.

逻辑非常简单,我只是记录处理程序方法执行的时间以及处理请求(包括渲染视图页面)所花费的总时间。

Spring MVC拦截器配置 (Spring MVC Interceptor Configuration)

We have to wire the spring interceptor to the requests, we can use mvc:interceptors element to wire all the interceptors. We can also provide URI pattern to match before including the spring interceptor for the request through mapping element.

我们必须将spring拦截器连接到请求,我们可以使用mvc:interceptors元素来连接所有拦截器。 我们还可以提供URI模式进行匹配,然后再通过映射元素为请求添加弹簧拦截器。

Our final spring bean configuration file (spring.xml) looks like below.

我们最终的spring 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>

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.

我将不解释该Web应用程序的所有其他组件,因为我们对它们不感兴趣,并且它们没有任何与Spring拦截器相关的特定配置。

Spring MVC拦截器应用测试 (Spring MVC Interceptor Application Testing)

Just deploy the application in servlet container and invoke the home controller, you will see logger output something like below.

只需将应用程序部署在servlet容器中并调用home控制器,您将看到logger的输出,如下所示。

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

The output confirms that the spring interceptor methods are executed in the order defined.

输出确认弹簧拦截器方法已按定义的顺序执行。

That’s all for using spring interceptors, you can download the Spring Interceptor example project from below link and try to have multiple interceptors and check by different order of configuration.

这就是使用Spring拦截器的全部内容,您可以从下面的链接下载Spring Interceptor示例项目,并尝试拥有多个拦截器并按不同的配置顺序进行检查。

翻译自: https://www.journaldev.com/2676/spring-mvc-interceptor-example-handlerinterceptor-handlerinterceptoradapter

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值