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值,并跳转到登录页面。

 

   

posted @ 2019-02-23 11:20  gcmh  阅读(576)  评论(0编辑  收藏  举报