• 1.5(Spring MVC学习笔记) 拦截器(Interceptor)


    一、拦截器

      1.1拦截器简介

      Spring中的拦截器类似Servlet中的过滤器(Filter),主要用于拦截用户请求,  

      并进行一定的处理操作(如验证权限、记录日志、设置编码方式等)。

      1.2拦截器实现

      SpringMVC实现拦截器主要通过实现HandlerInterceptor接口,

      或者是继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来实现。

      HandlerInterceptor接口中有三个方法:

      public boolean preHanlder(){...}:该方法在执行控制类方法之前执行,

      如果该方法返回值为false后续执行终止(拦截器,处理器,控制类都终止)。

      public void postHandler(){...}:该方法在控制类中方法执之后执行。

      public void afterCompletion(){...}:该方法最后执行,在视图渲染结束后执行。

      

      例如用户发送一个请求执行控制类中某个方法,首先执行preHanlder方法。

      然后判断preHandler方法的返回值为true则继续执行,为false则中止。

      接着当控制类中方法执行完后,执行拦截器中的postHandler方法。

      接着执行后续的视图解析器,渲染视图,最后执行拦截器中的afterCompletion().

       

      1.3拦截器配置

      定义好拦截器类后,在xml文件中配置即可。

      配置元素:

      <mvc:interceptors>:所有拦截器都配置在该元素下。

      子元素为<mvc:interceptors>,一个子元素代表一个拦截器,

      可配置多个

      <mvc:interceptor>:配置单个拦截器

      <mvc:mapping>:指定拦截器需要拦截的路径。

      <mvc:exclude-mapping>:指定拦截器不需要拦截的路径。

        path属性作用于<mvc:mapping><mvc:exclude-mapping>,

        用于指定拦截路径。

      <bean>:代表具体拦截器的实现类。

        在<mvc:interceptors>中配置<bena>,则该拦截器为全局拦截器会拦截所有请求。

        在<mvc:interceptor>元素中配置,为拦截指定的路径。

     <!-- 配置拦截器 -->
           <mvc:interceptors>
           <!-- 配置在interceptors中为全局拦截器 -->
               <bean class = "com.springmvc.interceptor.CustomInterceptor"/>
               <!-- 单个拦截器 -->
               <mvc:interceptor>
                   <!-- 配置拦截内容,拦截所有内容 -->
                   <mvc:mapping path="/**"/>
                   <!-- 配置不拦截内容 -->
                   <mvc:exclude-mapping path=""/>
                   <!-- 对应的拦截器 -->
                   <bean class = "xxx.xxx.xxx"/>
               </mvc:interceptor>
           </mvc:interceptors>

      下面看一个拦截器的例子

    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_3_1.xsd"
      version="3.1"
      metadata-complete="true">
      <display-name>SpringMVC</display-name>
      
      
      <!-- 配置前端控制器 -->
      <servlet>
          <servlet-name>springmvc</servlet-name>
          <servlet-class >
              org.springframework.web.servlet.DispatcherServlet
          </servlet-class> 
          
          <!-- 初始化时加载配置文件,该配置文件是在src目录下创建的。 -->
          <!-- <init-param>  该选项不配置,则做会自动寻找WEB-INF下名为springmvc-servlet.xml的文件。--> 
          <!--    <param-name>contextConfigLocation</param-name>-->
          <!--    <param-value>classpath:springmvc-config.xml</param-value>-->
          <!--</init-param>-->
          <!-- 当前servlet与容器一起加载 -->
          <load-on-startup>1</load-on-startup>
      </servlet>
      <!-- 所有请求都会被前端控制器拦截-->
      <servlet-mapping>
          <servlet-name>springmvc</servlet-name>
          <url-pattern>/</url-pattern>
      </servlet-mapping>
    </web-app>

    CustomInterceptor.java(拦截器)

    import java.io.PrintStream;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    public class CustomInterceptor implements HandlerInterceptor{
        //在HadlerAdapter之前执行(简单的看就是在访问控制类之前执行)
        PrintStream out  = System.out;
        @Override
        public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
            // TODO Auto-generated method stub
            out.println("preHandle...");
            return true;
        }
        
        //在控制器方法调用后,视图解析器之前执行。
        @Override
        public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
                throws Exception {
            // TODO Auto-generated method stub
            out.println("postHandle...");
        }
        
        //最后执行,
        @Override
        public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
                throws Exception {
            out.println("afterCompletionHandle...");
        }
    
    }

    springmvc-servlet.xml

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans     xmlns="http://www.springframework.org/schema/beans" 
            xmlns:mvc="http://www.springframework.org/schema/mvc"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xmlns:context="http://www.springframework.org/schema/context"
            xmlns:tx="http://www.springframework.org/schema/tx"
             xsi:schemaLocation=" 
                 http://www.springframework.org/schema/mvc 
                http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd 
                http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans-4.3.xsd 
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context-4.3.xsd"> 
           <!-- 开启扫描 -->
           <context:component-scan base-package = "com.springmvc.*"></context:component-scan> 
           <!-- testJson -->
           <!-- 配置注解驱动 -->
           <mvc:annotation-driven/>
           <!-- 指定某些文件不被前端控制器拦截,直接访问静态文件。 -->     
           <!-- 设置视图处理器及其前缀后缀 -->
           <bean id = "viewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver">
               <property name="prefix" value = "/WEB-INF/jsp/"></property>
               <property name="suffix" value = ".jsp"></property>
           </bean> 
           
           <!-- 配置拦截器 -->
           <mvc:interceptors>
           <!-- 配置在interceptors中为全局拦截器 -->
               <bean class = "com.springmvc.interceptor.CustomInterceptor"/>
           </mvc:interceptors>
           
    </beans>

    控制类

    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class InterceptorsControl {
        @RequestMapping("/testInterceptor")
        public String handler() {
            System.out.println("handler");
            return "success";
        }
    }

    success.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <%@ page import="com.springmvc.binderList.*" %>
    <!DOCTYPE html>
    
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
         success <br/>
         
    </body>
    </html>

       1.4多个过滤器

      多个过滤器配置与上述类似,只是在<mvc:interceptors>中配置多个<mvc:interceptor>即可。

      关键是多个过滤器的执行顺序。

      

      假设有拦截器1~n,

      执行顺序为: pre(1) pre(2)....pre(n)   post(n) post(n-1)....post(1)   after(n)after(n-1)...after(1)

       

      先将上述CustomInterceptor中的所有打印语句中添加一个数字1。

      System.out.println("perHadler1")

      

      在将Customlnterceptor.java文件复制,并改名为CustomInterceptor2.java

      并将其中数字1改为2.

      

      修改springmvc-servlet.xml 

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans     xmlns="http://www.springframework.org/schema/beans" 
            xmlns:mvc="http://www.springframework.org/schema/mvc"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xmlns:context="http://www.springframework.org/schema/context"
            xmlns:tx="http://www.springframework.org/schema/tx"
             xsi:schemaLocation=" 
                 http://www.springframework.org/schema/mvc 
                http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd 
                http://www.springframework.org/schema/beans 
                http://www.springframework.org/schema/beans/spring-beans-4.3.xsd 
                http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context-4.3.xsd"> 
           <!-- 开启扫描 -->
           <context:component-scan base-package = "com.springmvc.*"></context:component-scan> 
           <!-- testJson -->
           <!-- 配置注解驱动 -->
           <mvc:annotation-driven/>
           
           <bean id = "viewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver">
               <property name="prefix" value = "/WEB-INF/jsp/"></property>
               <property name="suffix" value = ".jsp"></property>
           </bean> 
           
           <!-- 配置拦截器 -->
           <mvc:interceptors>
           <!-- 拦截器1 -->
                   <mvc:interceptor>
                       <mvc:mapping path="/testInterceptor"/>
                       <bean class = "com.springmvc.interceptor.CustomInterceptor"/>
                   </mvc:interceptor>
           <!-- 拦截器2 -->
                   <mvc:interceptor>
                       <mvc:mapping path="/testInterceptor"/>
                       <bean class = "com.springmvc.interceptor.CustomInterceptor2"/>
                   </mvc:interceptor>
           </mvc:interceptors>      
    
    </beans>

    二、拦截器登录注册案例

      

    User.java(POJO类)

    public class User {
        private int id;
        private String userName;
        private String password;
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        
        public String getUserName() {
            return userName;
        }
        public void setUserName(String userName) {
            this.userName = userName;
        }
        public String getPassword() {
            return password;
        }
        public void setPassword(String password) {
            this.password = password;
        }
    }

    Validate.java(拦截器)

    拦截所有请求进行判断,

    如果是去往登录页面或是登录验证放行,

    如果已登录放行,

    其它则跳转到登录页面。

    未登录情况下无法任何资源页面,只能访问登录页面

    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 Validate implements HandlerInterceptor{
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object arg2, Exception arg3)
                throws Exception {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object arg2, ModelAndView arg3)
                throws Exception {
            // TODO Auto-generated method stub
            
        }
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
            // TODO Auto-generated method stub
            System.out.println("into interceptor");
            String url = request.getRequestURI();
            HttpSession session = request.getSession();
            //去往登录页面放行 或者是登录验证放行
            if(url.indexOf("/login") > 0 || url.indexOf("/checkLogin") > 0)
                return true;
            //已登录放行
            if(session.getAttribute("user") != null)
                return true;
            //既不是去登录页面,同时未登录则跳转到登录页面,并提升未登录,请登录。
            request.setAttribute("msg", "未登录,请登录");
            request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
            return false;
        }
    
    }

    UserController.java(控制类)

    import javax.servlet.http.HttpSession;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @Controller
    public class UserController {
        //登录验证
        @RequestMapping("/checkLogin")
        public String checkLogin(User user, Model model, HttpSession session) {
            String userName = user.getUserName();
            String password = user.getPassword();
            //模拟数据查询
            if(userName != null && password != null &&
                    userName.equals("hcf") && password.equals("123456")) {
                //登录成功后设置session用于记录登录状态
                session.setAttribute("user", user);
                return "main";
            }
            model.addAttribute("msg", "用户名或密码错误或为空!");
            return "login";    
        }
        
        //跳转main
        @RequestMapping("/main")
        public String toMain() {
            return "main";
        }
        
        //跳转登录页面
        @RequestMapping("/login")
        public String login() {
            return "login";
        }
        
        //注销用户,即销毁session
        @RequestMapping("/loginOut")
        public String loginOut(HttpSession session) {
            session.invalidate();
            return "login";
        }
    }

    login.jsp (登录页面)

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        ${msg}<br>                                      <!--表达提交后进行登录验证-->
        <form action = "${pageContext.request.contextPath}/checkLogin" method = "post">
            用户名:<input type = "text" name = "userName"/><br/>  <!--name属性的值要和POJO类中属性名相同才可自动填充-->
            密   码:<input type = "text" name = "password"/><br/>
            <input type = "submit"  value = "登录"/>
        </form>
    </body>
    </html>

    main.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
        
        weclome:<br>
        ${sessionScope.user.userName}
        <a href = "${pageContext.request.contextPath}/loginOut">注销</a>
        
    </body>
    </html>

    用户请求访问main.jsp,会被拦截,判断是否登录。

    如果登录则放行,执行控制类中的跳转主页方法。

    如果未登录则设置msg值,并跳转登录页面。

    用户访问登录页面直接放行。

    登录页面提交表单后也会被拦截,拦截器判断为登录检查放行。

    控制类中会对用户名及密码进行检查。

    密码正确设置session保持登录状态,并跳转到main.jsp.

    密码错误则设置msg值,并跳转到登录页面。

       

  • 相关阅读:
    建立自己的影响力
    在病房垒代码
    知乎确实不错
    不在乎你用到了什么技术,而在于你提供了哪些有价值的东西
    oschina上有不少好的项目
    我为何坚守Java?
    掌握了学习方法才能学到更多知识
    Jrebel实现Jetty 热部署
    互联网到底能干什么?我们还能干些什么?
    centos 阿里云 安装VNC Viewer
  • 原文地址:https://www.cnblogs.com/huang-changfan/p/10419184.html
Copyright © 2020-2023  润新知