Trang chủHướng dẫnVí dụ về Spring MVC Interceptor: HandlerInterceptorAdapter, HandlerInterceptor
Chuyên gia

Ví dụ về Spring MVC Interceptor: HandlerInterceptorAdapter, HandlerInterceptor

CyStack blog 5 phút để đọc
CyStack blog25/08/2025
Locker Avatar

Bao Tran

Web Developer

Locker logo social
Reading Time: 5 minutes

Spring MVC Interceptor (Bộ chặn trong Spring) được dùng để chặn các yêu cầu từ máy khách và xử lý chúng. Đôi khi, chúng ta muốn chặn HTTP Request và thực hiện một số xử lý trước khi chuyển nó đến các phương thức xử lý của bộ điều khiển. Đó là lúc Spring MVC Interceptor phát huy tác dụng.

Spring MVC Interceptor

Spring MVC Interceptor

Chúng ta có thể tạo Spring Interceptor riêng bằng cách triển khai giao diện org.springframework.web.servlet.HandlerInterceptor hoặc bằng cách ghi đè lớp trừu tượng org.springframework.web.servlet.handler.HandlerInterceptorAdapter, lớp này cung cấp các cài đặt cơ bản của giao diện HandlerInterceptor. Cách này tương tự như việc chúng ta đã có các Struts2 Interceptor.

Spring MVC Interceptor – HandlerInterceptor

Spring HandlerInterceptor khai báo ba phương thức dựa trên vị trí mà chúng ta muốn chặn yêu cầu HTTP.

  1. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): Phương thức này được sử dụng để chặn yêu cầu trước khi nó được chuyển cho phương thức xử lý (handler method). Phương thức này nên trả về ‘true’ để Spring biết tiếp tục xử lý yêu cầu thông qua một Spring Interceptor khác hoặc gửi nó đến phương thức xử lý nếu không còn Spring Interceptor nào. Nếu phương thức này trả về ‘false’, Spring framework sẽ giả định rằng yêu cầu đã được Spring Interceptor tự xử lý và không cần xử lý thêm. Trong trường hợp này, chúng ta nên sử dụng đối tượng response để gửi phản hồi cho yêu cầu của máy khách. Đối tượng handler là đối tượng xử lý được chọn để xử lý yêu cầu. Phương thức này cũng có thể ném ra Exception, trong trường hợp đó Spring MVC Exception Handling sẽ hữu ích để gửi trang lỗi làm phản hồi.
  2. void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): Phương thức HandlerInterceptor này được gọi khi HandlerAdapter đã gọi handler nhưng DispatcherServlet vẫn chưa hiển thị view. Phương thức này có thể được sử dụng để thêm các thuộc tính bổ sung vào đối tượng ModelAndView để dùng trong các trang view. Chúng ta có thể dùng phương thức Spring Interceptor này để xác định thời gian mà handler method đã mất để xử lý yêu cầu của máy khách.
  3. void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): Đây là một callback method (phương thức gọi lại) của HandlerInterceptor được gọi khi handler đã được thực thi và view đã được hiển thị.

Nếu có nhiều Spring Interceptor được cấu hình, phương thức preHandle() sẽ được thực thi theo thứ tự cấu hình, trong khi các phương thức postHandle()afterCompletion() sẽ được gọi theo thứ tự ngược lại.

Hãy tạo một ứng dụng Spring MVC đơn giản, nơi chúng ta sẽ cấu hình một Spring Interceptor để ghi lại thời gian của phương thức xử lý (controller handler method). Dự án ví dụ Spring Interceptor cuối cùng của chúng ta sẽ trông giống như hình ảnh bên dưới, chúng ta sẽ xem xét các thành phần mà chúng ta quan tâm.

Spring MVC Interceptors Project

Spring Interceptor – Lớp Controller

package com.journaldev.spring;

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Handles requests for the application home page.
 */
@Controller
public class HomeController {

	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

	@RequestMapping(value = "/home", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		logger.info("Welcome home! The client locale is {}.", locale);
		//adding some time lag to check interceptor execution
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);

		String formattedDate = dateFormat.format(date);

		model.addAttribute("serverTime", formattedDate );
		logger.info("Before returning view page");
		return "home";
	}

}

Tôi chỉ thêm một chút thời gian xử lý vào việc thực thi handler method để kiểm tra các phương thức của spring interceptor của chúng ta hoạt động như thế nào.

Interceptor trong Spring MVC – Triển khai HandlerInterceptorAdapter

Để đơn giản, tôi sẽ mở rộng lớp trừu tượng HandlerInterceptorAdapter. HandlerInterceptorAdapter là lớp bộ chuyển đổi trừu tượng cho giao diện HandlerInterceptor, nhằm đơn giản hóa việc triển khai các bộ chặn chỉ có pre-only/post-only.

