关于spring:写的太细了Spring-MVC拦截器的应用建议收藏再看

3次阅读

共计 12648 个字符,预计需要花费 32 分钟才能阅读完成。

Spring MVC 拦截器

  • 拦截器是 Spring MVC 中弱小的控件,它能够在进入处理器之前做一些操作,或者在处理器实现后进行操作,甚至是在渲染视图后进行操作。

拦截器概述

  • 对于任何优良的 MVC 框架,都会提供一些通用的操作,如申请数据的封装、类型转换、数据校验、解析上传的文件、避免表单的屡次提交等。晚期的 MVC 框架将这些操作都写死在外围控制器中,而这些罕用的操作又不是所有的申请都须要实现的,这就导致了框架的灵活性有余,可扩展性升高
  • SpringMVC 提供了 Interceptor 拦截器机制,相似于 Servlet 中的 Filter 过滤器,用于拦挡用户的申请并做出相应的解决。比方通过拦截器来进行用户权限验证,或者用来判断用户是否曾经登录。Spring MVC 拦截器是可插拔式的设计,须要某一性能拦截器,只需在配置文件中利用该拦截器即可;如果不须要这个性能拦截器,只需在配置文件中勾销利用该拦截器。
  • 在 Spring MVC 中定义一个拦截器有两种办法:实现 HandlerInterceptor 接口,实现 WebRequestInterceptor 接口.

实现 HandlerInterceptor 接口

首先来看看 HandlerInterceor 接口的源码,该接口位于 org.springframework.web.servlet 的包中,定义了三个办法,若要实现该接口,就要实现其三个办法:

preHandle() 办法 :该办法在执行控制器办法之前执行。返回值为 Boolean 类型,如果返回 false,示意拦挡申请,不再向下执行,如果返回 true,示意放行,程序持续向下执行(如果前面没有其余 Interceptor,就会执行 controller 办法)。所以此办法可对申请进行判断,决定程序是否继续执行,或者进行一些初始化操作及对申请进行预处理。

postHandle() 办法 :该办法在执行控制器办法调用之后,且在返回 ModelAndView 之前执行。因为该办法会在 DispatcherServlet 进行返回视图渲染之前被调用,所以此办法多被用于解决返回的视图,可通过此办法对申请域中的模型和视图做进一步的批改。

afterCompletion() 办法 :该办法在执行完控制器之后执行,因为是在 Controller 办法执行结束后执行该办法,所以该办法适宜进行一些资源清理,记录日志信息等解决操作。

实现了 HandlerInterceptor 接口之后,须要在 Spring 的类加载配置文件中配置拦截器实现类,能力使拦截器起到拦挡的成果,加载配置有两种形式:

针对 HandlerMapping 配置,样例代码如下:

这里为 BeanNameUrlHandlerMapping 处理器配置了一个 interceptors 拦截器链,该拦截器链蕴含了 myInterceptor1 和 myInterceptor2 两个拦截器,具体实现别离对应上面 id 为 myInterceptor1 和 myInterceptor2 的 bean 配置。

长处:此种配置的长处是针对具体的处理器映射器进行拦挡操作

毛病:毛病是如果应用多个处理器映射器,就要在多处增加拦截器的配置信息,比拟繁琐

针对全局配置,样例代码如下:

在下面的配置中,可在 mvc:interceptors 标签下配置多个拦截器其子元素 bean 定义的是全局拦截器,它会拦挡所有的申请;而 mvc:interceptor 元素中定义的是指定元素的拦截器,它会对指定门路下的申请失效,其子元素必须依照 mvc:mapping –> mvc:exclude-mapping –> bean 的程序,否则文件会报错。

实现 WebRequestInterceptor 接口

WebRequestInterceptor 中也定义了三个办法,也是通过这三个办法来实现拦挡的。这三个办法都传递了同一个参数 WebRequest,WebRequest 是 Spring 定义的一个接口,它外面的办法定义都根本跟 HttpServletRequest 一样,在 WebRequestInterceptor 中对 WebRequest 进行的所有操作都将同步到 HttpServletRequest 中,而后在以后申请中始终传递。三个办法如下:

(1) preHandle(WebRequest request):WebRequestInterceptor 的该办法返回值为 void,不是 boolean。所以该办法不能用于申请阻断,个别用于资源筹备。

(2) postHandle(WebRequest request, ModelMap model):preHandle 中筹备的数据都能够通过参数 WebRequest 拜访。ModelMap 是 Controller 解决之后返回的 Model 对象,能够通过扭转它的属性来扭转 Model 对象模型,达到扭转视图渲染成果的目标。

(3) afterCompletion(WebRequest request, Exception ex):。Exception 参数示意的是以后申请的异样对象,如果 Controller 抛出的异样曾经被解决过,则 Exception 对象为 null。

单个拦截器的执行流程

运行程序时,拦截器的执行时有肯定程序的,该程序与配置文件中所定义的拦挡的程序相干。如果程序中只定义了一个拦截器,则该单个拦截器在程序中的执行流程如图所示。

