和大彪一起来学习-SpringMvc之第四回(拦截器使用)

一、拦截器介绍

springmvc中的拦截器,简单来说就是对用户的请求进行拦截,我们可以在拦截用请求后进行预处理和后处理,可以在这里做日志记录、权限控制、请求用时计算等操作。和Servlet api中的Filter有点类似。

二、拦截器使用

1、编写拦截器

我们要自己编写拦截器,比较常用的方法是实现org.springframework.web.servlet.HandlerInterceptor类,我把这个类的源码贴出来吧,内部就三个方法,我们的业务可以在方法中实现。

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
	拦截器接口,内部就3个方法
**/
public interface HandlerInterceptor {

	/**[调用前] controller执行前调用此方法 返回true表示继续执行,返回false中止执行 这里可以加入登录校验、权限拦截等 **/

	boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
	    throws Exception;

	/**[调用后,但还未渲染视图] controller执行后但未返回视图前调用此方法 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示 **/
	void postHandle(
			HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
			throws Exception;

	/**[调用后,已经渲染视图] controller执行后且视图返回后调用此方法 这里可得到执行controller时的异常信息 这里可记录操作日志,资源清理等 **/
	void afterCompletion(
			HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception;

}

好的,那么下面我们尝试写个类来实现它,先把简单的拦截器先用起来。我们再来研究配置,下面增加了一些文件。

拦截器:

package com.billstudy.springmvc.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * 自定义拦截器01
 * @author Bill
 * @since V1.0 2015/02/04
 */
public class MyInterceptor01 implements HandlerInterceptor {
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
			Object handler) throws Exception {
		System.out.println("MyInterceptor01.preHandle()");
		return true;<span style="white-space:pre">	</span>// 这里返回true,则请求可以到Controller中
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response,
			Object handler, ModelAndView modelAndView) throws Exception {
		System.out.println("MyInterceptor01.postHandle()");
	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("MyInterceptor01.afterCompletion()");
	}

}

Controller:

package com.billstudy.springmvc.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * 通过请求本Controller内部方法,结合拦截器测试效果
 * @author Bill
 * @since V1.0 2015/02/04
 */
@Controller
@RequestMapping("/demo")
public class DemoController {

	@RequestMapping("/demo01")
	public ModelAndView demo01(HttpServletRequest request,HttpServletResponse response){
		System.out.println("DemoController.demo01()");
		ModelAndView result = new ModelAndView("/demo");
		result.addObject("msg", "我是萌哒哒的msg");
		return result;
	}

}

demo.jsp

<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>demo page</title>
</head>
<body>
	msg:${msg}
</body>
</html>

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:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context-3.1.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx-3.1.xsd ">

	<!-- auto scanner class path -->
	<context:component-scan base-package="com.billstudy.springmvc" />

	<mvc:annotation-driven />

	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/pages" />
		<property name="suffix" value=".jsp" />
	</bean> 

