SpringMVC之拦截器

本文详细介绍了SpringMVC中的处理器拦截器(Interceptor)和Servlet规范中的过滤器(Filter)的区别与联系。拦截器依赖于Spring框架,基于Java反射,常用于权限检查、日志记录等场景,而过滤器则更通用,可以对所有请求进行过滤。两者在执行顺序上,过滤器先于拦截器。文章还提供了拦截器的配置和使用示例,包括单个拦截器和多个拦截器的配置,并给出了登录拦截器的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是拦截器

SpringMVC的处理器拦截器,类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

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

二、拦截器作用

SpringMVC 框架中的拦截器用于对处理器进行预处理和后处理的技术。

可以定义拦截器链,连接器链就是将拦截器按着顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行。

拦截器和过滤器的功能比较类似,有以下区别:

  • 过滤器是 Servlet 规范的一部分,任何框架都可以使用过滤器技术;

拦截器是 SpringMVC 框架独有的。

  • 过滤器配置了 /*,可以拦截任何资源;

拦截器只会对控制器中的方法进行拦截。

拦截器也是 AOP 思想的一种实现方式。

三、拦截器与过滤器的区别

1)过滤器:

依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等。

2)拦截器:

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

过滤器(filter):

    1) filter属于Servlet技术,只要是web工程都可以使用
    2) filter主要对所有请求过滤
    3) filter的执行时机早于Interceptor

拦截器(interceptor)

    1) interceptor属于SpringMVC技术,必须要有SpringMVC环境才可以使用
    2) interceptor通常对处理器Controller进行拦截
    3) interceptor只能拦截dispatcherServlet处理的请求

 四、应用场景

    1)日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。

    2)权限检查:如登录检测,进入处理器检测是否登录,如果没有直接返回到登录页面;

    3)性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反向代理,如apache可以自动记录);

    4)通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个Controller中的处理方法都需要的,我们就可以使用拦截器实现。

五、拦截器的使用

单个拦截器

自定义拦截器,需要实现 HandlerInterceptor 接口

1.创建自定义拦截器

public class HelloInterceptor implements HandlerInterceptor {
    /**
     * 预处理,controller 方法执行前
     * 应用:用于身份认证、身份授权
     * return true 放行,执行下一个拦截器,如果没有,执行 controller 中的方法
     * return false 不放行,即不向下执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle...");
        return true;
    }

    /**
    * 后处理方法,controller 方法执行后,方法跳转 success.jsp 执行之前
    * 应用:从modelAndView出发:将公用的模型数据(比如菜单导航)在这里传到视图,也可以在这里统一指定视图
    */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
    }

    /**
    * success.jsp 页面执行后,该方法会执行
    * 应用:统一异常处理,统一日志处理
    */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
    }
}

2.在 spring-mvc.xml 中配置拦截器 

<!--配置拦截器-->
    <mvc:interceptors>
        <!--配置拦截器,多个拦截器时,顺序执行-->
        <mvc:interceptor>
            <!--配置拦截器对象-->
            <bean class="com.zking.ssm.book.interceptor.HelloInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>

3.测试拦截器

@Controller//用于标识处理器类
//@RequestMapping("/index")
public class IndexController {

    @RequestMapping("/")
    public String toIndex(){
        //ViewResolver:进行视图解析,前缀(prefix)+逻辑视图名+后缀(suffix)
        //完整路径=/WEB-INFO/jsp/index.jsp
        return "index";
    }
}
/**
 *分别输出:
 *  preHandle...
 *  postHandle...
 *  afterCompletion...
 *
 */

多个拦截器

注意:

  • 多个拦截器时,按照 springmvc.xml 配置的顺序执行。
  • (2个拦截器时) 拦截器1 preHandle 不放行,postHandle 和 afterCompletion 不会执行。
  • (2个拦截器时) 拦截器1 preHandle 不放行,拦截器2不执行。

 

 1.再创建一个拦截器

public class BookInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("BookInterceptor  preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("BookInterceptor  postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("BookInterceptor  afterCompletion");
    }
}

2.在 spring-mvc.xml 中配置多拦截器

    <mvc:interceptors>    
        <mvc:interceptor>
            <!--拦截所有请求-->
            <mvc:mapping path="/**"/>
            <bean class="com.zking.ssm.book.interceptor.HelloInterceptor"/>
        </mvc:interceptor>
        <mvc:interceptor>
            <!--拦截以book开头的请求-->
            <mvc:mapping path="/book/**"/>
            <bean class="com.zking.ssm.book.interceptor.BookInterceptor"/>
        </mvc:interceptor>
     </mvc:interceptors>

3.测试 

@Controller//用于标识处理器类
//@RequestMapping("/index")
public class IndexController {

    @RequestMapping("/")
    public String toIndex(){
        //ViewResolver:进行视图解析,前缀(prefix)+逻辑视图名+后缀(suffix)
        //完整路径=/WEB-INFO/jsp/index.jsp
        return "index";
    }
}
/**
 *分别输出:
 *  HelloInterceptor  preHandle....
 *  BookInterceptor  preHandle
 *  BookInterceptor  postHandle
 *  HelloInterceptor  postHandle....
 *  BookInterceptor  afterCompletion
 *  HelloInterceptor  afterCompletion....
 *
 */

六、登录实例

1.创建登录拦截器

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("/dto/toLogin")>0)
            return true;
        //判断是否是用户登录 放行
        if(url.indexOf("/dto/userLogin")>0)
            return true;
        //获取session
        HttpSession session = request.getSession();
        //获取session中的用户对象
        String  uname = (String) session.getAttribute("uname");
        //判断session中的用户对象是否存在,存在放行,不存在跳转登录页面
        if(uname!=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 {

    }
 }

2.配置登录拦截器

    <mvc:interceptors>
        <!--示例三:登录权限-->
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.zking.ssm.book.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

3.实现方法LoginController

由于没有连接数据库所以用户名:admin密码:123写死

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";
    }
}

4.测试

 提交去其他页面的地址也会被拦截

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值