SpringMVC拦截器

拦截器

1. 什么是拦截器

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

2. maven依赖

<dependencies>
    <!-- spring核心包-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springbean包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springcontext包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- spring表达式包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springAOP包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springAspects包 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- spring对web的支持 -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>
    <!-- springwebMVC -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.18.RELEASE</version>
    </dependency>

    <!-- 配置javaweb环境 -->
    <!-- servlet-api -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!-- jsp-api -->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.1</version>
      <scope>provided</scope>
    </dependency>
    <!-- jstl -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>

    <!-- jackson -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.5</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.5</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.5</version>
    </dependency>
</dependencies>

3. SpringMVC配置

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

    <!--字符编码过滤器-->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 通过隐藏域传参解决form表单的PUT与DELETE方式的请求 -->
    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 解决put请求传递参数的问题-->
    <filter>
        <filter-name>HttpPutFormContentFilter</filter-name>
        <filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HttpPutFormContentFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 配置前端控制器 -->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>/views/index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

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:p="http://www.springframework.org/schema/p"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:aop="http://www.springframework.org/schema/aop"
        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
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- springmvc的注解式开发 -->
    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.newcapec"/>

    <!-- MVC注解驱动 -->
    <mvc:annotation-driven/>

    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- 配置视图地址的前缀和后缀:简化视图地址 -->
        <property name="prefix" value="/views/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--不拦截静态资源-->
    <mvc:default-servlet-handler/>
</beans>

4. Controller

DemoController.java

@Controller
@RequestMapping("/demo")
public class DemoController {

    @RequestMapping("/find")
    public String find(){
        System.out.println("DemoController的find方法...");
        return "success";
    }

    @RequestMapping("/add")
    public String add(){
        System.out.println("DemoController的add方法...");
        return "success";
    }

    @RequestMapping("/edit")
    public String edit(){
        System.out.println("DemoController的edit方法...");
        return "success";
    }

    @RequestMapping("/remove")
    public String remove(){
        System.out.println("DemoController的remove方法...");
        return "success";
    }
}

EmpController.java

@Controller
@RequestMapping("/emp")
public class EmpController {

    @RequestMapping("/find")
    public String find(){
        System.out.println("EmpController的find方法...");
        return "success";
    }

    @RequestMapping("/add")
    public String add(){
        System.out.println("EmpController的add方法...");
        return "success";
    }

    @RequestMapping("/edit")
    public String edit(){
        System.out.println("EmpController的edit方法...");
        return "success";
    }

    @RequestMapping("/remove")
    public String remove(){
        System.out.println("EmpController的remove方法...");
        return "success";
    }
}

5. 拦截器定义

实现HandlerInterceptor接口,并且实现其中三个抽象方法

/**
 * springmvc中的拦截器对象
 * 1.编写代码:实现拦截器接口 HandlerInterceptor
 * 2.配置拦截器
 */
public class Demo1Interceptor implements HandlerInterceptor {

