ModelAndView و ViewResolvers – Spring MVC

چارچوب Spring MVC بر اساس مفهوم handler (کنترلر)هایی ساخته شده است که اشیائی از نوع org.springframework.web.servlet.ModelAndView بر می گردانند. نوع ModelAndView با توجه به محتوای قابل ذخیره در آن نام گذاری شده است؛ view با در دست داشتن یک مدل، باید قادر باشد یک پاسخ مناسب تولید کرده و آن را برای مشتری ارسال کند.

منظور از مدل، یک map، شامل کلیدهای (رشته های) نگاشت شده به مقادیر واقعی است. در زمان رندر کردن view، مقادیر map با توجه به تکنولوژی view استفاده شده در دسترس خواهند بود (به عنوان مثال، در زمان استفاده از Velocity درون VelocityContext و یا در زمان استفاده از JSP درون بستر درخواست قرار می گیرند).

کنترل یک درخواست باید به یک نمونه از ModelAndView منجر شود. DispatcherServlet می داند که چگونه از شی ModelAndView استفاده کند. این شئ در پایان کار، به یک نمونه از org.springframework.web.servlet.View نیاز خواهد داشت تا مسئولیت رندر کردن view را به آن بسپارد. برای مثال، می تواند از یک نمونه از تمپلیت های JSP و یا Velocity استفاده کند. برای ساختن یک شئ از نوع ModelAndView، می توان یکی از دو روش استفاده از شئ view و یا استفاده از یک نام منطقی را انتخاب کرد. برای به دست آوردن یک شئ واقعی از یک نام منطقی view، به یک نمونه از org.springframework.web.servlet.view.ViewResolver نیاز است. ViewResolverها وظیفه مدیریت و نگاشت بین نام منطقی viewها و همتایان واقعی شان را دارند. پیاده سازی های مختلف اینترفیس ViewResolver رفتار های مختلفی را در چگونگی نگاشت فراهم می کنند.

یک ViewResolver در تمام مولفه های دیگر مرتبط با وب، به صورت مشابه عمل می کند. به عنوان مثال، نیاز است حضور این شی در بستر برنامه وب اعلام شده و به طور خودکار توسط Spring استفاده شود. اجازه دهید با هم نگاهی به برخی از انواع ViewResolverهای فراهم شده توسط Spring بیاندازیم.

UrlBasedViewResolver

نام های منطقی view توسط یک نمونه از org.springframework.web.servlet.view.UrlBasedViewResolver، به طور مستقیم به URL تبدیل شده و برای شئ view ایجاد شده ارسال می شوند. شئ view نیز با توجه به این URL، پاسخ را رندر می کند. به عنوان مثال، URL می تواند به JavaServer Page، Velocity، و یا XSLT Style Sheet اشاره کند. UrlBasedViewResolver را می توان به شکل های مختلفی تنظیم کرد. ابتدا نیاز است یک کلاس view مشخص شود. کلاس view در نهایت کار، view مورد نظر ما را (JSP, Velocity) رندر می کند. روش تعریف URLها را می توان با استفاده از یک پیشوند و پسوند مشخص کرد.

UrlBasedViewResolver به دو صورت InternalResourceViewResolver و VelocityViewResolver پیاده سازی شده است. بین این دو حالت تفاوت های جزئی وجود دارد. مبدلی که معمولا مورد استفاده قرار می گیرد InternalResourceViewResolver بوده که نمونه پیاده سازی شده InternalResourceView است، اما می توان آن را به نحو دیگری پیاده سازی کرد. VelocityViewResolver برخی خواص Velocity را بر روی تمامی view اعمال می کند، اما این اجازه را نیز می دهد که آنها را بر اساس نیاز خود تغییر دهید. این خواص عبارتند از NumberTool و DateTool، که اجازه تغییر آسان قالب بندی اعداد و تاریخ را می دهند.

یک مثال:

 

