拦截器[ 登录认证场景应用 ]

有两种方式: 在springmvc.xml中配置

  方式1: 针对某一个HandlerMapping设置拦截[一般不推荐使用, 太麻烦]

 1 <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
 2         <property name="interceptors">
 3             <list>
 4                 <ref bean="handlerInterceptor1"/>
 5                 <ref bean="handlerInterceptor2"/>
 6             </list>
 7         </property>
 8     </bean>
 9     <bean id="handlerInterceptor1" class="com.itcast.ssm.interceptor.HandlerInterceptor1"/>
10     <bean id="handlerInterceptor2" class="com.itcast.ssm.interceptor.HandlerInterceptor2"/>

  方式2: 全局的拦截器[推荐使用]

1. 定义拦截器

拦截器1

 1 package com.itcast.ssm.interceptor;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 import org.springframework.web.servlet.HandlerInterceptor;
 6 import org.springframework.web.servlet.ModelAndView;
 7 
 8 /**
 9  * 测试拦截器1
10  */
11 public class HandlerInterceptor1 implements HandlerInterceptor {
12 
13     /**
14      * 进入Handler方法之前执行, 用于身份认证/身份授权
15      */
16     @Override
17     public boolean preHandle(HttpServletRequest request,
18             HttpServletResponse response, Object handler) throws Exception {
19         
20         System.out.println("HandlerInterceptor1....preHandle()");
21         return true;    // return false 表示拦截, 不向下执行, return true 表示放行
22     }
23 
24     /**
25      * 进入Handler方法之后, 返回ModelAndView之前执行
26      * 应用场景从modelAndView出发, 将一些公用的模型数据(比如菜单的导航)在这里传到视图, 也可以在这里统一制定视图
27      */
28     @Override
29     public void postHandle(HttpServletRequest request,
30             HttpServletResponse response, Object handler, ModelAndView mv)
31             throws Exception {
32         
33         System.out.println("HandlerInterceptor1....postHandle()");
34     }
35 
36     /**
37      * 执行Handler方法完成之后执行此方法
38      * 统一异常处理, 统一日志处理
39      */
40     @Override
41     public void afterCompletion(HttpServletRequest request,
42             HttpServletResponse response, Object handler, Exception ex)
43             throws Exception {
44         
45         System.out.println("HandlerInterceptor1....afterCompletion()");
46     }
47 }

 拦截器2

 1 package com.itcast.ssm.interceptor;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 import org.springframework.web.servlet.HandlerInterceptor;
 6 import org.springframework.web.servlet.ModelAndView;
 7 
 8 /**
 9  * 测试拦截器2
10  */
11 public class HandlerInterceptor2 implements HandlerInterceptor {
12 
13     /**
14      * 进入Handler方法之前执行, 用于身份认证/身份授权
15      */
16     @Override
17     public boolean preHandle(HttpServletRequest request,
18             HttpServletResponse response, Object handler) throws Exception {
19         
20         System.out.println("HandlerInterceptor2....preHandle()");
21         return true;    // return false 表示拦截, 不向下执行, return true 表示放行
22     }
23 
24     /**
25      * 进入Handler方法之后, 返回ModelAndView之前执行
26      * 应用场景从modelAndView出发, 将一些公用的模型数据(比如菜单的导航)在这里传到视图, 也可以在这里统一制定视图
27      */
28     @Override
29     public void postHandle(HttpServletRequest request,
30             HttpServletResponse response, Object handler, ModelAndView mv)
31             throws Exception {
32         
33         System.out.println("HandlerInterceptor2....postHandle()");
34     }
35 
36     /**
37      * 执行Handler方法完成之后执行此方法
38      * 统一异常处理, 统一日志处理
39      */
40     @Override
41     public void afterCompletion(HttpServletRequest request,
42             HttpServletResponse response, Object handler, Exception ex)
43             throws Exception {
44         
45         System.out.println("HandlerInterceptor2....afterCompletion()");
46     }
47 }

