1.拦截器
主要内容:
- 拦截器的定义
- 拦截器的配置
- 拦截器的执行流程
1.1.拦截器的概述
拦截器(Interceptor)与学习Java Web基础中的过滤器(Filter)类似,主要用于拦截用户请求并做出相应的处理。
应用场景:
- 权限验证:比如管理员页面,客户是不能访问的。
- 记录请求信息的日志
- 判断用户是否登陆:有些页面未登录用户是无法访问的。
主意回顾一下@ModelAttribute的作用,它也可以应用于登陆验证、权限验证。
1.1.1.拦截器的定义
拦截器的使用步骤:
- 定义拦截器
- 配置拦截器
定义一个拦截器的方法有两种:
- 实现
HandlerInterceptor
接口或继承其实现类 - 实现
WebRequestInterceptor
接口或继承其实现类
下面是实现HandlerInterceptor
接口来定义拦截器的示例:
package com.tao.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 拦截器类
* 通过实现HandlerInterceptor接口来定义一个拦截器
* @author 12505
*
*/
public class TestInterceptor implements HandlerInterceptor{
/**
* afterCompletion方法在控制器的处理请求方法执行完成后,即视图渲染结束之后执行
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("[afterCompletion方法] 执行");
}
/**
* postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("[postHandle方法] 执行");
}
/**
* preHandle方法在控制器的处理请求方法之前执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("[preHandle方法] 执行");
return true;
}
}
通过上面可以看到HandlerInterceptor
接口主要有三个方法。
- preHandle方法: 该方法在控制器处理请求的方法前执行,其返回值表示是否中断后续操作,false表示中断, true表示继续执行。
- postHandle方法:该方法在控制器处理请求的方法调用之后,视图解析之前执行。因此,可以通过该方法对请求域中的模型和视图做进一步处理。
- afterCompletion方法:该方法在视图解析之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
这些方法的执行顺序将在1.2.拦截器的执行顺序中做进一步的学习。
1.1.2.拦截器的配置
定义完拦截器之后,要想让其生效,就要在配置文件中进行配置。
其配置代码如下:
springmvc-servlet.xml
<!-- 拦截器的配置 -->
<mvc:interceptors>
<!-- 全局的拦截器,拦截所有请求(在这配置的bean是全局拦截器 ) -->
<bean class="com.tao.interceptor.TestInterceptor"/>
<!--指定路径的拦截器-->
<mvc:interceptor>
<!-- 配置拦截器的作用路径 -->
<mvc:mapping path="/**"/>
<!-- 配置不需要拦截的作用路径 -->
<mvc:exclude-mapping path="/login" />
<!-- 指定路径拦截器,拦截指定路径的请求(在这配置的bean是指定路径的拦截器) -->
<bean class="com.tao.interceptor.Interceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/goToTest"/>
<bean class="com.tao.interceptor.Interceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
<mvc:interceptors>
元素用于配置一组拦截器<bean>
元素全局拦截器,即拦截所有的请求。<mvc:interceptor>
元素定义指定路径的拦截器<mvc:mapping>
用于配置拦截器作用的路径<mvc:exclude-mapping>
用于配置不需要拦截的路径<bean>
配置指定路径拦截器。
##1.2.拦截器的执行顺序
1.2.1.单个拦截器执行顺序
先看一下一个拦截器的执行流程:
- 程序首先执行拦截器的preHandle方法
- 如果preHandle方法返回true,则执行控制器处理请求的方法;否则中断执行。
- 执行拦截器的postHandle方法
- 解析视图
- 执行拦截器的afterCompletion方法
- 结束
下面通过代码验证一下:
①创建web应用程序
②导入jar包
③配置web.xml文件
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>ssm01</display-name>
<!-- ①Spring IOC 容器的配置 -->
<!-- 加载类路径下的applicationContext.xml文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 指定以ContextLoaderListener方式启动Spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- ③配置DispatcherServlet [springmvc] -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 启动容器时立即加载servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
④创建控制器类
package com.tao.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 测试拦截器的控制器类
* @author 12505
*
*/
@Controller
public class InterceptorController {
/**
* 进入test的页面
* @return
*/
@RequestMapping("goToTest")
public String goToTest() {
System.out.println("[处理请求的方法] 正在测试拦截器,执行控制器的处理请求方法中");
return "test";
}
}
⑤创建拦截器类
package com.tao.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 拦截器类
* 通过实现HandlerInterceptor接口来定义一个拦截器
* @author 12505
*
*/
public class TestInterceptor implements HandlerInterceptor{
/**
* afterCompletion方法在控制器的处理请求方法执行完成后,即视图渲染结束之后执行
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("[afterCompletion方法] 执行");
}
/**
* postHandle方法在控制器的处理请求方法调用之后,解析视图之前执行
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("[postHandle方法] 执行");
}
/**
* preHandle方法在控制器的处理请求方法之前执行
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("[preHandle方法] 执行");
return true;
}
}
⑤springmvc-servlet.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- ①开启扫描机制扫描控制器的包 -->
<context:component-scan base-package="com.tao.controller"/>
<!-- ②开启Controller的注解, 这样注解才有效 -->
<mvc:annotation-driven/>
<!-- ③配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 这是一个全局的拦截器,拦截所有请求(interceptors的子元素bean是全局拦截器 ) -->
<bean class="com.tao.interceptor.TestInterceptor"/>
</mvc:interceptors>
</beans>
⑥创建视图jsp文件
test.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>测试拦截器</title>
</head>
<body>
这是视图
<% System.out.println("视图渲染结束。"); %>
</body>
</html>
执行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iD4VH1nv-1599210679549)(D:\笔记图片集\1599209632809.png)]
1.2.2.多个拦截器执行顺序
在web应用程序中通常是多个web同时工作,这时他们的preHandle方法将按照配置文件中拦截器的配置顺序执行,postHandle和afterCompletion方法则按照配置顺序的反序执行:
- 执行Interceptor1的preHandle方法
- 执行Interceptor2的preHandle方法
- 执行控制器中处理请求的方法
- 执行Interceptor2的postHandle方法
- 执行Interceptor1的postHandle方法
- 渲染视图
- 执行Interceptor2的afterCompletion方法
- 执行Interceptor1的afterCompletion方法
顺序用图片表示如下:
还是用上web应用。
新建Interceptor1、Interceptor2两个拦截器:
package com.tao.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 拦截器1号
* 用于测试多个拦截器的执行顺序
* @author 12505
*
*/
public class Interceptor1 implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println(this.getClass().getName()+" afterCompletion方法执行");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println(this.getClass().getName()+" postHandle方法执行");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println(this.getClass().getName()+" preHandle方法执行");
return true;
}
}
package com.tao.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 拦截器2号
* 用于测试多个拦截器的执行顺序
* @author 12505
*
*/
public class Interceptor2 implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println(this.getClass().getName()+" afterCompletion方法执行");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println(this.getClass().getName()+" postHandle方法执行");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println(this.getClass().getName()+" preHandle方法执行");
return true;
}
}
springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- ①开启扫描机制扫描控制器的包 -->
<context:component-scan base-package="com.tao.controller"/>
<!-- ②开启Controller的注解, 这样注解才有效 -->
<mvc:annotation-driven/>
<!-- ③配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置拦截路径 -->
<mvc:mapping path="/**"/>
<!-- 配置拦截器的bean -->
<bean class="com.tao.interceptor.Interceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/goToTest"/>
<bean class="com.tao.interceptor.Interceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
执行结果:
2.参考
- 陈恒 楼偶俊 张立杰 Java EE 框架整合开发入门到实践
- 博客:https://blog.csdn.net/u012401711/article/details/73741974