در این مثال نام view منطقی “welcome” به WEB-INF/jsps/welcome.jsp/ نگاشت می شود. کلاس JstlView استفاده شده، یک نمونه از استاندارد کتابخانه برچسب های جاوا را به بستر درخواست متصل خواهد کرد.

BeanNameViewResolver و XmlViewResolver

org.springframework.web.servlet.view.BeanNameViewResolver و org.springframework.web.servlet.view.XmlViewResolver  قابلیت های لازم را برای بازیابی view از یک BeanFactory را به وجود آورده اند. دومین کلاس، از یک BeanFactory استفاده می کند که به viewهایی اختصاص دارد که هنگامی که تولید می شوند برای بقیه از برنامه قابل مشاهده نیستند. BeanNameViewResolver تنها بر روی BeanFactory ای درخواست می فرستد که در آن اعلان شده است.

یک مثال:

 

فرض کنید شما از پیکربندی مشخص شده استفاده می کنید. پس از بازگرداندن welcome به عنوان نام view منطقی، BeanNameViewResolver شئ view مورد نظر را از بستر برنامه بازیابی و از آن برای رندر کردن JSP استفاده خواهد کرد.

همانطور که بالاتر گفته شد، XmlViewResolver اساسا رفتار مشابه ولی با یک تفاوت را دارد: یک BeanFactory که برای نگهداری viewها در نظر گرفته شده، ابتدا مقداردهی اولیه می شود و سپس در زمانی که یک view مورد نیاز باشد مورد استفاده قرار می گیرد. این به این معنی است که شما باید beanهای مورد نیاز خود را در یک فایل جداگانه، مانند WEBINF/views/views.xml/ اعلان کرده و آن را به صورت زیر به XmlViewResolver متصل کنید:

 

 

ResourceBundleViewResolver

رفتار org.springframework.web.servlet.view.ResourceBundleViewResolver شبیه XmlViewResolver است، اما زمانی که از مورد اول استفاده می کنیم، فایل های منابع حاوی تعاریف beanها به جای فایل های XML استفاده می شود. ResourceBundleViewResolver اجازه می دهد تا viewها برای اساس منطقه جغرافیایی و زبان مشخص شده در درخواست کاربر فراخوانی شوند.

 

نمونه کد قبلی دو فایل property را نشان می دهد که در یکی از آنها سه view قرار دارد و در دومی یک view برای یک زبان خاص، تغییر مقدار پیدا کرده است. توجه داشته باشید که بهتر است به جای ارائه JSPهای جداگانه، با استفاده از برچسب ها محلی سازی JSTL یا برچسب message به محلی سازی آنها بپردازیم. به هر حال برای نشان دادن رفتار ResourceBundleViewResolver، در اینجا نمونه ای، قرار گرفت.

پس از راه اندازی، ViewResolver فایل های منابع را، بازگزاری می کند. View مورد نظر بر اساس مکان و زبان مشخص شده در درخواست معین خواهد شد. به همراه تعریف beanها در viewResolver، یک defaultParentView وجود دارد. از آنجا که مشخص کردن کلاس view در هر یک از viewهایی که باید تعریف شود می تواند آزار دهنده باشد، defaultParentView برای تعیین مقادیر تعیین نشده (مانند کلاس view) مورد استفاده قرار می گیرد. سربار گذاری این تابع نیز ممکن است.

Spring با انواع فن آوری های view مجتمع شده است، که برخی از آنها نیاز به یک ViewResolver خاص دارد.

زنجیره ای از Resolverها

در حالی که یک view resolver در اکثر موارد کفایت می کند، Spring امکان استفاده از زنجیره ای از resolverها را فراهم کرده است. زنجیره ای از view resolver زمانی ایده آل است که شما می خواهید امکان جایگزین کردن داشته باشد، پشتیبانی از فن آوری های مختلف view داشته باشید، و یا قالب های خود را در مکان های مختلف ذخیره کرده باشید.

