مثال على Spring MVC Interceptor HandlerInterceptorAdapter، HandlerInterceptor

المعاملات الربيعية تُستخدم لاعتراض طلبات العملاء ومعالجتها. في بعض الأحيان نرغب في التقاط طلب http والقيام ببعض المعالجة قبل تسليمه إلى أساليب معالج الوحدات التحكم. هنا تأتي معاملات spring mvc في المساعدة.

المعاملات الربيعية

تمامًا كما نملك معاملات struts2 ، يمكننا إنشاء معاملات spring الخاصة بنا سواء عن طريق تنفيذ واجهة org.springframework.web.servlet.handlerinterceptor أو عن طريق تجاوز الفئة الأساسية org.springframework.web.servlet.handler.handlerinterceptoradapter التي توفر التنفيذ الأساسي لواجهة handlerinterceptor.

معاملات الربيع – handlerinterceptor

تعلن handlerinterceptor في spring عن ثلاث طرق استنادًا إلى المكان الذي نرغب في اعتراض طلب http.

  1. boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler): يُستخدم هذا الأسلوب لالتقاط الطلب قبل تسليمه إلى أسلوب المعالج. يجب على هذا الأسلوب أن يعيد ‘true’ لإعلام Spring بمعالجة الطلب من خلال معقد آخر لـ Spring أو إرساله إلى أسلوب المعالج إذا لم يكن هناك معقدات Spring أخرى. إذا عاد هذا الأسلوب ‘false’، يفترض إطار العمل Spring أن الطلب قد تم معالجته بواسطة معقد Spring نفسه ولا حاجة إلى معالجة إضافية. يجب علينا استخدام كائن الاستجابة لإرسال الاستجابة إلى طلب العميل في هذه الحالة. كائن handler هو كائن المعالج المختار لمعالجة الطلب. يمكن لهذا الأسلوب أيضًا أن يُلقي استثناء، في هذه الحالة يجب أن يكون Manejo de Excepciones de Spring MVC مفيدًا لإرسال صفحة الخطأ كاستجابة.
  2. void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView): يُستدعى هذا الأسلوب التابع للمعقد HandlerInterceptor عندما يكون HandlerAdapter قد استدعى المعالج ولكن DispatcherServlet لم يقم بعرض العرض بعد. يمكن استخدام هذا الأسلوب لإضافة سمة إضافية إلى كائن ModelAndView لاستخدامه في صفحات العرض. يمكننا استخدام هذا الأسلوب المعقد لـ Spring لتحديد الوقت الذي يستغرقه أسلوب المعالج لمعالجة طلب العميل.
  3. الفراغ بعدالانتهاء(HttpServletRequest request، HttpServletResponse response، Object handler، Exception ex): هذه هي طريقة رد الاستدعاء لـ HandlerInterceptor والتي يتم استدعاؤها مرة واحدة يتم تنفيذ المعالج ويتم عرض الرأي.

إذا كان هناك عدة interceptors مكونة في Spring، يتم تنفيذ طريقة preHandle() بترتيب التكوين بينما يتم استدعاء طرق postHandle() و afterCompletion() بالترتيب العكسي. لنقم بإنشاء تطبيق بسيط لـ Spring MVC حيث سنقوم بتكوين Interceptor لتسجيل توقيتات طريقة معالجة تحكم الوحدة. سيبدو مثالنا النهائي لمشروع مثال Interceptor لـ Spring كالصورة أدناه، سننظر في العناصر التي نحن مهتمون بها.

Spring Interceptor – فئة التحكم

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);
		// إضافة بعض التأخير الزمني للتحقق من تنفيذ Interceptor
		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 Interceptor – تنفيذ HandlerInterceptorAdapter

للبساطة، أقوم بتوسيع الفئة المجردة HandlerInterceptorAdapter. HandlerInterceptorAdapter هي فئة محولة مجردة لواجهة HandlerInterceptor، لتبسيط تنفيذ معقد مسبق/بعدي فقط.

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());
		//يمكننا إضافة سمات في modelAndView واستخدام ذلك في صفحة العرض
	}

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

}

المنطق بسيط حقًا، أنا فقط أسجل توقيت تنفيذ طريقة المعالج والوقت الإجمالي المستغرق في معالجة الطلب بما في ذلك عرض صفحة العرض.

تكوين معياري لوسيط Spring MVC

علينا ربط معيار spring بالطلبات، يمكننا استخدام العنصر mvc:interceptors لربط جميع المعينات. يمكننا أيضًا توفير نمط URI للتطابق قبل تضمين معيار spring للطلب من خلال العنصر mapping. يبدو ملف تكوين شجرة الفاصل النهائية لدينا (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.

اختبار تطبيق معياري لوسيط Spring MVC

ما عليك سوى نشر التطبيق في حاوية servlet واستدعاء متحكم الصفحة الرئيسية، سترى إخراج المسجل شيئًا مثل ما يلي.

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

تؤكد الناتج أن طرق معوق الربيع تُنفذ بالترتيب المحدد. هذا كل شيء بالنسبة لاستخدام معوقات الربيع، يمكنك تنزيل مشروع مثال معوق الربيع من الرابط أدناه ومحاولة إضافة عدة معوقات والتحقق من ذلك باستخدام ترتيب مختلف للتكوين.

تنزيل مشروع معوقات الربيع

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