Spring MVC 拦截器 HandlerInterceptorAdapter、HandlerInterceptor 示例

Spring Interceptor 用于拦截客户端请求并处理它们,有时我们想要拦截 HTTP 请求并在将其交给控制器处理方法之前进行一些处理。

春天拦截器

spring interceptor, spring mvc interceptor, HandlerInterceptorAdapter, HandlerInterceptor 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.

春季拦截器 - HandlerInterceptor

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

  1. 联合国 ** boolean preHandle(HttpServlet request, HttpServletResponse 答复,对象处理器)**: 这种方法用于截取请求后再交给处理器方法. 这种方法应该返回"真",让斯普林知道通过另一个弹簧截取器处理请求,或者在没有再有弹簧截取器的情况下发送到处理器方法. 如果这种方法返回"假""春"框架,则假设该请求已经由"春"截取器自行处理,无需再作进一步处理. 在此情况下,我们应该使用响应对象来发送对客户请求的答复. 对象 _ handler_ 是选定处理请求的处理器对象 。 这种方法也可以投出例外,在这种情况下春季MVC例外处理. 春季MVC例外处理 – @ ExceptionHandler, @ CoptionAdvice, HandlerExceptionResolver, JSON Response Except Exception Exception Exception Exception Exception Exception Exception Exception Exception Exception Excolver, JSON Response Except Except ext) 对于发送错误页面作为响应应该有用.
  2. ** 无效员额 处理( HttpServlet 请求、 HttpServlet 响应、 对象处理器、 模型) 还有 查看模式 (原始内容存档于2018-09-21) (英语). And View) (**: 当HandlerAdapter援引了处理器,但调度器Servlet尚未显示视图时,这种HandlerInterceptor截取方法被调用. 这种方法可以用于给ModelAndView对象添加附加属性,用于视图页面. 我们可以使用这个弹簧截取器方法来确定处理客户端请求所用的时间.
  3. ** 完成后撤销(HttpServlet请求、HttpServletResponse回复、对象处理器、例外)**: 这是一个 Handler Interceptor 调用方法,一旦处理器被执行,视图被提供,即被调用. (单位:千美元) (英语)

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. Let's create a simple Spring MVC application where we will configure an Spring Interceptor to log timings of controller handler method. Our final Spring Interceptor example project will look like below image, we will look into the components that we are interested in. Spring MVC Interceptor, Spring Interceptor example, Spring interceptor

春季拦截器 - 控制器类

 1package com.journaldev.spring;
 2
 3import java.text.DateFormat;
 4import java.util.Date;
 5import java.util.Locale;
 6
 7import org.slf4j.Logger;
 8import org.slf4j.LoggerFactory;
 9import org.springframework.stereotype.Controller;
10import org.springframework.ui.Model;
11import org.springframework.web.bind.annotation.RequestMapping;
12import org.springframework.web.bind.annotation.RequestMethod;
13
14/**
15 * Handles requests for the application home page.
16 */
17@Controller
18public class HomeController {
19    
20    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
21    
22    @RequestMapping(value = "/home", method = RequestMethod.GET)
23    public String home(Locale locale, Model model) {
24    	logger.info("Welcome home! The client locale is {}.", locale);
25    	//adding some time lag to check interceptor execution
26    	try {
27    		Thread.sleep(1000);
28    	} catch (InterruptedException e) {
29    		e.printStackTrace();
30    	}
31    	Date date = new Date();
32    	DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
33    	
34    	String formattedDate = dateFormat.format(date);
35    	
36    	model.addAttribute("serverTime", formattedDate );
37    	logger.info("Before returning view page");
38    	return "home";
39    }
40    
41}

我只是在执行处理方法时添加一些处理时间来检查我们的春季拦截方法在行动。

春季MVC拦截器 - HandlerInterceptorAdapter实施

为了简化,我正在扩展抽象类 HandlerInterceptorAdapter. HandlerInterceptorAdapter 是 HandlerInterceptor 接口的抽象适配类,用于简化仅前/仅后拦截器的实施。

 1package com.journaldev.spring;
 2
 3import javax.servlet.http.HttpServletRequest;
 4import javax.servlet.http.HttpServletResponse;
 5
 6import org.slf4j.Logger;
 7import org.slf4j.LoggerFactory;
 8import org.springframework.web.servlet.ModelAndView;
 9import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
10
11public class RequestProcessingTimeInterceptor extends HandlerInterceptorAdapter {
12
13    private static final Logger logger = LoggerFactory
14    		.getLogger(RequestProcessingTimeInterceptor.class);
15
16    @Override
17    public boolean preHandle(HttpServletRequest request,
18    		HttpServletResponse response, Object handler) throws Exception {
19    	long startTime = System.currentTimeMillis();
20    	logger.info("Request URL::" + request.getRequestURL().toString()
21    			+ ":: Start Time=" + System.currentTimeMillis());
22    	request.setAttribute("startTime", startTime);
23    	//if returned false, we need to make sure 'response' is sent
24    	return true;
25    }
26
27    @Override
28    public void postHandle(HttpServletRequest request,
29    		HttpServletResponse response, Object handler,
30    		ModelAndView modelAndView) throws Exception {
31    	System.out.println("Request URL::" + request.getRequestURL().toString()
32    			+ " Sent to Handler :: Current Time=" + System.currentTimeMillis());
33    	//we can add attributes in the modelAndView and use that in the view page
34    }
35
36    @Override
37    public void afterCompletion(HttpServletRequest request,
38    		HttpServletResponse response, Object handler, Exception ex)
39    		throws Exception {
40    	long startTime = (Long) request.getAttribute("startTime");
41    	logger.info("Request URL::" + request.getRequestURL().toString()
42    			+ ":: End Time=" + System.currentTimeMillis());
43    	logger.info("Request URL::" + request.getRequestURL().toString()
44    			+ ":: Time Taken=" + (System.currentTimeMillis() - startTime));
45    }
46
47}

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

春季MVC拦截器配置

我们必须将 Spring Interceptor 连接到请求中,我们可以使用 **mvc:interceptors ** 元素连接所有拦截器。我们还可以提供 URI 模式来匹配,然后将 Spring Interceptor 连接到请求中,通过 mapping 元素。

 1<?xml version="1.0" encoding="UTF-8"?>
 2<beans:beans xmlns="https://www.springframework.org/schema/mvc"
 3    xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:beans="https://www.springframework.org/schema/beans"
 4    xmlns:context="https://www.springframework.org/schema/context"
 5    xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
 6    	https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
 7    	https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
 8
 9    <!-- DispatcherServlet Context: defines this servlet's request-processing 
10    	infrastructure -->
11
12    <!-- Enables the Spring MVC @Controller programming model -->
13    <annotation-driven />
14
15    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
16    	up static resources in the ${webappRoot}/resources directory -->
17    <resources mapping="/resources/**" location="/resources/" />
18
19    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
20    	in the /WEB-INF/views directory -->
21    <beans:bean
22    	class="org.springframework.web.servlet.view.InternalResourceViewResolver">
23    	<beans:property name="prefix" value="/WEB-INF/views/" />
24    	<beans:property name="suffix" value=".jsp" />
25    </beans:bean>
26
27    <!-- Configuring interceptors based on URI -->
28    <interceptors>
29    	<interceptor>
30    		<mapping path="/home" />
31    		<beans:bean class="com.journaldev.spring.RequestProcessingTimeInterceptor"></beans:bean>
32    	</interceptor>
33    </interceptors>
34
35    <context:component-scan base-package="com.journaldev.spring" />
36
37</beans:beans>

我不会解释网页应用程序的所有其他组件,因为我们对它们并不感兴趣,而且它们没有任何特定的春天拦截器相关配置。

春季 MVC 拦截器应用程序测试

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

1INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: Start Time=1396906442086
2INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is en_US.
3INFO : com.journaldev.spring.HomeController - Before returning view page
4Request URL::https://localhost:9090/SpringInterceptors/home Sent to Handler :: Current Time=1396906443098
5INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: End Time=1396906443171
6INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::https://localhost:9090/SpringInterceptors/home:: Time Taken=1085

输出证实了春天拦截器的方法是按照定义的顺序执行的. 对于使用春天拦截器来说,您可以从下面的链接下载春天拦截器示例项目,并尝试有多个拦截器并按不同的配置顺序检查。

[下载《春季拦截者项目》(LINK0)]

Published At
Categories with 技术
Tagged with
comments powered by Disqus