11、拦截器(springmvc笔记)

一、拦截器入门(工程springmvc-mybatis10

1.1 拦截器的定义

HandlerInterceptor1.java

package cn.itcast.ssm.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

//测试拦截器1
public class HandlerInterceptor1 implements HandlerInterceptor{
    
    //在进入handler方法之前执行,用于身份认证、身份授权等权限管理
    //比如身份认证,如果认证没有通过,则需要此方法拦截,不再向下执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        
        System.out.println("第一个拦截器----执行前");
        //返回false表示拦截,不向下执行
        return false;
    }
    
    //在进入handler方法之后同时在返回modelAndView之前
    //应用场景从modelAndView出发,将一些公用的模型数据在这里传递到视图中(比如菜单的导航)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("第一个拦截器----执行中");
    }
    //在执行handler方法之后执行
    //应用场景:可以使用统一的异常处理,还可以用于统一的日志处理
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("第一个拦截器----执行后");
    }
}

说明:拦截器需要实现HandlerInterceptor接口,同时覆写其中的三个方法。

1.2 拦截器的配置

  • 方式一:springmvc的拦截器是针对HandlerMapping进行拦截设置的,如果在某个HandlerMapping中配置拦截器,经过该HandlerMapping映射成功的Handler最终才使用该拦截器。针对某个mapping配置拦截器:
<bean
    class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
    <property name="interceptors">
        <list>
            <ref bean="handlerInterceptor1"/>
            <ref bean="handlerInterceptor2"/>
        </list>
    </property>
</bean>
    <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
    <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>

不过这种方式比较麻烦,一般不推荐。

  • 方式二:
    定义好拦截器之后我们还需要将其配置到springmvc中,在springmvc.xml中:
<!--拦截器 -->
<mvc:interceptors>
    <!--多个拦截器,顺序执行 -->
    <mvc:interceptor>
        <mvc:mapping path="/**" /><!-- 表示拦截所有的url,包括子url路径 -->
        <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor1"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/**" />
        <bean class="cn.itcast.ssm.interceptor.HandlerInterceptor2"></bean>
    </mvc:interceptor>
</mvc:interceptors>

1.3 测试

这里我们再定义一个拦截器:
HandlerInterceptor2.java

package cn.itcast.ssm.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

//测试拦截器2
public class HandlerInterceptor2 implements HandlerInterceptor{
    
    //在进入handler方法之前执行,用于身份认证、身份授权等权限管理
    //比如身份认证,如果认证没有通过,则需要此方法拦截,不再向下执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        System.out.println("第二个拦截器----执行前");
        //返回false表示拦截,不向下执行
        return false;
    }
    
    //在进入handler方法之后同时在返回modelAndView之前
    //应用场景从modelAndView出发,将一些公用的模型数据在这里传递到视图中(比如菜单的导航)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("第二个拦截器----执行中");
    }
    //在执行handler方法之后执行
    //应用场景:可以使用统一的异常处理,还可以用于统一的日志处理
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("第二个拦截器----执行后");
    }
}

说明:

  • 1、可以看到这里我们两个拦截器中都不放行(preHandle方法返回false)测试结果为:
第一个拦截器----执行前
第二个拦截器----执行前
第二个拦截器----执行中
第一个拦截器----执行中
第二个拦截器----执行后
第一个拦截器----执行后

结论:当都放行时方法preHandle按顺序执行,postHandleafterCompletion逆向执行。

  • 2、拦截器1放行,拦截器2不放行(将拦截器2的preHandle方法返回false),测试结果为:
第一个拦截器----执行前
第二个拦截器----执行前
第一个拦截器----执行后

结论:拦截器1放行,拦截器2的preHandle方法才会执行。拦截器2的preHandle方法不放行,则拦截器2的另外两个方法不会执行。只要有一个拦截器不放行,则postHandle方法都不会执行。

  • 3、两个拦截器都不放行,即都返回false。测试结果为:
第一个拦截器----执行前

结论:拦截器1的preHandle不放行,其余方法和其他拦截器中的方法都不会执行。

1.4 小结

根据测试结果,对拦截器进行应用,比如一个统一的日志处理拦截器,则需要将其放在拦截器链中的第一个位置,并且方法preHandle一定要放行。
比如一个登录认证的拦截器,需要将其放在拦截器链中的第一个位置。但是一般在日志拦截器后面。再比如一个权限校验的拦截器,应该放在登录认证拦截器之后。

二、拦截器的应用(工程springmvc-mybatis11

2.1 需求

用户请求url,拦截器进行拦截校验,如果请求的url是不需要登录就可以访问的url(公开地址),则放行。如果请求的url是需要登录才可以访问的url,用户session不存在,则跳转到的登录页面,否则放行。

2.2 Controller方法

LoginController.java

package cn.itcast.ssm.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class LoginController {
    //登录
    @RequestMapping("/login")
    public String login(HttpSession session, String username, String password) throws Exception{
        
        //进行身份认证
        session.setAttribute("username", username);//在session中保存用户身份信息
        //重定向商品列表页面
        return "redirect:/items/queryItems.action";
    }
    
    //退出
    @RequestMapping("/logout")
    public String logout(HttpSession session) throws Exception{
        //清除session
        session.invalidate();
        return "redirect:/items/queryItems.action";
    }
}

2.3 登录认证拦截实现

LoginInterceptor.java

package cn.itcast.ssm.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

//登录认证拦截器
public class LoginInterceptor implements HandlerInterceptor{
    
    //在进入handler方法之前执行,用于身份认证、身份授权等权限管理
    //比如身份认证,如果认证没有通过,则需要此方法拦截,不再向下执行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        
        //获取请求的url
        String url = request.getRequestURI();
        //判断url是否是公开地址,实际使用时应该将公开地址配置在配置文件中,这里公开地址是登录提交的地址
        if(url.indexOf("login.action") >= 0){
            //如果是登录提交,则放行
            return true;
        }
        //判断session
        HttpSession session = request.getSession();
        //从session中取出用于身份信息
        String username = (String) session.getAttribute("username");
        if(username != null){
            //身份信息存在,放行
            return true;    
        }
        //没有校验通过,表示用户身份需要认证,此时需要跳转到登录页面
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        //返回false表示拦截,不向下执行
        return false;
    }
    
    //在进入handler方法之后同时在返回modelAndView之前
    //应用场景从modelAndView出发,将一些公用的模型数据在这里传递到视图中(比如菜单的导航)
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView modelAndView) throws Exception {
        
    }
    //在执行handler方法之后执行
    //应用场景:可以使用统一的异常处理,还可以用于统一的日志处理
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    }
}

2.4 拦截器配置

和之前一样:

<mvc:interceptor>
    <mvc:mapping path="/**" /><!-- 登录认证拦截器 -->
    <bean class="cn.itcast.ssm.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>

2.5 测试

在测试之前我们可以在页面itemsList.jsp中加上一些信息:

当前用户:${username },
<c:if test="${username != null}">
    <a href="${pageContext.request.contextPath }/logout.action">退出</a>
</c:if>

而登录页面为jsp/login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>系统登录</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
</head>
<body>
    <form action="${pageContext.request.contextPath }/login.action" method="post">
        用户名: <input type="text" name="username" /> <br> 
        密码: <input type="password" name="password" />
        <br> <input type="submit" value="登录" />
    </form>
</body>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容