Spring MVC מפנה HandlerInterceptorAdapter, משל HandlerInterceptor

בין אם מדובר ב-

אינטרספטור של Spring

המיועד להפריע בבקשות הלקוח ולעבדן, או בכך שרוצים להפריע בבקשת HTTP ולבצע עיבוד לפני שהיא מועברת למתקשר הפעולות של הטופס (Controller handler methods), האינטרספטור של Spring MVC מסייע.

אינטרספטור של Spring – HandlerInterceptor

הַאִינטֶרְסֶפְטּוֹר של Spring HandlerInterceptor מצהיר על שלושה מתודות בהתאם למקום בו רוצים להפריע בבקשת HTTP.

  1. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): ‫‪שיטה זו משמשת להתערבות בבקשה לפני שהיא מועברת לשיטת הטיפול. יש להחזיר 'true' כדי לאפשר ל־Spring לעבד את הבקשה דרך מתערב נוסף של Spring או לשלוח אותה לשיטת הטיפול אם אין מתערבים נוספים של Spring. אם השיטה מחזירה 'false', מערכת ה־Spring מניחה כי הבקשה טופלה על ידי מתערב ה־Spring עצמו ואין צורך בעיבוד נוסף. עלינו להשתמש באובייקט התגובה כדי לשלוח תגובה לבקשת הלקוח במקרה זה. אובייקט handler הוא אובייקט הטיפול שנבחר לטפל בבקשה. גם יכול להתגרות בחריגה, במקרה זה יש להשתמש ב־טיפול בחריגות ב־Spring MVC כדי לשלוח עמוד שגיאה כתגובה.
  2. void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): ‫‪שיטת מתערב של HandlerInterceptor זו נקראת כאשר HandlerAdapter קרא למטפל אך DispatcherServlet עדיין לא עשה רנדום לתצוגת הנוף. ניתן להשתמש בשיטה זו כדי להוסיף מאפיין נוסף לאובייקט ModelAndView כדי לשימוש בעמודי התצוגה. ניתן להשתמש בשיטת מתערב זו של Spring כדי לקבוע את הזמן שנדרש לשיטת הטיפול לעבד את בקשת הלקוח.
  3. void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex): זהו שיטת קריאת חזרה של HandlerInterceptor שנקראת לאחר שהמטפל בוצע והתצוגה נמצאת.

אם ישנם מספר של Interceptors של Spring מוגדרים, שיטת preHandle() מתבצעת לפי סדר התצורה בעוד ששיטות postHandle() ו-afterCompletion() מופעלות בסדר הפוך. בואו ניצור אפליקציה פשוטה של Spring MVC בה נקבע מתקן Spring לרישום של זמני ניתוב של שיטת המטפל של הבקר. פרויקט הדוגמה של המתקן Spring הסופי שלנו יראה כמו בתמונה למטה, ונסתכל על הרכיבים שאנו מתעניינים בהם.

מתקן Spring – מחלקת הבקר

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);
		//הוספת קישור זמן מסוים כדי לבדוק את ביצועי המתקן
		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";
	}
	
}

I am just adding some processing time in the execution of the handler method to check our spring interceptor methods in action.

מתקן Spring MVC – מימוש HandlerInterceptorAdapter

עבור פשטות, אני מרחיב על מחלקת המופע המופשטת HandlerInterceptorAdapter. HandlerInterceptorAdapter הוא מחלקת אדפטור אבסטרקטית עבור ממשק HandlerInterceptor, ליישום פשוט של interceptors של פונקציות יד/אחרי בלבד.

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);
		//אם יוחזר false, אנו צריכים לוודא שהתשובה נשלחה
		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());
		//נוכל להוסיף מאפיינים במודל-תצורה ולהשתמש בהם בדף התצוגה
	}

	@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));
	}

}

הלוגיקה היא ממש פשוטה, אני רק מקליט את זמני ביצוע של שיטת הטפל ואת הזמן הכולל הדרוש לעיבוד הבקשה כולל דף התצוגה.

תצורת Interceptor של Spring MVC

עלינו לחבר את Interceptor של Spring לבקשות, נוכל להשתמש באלמנט mvc:interceptors לחיבור כל ה-interceptors. נוכל גם לספק דפוס URI להתאמה לפני כלולת ה-interceptor של Spring לבקשה דרך אלמנט mapping. קובץ תצורת ה-Bean של Spring שלנו (spring.xml) נראה כמו שמתואר למטה.

<?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>

I will not explain all other components of the web application, because we are not interested in them and they don’t have any specific spring interceptor related configuration.

בדיקות בישול Interceptor של Spring MVC

פשוט הפעילו את היישום בתכונת הטפל וקראו לבקרת הבית, תראו פלט של לוגר דומה למה שמתואר למעלה.

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

הפלט מאשר כי שיטות האינטרספטור של הקפיץ מתבצעות בסדר המוגדר. זהו הכל לשימוש באינטרספטורים של Spring, תוכל להוריד את פרויקט הדוגמה של Spring Interceptor מהקישור למטה ולנסות להשתמש במספר אינטרספטורים ולבדוק באמצעות שינוי של סדר ההגדרה.

הורד פרויקט אינטרספטורים של Spring

Source:
https://www.digitalocean.com/community/tutorials/spring-mvc-interceptor-example-handlerinterceptor-handlerinterceptoradapter