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文件中配置即可。

  配置元素:

  :所有拦截器都配置在该元素下。

  子元素为,一个子元素代表一个拦截器,

  可配置多个

  :配置单个拦截器

  :指定拦截器需要拦截的路径。

  :指定拦截器不需要拦截的路径。

    path属性作用于,

    用于指定拦截路径。

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

    在中配置,则该拦截器为全局拦截器会拦截所有请求。

    在元素中配置,为拦截指定的路径。

 
       <mvc: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>SpringMVCdisplay-name>
  
  
  
  <servlet>
      <servlet-name>springmvcservlet-name>
      <servlet-class >
          org.springframework.web.servlet.DispatcherServlet
      servlet-class> 
      
      
       
      
      
      
      
      <load-on-startup>1load-on-startup>
  servlet>
  
  <servlet-mapping>
      <servlet-name>springmvcservlet-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> 
       
       
       <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>
       
           <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 heretitle>
head>
<body>
     success <br/>
     
body>
html>

   1.4多个过滤器

  多个过滤器配置与上述类似,只是在中配置多个即可。

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

  假设有拦截器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> 
       
       
       <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>
       
               <mvc:interceptor>
                   <mvc:mapping path="/testInterceptor"/>
                   <bean class = "com.springmvc.interceptor.CustomInterceptor"/>
               mvc:interceptor>
       
               <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 heretitle>
head>
<body>
    ${msg}<br>                                      
    <form action = "${pageContext.request.contextPath}/checkLogin" method = "post">
        用户名:<input type = "text" name = "userName"/><br/>  
        密   码:<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 heretitle>
head>
<body>
    
    weclome:<br>
    ${sessionScope.user.userName}
    <a href = "${pageContext.request.contextPath}/loginOut">注销a>
    
body>
html>

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

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

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

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

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

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

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

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