package com.journaldev.spring;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class RequestProcessingTimeInterceptor extends HandlerInterceptorAdapter {

	private static final Logger logger = LoggerFactory
			.getLogger(RequestProcessingTimeInterceptor.class);

	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		long startTime = System.currentTimeMillis();
		logger.info("Request URL::" + request.getRequestURL().toString()
				+ ":: Start Time=" + System.currentTimeMillis());
		request.setAttribute("startTime", startTime);
		//if returned false, we need to make sure 'response' is sent
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("Request URL::" + request.getRequestURL().toString()
				+ " Sent to Handler :: Current Time=" + System.currentTimeMillis());
		//we can add attributes in the modelAndView and use that in the view page
	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		long startTime = (Long) request.getAttribute("startTime");
		logger.info("Request URL::" + request.getRequestURL().toString()
				+ ":: End Time=" + System.currentTimeMillis());
		logger.info("Request URL::" + request.getRequestURL().toString()
				+ ":: Time Taken=" + (System.currentTimeMillis() - startTime));
	}

}

Logic ở đây rất đơn giản, tôi chỉ ghi lại thời gian thực thi của handler method và tổng thời gian cần để xử lý yêu cầu, bao gồm cả việc hiển thị trang xem.

Cấu hình Spring MVC Interceptor

Chúng ta phải kết nối spring interceptor với các yêu cầu. Chúng ta có thể sử dụng phần tử mvc:interceptors để kết nối tất cả các bộ chặn. Chúng ta cũng có thể cung cấp mẫu URI để so khớp trước khi thêm spring interceptor vào yêu cầu thông qua phần tử mapping. Tệp cấu hình spring bean cuối cùng của chúng ta (spring.xml) sẽ trông như dưới đây.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="<https://www.springframework.org/schema/mvc>"
	xmlns:xsi="<https://www.w3.org/2001/XMLSchema-instance>" xmlns:beans="<https://www.springframework.org/schema/beans>"
	xmlns:context="<https://www.springframework.org/schema/context>"
	xsi:schemaLocation="<https://www.springframework.org/schema/mvc> <https://www.springframework.org/schema/mvc/spring-mvc.xsd>
		<https://www.springframework.org/schema/beans> <https://www.springframework.org/schema/beans/spring-beans.xsd>
		<https://www.springframework.org/schema/context> <https://www.springframework.org/schema/context/spring-context.xsd>">

	<!-- DispatcherServlet Context: defines this servlet's request-processing
		infrastructure -->

	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving
		up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources
		in the /WEB-INF/views directory -->
	<beans:bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>

	<!-- Configuring interceptors based on URI -->
	<interceptors>
		<interceptor>
			<mapping path="/home" />
			<beans:bean class="com.journaldev.spring.RequestProcessingTimeInterceptor"></beans:bean>
		</interceptor>
	</interceptors>

	<context:component-scan base-package="com.journaldev.spring" />

</beans:beans>

Tôi sẽ không giải thích tất cả các thành phần khác của ứng dụng web, bởi vì chúng ta không quan tâm đến chúng và chúng không có bất kỳ cấu hình nào liên quan đến spring interceptor cụ thể.

Kiểm tra ứng dụng Spring MVC Interceptor

Chỉ cần triển khai ứng dụng vào vùng chứa servlet và gọi bộ điều khiển home, bạn sẽ thấy kết quả đầu ra của bộ ghi (logger output) tương tự như dưới đây.

INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::<https://localhost:9090/SpringInterceptors/home::> Start Time=1396906442086
INFO : com.journaldev.spring.HomeController - Welcome home! The client locale is en_US.
INFO : com.journaldev.spring.HomeController - Before returning view page
Request URL::<https://localhost:9090/SpringInterceptors/home> Sent to Handler :: Current Time=1396906443098
INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::<https://localhost:9090/SpringInterceptors/home::> End Time=1396906443171
INFO : com.journaldev.spring.RequestProcessingTimeInterceptor - Request URL::<https://localhost:9090/SpringInterceptors/home::> Time Taken=1085

Kết quả đầu ra xác nhận rằng các phương thức của spring interceptor được thực thi theo thứ tự đã được định nghĩa. Đó là tất cả về cách sử dụng các bộ chặn trong Spring. Bạn có thể tải dự án ví dụ về Spring Interceptor từ liên kết bên dưới và thử tạo nhiều bộ chặn khác nhau, sau đó kiểm tra chúng với các thứ tự cấu hình khác nhau.

Tải xuống Dự án Spring Interceptors

0 Bình luận

Đăng nhập để thảo luận

Chuyên mục Hướng dẫn

Tổng hợp các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.

Đăng ký nhận bản tin của chúng tôi

Hãy trở thành người nhận được các nội dung hữu ích của CyStack sớm nhất

Xem chính sách của chúng tôi Chính sách bảo mật.

Đăng ký nhận Newsletter

Nhận các nội dung hữu ích mới nhất