程序首先执行拦截器类中的 preHandle() 办法,如果该办法返回值是 true,则程序会持续向下执行处理器中的办法,否则不再向下执行;在业务控制器类 Controller 解决完申请后,会执行 postHandle() 办法,而后会通过 DispatcherServlet 向客户端返回相应;在 DispatcherServlet 解决完申请后,才会执行 afterCompletion() 办法。

单个拦截器的执行流程

上面在 springmvc- 6 的我的项目中通过示例来演示单个拦截器的执行流程,步骤如下:

(1) 在 src 目录下的 com.springmvc.controller 包中的 UserController 类中,新建一个 hello() 办法,并应用 @RequestMapping 注解进行映射。

package com.springmvc.controller;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.support.RequestContext;
import com.springmvc.entity.User;

@Controller
public class UserController {@RequestMapping("/hello")
    public String hello() {System.out.println("Hello!Controller 控制器类执行 hello 办法");
        return "hello";
    }

}

(2) 在 src 目录下,新建一个 com.springmvc.interceptor 包,创立拦截器类 MyInterceptor,实现 HandlerInterceptor 接口。

package com.springmvc.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 MyInterceptor implements HandlerInterceptor{

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
     Object handler)
            throws Exception {System.out.println("MyInterceptor 拦截器执行 preHandle() 办法");
        return true;
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {System.out.println("MyInterceptor 拦截器执行 afterCompletion 办法");
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("MyInterceptor 拦截器执行 postHandle() 办法");
    }

}

(3) 在 springmvc.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:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        ">
  <!-- 配置主动扫描的包 -->
  <context:component-scan base-package="com.springmvc"/>
  <!-- 主动注册处理器映射器和处理器适配器 -->
  <mvc:annotation-driven/>

  <!-- 配置视图解析器,将控制器办法返回的逻辑视图解析为物理视图 -->
  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="prefix" value="/ch11/"></property>
  <property name="suffix" value=".jsp"></property>
  </bean>  

  <!-- 如果不想通过控制器类的解决办法间接转发到页面,能够通过 mvc:view-controller 元素来实现 -->
  <mvc:view-controller path="/success" view-name="success"/>  
  <mvc:view-controller path="/index" view-name="index"/>

  <mvc:default-servlet-handler/>

  <mvc:interceptors>
  <!-- 应用 bean 间接定义在 mvc:interceptors 上面的拦截器将拦挡所有申请 -->
  <bean class="com.springmvc.interceptor.MyInterceptor"/>
  </mvc:interceptors>

 </beans>        

(4) 在 ch11 文件夹中,创立一个 hello.jsp 页面文件,在主体局部编写“拦截器执行过程实现!”提示信息。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
拦截器执行过程实现!
</body>
</html>

(5) 重启 Tomcat,拜访 http://localhost:8080/springmvc-6/hello,浏览器会跳转到 hello.jsp 页面,控制台的输入后果。

多个拦截器的执行流程

在一个 Web 工程中,甚至在一个 HandlerMapping 处理器适配器中都能够配置多个拦截器,每个拦截器都依照提前配置好的程序执行。它们外部的执行法则并不像多个一般 Java 类一样,它们的设计模式是基于“责任链”的模式。

上面通过图例来形容多个拦截器的执行流程,假如有两个拦截器 MyInterceptor1 和 MyInterceptor2,将 MyInterceptor1 配置在前,如图所示。

当多个拦截器同时工作时,它们的 preHandle() 办法会依照配置文件中拦截器的配置程序执行,而它们的 postHandle() 办法和 afterCompletion() 办法则会依照配置程序的反序执行

多个拦截器的执行流程

批改单个拦截器执行流程的实例,来演示多个拦截器的执行,步骤如下:

(1) 在 com.springmvc.interceptor 包中,新建两个拦截器类 MyInterceptor1 和 MyInterceptor2,这两个拦截器类均实现了 HandlerInterceptor 接口,其代码与 MyInterceptor 类似。

MyInterceptor1

package com.springmvc.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 MyInterceptor1 implements HandlerInterceptor{

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
     Object handler)
            throws Exception {System.out.println("MyInterceptor1 拦截器执行 preHandle() 办法");
        return true;
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {System.out.println("MyInterceptor1 拦截器执行 afterCompletion 办法");

    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, 
    Object handler,
            ModelAndView modelAndView) throws Exception {System.out.println("MyInterceptor1 拦截器执行 postHandle() 办法");

    }
}

MyInterceptor2