	<mvc:interceptors>
		<mvc:interceptor>
			<!--
				path="/user/*.do"  /user/所有请求
				path="/*/*" 	任意两级请求
				path="*" 	无效
				path="/**" 任意请求
			 -->
			<mvc:mapping path="/**"/>
			<bean class="com.billstudy.springmvc.interceptor.MyInterceptor01" />
		</mvc:interceptor>
	</mvc:interceptors>

</beans>

好的,下面部署到Tomcat测试下。

控制台输出:

怎么样,效果是这样的吧。

三、配置和运行流程说明

我们前面在springmvc-servlet.xml中配置拦截器时,是配置的全局拦截器,也就是说所有映射器请求都会被拦截。因为我们可以配置多个Mapping。

若是只想对某单个Mapping使用拦截器可以在其内部注入一个interceptors的属性,通过查看源码。我们发现在所有的Mapping父类,也就是org.springframework.web.servlet.handler.AbstractHandlerMapping,它内部有Listinterceptors
= new ArrayList()这么一个集合。所以所有的Mapping都可以通过它注入拦截器链。

假设我们只想个单个Mapping注入拦截器可以这么配置:

<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
	<property name="<span style="color:#ff0000;">interceptors</span>">
		<list>
			<bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1" />
			<bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2" />
			<span style="color:#ff0000;">// ... 可以配置多个,按配置的顺序调用</span>
		</list>
	</property>
</bean>

配置全局的拦截器就是:

<mvc:interceptors>
		<mvc:interceptor>
			<!--
				path="/user/*.do"  /user/所有请求
				path="/*/*" 	任意两级请求
				path="*" 	无效
				path="/**" 任意请求
			 -->
			<mvc:mapping path="/**"/>
			<bean class="com.billstudy.springmvc.interceptor.MyInterceptor01" />
		</mvc:interceptor>
		<span style="color:#ff0000;"><!-- 这里也可以配置多个 mvc:interceptor 标签 --></span>
	</mvc:interceptors>

下面测试一下,preHandle,postHandle,afterCompletion的运行规则,我们可以多写几个Interceptor来测试。

增加了2个拦截器后,配置修改如下:

<mvc:interceptors>
		<mvc:interceptor>
			<mvc:mapping path="/**"/>
			<bean class="com.billstudy.springmvc.interceptor.MyInterceptor01" />
		</mvc:interceptor>
		<mvc:interceptor>
			<mvc:mapping path="/**"/>
			<bean class="com.billstudy.springmvc.interceptor.MyInterceptor02" />
		</mvc:interceptor>
		<mvc:interceptor>
			<mvc:mapping path="/**"/>
			<bean class="com.billstudy.springmvc.interceptor.MyInterceptor03" />
		</mvc:interceptor>
		<!-- 这里也可以配置多个 mvc:interceptor 标签 -->
	</mvc:interceptors>

目前所有的拦截器都是简单打印运行的方法,以及所有的preHandler都是返回true,那么我们来看看请求后。控制台打印的顺序是怎样的?

我们可以看到,pre是按照配置的顺序调用的。而post,after则是逆序调用的。 有没有一种递归的感觉,哈哈..

下面来测试将Interceptor 的 preHandler返回false,那么请求到了这里之后就会截断,并且访问不了Controller.那这个时候,拦截器又是如何运行的呢?

修改后代码如下:

package com.billstudy.springmvc.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * 自定义拦截器02
 * @author Bill
 * @since V1.0 2015/02/04
 */
public class MyInterceptor02 implements HandlerInterceptor {
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
			Object handler) throws Exception {
		System.out.println("MyInterceptor02.preHandle()");
		<strong><span style="color:#cc0000;">return false; // 这里返回false,请求在这里被截断!</span></strong>
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response,
			Object handler, ModelAndView modelAndView) throws Exception {
		System.out.println("MyInterceptor02.postHandle()");
	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("MyInterceptor02.afterCompletion()");
	}

}

运行输出:

咦,拦截器2的after和拦截器3的方法输入哪去了?post好像一个都不见了,这是为什么呢?

1.首先请求按照拦截器配置的顺序,进入到拦截器1的preHandler方法,这个时候返回true,继续执行

2.进入拦截器链2的preHandler,这里返回了false,那么请求在这里就被哄回家了,相当于springmvc 告诉它。你被拦截了,后面的操作你进行不了,回去吧。 哈哈

3.这个时候,萌哒哒的请求就没办法了,只能打道回府了。 但是因为它通过了拦截器1的preHandler的方法,所以after方法会被执行.

4.至于拦截器3,请求根本没有接触到,所以和拦截器3所有相关方法都没有被执行.

请求被哄回去之后,因为它没有抵达 com.billstudy.springmvc.controller.DemoController.demo01(HttpServletRequest, HttpServletResponse) 这个方法,所以msg的值也是空的.那我们页面其实是这样的:

拦截器三个方法运行结论:

preHandle按拦截器定义顺序调用

postHandler按拦截器定义逆序调用

afterCompletion按拦截器定义逆序调用

postHandler在拦截器链内所有拦截器返成功调用

afterCompletion只有preHandle返回true才调用

好了,到这里就结束了,拦截器你会用了吗?这里是 热爱生活,热爱技术,喜欢交友的大彪
. (ps:最近加班又多起来了,更新频率没那么快,抱歉啊。回到家整个人都有点晕晕的。。 ^ _ ^ ) 目前springmvc更新就到这里结束了,项目开发也差不多够用了呢,后面打算写下mybatis相关。

时间: 2024-08-07 22:28:10

和大彪一起来学习-SpringMvc之第四回(拦截器使用)的相关文章

和大彪一起来学习-SpringMvc之第三回(注解使用详解)

简述: 在上一篇文章中,介绍了适配器和映射器的一些概念,这篇文章主要是介绍SpringMvc注解的使用,下面先从一个最简单注解程序开始,慢慢引入一些常用的注解(@Controller,@Component,@Service,@Repository,@RequestMapping,@InitBinder,@RequestParam,@PathVariable,@RequestBody ,@ResponseBody). 一.第一个注解项目 1.创建项目,加入Jar包,编写web.xml 可以加入第一

SpringMVC笔记(四)拦截器

一.拦截器:Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必 须实现HandlerInterceptor接口 二.实现步骤: 1.自定义实现类实现HandlerInterceptor接口 2.在springMVC中配置文件中的配置相应的拦截器 实现的代码: 1.自定义实现类 package com.neuedu.springmvc.interceptor; import javax.servlet.http.HttpServletRe

和大彪一起来学习-SpringMvc之第二回(控制器,适配器说明)

简述: 在上一篇文章中,我们学会了如何搭建一个简单SpringMvc HelloWorld程序,这篇文章主要是介绍一些常用的控制器,适配器学习和作用. 一.HandlerMapping处理器映射器 HandlerMapping 给前端控制器返回一个HandlerExecutionChain 对象(包含一个Handler (后端控制器)对象.多个HandlerInterceptor 拦截器)对象. 1).BeanNameUrlHandlerMapping Bean别名路径映射器 BeanNameU

SpringMVC案例3----spring3.0项目拦截器、ajax、文件上传应用

依然是项目结构图和所需jar包图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmVuamFtaW5fd2h4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" > watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmVuamFtaW5fd2h4/font/5a6L5L2T/fontsize/400/fil

springmVC源码分析之拦截器

一个东西用久了,自然就会从仅使用的层面上升到探究其原理的层面,在javaweb中springmvc更是如此,越是优秀的框架,其底层实现代码更是复杂,而在我看来,一个优秀程序猿就相当于一名武林高手,不断进阶武功秘籍,越是高深莫测的功夫,越是要探究其原理,而springmvc就是一本十分深奥的武功秘籍. 说起拦截器,说不得不和过滤器进行对比,在此贴图一张不进行多加解释,简单的来说拦截器能作用于controller层方法实现的前后. 在这里先列出一个简单的controller层的实现 正常访问之后我们

Struts2学习(三)———— 输入校验和拦截器

一.输入校验 在以前我们写一个登录页面时,并没有限制用户的输入,不管用户输入什么,我们都存入数据库中,很显然这是不行的,我们需要检测用户输入的文本是否合法,是否符合我们需要的文本格式,符合菜放行,而struts2中就有这种功能,能帮我们在服务器段进行判断,比如用户名不能为空,年龄只能在0-100之间等.现在我们就来说说如何使用struts2中的校验功能把. 分为两种,编程式校验和配置校验(XML配置校验) 1.1编程式校验, 对action中所有方法都执行校验 实现Validateable接口,

SpringMVC源码阅读:拦截器

1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring4.3.7)分析,弄清楚SpringMVC拦截器的工作原理 2.源码分析 进入SpringMVC核心类DispatcherServlet的doDispatch方法,在SpringMVC源码阅读:核心分发器DispatcherServlet曾经分析过,这里再分析一遍 936行获得HandlerExec

学习SpringMVC(二十四)之异常处理

1.在@ExceptionHandler 方法的入参中可以加入 Exception 类型的参数, 该参数即对应发生的异常对象 [email protected]方法的入参中不能传入 Map.若希望把异常信息传导页面上,需要使用 ModelAndView作为返回值 [email protected] 方法标记的异常有优先级的问题.会先处理匹配度高的异常 直接上实例: 在Controller中: <span style="font-size:18px;"><span st

myBatis学习笔记(10)——使用拦截器实现分页查询

1. Page package com.sm.model; import java.util.List; public class Page<T> { public static final int DEFAULT_PAGE_SIZE = 20; protected int pageNo = 1; // 当前页, 默觉得第1页 protected int pageSize = DEFAULT_PAGE_SIZE; // 每页记录数 protected long totalRecord = -1