2. 在springmvc.xml中配置拦截器

 1 <!-- 配置全局拦截器 -->
 2     <mvc:interceptors>
 3         <!-- 多个拦截器, 按先后顺序执行 -->
 4         <mvc:interceptor>
 5             <!-- /**表示拦截所有URL, 包括其子URL路径 -->
 6             <mvc:mapping path="/**"/>
 7             <bean class="com.itcast.ssm.interceptor.HandlerInterceptor1"/>
 8         </mvc:interceptor>
 9         <mvc:interceptor>
10             <mvc:mapping path="/**"/>
11             <bean class="com.itcast.ssm.interceptor.HandlerInterceptor2"/>
12         </mvc:interceptor>
13     </mvc:interceptors>

测试1:[测试背景, springmvc+spring+mybatis整合项目demo]

  http://localhost:8080/ssm_items/items/editItemsShow.action

后台打印:

  HandlerInterceptor1....preHandle()
  HandlerInterceptor2....preHandle()

  HandlerInterceptor2....postHandle()
  HandlerInterceptor1....postHandle()

  HandlerInterceptor2....afterCompletion()
  HandlerInterceptor1....afterCompletion()

 总结:
     1. preHandle()方法按照顺序执行
     2. postHandle()和afterCompletion()方法逆向执行

----------------------------------------------------------------------

测试2:

把拦截器2的preHandle()方法返回值改成false, 再测试, 后台打印:

  HandlerInterceptor1....preHandle()
  HandlerInterceptor2....preHandle()
  HandlerInterceptor1....afterCompletion()

总结:
    拦截器1的preHandle放行, 拦截器2的proHandle才会执行
    拦截器2的preHandle不放行, 拦截器2的postHandle和afterCompletion不会执行
   只要有一个拦截器不放行, postHandle方法都不会执行

测试3: 后台打印

  HandlerInterceptor1....preHandle()

拦截器1不放行, 后面的都不会执行
根据测试结果, 对拦截器的应用:
    1. 统一日志处理拦截器
    需要将该拦截器的preHandle方法设置为放行, 并且将该拦截器放在配置文件中的拦截器链的第一个位置, 因为这样,[中间可能设置有多个拦截器, 
但不管中间的拦截器的preHandle方法怎么设置, 但是只要统一日志处理的拦截器的preHandle方法放行, 其afterCompletion方法就会被执行]
该拦截器的afterCompletion方法才会被执行(而这个方法就是用于写统一日志处理的)
2. 登录认证拦截器 将其放在拦截器链中的第一个位置(但是位置不能超过统一日志处理的拦截器) 3. 权限校验拦截器 放在登录认证拦截器之后, 因为只有登录通过之后才会校验权限

总结这三个拦截器在拦截器链中的放置顺序: 1. 统一日志处理拦截器 2. 登录认证拦截器 3. 权限校验拦截器

 

拦截器的应用:  登录认证

需求分析:

  1. 用户请求URL

  2. 拦截器进行拦截校验

  * 如果请求的URL是公开地址(即: 无需登录即可访问的URL, 比如网站的首页), 放行

  * 如果用户session不存在, 跳转到登录页面

  * 如果用户session存在, 放行, 继续操作

实现:

  1. 编写认证登录的handler: LoginController.java

 1 package com.itcast.ssm.controller;
 2 
 3 import javax.servlet.http.HttpSession;
 4 import org.springframework.stereotype.Controller;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 
 7 @Controller
 8 public class LoginController {
 9     
10     // 登录
11     @RequestMapping("/login")
12     public String login(HttpSession session, String username, String password) throws Exception {
13         
14         // 中间过程省略不写(这里要调用service方法进行用户身份验证)
15         
16         // 将合法的用户身份信息保存到session中
17         session.setAttribute("username", username);
18         
19         // 如果登录成功, 重定向到商品列表页面, 否则返回重新登录
20         return "redirect:items/queryItems.action";
21     }
22     
23     // 退出
24     @RequestMapping("/logout")
25     public String logout(HttpSession session) throws Exception {
26         
27         // 清除session, 重定向到登录页面
28         session.invalidate();
29         return "redirect:items/queryItems.action";
30     }
31 }

  2. 编写认证登录的拦截器LoginInterceptor.java

 1 package com.itcast.ssm.interceptor;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 import javax.servlet.http.HttpSession;
 6 import org.springframework.web.servlet.HandlerInterceptor;
 7 import org.springframework.web.servlet.ModelAndView;
 8 
 9 /**
10  * 登录认证拦截器
11  */
12 public class LoginInterceptor implements HandlerInterceptor {
13 
14     @Override
15     public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
16             Object handler) throws Exception {
17         
18         // 获取请求的URL
19         String url = request.getRequestURI();
20         
21         // 判断URL是否是公开地址(实际使用时将公开地址配置在配置文件中)
22         if (url.indexOf("login.action") >= 0) {
23             // 如果是公开地址, 并且进行登录提交, 那么放行
24             return true;
25         }
26         
27         // 判断session中是否存在用户信息
28         HttpSession session = request.getSession();
29         String username = (String) session.getAttribute("username");
30         if (username != null) {
31             // 身份存在, 放行
32             return true;
33         }
34         
35         // 执行到这里表示用户身份不符合前面两个if判断, 那么用户身份需要验证
36         request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
37         return false;
38     }
39 
40     @Override
41     public void postHandle(HttpServletRequest request, HttpServletResponse response,
42             Object arg2, ModelAndView mv) throws Exception {
43 
44     }
45 
46     @Override
47     public void afterCompletion(HttpServletRequest request,
48             HttpServletResponse response, Object handler, Exception ex)
49             throws Exception {
50 
51     }
52 }

  3. 在springmvc.xml中配置认证登录的拦截器

