Spring 框架入门教程
1. 1. Spring 框架 2. 2. Spring 5 3. 3. Spring WebFlux 4. 4. 先介绍一下 Spring 5. 5. 什么是 Spring 依赖注入 6. 6. 什么是 Spring IoC 容器 和 Bean 7. 7. Spring Bean 的生命周期 8. 8. Spring REST 开发 9. 9. Spring REST XML 10. 10. Spring RestTemplate 开发 11. 11. Spring AOP 切面编程 12. 12. Spring AOP 方法调优 13. 13. Spring 注解详解 14. 14. Spring 核心注解之 @Autowired 15. 15. Spring 核心注解之 @RequestMapping 16. 16. Spring MVC 开发样例 17. 17. Spring MVC 开发指南 18. 18. Spring MVC 异常处理机制 19. 19. Spring MVC Validator 20. 20. Spring MVC 拦截器 21. 21. Spring MVC 文件上传 22. 22. Spring MVC 国际化(i18n) 23. 23. Spring MVC Hibernate MqSQL 24. 24. Spring ORM 25. 25. Spring ORM JPA 26. 26. Spring Data JPA 27. 27. Spring 事务管理 28. 28. 常用的 Spring JdbcTemplate 29. 29. Spring Security 简介 30. 30. Spring Security 教程 31. 31. Spring Security UserDetailsService 32. 32. Spring MVC 登录注销简单案例 33. 33. Spring Security Roles 34. 34. Spring Boot Tutorial 35. 35. Spring Boot Components 36. 36. Spring Boot CLI Hello World 37. 37. Spring Boot Initilizr Web 38. 38. Spring Boot Initilizr IDE 39. 39. Spring Boot Initilizr CLI 40. 40. Spring Boot Initilizr Tools 41. 41. Spring Boot MongoDB 42. 42. Spring Boot Redis Cache 43. 43. Spring Boot 常见面试问题 44. 44. Spring Batch 45. 45. Spring Batch 批处理示例 46. 46. Spring AMQP 47. 47. Spring RabbitMQ 48. 48. Spring AMQP RabbitMQ 49. 49. Apache ActiveMQ 安装与启动 50. 50. Spring ActiveMQ 教程 51. 51. Spring ActiveMQ 示例 52. 52. Spring JDBC 53. 53. Spring DataSource JNDI 54. 54. Spring Hibernate 55. 55. Spring Primefaces JPA 56. 56. Spring Primefaces MongoDB 57. 57. Spring Primefaces Hibernate 58. 58. SpringRoo Primefaces Hibernate 59. 59. Spring JSF 60. 60. Spring JDF Hibernate 61. 61. Spring Data MongoDB 62. 62. Spring 常见面试问题

20. Spring MVC 拦截器

Spring拦截器用于拦截客户端请求并处理它们。有时我们想截获HTTP请求并在将其交给控制器处理程序方法之前进行一些处理。这就是Spring Mvc拦截器派上用场的地方。

Spring拦截器

就像我们一样Struts2拦截器,我们可以通过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.

Spring拦截器

Spring拦截器根据要拦截HTTP请求的位置声明三个方法。

  1. 布尔预处理(HttpServletRequest请求、HttpServletResponse响应、对象处理程序):此方法用于在请求移交给handler方法之前拦截请求。此方法应返回‘;true’;以让Spring知道如何通过另一个Spring拦截器处理请求,或者如果没有其他Spring拦截器,则将其发送给handler方法。

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

    对象经办人选择处理程序处理请求。在这种情况下,这个方法也可以抛出异常Spring MVC异常处理将错误页作为响应发送应该很有用。

  2. void postHandle(HttpServletRequest请求,HttpServletResponse响应,对象处理程序,ModelAndView ModelAndView):当HandlerAdapter已调用处理程序但DispatcherServlet尚未呈现视图时,将调用此HandlerInterceptor拦截器方法。此方法可用于向要在视图页中使用的ModelAndView对象添加其他属性。我们可以使用这个spring拦截器方法来确定handler方法处理客户机请求所用的时间。
  3. 完成后无效(HttpServletRequest请求、HttpServletResponse响应、对象处理程序、异常ex):这是一个HandlerInterceptor回调方法,在执行处理程序并呈现视图后将调用该方法。

如果配置了多个spring拦截器,预处理()方法按配置的顺序执行,而postHandle()竣工后()方法按相反的顺序调用。

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

我们最后的Spring拦截器示例项目将如下图所示,我们将研究我们感兴趣的组件。

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

我只是在handler方法的执行中添加一些处理时间,以检查spring拦截器方法的运行情况。

Spring MVC拦截器和handler拦截器适配器实现

为了简单起见,我扩展了抽象类HandlerInterceptorAdapter. HandlerInterceptorAdapter is abstract adapter class for the HandlerInterceptor interface, for simplified implementation of pre-only/post-only interceptors.


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:拦截器元素来连接所有的拦截器。我们还可以在包含请求的spring拦截器之前提供匹配的URI模式测绘元素。

最后一个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
	>
		<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></beans:bean>
		</interceptor>
	</interceptors>

	<context:component-scan base-package="com.journaldev.spring" />

</beans:beans>

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

Spring Mvc拦截器应用测试

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


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拦截器示例项目,并尝试使用多个拦截器并按不同的配置顺序进行检查。