Hướng dẫn sử dụng Spring MVC Interceptor
Công ty Vĩnh Cửu tuyển dụng lập trình viên Java

1- Spring Interceptor là gì?

Khi bạn tới công ty và muốn gặp sếp của công ty đó. Bạn cần phải đi qua các chốt chặn (Interceptor), các chốt chặn ở đây có thể là người bảo vệ cổng, nhân viên lễ tân,..

Trong Spring, khi một request được gửi đến controller, trước khi request được sử lý bởi Controller, nó phải vượt qua các Interceptor (0 hoặc nhiều).

Spring Interceptor là một khái niệm khá giống với Servlet Filter.

Spring Interceptor chỉ áp dụng đối với các request đang được gửi đến một Controller.
Bạn có thể sử dụng Interceptor để làm một số việc, chẳng hạn như ghi lại Log, thêm hoặc cập nhập các cấu hình trước khi request được sử lý bởi Controller, ...
Một trong các ứng dụng Spring MVC có sử dụng Interceptor là "Ứng dụng web đa ngôn ngữ". Bạn có thể xem thêm về ứng dụng này tại đây:
Class Interceptor của bạn cần phải thi hành interface org.springframework.web.servlet.HandlerInterceptor hoặc mở rộng từ class org.springframework.web.servlet.handler.HandlerInterceptorAdapter.
Bạn cần phải triển khai 3 phương thức trìu tượng:
  • public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
  • public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView)
  • public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
Chú ý: phương thức preHandle trả về true hoặc false. Nếu trả về true nghĩa là request sẽ tiếp tục đi tới đích của nó (Là một Controller) .
Một request có thể phải vượt qua nhiều Interceptor. Hình dưới đây minh họa điều đó.

2- Tạo Maven Project

  • File/New/Other..
  • Group Id: org.o7planning
  • Artifact Id: SpringMVCInterceptor
  • Package: org.o7planning.springmvcinterceptor
Project đã được tạo ra:
Đảm bảo bạn sử dụng Java >=6.
Project Properties:

3- Khai báo Maven và web.xml

Sử dụng Servlet >= 3.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
   
    <display-name>SpringMVCInterceptor</display-name>
   
</web-app>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">


<modelVersion>4.0.0</modelVersion>
<groupId>org.o7planning</groupId>
<artifactId>SpringMVCInterceptor</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>SpringMVCInterceptor Maven Webapp</name>
<url>http://maven.apache.org</url>


  <dependencies>
      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>3.8.1</version>
          <scope>test</scope>
      </dependency>


      <!-- Servlet API -->
      <!-- http://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>javax.servlet-api</artifactId>
          <version>3.1.0</version>
          <scope>provided</scope>
      </dependency>


      <!-- Jstl for jsp page -->
      <!-- http://mvnrepository.com/artifact/javax.servlet/jstl -->
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>jstl</artifactId>
          <version>1.2</version>
      </dependency>


      <!-- JSP API -->
      <!-- http://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
      <dependency>
          <groupId>javax.servlet.jsp</groupId>
          <artifactId>jsp-api</artifactId>
          <version>2.2</version>
          <scope>provided</scope>
      </dependency>



      <!-- Spring dependencies -->
      <!-- http://mvnrepository.com/artifact/org.springframework/spring-core -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>4.3.3.RELEASE</version>
      </dependency>

      <!-- http://mvnrepository.com/artifact/org.springframework/spring-web -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-web</artifactId>
          <version>4.3.3.RELEASE</version>
      </dependency>

      <!-- http://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-webmvc</artifactId>
          <version>4.3.3.RELEASE</version>
      </dependency>


  </dependencies>
 
 
  <build>
      <finalName>SpringMVCInterceptor</finalName>
      <plugins>

          <!-- Config: Maven Tomcat Plugin -->
          <!-- http://mvnrepository.com/artifact/org.apache.tomcat.maven/tomcat7-maven-plugin -->
          <plugin>
              <groupId>org.apache.tomcat.maven</groupId>
              <artifactId>tomcat7-maven-plugin</artifactId>
              <version>2.2</version>
            
              <!-- Config: contextPath and Port (Default - /SpringMVCInterceptor : 8080) -->
            
              <!--
              <configuration>
                  <path>/</path>
                  <port>8899</port>
              </configuration>
              -->
          </plugin>
      </plugins>
  </build>
 
</project>

4- Cấu hình Spring MVC

SpringWebAppInitializer.java
package org.o7planning.springmvcinterceptor.config;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

public class SpringWebAppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext();
        appContext.register(ApplicationContextConfig.class);

        ServletRegistration.Dynamic dispatcher = servletContext.addServlet("SpringDispatcher",
                new DispatcherServlet(appContext));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }

}
ApplicationContextConfig.java
package org.o7planning.springmvcinterceptor.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration

@ComponentScan("org.o7planning.springmvcinterceptor.*")
public class ApplicationContextConfig {

    @Bean(name = "viewResolver")
    public InternalResourceViewResolver getViewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();

        viewResolver.setPrefix("/WEB-INF/pages/");
        viewResolver.setSuffix(".jsp");

