SpringMVC的拦截器(十四)

你未看此花时,则此花与汝心同归于寂, 你来看此花时,此花颜色一时明白起来,便知此花不在你的心外。
上一章简单介绍了SpringMVC的异常处理和REST风格的实例应用(十三),如果没有看过,请观看上一章

一. 拦截器

常见的拦截器有登录拦截器,日志拦截器,权限拦截器,异常拦截器,性能拦截器等。

可以与 Struts2的拦截器进行联合性学习。 可以参考老蝴蝶以前写的文章:
Struts2拦截器的简单应用,登录权限拦截器及与过滤器的区别(八)

SpringMVC实现拦截器,需要实现 org.springframework.web.servlet.HandlerInterceptor 接口。

package org.springframework.web.servlet;

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

public abstract interface HandlerInterceptor
{
  public abstract boolean preHandle(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse, Object paramObject)
    throws Exception;
  
  public abstract void postHandle(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse, Object paramObject, ModelAndView paramModelAndView)
    throws Exception;
  
  public abstract void afterCompletion(HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse, Object paramObject, Exception paramException)
    throws Exception;
}

HandlerInterceptor 接口中,有三个方法, preHandler,postHandle,afterCompletion.

1 .preHandler(request,response,obj) 该方法在控制器的处理请求方法之前执行,返回值是boolean, 为true时表示向下执行,为false 时表示中断执行。 通常在这个方法中进行验证拦截。

2 .postHandler(request,response,obj,modelAndView) 该方法在控制器的处理请求方法之后,在解析视图之前执行,可以对请求域 request中的模型和视图进行更一步的修改。

3 .afterCompletion(request,response,obj,exception) 该方法在控制器的处理请求方法执行完成后执行,即视图渲染结束后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。

关于springmvc的配置均采用以前的形式, web.xml 中有字符乱码过滤器, DispatcherServlet 过滤器的url-pattern 设置的是 /, 即采用REST 风格。 springmvc.xml 去掉了 fastjson的配置,保留最开始的。 <mvc:annotation-driven></mvc:annotation-driven> 利用 <mvc:resources 配置了静态的资源。

二. 简单拦截器的配置及执行顺序

二.一 创建登录的拦截器 LoginInterceptor1.java

package com.yjl.interceptor;

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

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

public class LoginInterceptor1 implements HandlerInterceptor{

	@Override
	public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3){
		System.out.println("控制器方法执行之后,视图解析器之后执行1");
	}
	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
			throws Exception {
		System.out.println("控制器方法执行之后,视图解析器之前执行1");
		
	}
	@Override
	public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
		System.out.println("会在控制器方法之前执行1");
		return true;
	}
}

二.二 后端代码 UserAction

//转到登录的页面
	@RequestMapping(value="toLogin")
	public String toLogin(Model model){
		model.addAttribute("user",new User());
		System.out.println("执行toLogin方法");
		return "user/login";
	}
	@RequestMapping(value="login")
	public String login(User user,HttpSession session){
		System.out.println("执行Login方法");
		if("两个蝴蝶飞".equals(user.getName())&&"1234".equals(user.getPassword()))
		{
			session.setAttribute("userLogin", user);
			return "user/list";
		}else{
			return "user/login";
		}
	}

二.三 前端代码 login.jsp 设置

<body>
	<h2>两个蝴蝶飞,拦截器使用</h2>
	<form:form action="login" commandName="user" type="post">
		<form:label path="name">用户名:</form:label>
		<form:input path="name"/><br/>
		<form:label path="password">密码:</form:label>
		<form:input path="password"/><br/>
		<form:button>提交</form:button>
	</form:form>
</body>

二.四 springmvc.xml 配置拦截器

    <mvc:annotation-driven></mvc:annotation-driven>
    
    <!-- 配置拦截器 -->
<mvc:interceptors>
  
    	<mvc:interceptor>
			<!--mvc:mapping 表示拦截的路径, /** 表示全部的路径  -->
    		<mvc:mapping path="/**"/>
    		<bean class="com.yjl.interceptor.LoginInterceptor1"></bean>
    	</mvc:interceptor>
    </mvc:interceptors>

二.五 重启服务器,进行验证

当输入网址 : http://localhost:8027/SpringMVC09/user/toLogin   进行访问时
控制台打印输出:

有图片。

在前端输入数据, 用户名和密码 均输入正确的, 即输入 两个蝴蝶飞和 1234,点击提交:

有图片

控制台打印输出:

有图片

拦截器配置成功。

可知,拦截器的执行顺序是 preHandler–>UserAction中的方法,如 login----->postHandle—> afterCompletion 。

这只是一个拦截器,当多个拦截器,如三个时,又是如何执行的呢?

三. 多个拦截器之间的执行顺序

保留上面的配置,再创建两个拦截器 LoginInterceptor2 和LoginInterceptor3

三.一 创建 LoginInterceptor2 拦截器和 LoginInterceptor3 拦截器

LoginInterceptor2.java

package com.yjl.interceptor;

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

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

public class LoginInterceptor2 implements HandlerInterceptor{
	@Override
	public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3){
		System.out.println("控制器方法执行之后,视图解析器之后执行2");
	}

	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
			throws Exception {
		System.out.println("控制器方法执行之后,视图解析器之前执行2");
		
	}
	@Override
	public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
		System.out.println("会在控制器方法之前执行2");
		return true;
	}
}

LoginInterceptor3.java

package com.yjl.interceptor;

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

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

public class LoginInterceptor3 implements HandlerInterceptor{
	@Override
	public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3){
		System.out.println("控制器方法执行之后,视图解析器之后执行3");
	}

	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
			throws Exception {
		System.out.println("控制器方法执行之后,视图解析器之前执行3");
		
	}
	@Override
	public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
		System.out.println("会在控制器方法之前执行3");
		return true;
	}
}

三.二 后端 UserAction 保持不变

三.三 前端 login.jsp 代码保持不变

三.四 springmvc.xml 配置多个拦截器,注意顺序

    <mvc:annotation-driven></mvc:annotation-driven>
    <!-- 配置拦截器 -->
<mvc:interceptors>
		<!--可配置狐假虎威-->
    	<mvc:interceptor>
    		<mvc:mapping path="/**"/>
    		<bean class="com.yjl.interceptor.LoginInterceptor1"></bean>
    	</mvc:interceptor>
    	<mvc:interceptor>
    		<mvc:mapping path="/**"/>
    		<bean class="com.yjl.interceptor.LoginInterceptor2"></bean>
    	</mvc:interceptor>
    	<mvc:interceptor>
    		<mvc:mapping path="/**"/>
    		<bean class="com.yjl.interceptor.LoginInterceptor3"></bean>
    	</mvc:interceptor>
    </mvc:interceptors>

三.五 重启服务器,进行验证

执行 toLogin 方法时,

控制台打印输出:

有图片。

输入用户名为 ‘两个蝴蝶飞’,密码为’abc’,错误密码时, 执行 login 方法时,控制台打印输出:

有图片

拦截器的执行顺序,是preHandler: 1,2,3, login方法, postHandle: 3,2,1,afterCompletion:3,2,1 的顺序执行的。

三.六 配置不同的拦截器的是否通过,验证preHandler() 返回false的情况。

1 .设置 LoginInterceptor1 通过, LoginInterceptor2 通过, LoginInterceptor3 不通过

即 LoginInterceptor1 中的 preHandler() 方法返回 true, LoginInterceptor2 中的 preHandler()方法返回true,
LoginInterceptor3 中的preHandler() 方法返回 false.

这个时候,执行 toLogin() 方法

控制台打印输出:

有图片。

前端不显示任何东西, 没有返回到视图。

2 .设置 LoginInterceptor1 通过, LoginInterceptor2 不通过, LoginInterceptor3 不通过

即 LoginInterceptor1 中的 preHandler() 方法返回 true, LoginInterceptor2 中的 preHandler()方法返回false,
LoginInterceptor3 中的preHandler() 方法返回 false.

这个时候,执行 toLogin() 方法

控制台打印输出:

有图片。

前端不显示任何东西, 没有返回到视图。

3 .设置 LoginInterceptor1 通过, LoginInterceptor2 不通过, LoginInterceptor3 通过

即 LoginInterceptor1 中的 preHandler() 方法返回 true, LoginInterceptor2 中的 preHandler()方法返回false,
LoginInterceptor3 中的preHandler() 方法返回 true.

这个时候,执行 toLogin() 方法

控制台打印输出:

有图片。

前端不显示任何东西, 没有返回到视图。

2 不通过了,2以后的拦截器均不执行。

3 .设置 LoginInterceptor1 不通过, LoginInterceptor2 不通过, LoginInterceptor3 通过

即 LoginInterceptor1 中的 preHandler() 方法返回 false, LoginInterceptor2 中的 preHandler()方法返回false,
LoginInterceptor3 中的preHandler() 方法返回 true.

这个时候,执行 toLogin() 方法

控制台打印输出:

有图片。

前端不显示任何东西, 没有返回到视图。

可知, 当 preHandler() 方法返回 false 时,只执行 preHandle()方法,不执行 控制器的请求方法 和拦截器以后的 postHandle 方法 和 afterCompletion()方法。

一般系统中所用的拦截器 ,日志拦截器,登录拦截器, 权限拦截器, 需要将日志拦截器设置为true,一定通过, 登录拦截器和权限拦截器 根据验证后的结果,如果登录了,就返回true,没有登录就返回false, 权限如果有就返回true,没有就返回false.且登录拦截器要放置在权限拦截器之前。

三.七 拦截器配置中的属性

在 mvc:interceptor 节点中,有三个元素。 mvc:mapping,mvc:exclude-mapping,bean 。

其中,顺序不能写颠倒, 一定要按照 mvc:mapping, mvc:exclude-mapping, bean 的顺序进行。

mvc:mapping, 表示拦截的路径, 如查询,添加,删除等功能, 一般要拦截的路径比较多。 /** 表示全部的路径。

<mvc:mapping path="/**"/>

mvc:exclude-mapping, 表示拦截的路径, 如 跳转到登录的页面, 登录, 注册的页面,注册,忘记密码 。 这个要写在拦截 mvc:mapping的下面,且必须要显示的写上 拦截的路径。

如不拦截跳转到登录的页面的功能。

<!--拦截所有的-->
<mvc:mapping path="/**"/>
<!--不拦截 /user/login 路径 。 记住,不写 项目名-->
<mvc:exclude-mapping path="/user/toLogin"/>

当然,在拦截的时候,也可以拦截多个。 要写多个mvc:exclude-mapping, 而不是像Struts2那样加 , 分隔。

如拦截 跳转到登录,登录,注册,跳转到注册,忘记密码时

<mvc:mapping path="/**"/>
    		<mvc:exclude-mapping path="/user/toLogin"/>
    		<mvc:exclude-mapping path="/user/login"/>
    		<mvc:exclude-mapping path="/user/toRegister"/>
    		<mvc:exclude-mapping path="/user/register"/>
    		<mvc:exclude-mapping path="/user/forgetPassword"/>

注意,在web.xml 配置的是REST 风格, 即 Dispatcher 的url-pattern 配置的是 /, 如果像以前那样,配置的是*.action,

那么这个配置就需要在后面添加.action 了。

<mvc:mapping path="/**"/>
    		<mvc:exclude-mapping path="/user/toLogin.action"/>
    		<mvc:exclude-mapping path="/user/login.action"/>
    		<mvc:exclude-mapping path="/user/toRegister.action"/>
    		<mvc:exclude-mapping path="/user/register.action"/>
    		<mvc:exclude-mapping path="/user/forgetPassword.action"/>

要注意对应。

<mvc:mapping 也可以配置多个。

路径要写全路径, 不能够简写。 如 <mvc:exclude-mapping path="/toLogin"/> 这样是不行的。

支持后面 *的形式。 如

<mvc:exclude-mapping path="/user/toLo*"/>
<mvc:exclude-mapping path="/user/log*"/>

/user/toLo1234, /user/toLogin, /user/logabc , /user/login 均是不拦截的。

前面的 * 也是可以的。

<mvc:exclude-mapping path="/*/toLo*"/>
<mvc:exclude-mapping path="/*/log*"/>

