SpringMVC springMVC的拦截器

1、 拦截器的做用

SpringMVC的处理器拦截器相似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者能够本身定义一些拦截器来实现特定的功能。css

1.【拦截器链】(Interceptor Chain): 将拦截器按必定的顺序链接成一条链。在访问被拦截的方法或者字段时,拦截器链中的拦截器就会按照以前定义的顺序被调用。html

2.过滤器与拦截器的区别java

拦截器是AOP思想的具体应用。web

过滤器 拦截器
servlet规范中的一部分,任何java web工程均可以使用 拦截器是SpringMVC框架本身的,只有使用了SpringMVC框架的工程才能使用
在url-pattern中配置了/*以后,能够对全部要访问的资源进行拦截 拦截器只会拦截访问的控制器方法, 若是访问的是jsp/html/css/image/js是不会进行拦截的

2、自定义拦截器的步骤

想要自定义拦截器,必须实现 HandlerInterceptor 接口。redis

1. 编写一个普通类实现HandlerInterceptor接口

/** 自定义拦截器 */
public class HanderInterceptorOne 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) {
        System.out.println("postHandle方法执行了");
    }

    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) {
        System.out.println("afterCompletion方法执行了");
    }
}

2. 配置拦截器

配置springMVC.xmlspring

<!-- 配置拦截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean id="handlerInterceptorOne"
              class="com.itheima.myInterceptor.HanderInterceptorOne"/>
    </mvc:interceptor>
</mvc:interceptors>

3. 【*】测试运行结果【下面全部测试的运行的代码都使用这一套】

1. 访问的index.jspsession

<%-- 测试拦截器 --%>
<a href="${pageContext.request.contextPath}/interceptor/function">拦截器测试</a>

2. 控制器代码mvc

/** 测试拦截器的控制器 */
@Controller
@RequestMapping("/interceptor")
public class InterceptorController {

    @RequestMapping("/function")
    public String testFunction() {
        System.out.println("控制器中的方法执行了");
        return "success";
    }
}

3. 运行结果app

preHandle拦截器拦截了
控制器中的方法执行了
postHandle方法执行了
afterCompletion方法执行了

3、拦截器的细节

1. 拦截器的放行框架

放行的含义是指,若是有下一个拦截器就执行下一个,若是该拦截器处于拦截器链的最后一个,则执行控制器中的方法。

拦截器放行.png

2. 拦截器中方法的说明

拦截器HandlerInterceptor接口中的三个方法详解。

2.1 boolean preHandle 方法

2.1.1 方法源码

default boolean preHandle(HttpServletRequest request, 
				HttpServletResponse response, 
				Object handler) throws Exception {
    return true;
}

2.1.2 如何调用:按照拦截器定义顺序调用

2.1.3 什么时候调用:只要配置了都会被调用

2.1.4 逻辑功能:若是开发者决定该拦截器对请求拦截处理后还要调用其余的拦截器,或者是业务处理器去进行处理,则返回true。若是开发者决定不须要再调用其余的组件去处理请求,则返回false。

2.2 void postHandle 方法

2.2.1 方法源码

default void postHandle(HttpServletRequest request, 
				HttpServletResponse response, 
				Object handler, 
				@Nullable ModelAndView modelAndView) throws Exception {}

2.2.2 如何调用:按照拦截器定义逆序调用

2.2.3 什么时候调用:拦截器链内全部拦截器返回成功时调用

2.2.4 逻辑功能:在业务处理器处理完请求后,可是DispatcherServlet向客户端返回响应前被调用,在该方法中对用户请求request进行处理。

2.3 void afterCompletion 方法

2.3.1 方法源码

default void afterCompletion(HttpServletRequest request, 
				HttpServletResponse response, 
				Object handler, 
				@Nullable Exception ex) throws Exception {}

2.3.2 如何调用:按拦截器定义逆序调用

2.3.3 什么时候调用:只有对应的preHandle返回true才会被调用

2.3.4 逻辑功能在DispatcherServlet彻底处理完请求后被调用,能够在该方法中进行一些资源清理的操做。

3. 拦截器的做用路径

做用路径能够经过在配置文件中配置。能够配置多个

<!-- 配置拦截器的做用范围 -->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        -- 用于指定拦截的url,能够配置多个

        <mvc:exclude-mapping path="/xxx"/>
        -- 用于指定排除的url,能够配置多个

        <bean id="handlerInterceptorOne"
              class="com.itheima.myInterceptor.HanderInterceptorOne"/>
    </mvc:interceptor>
</mvc:interceptors>

4. 多个拦截器的执行顺序

多个拦截器是按照配置的顺序决定的,下面以前后配置HandlerInterceptorDemo1/HandlerInterceptorDemo2为例:

4、正常流程测试案例

1. 拦截器1代码

public class HandlerInterceptorDemo1 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("拦截器1:preHandle拦截器拦截了");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        System.out.println("拦截器1:postHandle方法在DispatcherServlet响应前执行了");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("拦截器1:afterCompletion方法在DispatcherServlet响应后执行了");
    }
}

2. 拦截器2代码

将拦截器中的输出语句中的拦截器1换成拦截器2,类名换成HandlerInterceptorDemo2

3. 配置文件

<!-- 正常执行的拦截器配置,按照配置的顺序执行 -->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean id="handlerInterceptorDemo1" class="com.itheima.myInterceptor.HandlerInterceptorDemo1"/>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean id="handlerInterceptorDemo2" class="com.itheima.myInterceptor.HandlerInterceptorDemo2"/>
    </mvc:interceptor>
</mvc:interceptors>

4. 测试代码

访问的index.jsp代码和控制器代码同上【*】测试运行结果...

5. 执行结果

拦截器1:preHandle拦截器拦截了
拦截器2:preHandle拦截器拦截了
控制器中的方法执行了
拦截器2:postHandle方法在DispatcherServlet响应前执行了
拦截器1:postHandle方法在DispatcherServlet响应前执行了
拦截器2:afterCompletion方法在DispatcherServlet响应后执行了
拦截器1:afterCompletion方法在DispatcherServlet响应后执行了

5、中断流程测试

1. 拦截器1代码

同上一个案例的拦截器1的代码

2. 拦截器2代码

public class HandlerInterceptorDemo2 implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("拦截器2:preHandle拦截器拦截了");
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
        System.out.println("拦截器2:postHandle方法在DispatcherServlet响应前执行了");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        System.out.println("拦截器2:afterCompletion方法在DispatcherServlet响应后执行了");
    }
}

3. 配置文件

同上一个案例的配置文件

4. 测试代码

访问的index.jsp代码和控制器代码同上【*】测试运行结果...

5. 执行结果

拦截器1:preHandle拦截器拦截了
拦截器2:preHandle拦截器拦截了
拦截器1:afterCompletion方法在DispatcherServlet响应后执行了

6、拦截器的简单案例

验证用户是否登陆(认证用户)

1. 实现思路

1.1 有一个登录页面,须要写一个controller访问页面。

1.2 登录页面有一提交表单的动做。须要在controller中处理。

1.2.1 判断用户名密码是否正确。
1.2.2 若是正确,向session(redis)中写入用户信息。
1.2.3 返回登录成功。

1.3 拦截用户请求,判断用户是否登录。

1.3.1 若是用户已经登录。放行 1.3.2 若是用户未登录,跳转到登录页面

2. 控制器代码

@Controller
@RequestMapping("/user")
public class UserController {

    /** 跳转到登录页面 */
    @RequestMapping("/jumplogin")
    public String jumpLogin(Model model) throws Exception {
        return "login";
    }

    /** 登录提交 */
    @RequestMapping("/login")
    public String login(HttpSession session, String userid, String pwd) throws Exception {
        // 向session记录用户身份信息
        session.setAttribute("user", userid);
        return "success";
    }

    /** 退出登录 */
    @RequestMapping("logout")
    public String logout(HttpSession session) throws Exception {
        // session 过时
        session.invalidate();

        return "login";
    }
}

3. 拦截器代码

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException, IOException {
        // 若是是登录页面则放行
        System.out.println("uri: " + request.getRequestURI());
        if (request.getRequestURI().contains("login")) {
            return true;
        }

        HttpSession session = request.getSession();

        // 若是用户已登录也放行
        if(session.getAttribute("user") != null) {
            return true;
        }

        // 用户没有登录跳转到登录页面
        request.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(request, response);
        return false;
    }
}

4. springMVC.xml配置

<!-- 登录案例的拦截器 -->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean id="loginInterceptor" class="com.itheima.myInterceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

5. 登录页面login.jsp

<form action="${pageContext.request.contextPath}/user/login">
    用户名:<input type="text" name="userid"> <br>
    密码: <input type="password" name="pwd"> <br>
    <input type="submit" value="提交">
</form>
相关文章
相关标签/搜索