赞
踩
目录
Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。
(这个拦截器的功能相当于web阶段学习的那个filter,那么我们知道,filter是对于我们访问的目标资源进行相应的干预,比如我有个目标资源Servlet,如果你的请求地址没有写错,一般就能直接访问到目标资源,但是我们学到这个filter之后发现,即使地址没写错,你这个目标资源也不一定被访问到,因为中间有filter的过滤器,如果这个filter放行的话才能访问拿到目标资源,不放行就访问不到目标资源,这里的interceptor跟filter过滤器的功能是一样的,那么在SpringMVC技术当中,我们的目标资源就是Controller当中的一些方法,同样目前也是只要url没写错,那个方法肯定是百分之百可以被访问到。学了拦截器就知道写对了地址也不一定可以访问那个资源方法)
将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain)。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
拦截器也是AOP思想的具体实现。
区别 | 过滤器 | 拦截器 |
---|---|---|
使用范围 | 是 servlet 规范中的一部分,任何Java Web 工程都可以使用 | 是 SpringMVC 框架自己的,只有使用了SpringMVC 框架的工程才能用 |
拦截范围 | 在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截 | 只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的 |
注:filter可以对所有资源进行拦截,包括静态资源,Interceptor只能对Controller中方法进行拦截,静态资源拦截不了。
自定义拦截器很简单,只有如下三步:
1、创建拦截器类实现HandlerInterceptor接口
(实现HandlerInterceptor接口,内部有相应的方法需要我们去实现)
2、配置拦截器
(在springmvc.xml中进行配置)
3、测试拦截器的拦截效果
首先来看环境,有个IndexController,就是我们要访问的目标资源,内部有个show方法,对应的虚拟地址是/text,那么现在启动这个工程,因为是没有Intercepor,最终是跳转到index.jsp,这里访问的目标方法就是这个toIndex方法,然后在返回跳转到index.jsp页面
那么按照前面你的步骤,我们就可以开始来实现拦截器
1、创建拦截器类实现HandlerInterceptor接口
(这里有三个方法需要我们去重写)
- package com.ftp.interceptor;
-
- import org.springframework.web.servlet.HandlerInterceptor;
- import org.springframework.web.servlet.ModelAndView;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.util.logging.Handler;
-
- public class IndexInterceptor1 implements HandlerInterceptor {
-
- /**
- * 预处理,controller 方法执行前
- * return true 放行,执行下一个拦截器,如果没有,执行 controller 中的方法
- * return false 不放行,即不向下执行
- */
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
- System.out.println("第一个拦截器");
- String book = request.getParameter("book");
- System.out.println("preHandle1 方法将在请求处理之前进行调用");
- /*if(book==null){
- System.out.println("停止1");
- return false;
- }*/
- return true;
- }
-
- /**
- * 后处理方法,controller 方法执行后,方法跳转 success.jsp 执行之前
- * 应用:从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
- */
- public void postHandle(HttpServletRequest request, HttpServletResponse
- response, Object handler, ModelAndView modelAndView) {
- System.out.println("postHandle1 该方法是在当前请求进行处理之后被调用");
- }
-
- /**
- * success.jsp 页面执行后,该方法会执行
- * 应用:统一异常处理,统一日志处理
- */
- public void afterCompletion(HttpServletRequest request, HttpServletResponse
- response, Object handler, Exception ex) {
- System.out.println("afterCompletion1 该方法将在整个请求结束之后");
- }
-
- }
2、在SpringMVC核心配置文件中配置拦截器
- <!--配置拦截器-->
- <mvc:interceptors>
- <!--配置拦截器,多个拦截器时,顺序执行-->
- <mvc:interceptor>
- <!--要拦截的具体的方法-->
- <mvc:mapping path="/*/text"/>
- <!--不去拦截的方法
- <mvc:exclude-mapping path=""/>
- -->
- <!--配置拦截器对象-->
- <bean class="com.ftp.interceptor.IndexInterceptor1"/>
- </mvc:interceptor>
- </mvc:interceptors>
测试拦截器的拦截效果(编写目标方法)
- @Controller
- @RequestMapping("/index")
- public class IndexController {
-
- @RequestMapping("/text")
- public String toIndex(HttpServletRequest request , HttpServletResponse response, HttpSession session){
- //视图解析器=前缀+逻辑视图名+后缀
- //前缀 /WEB-INF/jsp
- //逻辑视图名 index
- //后缀 .jsp
- System.out.println("controller方法一中");
- return "index";
- }
-
-
- }
测试拦截器的拦截效果(访问网址),控制台输出:
再创建一个拦截器类实现HandlerInterceptor接口
- package com.ftp.interceptor;
-
- import org.springframework.web.servlet.HandlerInterceptor;
- import org.springframework.web.servlet.ModelAndView;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
-
- public class IndexInterceptor2 implements HandlerInterceptor {
-
- /**
- * 预处理,controller 方法执行前
- * return true 放行,执行下一个拦截器,如果没有,执行 controller 中的方法
- * return false 不放行,即不向下执行
- */
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
- System.out.println("第二个拦截器");
- String bookId = request.getParameter("bookId");
- System.out.println("preHandle2 方法将在请求处理之前进行调用2 ");
- /*if(bookId==null){
- System.out.println("停止2");
- return false;
- }*/
- return true;
- }
-
- /**
- * 后处理方法,controller 方法执行后,方法跳转 success.jsp 执行之前
- * 应用:从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
- */
- public void postHandle(HttpServletRequest request, HttpServletResponse
- response, Object handler, ModelAndView modelAndView) {
- System.out.println("postHandle2 该方法是在当前请求进行处理之后被调用2");
- }
-
- /**
- * success.jsp 页面执行后,该方法会执行
- * 应用:统一异常处理,统一日志处理
- */
- public void afterCompletion(HttpServletRequest request, HttpServletResponse
- response, Object handler, Exception ex) {
- System.out.println("afterCompletion2 该方法将在整个请求结束之后2");
- }
-
- }
2、在SpringMVC核心配置文件中配置多个拦截器
- <!--配置拦截器-->
- <mvc:interceptors>
- <!--配置拦截器,多个拦截器时,顺序执行-->
- <mvc:interceptor>
- <!--要拦截的具体的方法-->
- <mvc:mapping path="/*/text"/>
- <!--不去拦截的方法
- <mvc:exclude-mapping path=""/>
- -->
- <!--配置拦截器对象-->
- <bean class="com.ftp.interceptor.IndexInterceptor1"/>
- </mvc:interceptor>
- <mvc:interceptor>
- <!--要拦截的具体的方法-->
- <mvc:mapping path="/*/text"/>
- <!--不去拦截的方法
- <mvc:exclude-mapping path=""/>
- -->
- <!--配置拦截器对象-->
- <bean class="com.ftp.interceptor.IndexInterceptor2"/>
- </mvc:interceptor>
- </mvc:interceptors>
测试结果:
3.执行顺序:
=======> IndexInterceptor1:preHandle()
=======> IndexInterceptor2:preHandle()
.......
=======> IndexInterceptor2:postHandle()
=======> IndexInterceptor1:postHandle()
=======> IndexInterceptor2:afterCompletion()
=======> IndexInterceptor1 :afterCompletion()
方法名 | 说明 |
---|---|
preHandle() | 方法将在请求处理之前进行调用,该方法的返回值是布尔值Boolean类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法 |
postHandle() | 该方法是在当前请求进行处理之后被调用,前提是preHandle 方法的返回值为true 时才能被调用,且它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作 |
afterCompletion() | 该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行,前提是preHandle 方法的返回值为true 时才能被调用 |
自定义拦截器步骤:
① 创建拦截器类实现HandlerInterceptor接口
② 配置拦截器
③ 测试拦截器的拦截效果
应用场景
1)日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
2)权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面;
3)性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);
4)通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个Controller中的处理方法都需要的,我们就可以使用拦截器实现。
登录拦截权限案例
1、LoginController.java
- package com.zking.ssm.book.controller;
-
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
-
- import javax.servlet.http.HttpSession;
-
- @Controller
- public class LoginController {
-
- /**
- * 跳转到登录页面
- * @return
- */
- @RequestMapping("tologin")
- public String toLogin(){
- return "login";
- }
-
- /**
- * 登录方法
- * @param username 账号
- * @param password 密码
- * @return
- */
- @RequestMapping("/userLogin")
- public String userLogin(String username, String password, HttpSession session, Model model){
- if("admin".equals(username)|| password.equals("123")){
- session.setAttribute("username",username);
- //这里的"/"是跳转的@RequestMapping配置的值
- return "redirect:/";
- }
-
- model.addAttribute("msg","账号或者密码错误");
- return "login";
- }
-
-
- /**
- * 安全退出
- * @param session
- * @return
- */
- @RequestMapping("/userLogout")
- public String userLogout(HttpSession session){
- //清空session
- session.invalidate();
-
- return "redirect:tologin";
- }
-
-
-
- }
2.LoginInterceptor.java
- package com.zking.ssm.book.interceptor;
-
- import org.springframework.web.servlet.HandlerInterceptor;
- import org.springframework.web.servlet.ModelAndView;
-
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
-
- public class LoginInterceptor implements HandlerInterceptor {
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
- //获取请求路径
- String url = request.getRequestURI();
- System.out.println(url);
- //判断是否是跳转登录页面的请求 放行
- if(url.indexOf("/tologin")>0)
- return true;
- //判断是否是用户登录 放行
- if(url.indexOf("/userLogin")>0)
- return true;
- //获取session
- HttpSession session = request.getSession();
- //获取session中的用户对象
- String username = (String) session.getAttribute("username");
- //判断session中的用户对象是否存在,存在放行,不存在跳转登录页面
- if(username!=null)
- return true;
- request.setAttribute("msg","您还没有登录,请登录!");
- request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response);
- return false;
- }
-
- @Override
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
-
- }
-
- @Override
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
-
- }
- }
spring-mvc.xml
- <mvc:interceptor>
- <mvc:mapping path="/**/"/>
- <bean class="com.zking.ssm.book.interceptor.LoginInterceptor"/>
- </mvc:interceptor>
测试:
1、账号密码错误的情况下
2、在未登录的情况下访问首页
3、在进入首页后退出再直接浏览首页
至此,SpringMVC拦截器介绍完毕,由于作者水平有限难免有疏漏,欢迎留言纠错。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。