package com.springmvc.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 MyInterceptor2 implements HandlerInterceptor{public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {System.out.println("MyInterceptor2 拦截器执行 preHandle() 办法");
        return true;
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {System.out.println("MyInterceptor2 拦截器执行 afterCompletion 办法");

    }
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {System.out.println("MyInterceptor2 拦截器执行 postHandle() 办法");

    }
}

(2) 在 springmvc.xml 的配置文件中,首先正文掉后面配置的 MyInterceptor 拦截器,而后在 mvc:interceptors 元素内配置下面所定义的的两个拦截器。

<mvc:interceptors>
  <!-- 定义多个拦截器 -->
   <mvc:interceptor><!-- 拦截器 1 -->
     <mvc:mapping path="/**"/><!-- 配置拦截器所作用的门路 -->
     <!-- 定义在 <mvc:interceptor> 上面的拦截器示意对匹配门路申请才进行拦挡 -->
     <bean class="com.springmvc.interceptor.MyInterceptor1"></bean>
   </mvc:interceptor>

   <mvc:interceptor><!-- 拦截器 2 -->
     <mvc:mapping path="/hello"/>
     <bean class="com.springmvc.interceptor.MyInterceptor2"></bean>
   </mvc:interceptor>
  </mvc:interceptors>

(3) 重启 Tomcat,拜访 http://localhost:8080/springmvc-6/hello,程序正确运行后,浏览器会跳转到 hello.jsp 页面,控制台输入内容如图所示。

2.3 应用拦截器实现用户登录权限验证

在 springmvc- 6 我的项目中实现应用拦截器实现用户登录权限验证,步骤如下:

(1) 在 com.springmvc.controller 包中,在控制器 UserController 类中,正文以前的办法,并在该类中定义向主页跳转、向登录页跳转、执行用户登录等操作的办法。

// 向用户登录页面的跳转办法
    @RequestMapping(value="/login",method=RequestMethod.GET)
    public String loginPage() {System.out.println("用户从 login 的申请到登录跳转 login.jsp");
        return "login";
    }
    // 用户实现登录的办法
    @RequestMapping(value="/login",method=RequestMethod.POST)
    public String login(User user,Model model,HttpSession session) {String loginName=user.getLoginName();
        String password=user.getPassword();
        if(loginName.equals("mary") && password.equals("123456")) {System.out.println("用户登录胜利");
            // 将用户增加至 session 中保留
            session.setAttribute("current_user", user);
            // 从新定向到主页的 index 跳转办法
            return "redirect:/index";
        }
        model.addAttribute("message", "账号或者明码谬误,请从新登录");
        // 跳转到登录页面
        return "login";
    }
    // 向主页跳转的办法
    @RequestMapping(value="/index",method=RequestMethod.GET)
    public String indexPage() {System.out.println("用户从 index 申请到主页跳转 index.jsp 页面");
        // 跳转到主页面
        return "index";
    }
    // 用户退出登录的办法
    @RequestMapping(value="/logout",method=RequestMethod.GET)
    public String logout(HttpSession session) {
        // 革除 session
        session.invalidate();
        System.out.println("退出性能实现, 革除 session,重定向到 login 申请");
        return "redirect:/login";// 重定向到登录页面的跳转办法
    }

(2) 在 com.springmvc.interceptor 包中,新建 LoginInterceptor 的拦截器类。

package com.springmvc.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 loginInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 获取申请的 URI
        String url=request.getRequestURI();
        if(!url.toLowerCase().contains("login")) {
            // 非登录申请, 获取 session, 判断是否有用户数据
            if(request.getSession().getAttribute("current_user")!=null) {
                // 曾经登录, 放行
                return true;
            }else {
                // 没有登录则跳转到登录页面
                request.setAttribute("message", "您还没有登录,请先登录");
                request.getRequestDispatcher("/ch11/login.jsp").forward(request, response);
            }
            }else {return true;// 登录申请,放行}
            return false;// 默认拦挡
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, 
    Object handler,ModelAndView modelAndView) throws Exception {HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
     Object handler, Exception ex)throws Exception {HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }

}

(3) 在 springmvc.xml 的配置文件中,首先正文后面配置过的拦截器,而后在 mvc:interceptors 元素内配置下面所定义的的 LoginInterceptor 拦截器。

<!-- 登录拦截器 -->
  <mvc:interceptors>
    <mvc:interceptor>
     <mvc:mapping path="/**"/><!-- 配置拦截器所作用的门路  -->
     <bean class="com.springmvc.interceptor.loginInterceptor"></bean>
    </mvc:interceptor>
  </mvc:interceptors>

(4) 在 ch11 文件夹中,新建登录页 login.jsp 和主页 index.jsp。

login.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>
<font color="red">${requestScope.message}</font><br/><br/>
<h3> 登录页面 </h3>
<form action="${pageContext.request.contextPath}/login" method="post">
账号:<input type="text" name="loginName"/><br/><br/>
明码:<input type="password" name="password"/><br/><br/>
<input type="submit" value="登录"/>
</form>
</body>
</html>

主页 index.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>
欢送: ${sessionScope.current_user.loginName}
<a href="${pageContext.request.contextPath}/logout"> 退出 </a>
</body>
</html>

(5) 重启 Tomcat,拜访 http://localhost:8080/springmvc-6/index,运行界面如图所示。

小结

Spring MVC 拦截器介绍了如何在 Spring MVC 我的项目中定义和配置拦截器,解说了单个拦截器和多个拦截器的执行流程,最初通过一个用户登录权限验证的示例解说了拦截器的理论利用,通过利用拦截器机制,Spring MVC 框架能够应用可插拔形式治理各种性能。

最初

感激你看到这里,文章有什么有余还请斧正,感觉文章对你有帮忙的话记得给我点个赞,每天都会分享 java 相干技术文章或行业资讯,欢送大家关注和转发文章!

正文完
 0