قرارداد درون Spring برای زنجیره ای از view resolverها به این صورت است که اگر یک view resolver، مقدار null را از متد resolveViewName() برگرداند، آنگاه از view resolver بعدی استفاده شود.

قبل از اینکه مثالی را از چگونگی ایجاد زنجیره view resolverها ببینید، به این نکته توجه کنید که برخی از view resolverها تلاش می کنند نام view مورد نظر را به آدرس تبدیل کنند و در مورد این که این منبع موجود است اطلاعی ندارند. این مورد برای تمام view resolverهایی است که کنترل را به یک موتور یا مکانیزم دیگری می دهند که به view resolver در مورد وجود یک منبع اطلاع نمی دهد. به طور خاص، این مورد برای تمام UrlBasedViewResolverها صادق است: InternalResourceViewResolver، FreeMarkerViewResolver و VelocityViewResolver. در نتیجه، این view resolverها همیشه باید در زنجیره، آخرین مورد باشند.

سربارگزاری یک view خاص

مثال زیر نشان میدهد که چگونه از دو view resolver استفاده کنیم. از این دو نوع، یکی بر اساس نام beanها و دیگری بر اساس فایل های منابع داخلی عمل می کند. این مثال نشان می دهد که چگونه یک view را سربارگزاری کرد. در این مورد، ما می خواهیم نتایج یک درخواست خاص را، به جای نمایش در یک صفحه HTML تولید شده توسط یک JSP، در یک فایل Excel نشان دهیم.

 

ما باید ترتیب را مشخص کنیم، زیرا DispatcherServlet نمی داند که ما به چه ترتیب می خواهیم از view resolverها استفاده شود. DispatcherServlet تمام view resolverها را تشخیص داده و آنها را بر اساس اینترفیس org.springframework.core.Ordered مرتب می کند، سپس آن ها را به ترتیب فراخوانی می کند. در این مورد، در صورتی که نام view برابر listShows باشد، BeanNameViewResolver باعث می شود Excel view رندر شود و در غیر این صورت، JSP رندر شود.

غیر فعال کردن زنجیره view resolver

ممکن است شرایطی به وجود آید که در آن کاربر، یک کنترلر تولید کرده که ViewResolver را نیز درون خود پیاده سازی کند. در حالی که این سوال وجود دارد که چرا اتفاق می تواند رخ دهد، Spring امکانی را برای غیر فعال کردن زنجیره view resolverها را برای این مورد فراهم کرده است. زنجیره سازی، تأثیر منفی بر روی عملکرد ندارد، بنابراین اگر شما نیاز به غیر فعال کردن آن ندارید، می توانید تنظیمات را به صورت پیش فرض رها کنید.

در صورتی که بخواهید زنجیره را غیر فعال کنید در فایل web.xml، قطعه کد زیر را وارد کنید:

 

 

در صورت نیاز می توانید به همین روش تشخیص HandlerMappingهای متعدد و HandlerExceptionResolverهای متعدد را غیر فعال کنید. برای این کار فقط باید پارامتر دهی اولیه را با مقادیر مناسب وارد کنید. برای resolverهای استثنا، مقدار detectAllHandlerExceptionResolvers و برای HandlerMappings، مقدار detectAllViewResolvers را برابر false قرار دهید. اگر شما مقدار پارامتر تشخیص چندین مولفه با نوع مشابه را برابر false کنید، در این صورت نیاز خواهید داشت نام beanها را مشخص کنید تا از این طریق به Spring بگویید کدام یک از تعاریف bean، نشان دهنده آن موردی است که شما مایل به استفاده از آن هستید.

تاکید می شود که در بیشتر مواقع شما به تغییر تنظیمات پیش فرض، که برای شناسایی تمام مولفه های هم نوع در دسترس است، نیاز ندارید. انعطاف پذیری Spring MVC به این معنی نیست که شما همیشه نیازمند به استفاده از تمام گزینه های ارائه شده باشید.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *