Spring MVC 入门(十一)Spring MVC 拦截器

11.1 Spring MVC 拦截器

    Interceptor 拦截器也是 Spring MVC 中相当重要的功能,它的主要作用是拦截用户的请求并进行相应的处理。Spring MVC 拦截器是可插拔的设计。如果需要使用某个拦截器,只需要在配置文件中应用该拦截器即可;如果不需要使用该拦截器,只需要在配置文件中取消应用该拦截器。不管是否应用某个拦截器,对 Spring MVC 框架不会有任何影响。

11.1.1 HandlerInterceptor 接口

    Spring MVC 中的 Interceptor 拦截器拦截请求是通过实现 HandlerInterceptor 接口来完成的。在 Spring MVC 中定义一个 Interceptor 拦截器非常简单,通常在要定义的 Interceptor 拦截器中实现 Spring 的 HandlerInterceptor 接口,或者继承抽象类 HandlerInterceptorAdapter。
    HandlerInterceptor 接口定义了三个方法,Spring MVC 就是通过这三个方法来对用户的请求进行拦截处理的。

  • boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handle)。该方法将在请求处理之前被调用。Spring MVC 中的 Interceptor 实行的是链式调用。即在一个应用中或者在一个请求中可以同时存在多个 Interceptor。每个 Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的是 Interceptor 中的 preHandle 方法,所以可以在这个方法中进行一些前置的初始化操作或者是对当前请求的一个预处理也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是 Boolean 类型的,当返回值是 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当返回值为 true 时就会继续调用下一个 Interceptor 的 preHandle 方法;如果已经是最后一个 Interceptor,就会调用当前请求的 Controller 方法。
  • void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView mv)。该方法和之后的 afterCompletion 方法都只能在当前所属的 Interceptor 的 preHandle 方法的返回值为 true 时才能被调用。postHandle 方法,顾名思义,就是在当前请求被处理之后,也就是 Controller 方法被调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对 Controller 处理之后的 ModleAndView 对象进行操作。postHandle 方法被调用的方向跟 preHandle 时相反的,也就是说先声明的 Interceptor 的 postHandle 方法反而会后执行,这个 Struts2 里面的 Interceptor 的执行过程类似。
  • void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception exception)。该方法也是在当前所属的Interceptor 的 preHandle 方法的返回值为 true 时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行。这个方法主要作用是进行资源清理

11.1.2 拦截器实现用户权限验证

    用户必须登录之后才可以访问网站首页,如果没有登陆就直接访问网站首页,则拦截器会拦截请求,并将请求重新转发到登陆页面,同时提示用户需要先登录再访问网站。

  1. 新建 loginForm.jsp 登录页面。
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>
    <h3>登陆页面</h3>
    <form:form action="login" method="post">
        <!--  提示信息  -->
        <font color="red">${requestScope.message }</font>
        <table>
            <tr>
                <td><label>登录名:</label></td>
                <td><input type="text" id="loginname" name="loginname"></td>
            </tr>
            <tr>
                <td><label>密码:</label></td>
                <td><input type="password" id="password" name="password"></td>
            </tr>
            <tr>
                <td><input type="submit" value="登录"></td>
            </tr>
        </table>
    </form:form>
</body>
</html>
  1. 新建 UserController 类处理登录请求和页面跳转。
package controller;

import domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpSession;

@Controller
public class UserController {
    /*
    *  处理 /login 请求
    */
    @RequestMapping(value = "/login")
    public ModelAndView login(String loginname, String password, ModelAndView mv, HttpSession session){
        // 模拟数据库根据登录名和密码查找用户,判断用户登录
        if (loginname != null && loginname.equals("ceshi")
            && password != null && password.equals("123456")){
            // 模拟创建用户
            User user = new User();
            user.setLoginname(loginname);
            user.setPassword(password);
            user.setUsername("管理员");
            // 登陆成功,将 user 对象设置到 HttpSession 作用域
            session.setAttribute("user",user);
            // 转发到 main 请求
            mv.setViewName("redirect:main");
        }else {
            // 登陆失败,设置失败提示信息,并跳转到登陆页面
            mv.addObject("message" , "登录名或密码错误,请重新输入!");
            mv.setViewName("loginForm");
        }
        return mv;
    }
}

  1. 新建 PageController 类用于处理页面跳转。
package controller;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class PageController {
    private final static Log logger = LogFactory.getLog(PageController.class);
    @RequestMapping(value = "/{formName}")
    public String pageName(@PathVariable String formName){
        return formName;
    }
}
  1. 新建 User 类用于接收页面登录用户信息。
package domain;

import java.io.Serializable;

public class User implements Serializable {
    private String loginname;
    private String password;
    private String username;

    public String getLoginname() {
        return loginname;
    }