四. 配置常见的登录拦截器

四.一 创建登录拦截器 LoginInterceptor (重点)

LoginInterceptor.java

package com.yjl.interceptor;

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

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

import com.yjl.pojo.User;

public class LoginInterceptor implements HandlerInterceptor{

	@Override
	public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
			throws Exception {
		
	}

	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
			throws Exception {
		
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
			Object obj) throws Exception {
		//获取请求的地址
		String uri=request.getRequestURI();
		
		//不需要拦截的地址, 可以放置在  springmvc.xml 中进行配置。
		String [] excludeURI=new String[]{"toLogin","login","toRegister","register","forgetPassword"};
		
		for(String str:excludeURI){
			if(uri.indexOf(str)>=0){ //如果包含,就直接通过。
				return true;
			}
		}
		
		HttpSession session=request.getSession();
		Object sessionObj=session.getAttribute("userLogin");
		if(sessionObj!=null){
			//如果不能转换,会报类型转换异常的。
			User user=(User)sessionObj;
			if(user!=null){	
				return true;
			}
		}
		//来替换 toLogin 里面的 model设置值。
		request.setAttribute("user",new User());
		request.getRequestDispatcher("/WEB-INF/jsp/user/login.jsp").forward(request, response);
		return false;
	}

}

四.二 后端 UserAction

@Controller
@RequestMapping(value="/user")
public class UserAction {
	//转到登录的页面
	@RequestMapping(value="toLogin")
	public String toLogin(Model model){
		model.addAttribute("user",new User());
		System.out.println("执行toLogin方法");
		return "user/login";
	}
	@RequestMapping(value="login")
	public String login(User user,HttpSession session){
		System.out.println("执行Login方法");
		if("两个蝴蝶飞".equals(user.getName())&&"1234".equals(user.getPassword()))
		{
			session.setAttribute("userLogin", user);
			return "user/list";
		}else{
			return "user/login";
		}
	}
	@RequestMapping(value="list")
	public String list(){
		//执行list方法
		return "user/list";
	}
	@RequestMapping(value="toRegister")
	public String toRegister(){
		return "user/register";
	}
	@RequestMapping(value="logout")
	public String logout(HttpSession session,Model model){
		session.invalidate();
		model.addAttribute("user",new User());
		System.out.println("执行logout方法");
		return "user/login";
	}
}

四.三 前端 login.jsp 页面

<body>
	<h2>两个蝴蝶飞,拦截器使用</h2>
	<form:form action="login" commandName="user" type="post">
		<form:label path="name">用户名:</form:label>
		<form:input path="name"/><br/>
		<form:label path="password">密码:</form:label>
		<form:input path="password"/><br/>
		<form:button>提交</form:button>
	</form:form>
</body>

四.四 登录成功后的 list.jsp 页面 和注册register.jsp

list.jsp

里面有注销的链接,来清除session

<body>
	员工${user.name}  &nbsp;&nbsp;&nbsp;&nbsp;<a href="logout">注销</a>
</body>

为了更详细的验证, 多添加一个 DeptAction 和 dept/list.jsp 页面

register.jsp

<body>
	注册页面
</body>

四.五 详细验证,添加Dept的信息

DeptAction.java

@Controller
@RequestMapping(value="/dept")
public class DeptAction {
	//转到登录的页面
	@RequestMapping(value="list")
	public String list(){
		return "dept/list";
	}
}

dept/ list.jsp 页面

<body>
	部门列表
</body>

四.六 springmvc.xml 配置登录拦截器 (重点)

<mvc:annotation-driven></mvc:annotation-driven>
 <mvc:interceptors>
    	<mvc:interceptor>
    		<mvc:mapping path="/**"/>
    		<bean class="com.yjl.interceptor.LoginInterceptor"></bean>
    	</mvc:interceptor>
    </mvc:interceptors>

四.七 重启服务器,进行验证

直接输入 : http://localhost:8027/SpringMVC09/dept/list 来访问部门,会跳转到登录的页面。

直接输入 : http://localhost:8027/SpringMVC09/user/logout ,会跳转到登录的页面。

直接输入 : http://localhost:8027/SpringMVC09/user/toRegister,会跳转到注册的页面

有图片。

当然,输入一个不存在的网址,如 http://localhost:8027/SpringMVC09/user/yuejl, 还是会报404的问题的。

在登录页面,输入 两个蝴蝶飞和1234时,

有图片

会跳转到 user/list.jsp 页面

有图片。

这个时候,再新开一个窗口,不要关闭浏览器。

直接输入: http://localhost:8027/SpringMVC09/dept/list

会显示部门列表,到 dept/list.jsp 页面

在这里插入图片描述

在user/list.jsp 页面,点击 注销, 注销后会跳转到 登录的页面。

再刷新刚才打开的那个窗口 dept/list.jsp 页面,发现会跳转到 登录的页面。

拦截器是正确的。

四.八 将拦截的网址放置在 springmvc.xml 中进行配置

LoginInterceptor.java 的 preHandle() 方法去掉 验证。

@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, 
			Object obj) throws Exception {
		//获取请求的地址
		String uri=request.getRequestURI();
		
		//不需要拦截的地址
		/* 
		String [] excludeURI=new String[]{"toLogin","login","toRegister","register","forgetPassword"};
		
		for(String str:excludeURI){
			if(uri.indexOf(str)>=0){ //如果包含,就直接通过。
				return true;
			}
		}
		*/
		HttpSession session=request.getSession();
		Object sessionObj=session.getAttribute("userLogin");
		if(sessionObj!=null){
			//如果不能转换,会报类型转换异常的。
			User user=(User)sessionObj;
			if(user!=null){	
				return true;
			}
		}
		//来替换 toLogin 里面的 model设置值。
		request.setAttribute("user",new User());
		request.getRequestDispatcher("/WEB-INF/jsp/user/login.jsp").forward(request, response);
		return false;
	}

springmvc.xml 中进行配置 <mvc:exclude-mapping

 <mvc:interceptors>
    	<mvc:interceptor>
    		<mvc:mapping path="/**"/>
    		<mvc:exclude-mapping path="/user/toLogin"/>
    		<mvc:exclude-mapping path="/user/login"/>
    		<mvc:exclude-mapping path="/user/toRegister"/>
    		<mvc:exclude-mapping path="/user/register"/>
    		<mvc:exclude-mapping path="/user/forgetPassword"/>
    		<bean class="com.yjl.interceptor.LoginInterceptor"></bean>
    	</mvc:interceptor>
    </mvc:interceptors>

重启服务器,进行验证, 与 四.七 的结果一致。 建议使用 四.八的配置方法。

谢谢!!!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

两个蝴蝶飞

你的鼓励,是老蝴蝶更努力写作的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值