    /**
     * preHandle方法,预处理
     * 作用:在请求进入指定Controller方法之前,执行的方法(对请求进行验证)
     * @param request 请求对象
     * @param response 响应对象
     * @param handler 请求将要执行的Controller对象
     * @return 布尔类型:true表示请求放行,继续向后执行(有可能进入下一个拦截器,也有可能进入Controller)
     *                  false表示拦截请求,请求不能继续向后执行
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Demo1Interceptor拦截器中的preHandle方法执行了...");
        return true;
    }

    /**
     * postHandle 后处理
     * @param request 请求对象
     * @param response 响应对象
     * @param handler 正在执行的Controller对象
     * @param modelAndView 模型和视图数据,Controller方法执行完成之后的返回值
     *
     * 注意:此方法必须在请求进入Controller之后才会执行,如果没有进入Controller是不会执行的
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Demo1Interceptor拦截器中的postHandle方法执行了...");
    }

    /**
     * afterCompletion 请求处理完成之后
     * @param request 请求对象
     * @param response 响应对象
     * @param handler 已经执行过的Controller对象
     * @param ex Controller方法抛出的异常对象
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("Demo1Interceptor拦截器中的afterCompletion方法执行了...");
    }
}

方法解析:

  1. preHandle方法
    在请求进入Controller方法之前调用此方法,起到拦截的作用
    如果preHandle方法返回值为true,表示放行(允许进入Controller方法)
    如果preHandle方法返回值为false,表示拦截(不允许进入Controller方法)
  2. postHandle方法
    请求进入Controller方法之后,但未结束之前,调用此方法
    可在返回的模型数据进行处理加工,比如加入公用信息以便页面显示
  3. afterCompletion方法
    请求离开Controller方法之后,调用此方法
    可获取异常信息,记录日志,资源清理等

6. 拦截器配置

<!-- 配置拦截器 -->
<mvc:interceptors>
    <!-- 一个拦截器 -->
    <mvc:interceptor>
        <!-- 配置此拦截器所拦截的路径
            拦截所有请求:/** 表示所有进入springmvc的请求
        -->
        <mvc:mapping path="/**"/>
        <!-- 注册拦截器对象 -->
        <bean class="com.newcapec.interceptor.Demo1Interceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

/* 与 /**的区别:

请求路径解析
/find配置/*或/**可进入
/demo/find配置/**可进入

7. 页面

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <div style="text-align: center">
        <h1>拦截器</h1>
        <h2>当前登录用户:${sessionScope.loginUser}</h2>
        <a href="demo/find">测试查询</a><br>
        <a href="demo/add">测试新增</a><br>
        <a href="demo/edit">测试编辑</a><br>
        <a href="demo/remove">测试删除</a><br>
        <a href="emp/find">员工查询</a><br>
        <a href="emp/add">员工新增</a><br>
        <a href="emp/edit">员工编辑</a><br>
        <a href="emp/remove">员工删除</a><br>
        <a href="auth/logout">退出系统</a><br>
    </div>
</body>
</html>

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <div style="text-align: center">
        <h1>操作成功</h1>
    </div>
</body>
</html>

8. 拦截器执行流程

定义第二个拦截器Demo2Interceptor.java

public class Demo2Interceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("第二个拦截器中的preHandle方法执行了...");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("第二个拦截器中的postHandle方法执行了...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("第二个拦截器中的afterCompletion方法执行了...");
    }
}

配置:

<!-- 多个拦截器的执行顺序,是按照配置的先后顺序 -->
<mvc:interceptor>
    <mvc:mapping path="/**"/>
    <bean class="com.newcapec.interceptor.Demo2Interceptor"/>
</mvc:interceptor>

8.1 正常运行流程

每个拦截器的preHandler方法都返回true

在这里插入图片描述

8.2 中断流程

Demo1Interceptor的preHandler方法返回true,Demo2Interceptor返回false

在这里插入图片描述

8.3 中断流程

每个拦截器的preHandler方法都返回false

在这里插入图片描述

8.4 总结

  • preHandle方法按拦截器定义顺序调用,postHandler方法按拦截器定义逆序调用,afterCompletion方法按拦截器定义逆序调用
  • postHandler方法在拦截器链内所有拦截器返true时调用
  • afterCompletion方法只要preHandle方法执行过,并且返回true时就会调用

9. 拦截器应用

用户身份认证拦截器的实现

9.1 Controller

@Controller
@RequestMapping("/auth")
public class LoginController {

    @RequestMapping("/login")
    public String login(String username, String password, HttpSession session, Model model){
        //模拟查询:根据用户名和密码查询数据
        if("admin".equals(username) && "123".equals(password)) {
           //比对成功,用户登录
           //将用户信息放入session域对象
           session.setAttribute("loginUser", username);
           return "index";
        }
        model.addAttribute("message", "username or password is invalid");
        return "login";
    }

    @RequestMapping("/logout")
    public String logout(HttpSession session){
        session.removeAttribute("loginUser");
        session.invalidate();
        return "login";
    }
}

9.2 拦截器

public class LoginInterceptor implements HandlerInterceptor {
    /**
     * 身份认证:
     * 过滤器:
     * 1.从session域中获取用户的登录信息
     * 2.判断用户信息是否为空
     * 3.不为空(表示已登录)放行(doFilter方法)
     * 4.为空(表示未登录)
     * 5.判断当前请求是否为登录请求或无需登录可执行请求(身份认证白名单)
     * 6.如果为白名单请求,放行
     * 7.如果不是,拦截,跳转login,信息提示...
     *
     * 拦截器:
     * 1.从session域中获取用户的登录信息
     * 2.判断用户信息是否为空
     * 3.不为空(表示已登录)放行(返回true)
     * 4.为空(表示未登录),拦截,跳转login,信息提示...
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("身份认证拦截器执行.....");
        HttpSession session = request.getSession();
        Object userInfo = session.getAttribute("loginUser");
        if(userInfo == null){
            request.setAttribute("message", "you are not login.");
            request.getRequestDispatcher("/views/login.jsp").forward(request, response);
            return false;
        }
        return true;
    }

    @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 {
    }
}

9.3 配置

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <!-- 配置拦截器不拦截路径,可使用通配符 -->
        <mvc:exclude-mapping path="/auth/login"/>
        <!--<mvc:exclude-mapping path="/demo/**"/>-->
        <bean class="com.newcapec.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

9.4 页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <div style="text-align: center">
        <h1>用户登录</h1>
        <div style="color: red;">${message}</div>
        <form action="auth/login" method="post">
            <p>用户名:<input type="text" name="username"></p>
            <p>&emsp;码:<input type="text" name="password"></p>
            <p><button>登录</button></p>
        </form>
    </div>
</body>
</html>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JTZ001

你的鼓励是我创作的最大动力?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值