    public void setLoginname(String loginname) {
        this.loginname = loginname;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}
  1. 新建 TestInterceptor 类,设计拦截器验证用户是否登录,如果没有登陆,不可以访问除登陆页面和登录请求的所有 Controller。
package interceptor;

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

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

/*
*  拦截器必须实现 HandlerInterceptor 接口
*/
public class TestInterceptor implements HandlerInterceptor {
    // 不拦截 "/loginForm" 和 "/login" 请求
    private static final String[] IGNORE_URI = {"/loginForm","/login"};
    /*
    *  该方法将整个请求完成之后执行,主要作用是用于清理资源,
    *  该方法也只能在当前 Interceptor 的 preHandle 方法的返回值为 true 时才会执行。*/
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler,Exception exception)throws Exception{
        System.out.println("TestInterceptor afterCompletion -->");
    }

    /*
    *  preHandle 方法是进行处理器拦截用的,该方法将在 Controller 处理之前进行调用,
    *  该方法的返回值为 true 拦截器才会继续往下执行,该方法的返回值为 false 时整个请求就结束了。*/
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("TestInterceptor preHandle -->");
        // flag 变量用于判断用户是否登录,默认为 false。
        boolean flag = false;
        // 获取请求的路径进行判断。
        String servletPath = request.getServletPath();
        // 判断请求是否需要拦截
        for (String s:IGNORE_URI){
            if (servletPath.contains(s)){
                flag = true;
                break;
            }
        }
        // 拦截请求
        if (!flag){
            // 1.获取 session 中的用户
            User user = (User)request.getSession().getAttribute("user");
            // 2. 判断用户是否已经登录
            if (user == null){
                // 如果用户没有登陆,则设置提示信息,跳转到登陆页面
                System.out.println("TestInterceptor 拦截请求!");
                request.setAttribute("message" , "请先登录再访问本网站!");
                request.getRequestDispatcher("loginForm").forward(request,response);
            }else {
                // 如果用户已经登录,则验证通过,放行
                System.out.println("TestInterceptor 放行请求!");
                flag = true;
            }
        }
        return flag;
    }

    /*
    *  该方法将在 Controller 的方法调用之后执行,方法中可以对 ModelAndView 进行操作,
    *  该方法也只能在当前 Interceptor 的 preHandle 方法的返回值为 true 时才会执行。
    */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("TestInterceptor postHandle -->");
    }
}
  1. 修改 Spring MVC 配置文件,增加拦截器配置。
<?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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <context:component-scan base-package="controller"/>
    <mvc:annotation-driven/>
    <mvc:default-servlet-handler/>
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/content/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>
    <!--  Spring MVC 拦截器定义  -->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--  拦截所有请求  -->
            <mvc:mapping path="/*"/>
            <!--  使用 bean 定义一个 Interceptor  -->
            <bean class="interceptor.TestInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>
  1. 新建 main.jsp 首页。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>首页</title>
</head>
<body>
    <h3>欢迎[ ${sessionScope.user.username } ] 访问!</h3>
</body>
</html>
  1. 修改 web.xml 。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
  1. 部署应用,在浏览器中输入如下 URL 测试:
http://localhost:8080/InterceptorTest/main

    结果如下图:
在这里插入图片描述
    输入正确的登录名“ceshi”,密码“123456”,点击登录,显示登录成功,跳转到网站首页:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring MVC拦截器是一种应用于请求和响应过程中的过滤器,可以用于对请求进行预处理、对响应进行后处理,以及在请求到达处理程序之前或处理程序返回响应之后执行某些操作。 在Spring MVC中,拦截器是通过实现HandlerInterceptor接口来实现的。该接口定义了三个方法,分别是preHandle()、postHandle()和afterCompletion()。 - preHandle()方法在请求到达处理程序之前执行,可以用于进行身份验证、权限校验等操作,如果该方法返回false,则请求将被拦截并不会到达处理程序。 - postHandle()方法在处理程序完成请求处理后但尚未返回响应时执行,可以用于修改响应或添加一些额外的信息。 - afterCompletion()方法在请求处理完成后执行,无论成功或失败都会执行,可以用于进行资源清理等操作。 要使用拦截器,需要在Spring配置文件中进行配置,并将其注册到DispatcherServlet中。 下面是一个简单的拦截器示例,用于记录请求处理时间: ```java public class TimeInterceptor implements HandlerInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(TimeInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { request.setAttribute("startTime", System.currentTimeMillis()); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { long startTime = (long) request.getAttribute("startTime"); long endTime = System.currentTimeMillis(); LOGGER.info("Request URL: {} , Time: {}ms", request.getRequestURL(), endTime - startTime); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // do nothing } } ``` 在Spring配置文件中进行配置: ```xml <mvc:interceptors> <bean class="com.example.TimeInterceptor" /> </mvc:interceptors> ``` 这样,每次请求处理完成后,日志中就会打印该请求的处理时间,以便进行性能优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值