SpringMVC---- SpringMVC拦截器

本文详细介绍了SpringMVC中的拦截器(Interceptor)及其与Servlet过滤器(Filter)的区别。拦截器主要用于对Controller方法进行预处理和后处理,实现AOP思想。文章通过实例展示了拦截器的创建、配置和执行顺序,并讨论了拦截器在日志记录、权限检查和性能监控等场景的应用。同时,给出了登录权限检查的拦截器案例。
摘要由CSDN通过智能技术生成

目录

拦截器(interceptor)的作用

拦截器和过滤器区别

拦截器快速入门

单个拦截器

多个拦截器

拦截器方法说明


拦截器(interceptor)的作用

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、在进入首页后退出再直接浏览首页

 

    

代码地址 提取码:c7kq

至此,SpringMVC拦截器介绍完毕,由于作者水平有限难免有疏漏,欢迎留言纠错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值