        return viewResolver;
    }
 
}
Các Interceptors sẽ được đăng ký với ứng dụng bởi class WebMvcConfig.
WebMvcConfig.java
package org.o7planning.springmvcinterceptor.config;

import org.o7planning.springmvcinterceptor.interceptor.AdminInterceptor;
import org.o7planning.springmvcinterceptor.interceptor.LogInterceptor;
import org.o7planning.springmvcinterceptor.interceptor.OldLoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {

 
   // Cấu hình để sử dụng các file nguồn tĩnh (html, image, ..)
   @Override
   public void addResourceHandlers(ResourceHandlerRegistry registry) {

   }

   @Override
   public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
       configurer.enable();
   }

   //
   @Override
   public void addInterceptors(InterceptorRegistry registry) {
   
       // LogInterceptor áp dụng cho mọi URL.
       registry.addInterceptor(new LogInterceptor());
 
       // Đường dẫn login cũ, không còn sử dụng nữa.
       // Sử dụng OldURLInterceptor để điều hướng tới một URL mới.
       registry.addInterceptor(new OldLoginInterceptor())//
               .addPathPatterns("/admin/oldLogin");

 
       // Interceptor này áp dụng cho các URL có dạng /admin/*
       // Loại đi trường hợp /admin/oldLogin
       registry.addInterceptor(new AdminInterceptor())//
               .addPathPatterns("/admin/*")//
               .excludePathPatterns("/admin/oldLogin");
   }

}

5- Interceptor classes

LogInterceptor được áp dụng cho mọi request đang tiến đến một Controller. (Xem cấu hình trong WebMvcConfig).
LogInterceptor.java
package org.o7planning.springmvcinterceptor.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class LogInterceptor extends HandlerInterceptorAdapter {

   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
           throws Exception {
       long startTime = System.currentTimeMillis();
       System.out.println("\n-------- LogInterception.preHandle --- ");
       System.out.println("Request URL: " + request.getRequestURL());
       System.out.println("Start Time: " + System.currentTimeMillis());

       request.setAttribute("startTime", startTime);
       
       return true;
   }

   @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
           ModelAndView modelAndView) throws Exception {
       System.out.println("\n-------- LogInterception.postHandle --- ");
       System.out.println("Request URL: " + request.getRequestURL());
 
       // Ở đây, bạn có thể add các attribute vào modelAndView
       // Và sử dụng nó trong các View (jsp,..)
   }

   @Override
   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
           throws Exception {
       System.out.println("\n-------- LogInterception.afterCompletion --- ");

       long startTime = (Long) request.getAttribute("startTime");
       long endTime = System.currentTimeMillis();
       System.out.println("Request URL: " + request.getRequestURL());
       System.out.println("End Time: " + endTime);

       System.out.println("Time Taken: " + (endTime - startTime));
   }

}
OldLoginInterceptor là một chốt chặn (interceptor), nếu người dùng nhập vào đường dẫn /admin/oldLogin nó sẽ chuyển hướng tới đường dẫn mới là /admin/login.
OldLoginInterceptor.java
package org.o7planning.springmvcinterceptor.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class OldLoginInterceptor extends HandlerInterceptorAdapter {

   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
           throws Exception {

       System.out.println("\n-------- OldLoginInterceptor.preHandle --- ");
       System.out.println("Request URL: " + request.getRequestURL());
       System.out.println("Sorry! This URL is no longer used, Redirect to /admin/login");
 
       response.sendRedirect(request.getContextPath()+"/admin/login");
       return false;
   }

   @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
           ModelAndView modelAndView) throws Exception {
     
  
       // Đoạn code này sẽ không được chạy.
       System.out.println("\n-------- OldLoginInterceptor.postHandle --- ");
   }

   @Override
   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
           throws Exception {
   
       // Đoạn code này sẽ không được chạy.      
       System.out.println("\n-------- QueryStringInterceptor.afterCompletion --- ");
   }

}
AdminInterceptor.java
package org.o7planning.springmvcinterceptor.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class AdminInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        System.out.println("\n-------- AdminInterceptor.preHandle --- ");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("\n-------- AdminInterceptor.postHandle --- ");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("\n-------- AdminInterceptor.afterCompletion --- ");
    }

}

6- Controllers

MainController.java
package org.o7planning.springmvcinterceptor.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class MainController {

  @RequestMapping(value = { "/", "/test" })
  public String test(Model model) {

      System.out.println("\n-------- MainController.test --- ");

      System.out.println(" ** You are in Controller ** ");

      return "test";
  }


  // Đường dẫn này không còn sử dụng nữa.
  // Nó sẽ bị chuyển hướng bởi OldLoginInterceptor
  @Deprecated
  @RequestMapping(value = { "/admin/oldLogin" })
  public String oldLogin(Model model) {

      // Code ở đây không bao giờ được chạy.

      return "oldLogin";
  }

  @RequestMapping(value = { "/admin/login" })
  public String login(Model model) {

      System.out.println("\n-------- MainController.login --- ");

      System.out.println(" ** You are in Controller ** ");

      return "login";
  }

}

7- Chạy ứng dụng

Chạy đường dẫn:
Và đây là Log xem trên màn hình Console:
Chạy URL:
Xem Log: