(IDEA)Sping MVC中拦截器的使用和细致阐述

概述 :

   SpringMVC的拦截器,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。 依赖于web框架,在实现 上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring 的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个 controller生命周期之内可以多次调用。

拦截器的作用:

拦截器在Spring MVC中的作用主要包括以下几个方面:

  1. 权限控制:拦截器可以用来对请求进行权限验证,比如检查用户是否登录、是否具有访问某个资源的权限等。

  2. 日志记录:拦截器可以用来记录请求的相关信息,比如请求的URL、请求参数、处理时间等,方便后续的监控和分析。

  3. 参数验证:拦截器可以在请求处理之前对参数进行验证,确保参数的合法性,避免不必要的错误发生。

  4. 统一处理:拦截器可以用来实现一些通用的功能,比如统一异常处理、统一返回结果格式等,提高代码的复用性和可维护性。

拦截器的实现原理:

拦截器的实现原理主要基于Spring MVC框架的HandlerInterceptor接口。当客户端发送请求时,请求会经过DispatcherServlet,DispatcherServlet会根据请求的URL找到对应的处理器(Controller),在执行处理器之前和之后会调用拦截器的preHandle和postHandle方法。

具体实现原理如下:

  1. 定义拦截器:我们可以通过实现HandlerInterceptor接口来定义自己的拦截器,该接口包括preHandle、postHandle和afterCompletion三个方法,分别用于在处理器执行之前、之后和完成之后执行相应的逻辑。

  2. 配置拦截器:在Spring MVC的配置文件中,我们可以通过配置WebMvcConfigurerAdapter类的addInterceptors方法来添加拦截器,并指定拦截器的拦截规则和顺序。

  3. 执行拦截器:当客户端发送请求时,DispatcherServlet会根据请求的URL找到对应的处理器,并在执行处理器之前调用拦截器的preHandle方法,如果preHandle方法返回true,则继续执行处理器,否则终止请求。处理器执行完成后,会调用拦截器的postHandle方法进行后续处理,最后调用afterCompletion方法进行资源清理。

拦截器内主要方法:

在Spring MVC中,拦截器主要包含以下几个主要方法:

  1. preHandle方法:在处理器执行之前调用,用于对请求进行预处理。该方法返回一个布尔值,如果返回true,则继续执行处理器;如果返回false,则终止请求。可以在该方法中进行权限校验、参数验证等操作。

  2. postHandle方法:在处理器执行之后、视图渲染之前调用(也就是handler中 代码return”页面“跳转之前),可以对处理器的执行结果进行后续处理。可以通过该方法修改ModelAndView对象,添加额外的数据或修改视图。

  3. afterCompletion方法:在整个请求处理完成后调用,即视图渲染完成后。可以用于清理资源、记录日志等操作。该方法在preHandle方法返回true时才会被调用。

通过实现这些方法,我们可以在拦截器中实现一些通用的功能,比如权限控制、日志记录、参数验证等。这些方法的调用顺序为preHandle -> 处理器执行 -> postHandle -> 视图渲染 -> afterCompletion。通过合理实现这些方法,可以实现灵活、高效的请求处理逻辑。

原理视图:

拦截器执行流程:

单个拦截器:

多个拦截器:

在Spring MVC中,如果配置了多个拦截器,它们的执行顺序是按照配置的顺序依次执行的。具体的执行流程如下:

  1. 当客户端发送请求时,请求会经过DispatcherServlet。

  2. DispatcherServlet会根据请求的URL找到对应的处理器(Controller)。

  3. 在执行处理器之前,会按照配置的顺序依次执行所有配置的拦截器的preHandle方法。如果其中任何一个拦截器的preHandle方法返回false,则后续的拦截器的preHandle方法和处理器都不会执行,请求直接结束。

  4. 如果所有拦截器的preHandle方法都返回true,则执行处理器的方法。

  5. 处理器执行完成后,会按照配置的顺序逆序执行所有拦截器的postHandle方法。

  6. 最后,会按照配置的顺序逆序执行所有拦截器的afterCompletion方法。在这个阶段,可以进行一些资源清理的操作。

注意:我们可以观察到:对于多个拦截器的执行,都是从第一个拦截器开始顺序进行,但是psthandle和aftercompletion都是逆序完成配置

 实际操作:

1、配置拦截器(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:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
 http://www.springframework.org/schema/context
 http://www.springframework.org/schema/context/spring-context-3.0.xsd
 http://www.springframework.org/schema/mvc
 http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
 
 <context:component-scan base-package="com.j2ee.controller" />
 <bean id="viewResolver"
 class="org.springframework.web.servlet.view.InternalResourceViewResolver">
 <property name="prefix" value="/WEB-INF/page/" />
 <property name="suffix" value=".jsp" />
 </bean>
 
 <mvc:interceptors> 
 <mvc:interceptor> 
 <mvc:mapping path="/login"/>
 <!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->
 <bean class="com.j2ee.interceptor.LoginInterceptor"/> 
 </mvc:interceptor>
 <!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->
 </mvc:interceptors>
 <!-- <bean id="simpleUrlHandlerMapping"
 class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
 <property name="mappings">
 <props>
 <prop key="/index">indexController</prop>
 </props>
 </property>
 </bean>
 <bean id="indexController" class="com.j2ee.controller.IndexController"></bean> -->
</beans>

注意:mvc:需要配置好约束,也就是文本中xmls里的约束内容

2、创建拦截器类

创建com.j2ee.interceptor包,在其下创建拦截器LoginInterceptor,内容:
package com.j2ee.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class LoginInterceptor extends HandlerInterceptorAdapter{
 /** 
 * 在业务处理器处理请求之前被调用 
 * 如果返回false 
 * 从当前的拦截器往回执行所有拦截器的afterCompletion(),再退出拦截器链
 * 如果返回true 
 * 执行下一个拦截器,直到所有的拦截器都执行完毕 
 * 再执行被拦截的Controller 
 * 然后进入拦截器链, 
 * 从最后一个拦截器往回执行所有的postHandle() 
 * 接着再从最后一个拦截器往回执行所有的afterCompletion() 
 */ 
 public boolean preHandle(HttpServletRequest request, 
 HttpServletResponse response, Object handler) throws Exception {
 HttpSession session = request.getSession();
 String username = (String)session.getAttribute("userName");
 if(username!=null)
 return true;
 request.setAttribute("msg","您还没有登陆,请登陆!");
 request.getRequestDispatcher("/WEB-INF/page/login.jsp").forward(request,response);
 return false;
 
 } 
 /**
 * 在业务处理器处理请求执行完成后,生成视图之前执行的动作 
 * 可在modelAndView中加入数据,比如当前时间
 */ 
 
 public void postHandle(HttpServletRequest request, 
 HttpServletResponse response, Object handler, 
 ModelAndView modelAndView) throws Exception { 
 
 } 
 /** 
 * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源等 
 * 
 * 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion() 
 */
 
 public void afterCompletion(HttpServletRequest request, 
 HttpServletResponse response, Object handler, Exception ex) 
 throws Exception { 
 } 
}

3、创建登录Web页面(login.jsp,位置:WEB-INF/page)

<%@ page language="java" import="java.util.*" isELIgnored="false" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
 <base href="<%=basePath%>">
 

 </head>
 
 <body>
 <h2>登陆</h2>
 <h3>${msg}</h3>
 <form action="${pageContext.request.contextPath}/addLogin} method="post">
 用户 :<input type="text" name="name" value=""><br />
 密码: <input type="password" name="password" value=""><br />
 <input type="submit" value="登陆">
 </form>
 </body>
</html

4、添加接收数据的方法。

package com.j2ee.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.j2ee.pojo.Users;
@Controller
public class LoginController {
 @RequestMapping("login")
 public ModelAndView login(){
 ModelAndView mav = new ModelAndView("login");
 return mav;
 }
 
 @RequestMapping("addLogin")
 public ModelAndView recieve(Users users,HttpSession session){
 ModelAndView mav = new ModelAndView();
 String name = users.getName();
 String passwd = users.getPassword();
 if("admin".equals(name) && "888".equals(passwd)){
 session.setAttribute("userName",name);
 mav.addObject("name", name);
 mav.setViewName("recieve");
 }else{
 mav.addObject("msg", "用户名和密码错误!");
 mav.setViewName("login");
 }
 return mav;
 }
}

5、创建接收数据Web页面(recieve.jsp,位置:WEB-INF/page)

<%@ page language="java" import="java.util.*" isELIgnored="false" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
 <base href="<%=basePath%>">
 
 <title>显示结果</title>
 
 </head>
 
 <body>
 <h2>session存储的用户信息:${name}</h2>
 <h3>user:${users.name}</h3>
 <h3>pwd:${users.password}</h3>
 </body>
</html>

6、测试:

配置好tomcat并开始输入测试,输入/login后缀开始测试

  • 34
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值