1 <!-- 配置全局拦截器: 多个拦截器, 按先后顺序执行, /**表示拦截所有URL, 包括其子URL路径 -->
2     <mvc:interceptors>
3         <!-- 登录验证拦截器 -->
4         <mvc:interceptor>
5             <mvc:mapping path="/**"/>
6             <bean class="com.itcast.ssm.interceptor.LoginInterceptor"/>
7         </mvc:interceptor>
8    </mvc:interceptors>

  4. 编写认证登录页面login.jsp

 1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
 3 <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
 4 <%
 5     String path = request.getContextPath();
 6     String basePath = request.getScheme() + "://"
 7             + request.getServerName() + ":" + request.getServerPort()
 8             + path + "/";
 9 %>
10 
11 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
12 <html>
13 <head>
14 <base href="<%=basePath%>">
15 <title>用户登录</title>
16 <meta http-equiv="pragma" content="no-cache">
17 <meta http-equiv="cache-control" content="no-cache">
18 <meta http-equiv="expires" content="0">
19 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
20 <meta http-equiv="description" content="This is my page">
21 </head>
22 
23 <body>
24     <h3>用户登录</h3>
25     <form action="${pageContext.request.contextPath }/login.action" method="post">
26         用户账号: <input type="text" name="username"/><br>
27         用户密码: <input type="password" name="password"/><br><br>
28         <input type="submit" value="登录"/>
29     </form>
30 </body>
31 </html>

  5. 测试

  (1) 直接输入http://localhost:8080/ssm_items/items/queryItems.action, 因为没有登录过, 而且session中没有用户身份信息, 

所以直接被打回到login.jsp页面进行登录

  

  (2) 输入张三, 123, 登录成功 

 

  (3) 重开一个页面, 直接输入http://localhost:8080/ssm_items/items/queryItems.action, 直接来到商品列表页面(因为session有数据)

  (4) 退出后, 再次输入第3不的地址, 又被打回到登录页面, 因为退出后session数据被销毁

至此登录认证完成...

 

posted @ 2017-03-24 03:21  半生戎马,共话桑麻、  阅读(211)  评论(0)    收藏  举报
levels of contents