天天看點

《Spring 5 官方文檔》18. Web MVC 架構

《Spring 5 官方文檔》18. Web MVC 架構

原文連結 譯者:dan

18.1  Spring Web MVC 架構的介紹

Spring Web模型視圖控制器(MVC)架構是圍繞一個DispatcherServlet設計的,它将請求分派給處理程式,具有可配置的處理程式映射,視圖解析,區域設定,本地化和主題解析,并且支援上傳檔案。預設的處理是基于注解

@Controller

@RequestMapping,提供一系列靈活的處理方法。随着Spring 3.0的推出,通過@PathVariable或者其他注解,

@Controller

機制開始允許你去建立 Rest風格的web站點和應用。

在Spring Web MVC 和 Spring中一條關鍵的準則是“對擴充開放,對修改關閉”

在Spring Web MVC中一些核心類的方法被标注為final,由于開發者不能用自已的方法去覆寫這些方法,這并不是任意的,而是特别考慮到這個原則。

對于這個準則的解釋,請參考Seth Ladd的Expert Spring Web MVC和Web Flow; 具體參見第一版第117頁的“A Look At Design”一節。 或者參見

Bob Martin, The Open-Closed Principle (PDF)

當你使用Spring MVC時,你不能在final方法增加切面。例如,你不能在AbstractController.setSynchronizeOnSession()增加切面,有關AOP 代理的更多資訊以及為什麼不能再Final方法增加切面,檢視第7.6.1節“了解AOP代理”。

在Spring Web MVC中,您可以使用任何對象作為指令或表單支援對象;你不需要實作一個特别架構接口或者基類。Spring資料綁定非常靈活:例如,你可以使用程式将類型不比對當作驗證錯誤而不是系統錯誤。 是以,您不需要将您的業務對象的屬性複制為簡單的無格式的字元串,僅用于處理無效送出,或者正确轉換字元串。 相反,通常最好直接綁定到您的業務對象。

Spring 的視圖處理也是相當靈活,控制器通常負責準備具有資料和選擇視圖名稱的模型映射,但它也可以直接寫入響應流并完成請求。視圖名稱解析可通過檔案擴充或Accept标頭内容類型協商進行高度配置,通過bean名稱,屬性檔案或甚至自定義的ViewResolver實作。模型(MVC中的M)是一個Map接口,可以完全提取視圖技術,你可以直接與基于模闆的渲染技術(如JSP和FreeMarker)內建,或直接生成XML,JSON,Atom和許多其他類型的内容。 模型Map可以簡單地轉換成适當的格式,如JSP請求屬性或FreeMarker模闆模型。

18.1.1 Spring Web MVC的特點

Spring Web 流程

Spring Web 流程 (SWF)的目的是成為最好的Web頁面應用流程管理方案,SWF與Servlet 和Portlet 環境中的Spring MVC和JSF等現有架構內建。如果你有一個這樣的業務流程,使用會話模型比純粹的請求要優,那麼SWF可能是一個選擇。

SWF允許您将邏輯頁面流作為在不同情況下可重用的自包含子產品捕獲,是以非常适合建構引導使用者通過驅動業務流程的受控導航的Web應用程式子產品。

更多關于SWF的資訊,請點選Spring Web Flow website.

Spring 的Web子產品包含許多獨特的web支援特性:

  • 明确并分離的角色.每個角色-控制器,驗證器,指令對象,建構對象,模型對象,分發器,映射處理器,視圖解析等等都是完全的一個特定對象
  • 架構和應用程式類作為JavaBeans的強大而直接的配置。 此配置功能包括跨上下文的簡單引用,例如從Web控制器到業務對象和驗證器。
  • 可适配,無入侵,靈活,定義您需要的任何控制器方法簽名,可能使用給定方案的參數注釋之一(例如@RequestParam,@RequestHeader,@PathVariable等)。
  • 可重用的業務代碼,不需要重複,使用現有的業務對象作為指令或表單對象,而不是仿照它們來擴充特定的架構基類。
  • 自定義綁定和驗證,類型不比對作為應用程式級驗證錯誤,保持違規值,本地化日期和數字綁定等,而不是隻使用僅包含字元串的表單對象進行手動解析和轉換為業務對象。
  • 自定義的處理程式映射和視圖解析,從簡單的URL配置政策到複雜的,特制的政策,Spring比Web MVC架構更靈活,這些架構需要特定的技術。
  • 靈活的模型轉換,具有名稱/值的模型傳輸Map支援與任何視圖技術的輕松內建。
  • 本地,時區,主題自定義,支援具有或不具有Spring标簽庫的JSP,支援JSTL,支援FreeMarker而不需要額外的網橋等等。
  • 一個簡單而強大的JSP标簽庫,被稱為Spring标簽庫,為資料綁定和主題等功能提供支援。 自定義标簽允許在标記代碼方面具有最大的靈活性。 有關标簽庫描述符的資訊,請參見附錄Chapter 40, spring JSP Tag Library
  • 在Spring 2.0中引入的JSP表單标簽庫,使得在JSP頁面中的寫入表單更容易。 有關标簽庫描述符的資訊,請參見附錄Chapter 41, spring-form JSP Tag Library
  • Bean的生命周期範圍限定在目前的HTTP請求或HTTP Session中。 這不是Spring MVC本身的一個特定功能,而是Spring MVC使用的WebApplicationContext容器。 這些bean範圍在Section 3.5.4, “Request, session, application, and WebSocket scopes”

18.1.2 其他MVC實作的可插拔性

對于某些項目,非Spring MVC實作更為可取。許多團隊希望利用他們現有的技能和工具投資,例如使用JSF。

如果您不想使用Spring的Web MVC,但打算利用Spring提供的其他解決方案,您可以輕松地将您選擇的Web MVC架構與Spring內建。通過其ContextLoaderListener簡單地啟動一個Spring根應用程式上下文,并通過任何動作對象中的ServletContext屬性(或Spring的各自的幫助方法)通路它。沒有涉及“插件”,是以不需要專門的內建。從Web層的角度來看,您隻需使用Spring作為庫,将根應用程式上下文執行個體作為入口點。

即使沒有Spring的Web MVC,您的注冊bean和Spring的服務也可以在您的指尖。在這種情況下,Spring不會與其他Web架構競争。它簡單地解決了純Web MVC架構從bean配置到資料通路和事務處理的許多方面。是以您可以使用Spring中間層和/或資料通路層來豐富您的應用程式,即使您隻想使用JDBC或Hibernate的事務抽象。

18.2 分發

Spring的Web MVC架構與許多其他Web MVC架構一樣,以請求為驅動,圍繞一個中央Servlet設計,将請求發送給控制器,并提供了其他促進Web應用程式開發的功能。然而, Spring 的

DispatcherServlet

 做得更多.它和 Spring IoC 容器整合一起,它允許你使用Spring 每個特性.

Spring Web MVC DispatcherServlet的請求處理工作流程如下圖所示。 對設計模式熟悉的讀者将會認識到,DispatcherServlet是“前端控制器”設計模式的表達(這是Spring Web MVC與許多其他領先的Web架構共享的模式)。

下圖,在Spring Web MVC 中請求處理流程

《Spring 5 官方文檔》18. Web MVC 架構

DispatcherServlet是一個實際的Servlet(它繼承自HttpServlet基類),是以在Web應用程式中被聲明。 您需要使用URL映射來映射要DispatcherServlet處理的請求。 以下是Servlet 3.0+環境中的标準Java EE Servlet配置:

public class MyWebApplicationInitializer implements WebApplicationInitializer {
 @Override
 public void onStartup(ServletContext container) {
 ServletRegistration.Dynamic registration = container.addServlet("example", new DispatcherServlet());
 registration.setLoadOnStartup(1);
 registration.addMapping("/example/*");
 }
 }
 
           

在前面的示例中,以/ example開頭的所有請求都将由名為Example的DispatcherServlet執行個體處理。

WebApplicationInitializer是由Spring MVC提供的接口,可確定您的基于代碼的配置被檢測并自動用于初始化任何Servlet 3容器。這個名為AbstractAnnotationConfigDispatcherServletInitializer的接口的抽象基類實作通過簡單地指定其servlet映射和列出配置類來更容易地注冊DispatcherServlet,甚至建議您設定Spring MVC應用程式。有關更多詳細資訊,請參閱基于代碼的Servlet容器初始化。

DispatcherServlet是一個實際的Servlet(它繼承自HttpServlet基類),是以在Web應用程式的web.xml中聲明。您需要通過使用同一web.xml檔案中的URL映射來映射要DispatcherServlet處理的請求。這是标準的Java EE Servlet配置;以下示例顯示了這樣的DispatcherServlet聲明和映射:

<web-app>
	<servlet>
		<servlet-name>example</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>example</servlet-name>
		<url-pattern>/example/*</url-pattern>
	</servlet-mapping>

</web-app>      

如第3.15節“ApplicationContext的附加功能”中所述,Spring中的ApplicationContext執行個體可以被限定。 在Web MVC架構中,每個DispatcherServlet都有自己的WebApplicationContext,它繼承了已經在根WebApplicationContext中定義的所有bean。 根WebApplicationContext應該包含應該在其他上下文和Servlet執行個體之間共享的所有基礎架構bean。 這些繼承的bean可以在特定于servlet的範圍内被覆寫,您可以在給定的Servlet執行個體本地定義新的範圍特定的bean。

18.2. Spring Web MVC中的典型上下文層次結構

《Spring 5 官方文檔》18. Web MVC 架構

在初始化DispatcherServlet時,Spring MVC将在Web應用程式的WEB-INF目錄中查找名為[servlet-name] -servlet.xml的檔案,并建立在那裡定義的bean,覆寫使用相同名稱定義的任何bean的定義 在全球範圍内。 請考慮以下DispatcherServlet Servlet配置(在web.xml檔案中):

<web-app>
	<servlet>
		<servlet-name>golfing</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>golfing</servlet-name>
		<url-pattern>/golfing/*</url-pattern>
	</servlet-mapping>
</web-app>      

使用上述Servlet配置,您将需要在應用程式中有一個名為/WEB-INF/golfing-servlet.xml的檔案; 該檔案将包含您所有的Spring Web MVC特定元件(bean)。 您可以通過Servlet初始化參數更改此配置檔案的确切位置(有關詳細資訊,請參閱下文)。 單個DispatcherServlet方案也可能隻有一個根上下文。

《Spring 5 官方文檔》18. Web MVC 架構

這可以通過設定一個空的ContextConfigLocation servlet init參數進行配置,如下所示:

<web-app>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/root-context.xml</param-value>
	</context-param>
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value></param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app>      

WebApplicationContext是普通ApplicationContext的擴充,它具有Web應用程式所需的一些額外功能。 它與正常的ApplicationContext不同之處在于它能夠解析主題(參見第18.9節“使用主題”),并且知道它與哪個Servlet相關聯(通過連接配接到ServletContext)。 WebApplicationContext綁定在ServletContext中,并且通過在RequestContextUtils類上使用靜态方法,您可以随時查找WebApplicationContext,如果您需要通路它。 請注意,我們可以通過基于Java的配置實作相同的方式:

public class GolfingWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
           
@Override
 protected Class<?>[] getRootConfigClasses() {
 // GolfingAppConfig defines beans that would be in root-context.xml
 return new Class[] { GolfingAppConfig.class };
 }      
@Override
 protected Class<?>[] getServletConfigClasses() {
 // GolfingWebConfig defines beans that would be in golfing-servlet.xml
 return new Class[] { GolfingWebConfig.class };
 }      
@Override
 protected String[] getServletMappings() {
 return new String[] { "/golfing/*" };
 }      
}      

18.2.1 WebApplicationContext中的特殊Bean類型

Spring DispatcherServlet使用特殊的bean來處理請求并呈現适當的視圖。 這些bean是Spring MVC的一部分。 您可以通過在WebApplicationContext中簡單配置一個或多個選擇要使用的特殊bean。 但是,您最初不需要這樣做,因為Spring MVC維護一個預設bean清單,如果您沒有配置任何内容。 更多的在下一節。 首先看下表列出DispatcherServlet依賴的特殊bean類型。

表18.1. 在 WebApplicationContext中的特殊bean類型

Bean type Explanation
HandlerMapping 根據一些标準将傳入的請求映射到處理程式和前處理程式和後處理程式清單(處理程式攔截器),其細節由HandlerMapping實作而異。 最流行的實作支援注釋控制器,但其他實作也存在。
HandlerAdapter 幫助DispatcherServlet調用映射到請求的處理程式,而不管實際調用哪個處理程式。 例如,調用帶注釋的控制器需要解析各種注釋。 是以,HandlerAdapter的主要目的是屏蔽DispatcherServlet和這些細節
HandlerExceptionResolver 映射視圖的異常,也允許更複雜的異常處理代碼。
ViewResolver 将基于邏輯字元串的視圖名稱解析為實際的View類型。
LocaleResolver & LocaleContextResolver 解決用戶端正在使用的區域設定以及可能的時區,以便能夠提供國際化的視圖
ThemeResolver 解決您的Web應用程式可以使用的主題,例如,提供個性化的布局
MultipartResolver 解析multi-part請求,以支援從HTML表單處理檔案上傳。
FlashMapManager 存儲并檢索可以用于将屬性從一個請求傳遞到另一個請求的“輸入”和“輸出”FlashMap,通常是通過重定向。

18.2.2 預設DispatcherServlet 配置

如上一節中針對每個特殊bean所述,DispatcherServlet會維護預設使用的實作清單。此資訊儲存在包org.springframework.web.servlet中的檔案DispatcherServlet.properties中。

所有特殊豆都有一些合理的預設值。不久之後,您将需要自定義這些bean提供的一個或多個屬性。例如,将InternalResourceViewResolver設定的字首屬性配置為視圖檔案的父位置是很常見的。

無論細節如何,在這裡了解的重要概念是,一旦您在WebApplicationContext中配置了一個特殊的bean(如InternalResourceViewResolver),您可以有效地覆寫該特殊bean類型所使用的預設實作清單。例如,如果配置了InternalResourceViewResolver,則會忽略ViewResolver實作的預設清單。

在第18.16節“配置Spring MVC”中,您将了解配置Spring MVC的其他選項,包括MVC Java配置和MVC XML命名空間,這兩者都提供了一個簡單的起點,并且對Spring MVC的工作原理幾乎不了解。無論您如何選擇配置應用程式,本節中介紹的概念都是基礎的,應該對您有所幫助。

18.2.3 DispatcherServlet 處理序列

在您設定了DispatcherServlet并且針對該特定DispatcherServlet啟動了一個請求後,DispatcherServlet将按如下所示開始處理請求:

在請求中搜尋并綁定WebApplicationContext作為控件和程序中的其他元素可以使用的屬性。預設情況下,它将在DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE鍵下綁定。

語言環境解析器被綁定到請求,以使程序中的元素能夠解決在處理請求時使用的區域設定(渲染視圖,準備資料等)。如果您不需要語言環境解析,則不需要它。

主題解析器被綁定到使得諸如視圖之類的元素确定要使用哪個主題的請求。如果不使用主題,可以忽略它。

如果指定了多部分檔案解析器,則會檢查該請求的多部分;如果找到多部分,則請求被包裝在一個MultipartHttpServletRequest中,以便程序中的其他元素進一步處理。有關多部分處理的更多資訊,請參見第18.10節“Spring的多部分(檔案上傳)支援”。

搜尋适當的處理程式。如果找到處理程式,則執行與處理程式(預處理程式,後處理程式和控制器)關聯的執行鍊,以便準備模型或呈現。

如果傳回模型,則呈現視圖。如果沒有傳回模型(可能是由于預處理程式或後處理程式攔截請求,可能是出于安全原因),因為請求可能已經被滿足,是以不會呈現任何視圖。

在WebApplicationContext中聲明的處理程式異常解析程式在處理請求期間提取異常。使用這些異常解析器允許您定義自定義行為來解決異常。

Spring DispatcherServlet還支援傳回由Servlet API指定的最後修改日期。确定特定請求的最後修改日期的過程很簡單:DispatcherServlet查找适當的處理程式映射,并測試發現的處理程式是否實作了LastModified接口。如果是,則LastModified接口的long getLastModified(request)方法的值将傳回給用戶端。

您可以通過将Servlet初始化參數(init-param元素)添加到web.xml檔案中的Servlet聲明來自定義單獨的DispatcherServlet執行個體。有關支援的參數清單,請參見下表。

表18.2. DispatcherServlet 初始化參數

參數 解釋

contextClass

實作WebApplicationContext的類,它執行個體化了這個Servlet使用的上下文。 預設情況下,使用XmlWebApplicationContext。

contextConfigLocation

傳遞給上下文執行個體(由contextClass指定)以訓示可以找到上下文的字元串。 該字元串可能包含多個字元串(使用逗号作為分隔符)來支援多個上下文。 在具有兩次定義的bean的多個上下文位置的情況下,優先級最高。

namespace

WebApplicationContext的命名空間。 預設為[servlet-name] -servlet。

18.3 實作Controllers

控制器提供對通常通過服務接口定義的應用程式行為的通路。控制器解釋使用者輸入并将其轉換為由視圖表示給使用者的模型。 Spring以非常抽象的方式實作控制器,使您能夠建立各種各樣的控制器。

Spring 2.5引入了一種基于注釋的程式設計模型,用于使用諸如@RequestMapping,@RequestParam,@ModelAttribute等注釋的MVC控制器。以這種風格實作的控制器不必擴充特定的基類或實作特定的接口。此外,它們通常不直接依賴于Servlet API,但是如果需要,您可以輕松地配置對Servlet設施的通路。

@Controller

public class HelloWorldController {

@RequestMapping( “/ HelloWorld” 的)

public String helloWorld(Model model){

model.addAttribute(“message”,“Hello World!”);

return “helloWorld”;
}
}
您可以看到,@Controller和@RequestMapping注釋允許靈活的方法名稱和簽名。在這個特殊的例子中,該方法接受一個Model并傳回一個視圖名稱作為一個String,但是可以使用各種其他的方法參數和傳回值,如本節稍後所述。 @Controller和@RequestMapping和許多其他注釋構成了Spring MVC實作的基礎。本節介紹這些注釋以及它們在Servlet環境中最常用的注釋。

      

18.3.1 使用@Controller定義控制器

@Controller注釋表示特定的類用于控制器的角色。 Spring不需要擴充任何控制器基類或引用Servlet API。 但是,如果需要,您仍然可以參考Servlet特定的功能。

@Controller注釋作為注釋類的構造型,表示其作用。 排程程式掃描這些注釋類的映射方法,并檢測@RequestMapping注釋(請參閱下一節)。

您可以使用排程程式上下文中的标準Spring bean定義來明确定義帶注釋的控制器bean。 但是,@Controller構造型還允許自動檢測,與Spring通用支援對齊,用于檢測類路徑中的元件類并自動注冊它們的bean定義。要啟用自動檢測這些帶注釋的控制器,您可以向組态添加元件掃描。 使用spring-context模式,如以下XML代碼片段所示:

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

	<context:component-scan base-package="org.springframework.samples.petclinic.web"/>
	<!-- ... -->
</beans>

      

18.3.2 使用@RequestMapping映射請求

您可以使用@RequestMapping注釋将諸如/約會的URL映射到整個類或特定的處理程式方法。 通常,類級注釋将特定的請求路徑(或路徑模式)映射到表單控制器上,其他方法級注釋縮小了特定HTTP請求方法(“GET”,“POST”等)的主映射,或 HTTP請求參數條件。

Petcare示例中的以下示例顯示了使用此注釋的Spring MVC應用程式中的控制器:

@Controller
@RequestMapping("/appointments")
public class AppointmentsController {

	private final AppointmentBook appointmentBook;

	@Autowired
	public AppointmentsController(AppointmentBook appointmentBook) {
		this.appointmentBook = appointmentBook;
	}

	@RequestMapping(method = RequestMethod.GET)
	public Map<String, Appointment> get() {
		return appointmentBook.getAppointmentsForToday();
	}

	@RequestMapping(path = "/{day}", method = RequestMethod.GET)
	public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
		return appointmentBook.getAppointmentsForDay(day);
	}

	@RequestMapping(path = "/new", method = RequestMethod.GET)
	public AppointmentForm getNewForm() {
		return new AppointmentForm();
	}

	@RequestMapping(method = RequestMethod.POST)
	public String add(@Valid AppointmentForm appointment, BindingResult result) {
		if (result.hasErrors()) {
			return "appointments/new";
		}
		appointmentBook.addAppointment(appointment);
		return "redirect:/appointments";
	}
}      
在上面的例子中,@RequestMapping用在很多地方。 第一個用法是類型(類)級别,這表示此控制器中的所有處理程式方法都相對于/約會路徑。 get()方法還有一個@RequestMapping細化:它隻接受GET請求,這意味着/         appointments                 的HTTP GET調用此方法。 add()有一個類似的細化,getNewForm()将HTTP方法和路徑的定義組合成一個,以便通過該方法處理         appointments                 /新的GET請求。
getForDay()方法顯示了@RequestMapping:URI模闆的另一種用法。 (參見“URI模闆模式”一節)。
類級别上的@RequestMapping不是必需的。 沒有它,所有的路徑都是絕對的,而不是相對的。 PetClinic示例應用程式的以下示例顯示了使用@RequestMapping的多操作控制器:      
@Controller
public class ClinicController {

	private final Clinic clinic;

	@Autowired
	public ClinicController(Clinic clinic) {
		this.clinic = clinic;
	}

	@RequestMapping("/")
	public void welcomeHandler() {
	}

	@RequestMapping("/vets")
	public ModelMap vetsHandler() {
		return new ModelMap(this.clinic.getVets());
	}

}      
上述示例不指定GET與PUT,POST等,因為@RequestMapping預設映射所有HTTP方法。 使用@RequestMapping(method = GET)或@GetMapping來縮小映射。      

組合@RequestMapping變體

 Spring Framework 4.3引入了@RequestMapping注釋的以下方法級組合變體,有助于簡化常見HTTP方法的映射,并更好地表達注釋處理程式方法的語義。 例如,@GetMapping可以被讀取為GET @RequestMapping。      
  • @GetMapping

  • @PostMapping

  • @PutMapping

  • @DeleteMapping

  • @PatchMapping

以下示例顯示了使用已組合的@RequestMapping注釋簡化的上一節中的AppointmentsController的修改版本。

@Controller
@RequestMapping("/appointments")
public class AppointmentsController {

	private final AppointmentBook appointmentBook;

	@Autowired
	public AppointmentsController(AppointmentBook appointmentBook) {
		this.appointmentBook = appointmentBook;
	}

	@GetMapping
	public Map<String, Appointment> get() {
		return appointmentBook.getAppointmentsForToday();
	}

	@GetMapping("/{day}")
	public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
		return appointmentBook.getAppointmentsForDay(day);
	}

	@GetMapping("/new")
	public AppointmentForm getNewForm() {
		return new AppointmentForm();
	}

	@PostMapping
	public String add(@Valid AppointmentForm appointment, BindingResult result) {
		if (result.hasErrors()) {
			return "appointments/new";
		}
		appointmentBook.addAppointment(appointment);
		return "redirect:/appointments";
	}
}      

@Controller 和AOP 代理

在某些情況下,控制器可能需要在運作時用AOP代理進行裝飾。 一個例子是如果您選擇在控制器上直接使用@Transactional注釋。 在這種情況下,對于控制器,我們建議使用基于類的代理。 這通常是控制器的預設選項。 但是,如果控制器必須實作不是Spring Context回調的接口(例如InitializingBean,* Aware等),則可能需要顯式配置基于類的代理。 例如,使用<tx:annotation-driven />,更改為<tx:annotation-driven proxy-target-class =“true”/>。

Spring MVC 3.1中的@RequestMapping方法的新支援類

Spring 3.1分别為@RequestMapping方法引入了一組新的支援類,分别叫做RequestMappingHandlerMapping和RequestMappingHandlerAdapter。它們被推薦使用,甚至需要利用Spring MVC 3.1中的新功能和未來。預設情況下,MVC命名空間和MVC Java配置啟用新的支援類,但是如果不使用,則必須顯式配置。本節介紹舊支援類和新支援類之間的一些重要差別。

在Spring 3.1之前,類型和方法級請求映射在兩個單獨的階段進行了檢查 – 首先由DefaultAnnotationHandlerMapping選擇一個控制器,并且實際的調用方法被AnnotationMethodHandlerAdapter縮小。

使用Spring 3.1中的新支援類,RequestMappingHandlerMapping是唯一可以決定哪個方法應該處理請求的地方。将控制器方法作為從類型和方法級@RequestMapping資訊派生的每個方法的映射的唯一端點的集合。

這使得一些新的可能性。一旦HandlerInterceptor或HandlerExceptionResolver現在可以期望基于對象的處理程式是HandlerMethod,它允許它們檢查确切的方法,其參數和關聯的注釋。 URL的處理不再需要跨不同的控制器進行拆分。

還有下面幾件事情已經不複存在了:

  • 首先使用SimpleUrlHandlerMapping或BeanNameUrlHandlerMapping選擇控制器,然後基于@RequestMapping注釋來縮小方法。
  • 依賴于方法名稱作為一種落後機制,以消除兩個@RequestMapping方法之間的差異,這兩個方法沒有明确的路徑映射URL路徑, 通過HTTP方法。 在新的支援類中,@RequestMapping方法必須被唯一地映射。
  • 如果沒有其他控制器方法更具體地比對,請使用單個預設方法(無顯式路徑映射)處理請求。 在新的支援類中,如果找不到比對方法,則會引發404錯誤。

    上述功能仍然支援現有的支援類。 不過要利用新的Spring MVC 3.1功能,您需要使用新的支援類。

    URI 模版模式

    可以使用URI模闆友善地通路@RequestMapping方法中URL的所選部分。

    URI模闆是一個類似URI的字元串,包含一個或多個變量名稱。 當您替換這些變量的值時,模闆将成為一個URI。 所提出的RFC模闆RFC定義了URI如何參數化。 例如,URI模闆http://www.example.com/users/{userId}包含變量userId。 将fred的值配置設定給變量會得到http://www.example.com/users/fred。

    在Spring MVC中,您可以使用方法參數上的@PathVariable注釋将其綁定到URI模闆變量的值:

    @GetMapping("/owners/{ownerId}")
    public String findOwner(@PathVariable String ownerId, Model model) {
    	Owner owner = ownerService.findOwner(ownerId);
    	model.addAttribute("owner", owner);
    	return "displayOwner";
    }
    URI模闆“/ owners / {ownerId}”指定變量名ownerId。 當控制器處理此請求時,ownerId的值将設定為在URI的适當部分中找到的值。 例如,當/ owner / fred出現請求時,ownerId的值為fred。      
    @GetMapping("/owners/{ownerId}")
    public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {
    	// implementation omitted
    }      
    或者如果URI模闆變量名稱與方法參數名稱比對,則可以省略該詳細資訊。 隻要您的代碼使用調試資訊或Java 8上的參數編譯器标記進行編譯,Spring MVC将将方法參數名稱與URI模闆變量名稱相比對:
    @GetMapping("/owners/{ownerId}")
    public String findOwner(@PathVariable String ownerId, Model model) {
    	// implementation omitted
    }
    一個方法能夠有任意數量的         @PathVariable注解:
               
    @GetMapping("/owners/{ownerId}/pets/{petId}")
    public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
    	Owner owner = ownerService.findOwner(ownerId);
    	Pet pet = owner.getPet(petId);
    	model.addAttribute("pet", pet);
    	return "displayPet";
    }      
    當在Map <String,String>參數上使用@PathVariable注釋時,映射将填充所有URI模闆變量。
    URI模闆可以從類型和方法級别@RequestMapping注釋中進行組合。 是以,可以使用/ owner / 42 / pets / 21等URL調用findPet()方法。      
    @Controller
    @RequestMapping("/owners/{ownerId}")
    public class RelativePathUriTemplateController {
    
    	@RequestMapping("/pets/{petId}")
    	public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
    		// implementation omitted
    	}
    
    }
    一個@PathVariable參數可以是任何簡單的類型,如int,long,Date等。如果沒有這樣做,Spring将自動轉換為适當的類型或者抛出一個TypeMismatchException。 您還可以注冊解析其他資料類型的支援。. See the section called “Method Parameters And Type Conversion” 和the section called “Customizing WebDataBinder initialization”.      

    具有正規表達式的URI模闆模式

    有時您需要更精确地定義URI模闆變量。 考慮URL“/spring-web/spring-web-3.0.5.jar”。 你怎麼把它分解成多個部分?

    @RequestMapping注釋支援在URI模闆變量中使用正規表達式。 文法是{varName:regex},其中第一部分定義了變量名,第二部分定義了正規表達式。 例如:

    @RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{extension:\\.[a-z]+}")
    public void handle(@PathVariable String version, @PathVariable String extension) {
    	// ...
    }
    
          

    路徑模式

    除了URI模闆之外,@RequestMapping注釋和所有組合的@RequestMapping變體也支援Ant樣式的路徑模式(例如/myPath/*.do)。 還支援URI模闆變量和Ant-style glob的組合(例如/ owners / * / pets / {petId})。

    路徑模式比較

    當URL比對多個模式時,使用排序來查找最具體的比對。

    具有較低數量URI變量和通配符的模式被認為更具體。 例如/hotels/ {hotel} / *具有1個URI變量和1個通配符,被認為比/hotels/ {hotel} / **更具體,其中1個URI變量和2個通配符。

    如果兩個模式具有相同的計數,那麼較長的模式被認為更具體。 例如/ foo / bar *比較長,被認為比/ foo / *更具體。

    當兩個模式具有相同的計數和長度時,具有較少通配符的模式被認為更具體。 例如/hotels/ {hotel}比/hotels/ *更具體。

    下面有些額外增加的特殊的規則:

    • 預設映射模式/ **比任何其他模式都要小。 例如/ api / {a} / {b} / {c}更具體。
    • 諸如/ public / **之類的字首模式比不包含雙通配符的任何其他模式都不那麼具體。 例如/ public / path3 / {a} / {b} / {c}更具體。

For 有關詳細資訊,請參閱AntPathMatcher中的AntPatternComparator。 請注意,可以自定義PathMatcher(參見Section 18.16.11, “Path Matching” ).

具有占位符的路徑模式

@RequestMapping注釋中的模式支援對本地屬性和/或系統屬性和環境變量的$ {…}占位符。 在将控制器映射到的路徑可能需要通過配置進行定制的情況下,這可能是有用的。 有關占位符的更多資訊,請參閱PropertyPlaceholderConfigurer類的javadocs。

字尾模式比對

預設情況下,Spring MVC執行“。*”字尾模式比對,以便映射到/ person的控制器也隐式映射到/person.*。這使得通過URL路徑(例如/person.pdf,/person.xml)可以輕松地請求資源的不同表示。

字尾模式比對可以關閉或限制為一組明确注冊用于内容協商的路徑擴充。通常建議通過諸如/ person / {id}之類的常見請求映射來減少歧義,其中點可能不表示檔案擴充名,例如/person/[email protected] vs /person/[email protected]。此外,如下面的說明中所解釋的,字尾模式比對以及内容協商可能在某些情況下用于嘗試惡意攻擊,并且有充分的理由有意義地限制它們。

有關字尾模式比對配置,請參見第18.16.11節“路徑比對”,内容協商配置第18.16.6節“内容協商”。

字尾模式比對和RFD

反思檔案下載下傳(RFD)攻擊是由Trustwave在2014年的一篇論文中首次描述的。攻擊類似于XSS,因為它依賴于響應中反映的輸入(例如查詢參數,URI變量)。然而,不是将JavaScript插入到HTML中,如果基于檔案擴充名(例如.bat,.cmd)輕按兩下,則RFD攻擊依賴于浏覽器切換來執行下載下傳并将響應視為可執行腳本。

在Spring MVC @ResponseBody和ResponseEntity方法存在風險,因為它們可以呈現用戶端可以通過URL路徑擴充請求的不同内容類型。但是請注意,單獨禁用字尾模式比對或禁用僅用于内容協商的路徑擴充都可以有效地防止RFD攻擊。

為了全面保護RFD,在呈現響應體之前,Spring MVC添加了Content-Disposition:inline; filename = f.txt頭來建議一個固定和安全的下載下傳檔案。隻有當URL路徑包含既不是白名單的檔案擴充名,也沒有明确注冊用于内容協商的目的,這是完成的。但是,當URL直接輸入浏覽器時,可能會産生副作用。

許多常見的路徑擴充名預設為白名單。此外,REST API調用通常不是直接用于浏覽器中的URL。然而,使用自定義HttpMessageConverter實作的應用程式可以明确地注冊用于内容協商的檔案擴充名,并且不會為此類擴充添加Content-Disposition頭。見第18.16.6節“Content Negotiation”。

這是CVE-2015-5211工作的一部分。 以下是報告中的其他建議:

  • 編碼而不是轉義JSON響應。 這也是OWASP XSS的建議。 有關Spring的例子,請參閱spring-jackson-owasp.
  • 将字尾模式比對配置為關閉或僅限于明确注冊的字尾
  • 配置使用屬性“useJaf”和“ignoreUnknownPathExtensions”設定為false的内容協商,這将導緻具有未知擴充名的URL的406響應。 但是請注意,如果URL自然希望有一個結束點,這可能不是一個選擇。
  • 添加X-Content-Type-Options:nosniff頭到響應。 Spring Security 4預設情況下執行此操作。

矩陣變量

URI規範RFC 3986定義了在路徑段中包含名稱 – 值對的可能性。規格中沒有使用具體術語。可以應用一般的“URI路徑參數”,盡管來自Tim Berners-Lee的舊文章的更獨特的“Matrix URI”也經常被使用并且是相當熟知的。在Spring MVC中,這些被稱為矩陣變量。

矩陣變量可以出現在任何路徑段中,每個矩陣變量用“;”分隔(分号)。例如:“/ cars; color = red; year = 2012”。多個值可以是“,”(逗号)分隔“color = red,green,blue”,或者變量名稱可以重複“color = red; color = green; color = blue”。

如果URL預期包含矩陣變量,則請求映射模式必須使用URI模闆來表示它們。這確定了請求可以正确比對,無論矩陣變量是否存在,以及它們提供什麼順序。

以下是提取矩陣變量“q”的示例:

// GET /pets/42;q=11;r=22

@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {

	// petId == 42
	// q == 11

}
由于所有路徑段都可能包含矩陣變量,是以在某些情況下,您需要更具體地确定變量預期位于何處:      
// GET /owners/42;q=11/pets/21;q=22

@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
		@MatrixVariable(name="q", pathVar="ownerId") int q1,
		@MatrixVariable(name="q", pathVar="petId") int q2) {

	// q1 == 11
	// q2 == 22

}
矩陣變量可以定義為可選參數,并指定一個預設值:      
// GET /pets/42

@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {

	// q == 1

}
所有矩陣變量可以在Map中獲得:      
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23

@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
		@MatrixVariable MultiValueMap<String, String> matrixVars,
		@MatrixVariable(pathVar="petId"") MultiValueMap<String, String> petMatrixVars) {

	// matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
	// petMatrixVars: ["q" : 11, "s" : 23]

}
請注意,為了使用矩陣變量,您必須将RequestMappingHandlerMapping的removeSemicolonContent屬性設定為false。 預設設定為true。
MVC Java配置和MVC命名空間都提供了使用矩陣變量的選項。
如果您使用Java配置,使用MVC Java Config的進階自定義部分将介紹如何自定義RequestMappingHandlerMapping。
在MVC命名空間中,<mvc:annotation-driven>元素具有一個應該設定為true的enable-matrix-variables屬性。 預設情況下設定為false。      
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd">

	<mvc:annotation-driven enable-matrix-variables="true"/>

</beans>      

Consumable Media 類型

您可以通過指定consumable media類型的清單來縮小主要映射。 隻有當Content-Type請求頭與指定的媒體類型比對時,才會比對該請求。 例如:

@PostMapping(path = "/pets", consumes = "application/json")
public void addPet(@RequestBody Pet pet, Model model) {
	// implementation omitted
}
consumable media類型表達式也可以在!text / plain中否定,以比對除Content-Type of text / plain之外的所有請求。 還要考慮使用MediaType中提供的常量,例如APPLICATION_JSON_VALUE和APPLICATION_JSON_UTF8_VALUE。      

Producible Media 類型

您可以通過指定producible media類型清單來縮小主要映射。 隻有當Accept請求頭比對這些值之一時,才會比對該請求。 此外,使用産生條件確定用于産生響應的實際内容類型與産生條件中指定的媒體類型相關。 例如:

@GetMapping(path = "/pets/{petId}", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {
	// implementation omitted
}
就像消費一樣,可生産的媒體類型表達式可以被否定為!text / plain,以比對除了接受頭檔案值為text / plain的所有請求。 還要考慮使用MediaType中提供的常量,例如APPLICATION_JSON_VALUE和APPLICATION_JSON_UTF8_VALUE。      

請求參數和頭部值

您可以通過請求參數條件(如“myParam”,“!myParam”或“myParam = myValue”)縮小請求比對。 前兩個測試請求參數存在/不存在,第三個為特定參數值。 下面是一個請求參數值條件的例子:

@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {

	@GetMapping(path = "/pets/{petId}", params = "myParam=myValue")
	public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
		// implementation omitted
	}

}      
也可以根據特定的請求頭值來測試請求頭存在/不存在或比對:      
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {

	@GetMapping(path = "/pets", headers = "myHeader=myValue")
	public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
		// implementation omitted
	}

}

      

HTTP 頭部和 HTTP 可選項

映射到“GET”的@RequestMapping方法也隐式映射到“HEAD”,即不需要明确聲明“HEAD”。處理HTTP HEAD請求就像是HTTP GET一樣,而不是僅寫入正文,僅計數位元組數,并設定“Content-Length”頭。

@RequestMapping方法内置支援HTTP選項。預設情況下,通過将所有@RequestMapping方法上顯式聲明的具有比對URL模式的HTTP方法設定為“允許”響應頭來處理HTTP OPTIONS請求。當沒有明确聲明HTTP方法時,“允許”标題設定為“GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS”。理想地總是聲明@RequestMapping方法要處理的HTTP方法,或者使用專用的組合@RequestMapping變體之一(參見“Composed @RequestMapping Variants”一節)。

雖然不需要@RequestMapping方法可以映射到HTTP HEAD或HTTP選項,也可以兩者相容。

18.3.3 定義@RequestMapping 處理方法

@RequestMapping處理方法可以有非常靈活的簽名。 支援的方法參數和傳回值将在以下部分中介紹。 大多數參數可以按任意順序使用,唯一的例外是BindingResult參數。 這将在下一節中介紹。

支援的方法參數類型

下面是支援的方法參數類型:

  • org.springframework.web.context.request.WebRequest

    or

    org.springframework.web.context.request.NativeWebRequest

    . 允許通用請求參數通路以及請求/會話屬性通路,而不涉及本機Servlet API。
  • Request or response objects (Servlet API). 選擇任意特定的請求或響應類型, for example

    ServletRequest

    or

    HttpServletRequest

    or Spring’s

    MultipartRequest

    /

    MultipartHttpServletRequest

    .
  • Session對象(Servlet API)類型為HttpSession。 此類型的參數強制存在相應的會話。 是以,這樣的論證從不為空。

會話通路可能不是線程安全的,特别是在Servlet環境中。 如果允許多個請求同時通路會話,請考慮将RequestMappingHandlerAdapter的“synchronizeOnSession”标志設定為“true”。

  • java.servlet.http.PushBuilder用于關聯的Servlet 4.0推送建構器API,允許程式設計的HTTP / 2資源推送。
  • java.security.Principal(或一個特定的Principal實作類(如果已知)),包含目前驗證的使用者。
  • org.springframework.http.HttpMethod為HTTP請求方法,表示為Spring的HttpMethod枚舉。
  • 由目前請求區域設定的java.util.Locale,由最具體的語言環境解析器确定,實際上是在MVC環境中配置的LocaleResolver / LocaleContextResolver。
  • 與目前請求相關聯的時區的java.util.TimeZone(Java 6+)/ java.time.ZoneId(Java 8+),由LocaleContextResolver确定。
  • java.io.InputStream / java.io.Reader,用于通路請求的内容。該值是由Servlet API公開的原始InputStream / Reader。
  • java.io.OutputStream / java.io.Writer用于生成響應的内容。該值是由Servlet API公開的原始OutputStream / Writer。
  • @PathVariable注釋參數,用于通路URI模闆變量。請參閱the section called “URI Template Patterns”.
  • @MatrixVariable注釋參數,用于通路位于URI路徑段中的名稱/值對。請參閱 the section called “Matrix Variables”.
  • @RequestParam用于通路特定Servlet請求參數的注釋參數。參數值将轉換為聲明的方法參數類型。請參閱 the section called “Binding request parameters to method parameters with @RequestParam”.
  • @RequestHeader用于通路特定Servlet請求HTTP标頭的注釋參數。參數值将轉換為聲明的方法參數類型。請參閱 the section called “Mapping request header attributes with the @RequestHeader annotation”.
  • @RequestBody用于通路HTTP請求體的注釋參數。使用HttpMessageConverters将參數值轉換為聲明的方法參數類型。請參閱the section called “Mapping the request body with the @RequestBody annotation”.
  • @RequestPart注釋參數,用于通路“multipart / form-data”請求部分的内容。請參見Section 18.10.5, “Handling a file upload request from programmatic clients” 和Section 18.10, “Spring’s multipart (file upload) support”.
  • @SessionAttribute用于通路現有的永久會話屬性(例如,使用者認證對象)的注釋參數,而不是通過@SessionAttributes作為控制器工作流的一部分臨時存儲在會話中的模型屬性。
  • @RequestAttribute用于通路請求屬性的注釋參數。
  • HttpEntity <?>參數通路Servlet請求HTTP頭和内容。請求流将使用HttpMessageConverters轉換為實體。請參閱 the section called “Using HttpEntity”.
  • java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap用于豐富暴露于Web視圖的隐式模型。
  • org.springframework.web.servlet.mvc.support.RedirectAttributes來指定在重定向情況下使用的精确的屬性集,并且還添加Flash屬性(臨時存儲在伺服器端的屬性,使其可以在請求之後使用重定向)。請參見 the section called “Passing Data To the Redirect Target” 和Section 18.6, “Using flash attributes”.
  • 根據@InitBinder方法和/或HandlerAdapter配置,指令或表單對象将請求參數綁定到bean屬性(通過setter)或直接轉換為字段,并進行可定制的類型轉換。請參閱RequestMappingHandlerAdapter上的webBindingInitializer屬性。預設情況下,這些指令對象及其驗證結果将作為模型屬性公開,使用指令類名稱 – 例如。對于“some.package.OrderAddress”類型的指令對象的model屬性“orderAddress”。 ModelAttribute注釋可以用于方法參數來自定義所使用的模型屬性名稱。
  • org.springframework.validation.Errors / org.springframework.validation.BindingResult驗證前一個指令或表單對象的結果(即在前面的方法參數)。
  • 用于将表單處理标記為完整的org.springframework.web.bind.support.SessionStatus狀态句柄,它觸發在處理程式類型級别上由@SessionAttributes注釋訓示的會話屬性的清除。
  • org.springframework.web.util.UriComponentsBuilder用于準備與目前請求的主機,端口,方案,上下文路徑以及servlet映射的文字部分相關的URL的建構器。

錯誤或BindingResult參數必須遵循正在綁定的模型對象,因為方法簽名可能有多個模型對象,Spring将為每個模型對象建立一個單獨的BindingResult執行個體,是以以下示例将不起作用:

BindingResult和@ModelAttribute的排序無效。

@PostMapping
public String processSubmit(@ModelAttribute("pet") Pet pet, Model model, BindingResult result) { ... }
注意,Pet和BindingResult之間有一個Model參數。 要使其工作,您必須重新排序參數如下:      
@PostMapping
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result, Model model) { ... }      

支援的方法傳回類型

以下是支援的傳回類型:

  • 一個ModelAndView對象,其中模型隐含地豐富了指令對象和@ModelAttribute注釋引用資料通路器方法的結果。
  • 一個Model對象,其視圖名稱通過RequestToViewNameTranslator隐式确定,隐式豐富了指令對象的模型以及@ModelAttribute注釋引用資料通路器方法的結果。
  • 用于暴露模型的Map對象,其視圖名稱通過RequestToViewNameTranslator隐式确定,隐式豐富了指令對象的模型以及@ModelAttribute注釋引用資料通路器方法的結果。
  • 一個View對象,其模型通過指令對象和@ModelAttribute注釋引用資料通路器方法隐式确定。處理程式方法也可以通過聲明一個Model參數(見上文)以程式設計方式豐富模型。
  • 解釋為邏輯視圖名稱的字元串值,模型通過指令對象和@ModelAttribute注釋引用資料通路器方法隐式确定。處理程式方法也可以通過聲明一個Model參數(見上文)以程式設計方式豐富模型。
  • 如果方法處理響應本身(通過直接寫入響應内容,為此目的聲明一個類型為ServletResponse / HttpServletResponse的參數),或者如果視圖名稱通過RequestToViewNameTranslator隐式确定(不在處理程式方法簽名)。
  • 如果該方法用@ResponseBody注釋,則傳回類型将寫入響應HTTP主體。傳回值将使用HttpMessageConverters轉換為聲明的方法參數類型。請參閱 the section called “Mapping the response body with the @ResponseBody annotation”.
  • 一個HttpEntity <?>或ResponseEntity <?>對象來提供對Servlet響應HTTP頭和内容的通路。實體将使用HttpMessageConverters轉換為響應流。請參閱 the section called “Using HttpEntity”.
  • 一個HttpHeaders對象傳回沒有正文的響應。
  • 當應用程式想要在由Spring MVC管理的線程中異步生成傳回值時,可以傳回Callable <?>。
  • 當應用程式想從自己選擇​​的線程生成傳回值時,可以傳回DeferredResult <?>
  • 當應用程式想要從線程池送出中産生值時,可以傳回ListenableFuture <?>或CompletableFuture <?> / CompletionStage <?>。
  • 可以傳回ResponseBodyEmitter以異步地将多個對象寫入響應;也支援作為ResponseEntity内的主體。
  • 可以傳回SseEmitter以将異步的Server-Sent事件寫入響應;也支援作為ResponseEntity内的主體。
  • 可以傳回StreamingResponseBody以異步寫入響應OutputStream;也支援作為ResponseEntity内的主體
  • 任何其他傳回類型都被認為是要暴露給視圖的單一模型屬性,使用在方法級别(或基于傳回類型類名稱的預設屬性名稱)中通過@ModelAttribute指定的屬性名稱。該模型隐含地豐富了指令對象和@ModelAttribute注釋引用資料通路器方法的結果。

通過@RequestParam綁定請求參數到方法

使用@RequestParam注解将請求參數綁定到控制器中的方法參數。
以下代碼片段顯示用法:      
@Controller
@RequestMapping("/pets")
@SessionAttributes("pet")
public class EditPetForm {

	// ...

	@GetMapping
	public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
		Pet pet = this.clinic.loadPet(petId);
		model.addAttribute("pet", pet);
		return "petForm";
	}

	// ...

}      
預設情況下,使用此注釋的參數是必需的,但您可以通過将@ RequestParam的必需屬性設定為false(例如@RequestParam(name =“id”,required = false))來指定參數是可選的。
如果目标方法參數類型不是String,則會自動應用類型轉換。 請參閱“方法參數和類型轉換”一節。
當在Map <String,String>或MultiValueMap <String,String>參數上使用@RequestParam注釋時,映射将填充所有請求參數。      

使用@RequestBody注釋映射請求體

@RequestBody方法參數注釋表示方法參數應綁定到HTTP請求體的值。 例如:

@PutMapping("/something")
public void handle(@RequestBody String body, Writer writer) throws IOException {
	writer.write(body);
}
通過使用HttpMessageConverter将請求體轉換為method參數。 HttpMessageConverter負責将HTTP請求消息轉換為對象,并從對象轉換為HTTP響應體。 RequestMappingHandlerAdapter支援帶有以下預設HttpMessageConverters的@RequestBody注釋:      
  • byteArrayHttpMessageConverter

    converts byte arrays.
  • StringHttpMessageConverter

    converts strings.
  • FormHttpMessageConverter

    converts form data to/from a MultiValueMap<String, String>.
  • SourceHttpMessageConverter

    converts to/from a javax.xml.transform.Source.
有關這些轉換器的更多資訊,請參閱消息轉換器。 另請注意,如果使用MVC命名空間或MVC Java配置,預設情況下會注冊更廣泛的消息轉換器。 有關詳細資訊,請參見第18.16.1節“啟用MVC Java配置或MVC XML命名空間”。 Section 18.16.1, “Enabling the MVC Java Config or the MVC XML Namespace” 
如果您打算讀寫XML,則需要使用org.springframework.oxm包中的特定Marshaller和Unmarshaller實作配置MarshallingHttpMessageConverter。 下面的示例顯示了如何直接在配置中執行此操作,但是如果您的應用程式通過MVC命名空間或MVC Java配置進行配置,請參見第18.16.1節“啟用MVC Java配置或MVC XML命名空間”。      
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
	<property name="messageConverters">
		<util:list id="beanList">
			<ref bean="stringHttpMessageConverter"/>
			<ref bean="marshallingHttpMessageConverter"/>
		</util:list>
	</property>
</bean>

<bean id="stringHttpMessageConverter"
		class="org.springframework.http.converter.StringHttpMessageConverter"/>

<bean id="marshallingHttpMessageConverter"
		class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
	<property name="marshaller" ref="castorMarshaller"/>
	<property name="unmarshaller" ref="castorMarshaller"/>
</bean>

<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>
@RequestBody方法參數可以用@Valid注釋,在這種情況下,它将使用配置的Validator執行個體進行驗證。 當使用MVC命名空間或MVC Java配置時,會自動配置一個JSR-303驗證器,假設在類路徑上可用JSR-303實作。
就像@ModelAttribute參數一樣,可以使用一個Errors參數來檢查錯誤。 如果未聲明此類參數,則将引發MethodArgumentNotValidException異常。 該異常在DefaultHandlerExceptionResolver中處理,它将向用戶端發送一個400錯誤。
      

使用@ResponseBody注解映射響應體

使用

@RequestParam

注釋将請求參數綁定到控制器中的方法參數。

以下代碼片段顯示用法:

@Controller 
@RequestMapping(“/ pets”)
@SessionAttributes(“pet”)
 public  class EditPetForm { // ... @GetMapping public String setupForm( @RequestParam(“petId”)int petId,ModelMap model){
		Pet pet = this .clinic.loadPet(petId); 
		model.addAttribute( “pet”,pet);
		傳回“petForm” ; 
	} // ...

	

	
	 

	

}      

使用這個注解的參數預設情況下必需的,但你可以指定一個參數是通過設定可選

@RequestParam

required

屬性

false

(如

@RequestParam(name="id", required=false)

)。

如果目标方法參數類型不是,則會自動應用類型轉換

String

。請參閱“方法參數和類型轉換”一節。

@RequestParam

在一個

Map<String, String>

或者

MultiValueMap<String, String>

參數上使用注釋時,地圖将填充所有請求參數。

使用@RequestBody注釋映射請求體

所述

@RequestBody

方法參數注釋訓示方法參數應綁定到HTTP請求正文的值。例如:

@PutMapping(“/ something”)
 public  void handle( @RequestBody String body,Writer writer) throws IOException {
	writer.write(body); 
}      

您可以使用a将請求體轉換為method參數

HttpMessageConverter

HttpMessageConverter

負責從HTTP請求消息轉換為對象,并從對象轉換為HTTP響應正文。該

RequestMappingHandlerAdapter

支援

@RequestBody

使用以下預設注釋

HttpMessageConverters

  • ByteArrayHttpMessageConverter

    轉換位元組數組。
  • StringHttpMessageConverter

    轉換字元串。
  • FormHttpMessageConverter

    将表單資料轉換為/從MultiValueMap <String,String>轉換。
  • SourceHttpMessageConverter

    轉換為/從javax.xml.transform.Source轉換。

有關這些轉換器的更多資訊,請參閱消息轉換器。另請注意,如果使用MVC命名空間或MVC Java配置,預設情況下會注冊更廣泛的消息轉換器。有關詳細資訊,請參見第18.16.1節“啟用MVC Java配置或MVC XML命名空間”。

如果您打算讀寫XML,則需要 從包中

MarshallingHttpMessageConverter

配置特定的

Marshaller

和實作。下面的示例顯示了如何直接在配置中執行此操作,但是如果您的應用程式通過MVC命名空間或MVC Java配置進行配置,請參見第18.16.1節“啟用MVC Java配置或MVC XML命名空間”。

Unmarshaller

org.springframework.oxm

<豆 類 = “org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter” > 
	<屬性 名 = “了MessageConverter” > 
		<util的:清單 ID = “beanList” > 
			<REF  豆 = “stringHttpMessageConverter” /> 
			< ref  bean = “marshallingHttpMessageConverter” /> 
		</ util:list> 
	</ property> 
</ bean> 

<bean  id = “stringHttpMessageConverter” 
		class = “org.springframework.http。轉換器.StringHttpMessageConverter“ /> 

<bean  id = ”marshallingHttpMessageConverter“ 
		class = ”org.springframework.http.converter.xml.MarshallingHttpMessageConverter“ > 
	<property  name = ”marshaller“  ref = ”castorMarshaller“ /> 
	<property  name = ”unmarshaller“  ref = “castorMarshaller” /> 
</ bean> 

<bean  id = “castorMarshaller”  class = “org.springframework.oxm.castor.CastorMarshaller”/>      

一種

@RequestBody

方法參數可以與進行注釋

@Valid

,在這種情況下,它将使用配置的驗證

Validator

執行個體。當使用MVC命名空間或MVC Java配置時,會自動配置一個JSR-303驗證器,假設在類路徑上可用JSR-303實作。

就像使用

@ModelAttribute

參數,一個

Errors

參數可以用來檢查錯誤。如果沒有宣布這樣的論據,

MethodArgumentNotValidException

将會提出一個。在異常處理

DefaultHandlerExceptionResolver

,它發送

400

錯誤回到用戶端。

《Spring 5 官方文檔》18. Web MVC 架構
有關通過MVC命名空間或MVC Java配置配置消息轉換器和驗證器的資訊,請參見第18.16.1節“啟用MVC Java配置或MVC XML命名空間”。

使用@ResponseBody注釋映射響應體

@ResponseBody

注釋是類似

@RequestBody

。該注釋可以放在一個方法上,并訓示傳回類型應該直接寫入HTTP響應體(而不是放在模型中,或者解釋為視圖名稱)。例如:

@GetMapping(“/ something”)
@ResponseBody
 public String helloWorld(){
	 return  “Hello World” ; 
}      

上述示例将導緻文本

Hello World

被寫入HTTP響應流。

與之一樣

@RequestBody

,Spring通過使用一個轉換将傳回的對象轉換為響應體

HttpMessageConverter

。有關這些轉換器的更多資訊,請參閱上一部分和消息轉換器。

使用@RestController注釋建立REST控制器

控制器實作REST API是一個非常常見的用例,是以僅提供JSON,XML或定制的MediaType内容。為友善起見,您可以使用以下

@RequestMapping

方式

@ResponseBody

來注釋您的控制器類,而不是注釋所有 方法

@RestController

@RestController

is a stereotype annotation that combines

@ResponseBody

and

@Controller

. More than that, it gives more meaning to your Controller and also may carry additional semantics in future releases of the framework.

與正常

@Controller

S,A

@RestController

可以通過協助

@ControllerAdvice

@RestControllerAdvice

豆類。有關 更多詳細資訊,請參閱“使用@ControllerAdvice和@RestControllerAdvice建議控制器”一節。

使用HttpEntity

HttpEntity

是相似的

@RequestBody

@ResponseBody

。除了通路請求和響應主體之外

HttpEntity

(和響應特定子類

ResponseEntity

)還允許通路請求和響應頭,如下所示:

@RequestMapping(“/ something”)
 public ResponseEntity <String> handle(HttpEntity < byte []> requestEntity) throws UnsupportedEncodingException {
	String requestHeader = requestEntity.getHeaders()。getFirst( “MyRequestHeader”);
	byte [] requestBody = requestEntity.getBody(); //使用請求頭和身體 
	做某事HttpHeaders responseHeaders = new HttpHeaders(); 
	responseHeaders.set( “MyResponseHeader”, “MyValue”);
	傳回新的 ResponseEntity <String>( “Hello World”,responseHeaders,HttpStatus。建立); 
}

	
      

上述示例擷取

MyRequestHeader

請求标頭的值,并将其作為位元組數組讀取。它将

MyResponseHeader

響應添加到

Hello World

響應流中,并将響應狀态代碼設定為201(已建立)。

至于

@RequestBody

@ResponseBody

,Spring使用

HttpMessageConverter

從和請求和響應流轉換。有關這些轉換器的更多資訊,請參閱上一部分和消息轉換器。

在方法上使用@ModelAttribute

@ModelAttribute

注釋可以對方法或方法的參數來使用。本節将介紹其在方法上的用法,下一節将介紹其在方法參數上的用法。

An

@ModelAttribute

on a method indicates the purpose of that method is to add one or more model attributes. Such methods support the same argument types as

@RequestMapping

methods but cannot be mapped directly to requests. Instead

@ModelAttribute

methods in a controller are invoked before

@RequestMapping

methods, within the same controller. A couple of examples:

//添加一個屬性
//該方法的傳回值被添加到名為“account”的模型中
//您可以通過@ModelAttribute(“myAccount”)

@ModelAttribute
自定義名稱@ModelAttribute public Account addAccount(@RequestParam String number) {
	 return accountManager.findAccount(number); 
} //添加多個屬性@ModelAttribute public void populateModel(@RequestParam String number,Model model){ 
	model.addAttribute(accountManager.findAccount(number)); //添加更多... 
}




 
      

@ModelAttribute

方法用于填充具有常用屬性的模型,例如使用狀态或寵物類型填充下拉清單,或者檢索諸如Account的指令對象,以便使用它來表示HTML表單上的資料。後一種情況在下一節進一步讨論。

注意兩種風格的

@ModelAttribute

方法。在第一個方法中,該方法通過傳回它隐式地添加一個屬性。在第二個方法中,該方法接受

Model

并添加任意數量的模型屬性。您可以根據需要選擇兩種風格。

控制器可以有多種

@ModelAttribute

方法。所有這些方法都

@RequestMapping

在相同控制器的方法之前被調用。

@ModelAttribute

方法也可以在一個

@ControllerAdvice

注釋類中定義,并且這種方法适用于許多控制器。有關更多詳細資訊,請參閱“使用@ControllerAdvice和@RestControllerAdvice建議控制器”一節。

《Spring 5 官方文檔》18. Web MVC 架構
當沒有明确指定模型屬性名稱時會發生什麼?在這種情況下,根據其類型将預設名稱配置設定給模型屬性。例如,如果該方法傳回類型的對象

Account

,則使用的預設名稱為“account”。您可以通過

@ModelAttribute

注釋的值更改它。如果直接添加屬性

Model

,請使用适當的重載

addAttribute(..)

方法 – 即,帶有或不帶有屬性名稱。

@ModelAttribute

批注可在使用

@RequestMapping

方法為好。在這種情況下,

@RequestMapping

方法的傳回值将被解釋為模型屬性而不是視圖名稱。視圖名稱是基于視圖名稱約定導出的,非常類似于傳回的方法

void

 - 請參見第18.13.3節“View – RequestToViewNameTranslator”。

在方法參數上使用@ModelAttribute

如上一節所述

@ModelAttribute

,可以在方法或方法參數上使用。本節介紹了其在方法參數中的用法。

一個

@ModelAttribute

上的方法參數訓示參數應該從模型中檢索。如果模型中不存在,參數首先被執行個體化,然後添加到模型中。一旦出現在模型中,參數的字段應該從具有比對名稱的所有請求參數中填充。這被稱為Spring MVC中的資料綁定,這是一種非常有用的機制,可以節省您逐個解析每個表單字段。

@PostMapping(“/ owners / {ownerId} / pets / {petId} / edit”)
 public String processSubmit( @ModelAttribute Pet pet){}      

鑒于上述例子,寵物執行個體可以從哪裡來?有幾個選擇:

  • 由于使用

    @SessionAttributes

     - 可能已經在模型中- 請參閱 “使用@SessionAttributes将模型屬性存儲在請求之間的HTTP會話中”一節。
  • 由于

    @ModelAttribute

    在同一控制器中的方法,它可能已經在模型中 – 如上一節所述。
  • 它可以基于URI模闆變量和類型轉換器(下面更詳細地解釋)來檢索。
  • 它可以使用其預設構造函數執行個體化。

一種

@ModelAttribute

方法是從資料庫中檢索屬性的常用方法,可以通過使用可選地在請求之間存儲屬性

@SessionAttributes

。在某些情況下,通過使用URI模闆變量和類型轉換器來檢索屬性可能很友善。這是一個例子:

@PutMapping(“/ accounts / {account}”)
 public String save( @ModelAttribute(“account”)帳戶帳号){
	 // ... 
}      

在此示例中,模型屬性(即“account”)的名稱與URI模闆變量的名稱相比對。如果您注冊

Converter<String, Account>

,可以将

String

帳戶值轉換為一個

Account

執行個體,則上述示例将無需使用

@ModelAttribute

方法。

下一步是資料綁定。該

WebDataBinder

級比賽要求參數名稱-包括查詢字元串參數和表單域-以模拟通過名稱屬性字段。在必要時已經應用了類型轉換(從字元串到目标字段類型)之後填充比對字段。資料綁定和驗證在 第5章驗證,資料綁定和類型轉換中介紹。自定義控制器級别的資料綁定過程将在“自定義WebDataBinder初始化”一節中介紹。

由于資料綁定,可能會出現錯誤,例如缺少必填字段或類型轉換錯誤。要檢查這些錯誤,請在

BindingResult

參數後立即添加一個

@ModelAttribute

參數:

@PostMapping(“/ owners / {ownerId} / pets / {petId} / edit”)
 public String processSubmit( @ModelAttribute(“pet”)Pet Pet,BindingResult result){ if(result.hasErrors()){
		 return “petForm “ ; 
	} // ... 
}

	 

	
      

使用一個

BindingResult

你可以檢查是否發現錯誤,在這種情況下,渲染相同的形式通常是在Spring的

<errors>

表單标簽的幫助下顯示錯誤的。

請注意,在某些情況下,在沒有資料綁定的情況下擷取模型中的屬性可能是有用的。對于這種情況,您可以将其注入

Model

控制器,或者使用注釋上的

binding

标志:

@ModelAttribute
 public AccountForm setUpForm(){
     return  new AccountForm(); 
} @ModelAttribute public Account findAccount( @PathVariable String accountId){
     return accountRepository.findOne(accountId); 
} @PostMapping(“update”) public String update( @Valid AccountUpdateForm form,BindingResult result,
         @ModelAttribute(binding = false) Account account){ // ... 
}







      

除了資料綁定之外,您還可以使用自己的自定義驗證器調用驗證,傳遞與

BindingResult

用于記錄資料綁定錯誤相同的驗證器。這允許在一個地方累積資料綁定和驗證錯誤,并随後向使用者報告:

@PostMapping( “/老闆/ {} OWNERID /寵物/ {} petId /編輯”)
公共字元串processSubmit(新 PetValidator()驗證(PET,結果);
	如果(result.hasErrors()){
		回報“petForm” ;
	} // ... 
}@ModelAttribute("pet") Pet pet, BindingResult result) {

	 

	
      

或者您可以通過添加JSR-303

@Valid

注釋自動調用驗證:

@PostMapping(“/ owners / {ownerId} / pets / {petId} / edit”)
 public String processSubmit( @Valid @ModelAttribute(“pet”)Pet pet,BindingResult result){ if(result.hasErrors()){
		 return “petForm” ; 
	} // ... 
}

	 

	
      

有關如何配置和使用驗證的詳細資訊,請參見第5.8節“Spring驗證”和第5章驗證,資料綁定和類型轉換。

使用@SessionAttributes将模型屬性存儲在請求之間的HTTP會話中

類型級

@SessionAttributes

注釋聲明特定處理程式使用的會話屬性。這通常将列出模型屬性或模型屬性的類型,這些模型屬性或類型應該透明地存儲在會話或某些會話存儲中,作為後續請求之間的格式支援bean。

以下代碼片段顯示了此注釋的用法,指定了模型屬性名稱:

@Controller 
@RequestMapping(“/ editPet.do”)
@SessionAttributes(“pet”)
 public class EditPetForm {
	// ...
}      

使用@SessionAttribute通路預先存在的全局會話屬性

如果您需要通路全局管理的預先存在的會話屬性,即控制器外部(例如,通過過濾器),并且可能存在或可能不存在,

@SessionAttribute

則會使用方法參數上的注釋:

@RequestMapping(“/”)
 public String handle( @SessionAttribute User user){
	 // ... 
}      

對于需要添加或删除會話屬性的用例,請考慮注入

org.springframework.web.context.request.WebRequest

javax.servlet.http.HttpSession

控制方法。

為了在會話中臨時存儲模型屬性作為控制器工作流的一部分,請考慮使用“使用@SessionAttributes将模型屬性存儲在請求之間的HTTP會話中”

SessionAttributes

中 所述的一節。

使用@RequestAttribute來通路請求屬性

到類似

@SessionAttribute

@RequestAttribute

注釋可以被用于通路由濾波器或攔截器建立的預先存在的請求屬性:

@RequestMapping(“/”)
 public String handle( @RequestAttribute Client client){
	 // ... 
}      

使用“application / x-www-form-urlencoded”資料

以前的章節介紹了

@ModelAttribute

如何支援浏覽器用戶端的表單送出請求。建議與非浏覽器用戶端的請求一起使用相同的注釋。然而,在使用HTTP PUT請求時,有一個顯着的差別。浏覽器可以通過HTTP GET或HTTP POST送出表單資料。非浏覽器用戶端也可以通過HTTP PUT送出表單。這提出了一個挑戰,因為Servlet規範要求

ServletRequest.getParameter*()

一系列方法僅支援HTTP POST的表單域通路,而不支援HTTP PUT。

為了支援HTTP PUT和PATCH請求,該

spring-web

子產品提供了

HttpPutFormContentFilter

可以在以下配置中的過濾器

web.xml

<filter> 
	<filter-name> httpPutFormFilter </ filter-name> 
	<filter-class> org.springframework.web.filter.HttpPutFormContentFilter </ filter-class> 
</ filter> 

<filter-mapping> 
	<filter-name> httpPutFormFilter </ filter-name> 
	<servlet-name> dispatcherServlet </ servlet-name> 
</ filter-mapping> 

<servlet> 
	<servlet-name> dispatcherServlet </ servlet-name> 
	<servlet-class> org.springframework.web。 servlet.DispatcherServlet </ servlet-class> 
</ servlet>      

上述過濾器攔截具有内容類型的HTTP PUT和PATCH請求

application/x-www-form-urlencoded

,從請求的正文 中讀取表單資料,并包裝

ServletRequest

以便通過

ServletRequest.getParameter*()

一系列方法使表單資料可用 。

《Spring 5 官方文檔》18. Web MVC 架構
由于

HttpPutFormContentFilter

消耗了請求的正文,是以不應配置為依賴其他轉換器的PUT或PATCH URL

application/x-www-form-urlencoded

。這包括

@RequestBody MultiValueMap<String, String>

HttpEntity<MultiValueMap<String, String>>

使用@CookieValue注釋映射Cookie值

@CookieValue

注釋允許将方法參數綁定到HTTP cookie的值。

讓我們考慮以下cookie已被接收到http請求:

JSESSIONID = 415A4AC178C59DACE0B2C9CA727CDD84      

以下代碼示例示範如何擷取

JSESSIONID

cookie 的值:

@RequestMapping(“/ displayHeaderInfo.do”)
 public  void displayHeaderInfo( @CookieValue(“JSESSIONID”) String cookie){
	 // ... 
}      

如果目标方法參數類型不是,則會自動應用類型轉換

String

。請參閱“方法參數和類型轉換”一節。

使用@RequestHeader注釋映射請求标頭屬性

@RequestHeader

注釋允許将一個方法參數綁定到請求頭。

以下是一個示例請求标頭:

主機本地主機:8080 
接受文本/ html應用程式/ xhtml + xml應用程式/ xml; q = 0.9 
接受語言fr,en-gb; q = 0.7,en; q = 0.3 
接受編碼gzip,放大
Accept-Charset ISO -8859-1,utf-8; q = 0.7,*; q = 0.7 
保持活力300      

以下代碼示例示範了如何擷取

Accept-Encoding

Keep-Alive

标題的值:

@RequestMapping(“/ displayHeaderInfo.do”)
 public  void displayHeaderInfo( @RequestHeader(“Accept-Encoding”) String encoding,
		 @RequestHeader(“Keep-Alive”)  long keepAlive){
	 // ... 
}      

Type conversion is applied automatically if the method parameter is not

String

. See the section called “Method Parameters And Type Conversion”.

@RequestHeader

注解上的使用

Map<String, String>

MultiValueMap<String, String>

HttpHeaders

參數,則地圖被填充有所有标頭值。

《Spring 5 官方文檔》18. Web MVC 架構
内置支援可用于将逗号分隔的字元串轉換為字元串或類型轉換系統已知的其他類型的數組/集合。例如,注釋的方法參數

@RequestHeader("Accept")

可以是類型

String

,也可以是

String[]

List<String>

方法參數和類型轉換

從請求中提取的基于字元串的值(包括請求參數,路徑變量,請求标頭和cookie值)可能需要轉換為方法參數或字段的目标類型(例如,将請求參數綁定到參數中的字段

@ModelAttribute

)他們一定會。如果目标類型不是

String

,Spring将自動轉換為相應的類型。支援所有簡單的類型,如int,long,Date等。您可以進一步自定義通過轉換過程

WebDataBinder

(見稱為“定制WebDataBinder初始化”一節),或者通過注冊

Formatters

FormattingConversionService

(參見5.6節,“春字段格式”)。

自定義WebDataBinder初始化

要通過Spring定制與PropertyEditor的請求參數綁定

WebDataBinder

,可以使用

@InitBinder

控制器中的-annotated

@InitBinder

方法,

@ControllerAdvice

類中的方法或提供自定義

WebBindingInitializer

。有關更多詳細資訊,請參閱“使用@ControllerAdvice和@RestControllerAdvice建議控制器”一節。

使用@InitBinder自定義資料綁定

注釋控制器方法,

@InitBinder

允許您直接在控制器類中配置Web資料綁定。

@InitBinder

識别用于初始化

WebDataBinder

将用于填充命名和表示注釋處理程式方法的對象參數的方法。

這種init-binder方法支援方法支援的所有參數

@RequestMapping

,除了指令/表單對象和相應的驗證結果對象。Init-binder方法不能有傳回值。是以,它們通常被聲明為

void

。典型的參數包括

WebDataBinder

WebRequest

或者

java.util.Locale

允許代碼注冊上下文相關的編輯器。

以下示例示範

@InitBinder

如何

CustomDateEditor

為所有

java.util.Date

表單屬性配置一個 。

@Controller
 public  class MyFormController { @InitBinder protected void initBinder(WebDataBinder binder){
		SimpleDateFormat dateFormat = new SimpleDateFormat( “yyyy-MM-dd”); 
		dateFormat.setLenient(假); 
		binder.registerCustomEditor(日期類,新和CustomDateEditor(日期格式,FALSE)); 
	} // ... 
}

	
	 

      

或者,從Spring 4.2起,考慮使用

addCustomFormatter

來指定

Formatter

實作而不是

PropertyEditor

執行個體。如果您碰巧

Formatter

在共享

FormattingConversionService

中安裝一個基于安裝程式的 方法,那麼特别有用的方法可以重用于控制器特定的綁定規則調整。

@Controller
 public  class MyFormController { @InitBinder protected 
		binder.addCustomFormatter( new DateFormatter( “yyyy-MM-dd”)); 
	} // ... 
}

	
	 void initBinder(WebDataBinder binder) {

      
配置自定義WebBindingInitializer

要外部化資料綁定初始化,您可以提供

WebBindingInitializer

接口的自定義實作,然後通過為其提供自定義bean配置來啟用

RequestMappingHandlerAdapter

,進而覆寫預設配置。

PetClinic應用程式中的以下示例顯示了使用該接口的自定義實作的

WebBindingInitializer

配置

org.springframework.samples.petclinic.web.ClinicBindingInitializer

,它配置了幾個PetClinic控制器所需的PropertyEditor。

<bean  class = “org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter” > 
	<property  name = “cacheSeconds”  value = “0” /> 
	<property  name = “webBindingInitializer” > 
		<bean  class = “org .springframework.samples.petclinic.web.ClinicBindingInitializer“ /> 
	</ property> 
</ bean>      

@InitBinder

方法也可以在一個

@ControllerAdvice

注釋類中定義,在這種情況下,它們适用于比對控制器。這提供了使用a的替代方法

WebBindingInitializer

。有關更多詳細資訊,請參閱“使用@ControllerAdvice和@RestControllerAdvice建議控制器”一節。

通過@ControllerAdvice和@RestControllerAdvice為控制器提供建議

@ControllerAdvice

注釋是一個元件注釋允許實作類自動檢測通過類路徑掃描。當使用MVC命名空間或MVC Java配置時,它将自動啟用。

帶注釋的類

@ControllerAdvice

可以包含

@ExceptionHandler

@InitBinder

@ModelAttribute

注解的方法,這些方法将适用于

@RequestMapping

所有控制器的層次結構的方法,而不是内聲明它們控制器層次。

@RestControllerAdvice

是一種

@ExceptionHandler

方法

@ResponseBody

,預設情況下方法采用語義。

二者

@ControllerAdvice

@RestControllerAdvice

可以針對控制器的一個子集:

//目标所有使用@RestController注釋的控制器
@ControllerAdvice(annotations = RestController.class)
 public  class AnnotationAdvice {} //定位特定包中的所有控制器@ControllerAdvice(“org.example.controllers”) public class BasePackageAdvice {} // Target所有可配置設定給特定類的控制器@ControllerAdvice(assignableTypes = {ControllerInterface.class,AbstractController.class}) public class AssignableTypesAdvice {}



 



      

檢視

@ControllerAdvice

文檔了解更多詳細資訊。

傑克遜序列化視圖支援

有時将内容過濾将被序列化到HTTP響應主體的對象有時是有用的。為了提供這樣的功能,Spring MVC内置了對Jackson的Serialization Views進行渲染的支援。

要使用

@ResponseBody

傳回的控制器方法或控制器方法

ResponseEntity

,隻需

@JsonView

使用指定要使用的視圖類或接口的類參數添加注釋:

@RestController
 public  class UserController { @GetMapping(“/ user”)@JsonView(User.WithoutPasswordView.class) public User getUser(){
		 return new User( “eric”, “7!jd#h23”); 
	}
}公共類使用者{公共接口 WithoutPasswordView {};
	public Interface WithPasswordView extends WithoutPasswordView {}; 私人字元串使用者名;
	私人字元串密碼; public User(){
	}
	} @JsonView(WithoutPasswordView。class) public String getUsername(){
		 return this .username; 
	} @JsonView(WithPasswordView.class) public String getPassword(){
		 return this .password; 
	}
}

	
	
	 

 

	  

	

	

	public User(String username, String password) {
		this.username = username;
		this.password = password;

	
	 

	
      
《Spring 5 官方文檔》18. Web MVC 架構
請注意,盡管

@JsonView

允許指定多個類,但在控制器方法上的使用隻支援一個類參數。如果需要啟用多個視圖,請考慮使用複合接口。

對于依賴于視圖分辨率的控制器,隻需将序列化視圖類添加到模型中:

@Controller
 public  class UserController extends AbstractController {

	@GetMapping(“/ user”)
	 public String getUser(Model model){
		model.addAttribute(“user”,new User(“eric”,“7!jd#h23”));
		model.addAttribute(JsonView 類 .getName(),User.WithoutPasswordView。類);
		傳回 “userView” ;
	}
}      

傑克遜JSONP支援

為了啟用JSONP支援

@ResponseBody

ResponseEntity

方法,聲明一個

@ControllerAdvice

擴充的bean,

AbstractJsonpResponseBodyAdvice

如下所示,構造函數參數訓示JSONP查詢參數名稱:

@ControllerAdvice
 public  class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {

	public JsonpAdvice(){
		 super(“callback”);
	}
}      

對于依賴于視圖分辨率的控制器,當請求具有名為

jsonp

或者的查詢參數時,将自動啟用JSONP

callback

。這些名字可以通過

jsonpParameterNames

财産定制。

18.3.4異步請求處理

Spring MVC 3.2介紹了基于Servlet 3的異步請求處理。與往常一樣,一個控制器方法現在可以傳回一個

java.util.concurrent.Callable

并從Spring MVC管理的線程生成傳回值,而不是傳回一個 值。同時,主要的Servlet容器線程被退出并被釋放并允許處理其他請求。Spring MVC

Callable

在一個單獨的線程中調用一個單獨的線程

TaskExecutor

,當

Callable

傳回時,請求被分派回到Servlet容器,以使用傳回的值來恢複處理

Callable

。這是一個這樣一個控制器方法的例子:

@PostMapping
 public Callable <String> processUpload( final MultipartFile檔案){

	傳回 新的 Callable <String>(){
		 public String call()throws Exception {
			 // ... 
			return  “someView” ;
		}
	};

}      

另一個選項是控制器方法傳回一個執行個體

DeferredResult

。在這種情況下,傳回值也将從任何線程生成,即不由Spring MVC管理的線程。例如,可以響應于諸如JMS消息,計劃任務等的一些外部事件而産生結果。這是一個這樣一個控制器方法的例子:

@RequestMapping(“/ quotes”)
@ResponseBody
 public DeferredResult <String> quotes(){
	DeferredResult <String> deferredResult = new DeferredResult <String>();
	//将deferredResult儲存在某個地方.. 
	return deferredResult;
}

//在其他一些線程中... 
deferredResult.setResult(data);      

沒有任何Servlet 3.0異步請求處理功能的知識可能難以了解。這肯定有助于閱讀。以下是有關基本機制的幾個基本事實:

  • A

    ServletRequest

    可以通過調用進入異步模式

    request.startAsync()

    。這樣做的主要作用是Servlet以及任何過濾器都可以退出,但響應将保持開放狀态,以便稍後完成處理。
  • 可以用于進一步控制異步處理的

    request.startAsync()

    傳回 調用

    AsyncContext

    。例如,它提供的方法

    dispatch

    類似于Servlet API中的轉發,但它允許應用程式在Servlet容器線程上恢複請求處理。
  • ServletRequest

    提供對目前

    DispatcherType

    可用于處理所述初始請求,一個異步排程,正向,以及其他的排程類型之間進行區分。

考慮到上述情況,以下是異步請求處理的事件的順序

Callable

  • 控制器傳回a

    Callable

  • Spring MVC啟動異步處理,并在單獨的線程中送出

    Callable

    到一個

    TaskExecutor

    進行處理。
  • DispatcherServlet

    所有過濾器的退出Servlet容器線程,但反應仍然開放。
  • 所述

    Callable

    産生的結果和Spring MVC分派請求回Servlet容器以恢複處理。
  • DispatcherServlet

    再次調用和處理與來自所述異步生産結果恢複

    Callable

序列

DeferredResult

非常相似,除了由應用程式産生任何線程的異步結果:

  • 控制器傳回一個

    DeferredResult

    并将其儲存在某些記憶體中的隊列或清單中,可以通路它。
  • Spring MVC啟動異步處理。
  • DispatcherServlet

    所有配置的過濾器的退出請求處理線程,但反應仍然開放。
  • 應用程式

    DeferredResult

    從一些線程設定,Spring MVC将請求傳回給Servlet容器。
  • DispatcherServlet

    再次調用和處理與異步生産結果恢複。

有關異步請求處理的動機的進一步背景,何時或為什麼使用它,請閱讀 此部落格文章系列。

異步請求異常處理

如果

Callable

從控制器方法傳回的值在執行時引發異常,會發生什麼?簡短的答案與控制器方法引發異常時發生的情況相同。它經曆了正常異常處理機制。更長的解釋是,當

Callable

一個Exception Spring MVC排程到具有

Exception

結果的Servlet容器并導緻恢複請求處理時,

Exception

而不是控制器方法傳回值。使用時,

DeferredResult

您可以選擇是否調用

setResult

setErrorResult

使用

Exception

執行個體。

攔截異步請求

HandlerInterceptor

還可以實作

AsyncHandlerInterceptor

以執行

afterConcurrentHandlingStarted

回調,這就是所謂的代替

postHandle

afterCompletion

處理開始異步時。

A

HandlerInterceptor

還可以注冊一個

CallableProcessingInterceptor

或一個

DeferredResultProcessingInterceptor

以更深入地與異步請求的生命周期內建,例如處理逾時事件。有關

AsyncHandlerInterceptor

詳細資訊,請參閱Javadoc 。

DeferredResult

類型還提供了諸如

onTimeout(Runnable)

onCompletion(Runnable)

。有關

DeferredResult

詳細資訊,請參閱Javadoc 。

使用時,

Callable

您可以使用一個執行個體來包裝它

WebAsyncTask

,它還提供了逾時和完成的注冊方法。

HTTP流式傳輸

控制器方法可以異步地使用

DeferredResult

Callable

産生其傳回值,并且可以用于實作諸如 長輪詢的技術 ,其中伺服器可以盡快将事件推送到用戶端。

如果您想在單個HTTP響應中推送多個事件怎麼辦?這是一個與“長查詢”相關的技術,被稱為“HTTP流”。Spring MVC可以通過

ResponseBodyEmitter

可以用于發送多個對象的傳回值類型來實作,而不是像通常情況那樣

@ResponseBody

發送的對象,其中每個發送的對象都被寫入到響應中

HttpMessageConverter

這是一個例子:

@RequestMapping(“/ events”)
 public ResponseBodyEmitter handle(){
	ResponseBodyEmitter emitter = new ResponseBodyEmitter();
	//儲存發射的地方.. 
	傳回發射器;
}

//在其他一些線程 
emit.send(“Hello once”);

//再次在 
emitter.send(“Hello again”);

//并在某個時候完成 
emitter.complete();      

注意,

ResponseBodyEmitter

也可以用作身體

ResponseEntity

,以便自定義響應的狀态和标題。

HTTP流與伺服器發送的事件

SseEmitter

ResponseBodyEmitter

為伺服器發送事件提供支援 的子類。伺服器發送的事件是相同的“HTTP流”技術的另一個變體,除了從伺服器推送的事件根據W3C伺服器發送事件規範進行格式化。

伺服器發送事件可以用于其預期目的,即将事件從伺服器推送到用戶端。在Spring MVC中很容易做到,隻需傳回一個類型的值即可

SseEmitter

請注意,Internet Explorer不支援伺服器發送事件,而對于更進階的Web應用程式消息傳遞場景(如線上遊戲,協作,财務應用程式等),最好考慮Spring的WebSocket支援,其中包括SockJS風格的WebSocket仿真回落到非常廣泛的浏覽器(包括Internet Explorer)以及更進階别的消息傳遞模式,用于通過更多以消息為中心的體系結構中的釋出訂閱模型與用戶端進行互動。有關進一步的背景,請參閱 以下博文。

HTTP直接流向OutputStream

ResponseBodyEmitter

允許通過将對象寫入響應來發送事件

HttpMessageConverter

。這可能是最常見的情況,例如在編寫JSON資料時。但是有時候,繞過郵件轉換并直接寫入響應

OutputStream

(例如檔案下載下傳)是有用的。這可以在

StreamingResponseBody

傳回值類型的幫助下完成 。

這是一個例子:

@RequestMapping(“/ download”)
 public StreamingResponseBody handle(){
	 return  new StreamingResponseBody(){@
		 Override
		 public  void writeTo(OutputStream outputStream) throws IOException {
			 // write ...
		}
	};
}      

注意,

StreamingResponseBody

也可以用作身體

ResponseEntity

,以便自定義響應的狀态和标題。

配置異步請求處理

Servlet容器配置

對于配置

web.xml

為確定更新到版本3.0的應用程式:

<web-app  xmlns = “http://java.sun.com/xml/ns/javaee” 
	xmlns:xsi = “http://www.w3.org/2001/XMLSchema-instance” 
			http:// java。 sun.com/xml/ns/javaee 
			http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd” 
	版本 = “3.0” >

	...

</ web的應用>      

必須在

DispatcherServlet

通過

<async-supported>true</async-supported>

子元素中啟用異步支援

web.xml

。另外,任何

Filter

參與異步請求處理的任務都必須配置為支援ASYNC分派器類型。對于Spring Framework提供的所有過濾器,ASYNC排程器類型應該是安全的,因為它們通常是擴充的

OncePerRequestFilter

,并且具有對過濾器是否需要參與異步排程的運作時間檢查。

以下是一些web.xml配置示例:

<web-app  xmlns = “http://java.sun.com/xml/ns/javaee” 
	xmlns:xsi = “http://www.w3.org/2001/XMLSchema-instance” 
	xsi:schemaLocation = “
			http://java.sun.com/xml/ns/javaee
			http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd” 
	版本 = “3.0” >

	<filter> 
		<filter-name> Spring OpenEntityManagerInViewFilter </ filter-name> 
		<filter-class> org.springframework。〜.OpenEntityManagerInViewFilter </ filter-class> 
		<async-supported> true </ async-supported> 
	</ filter>

	<濾波器映射> 
		<濾波器名稱>春OpenEntityManagerInViewFilter </過濾器名稱> 
		<URL模式> / * </ URL模式> 
		<排程> REQUEST </排程程式> 
		<排程> ASYNC </排程程式> 
	</過濾器-mapping>

</ web的應用>      

如果使用Servlet 3,例如通過基于Java的配置

WebApplicationInitializer

,您還需要像之前一樣設定“asyncSupported”标志以及ASYNC排程器類型

web.xml

。為了簡化所有這些配置,請考慮擴充

AbstractDispatcherServletInitializer

或更好地

AbstractAnnotationConfigDispatcherServletInitializer

自動設定這些選項,并使其很容易注冊

Filter

執行個體。

Spring MVC配置

MVC Java配置和MVC命名空間提供了配置異步請求處理的選項。

WebMvcConfigurer

具有該方法

configureAsyncSupport

同時

<mvc:annotation-driven>

具有

<async-support>

子元素。

這些允許您配置用于異步請求的預設逾時值,如果未設定,則取決于底層的Servlet容器(例如Tomcat上的10秒)。您還可以配置一個

AsyncTaskExecutor

用于執行

Callable

從控制器方法傳回的執行個體。強制建議配置此屬性,預設情況下Spring MVC使用

SimpleAsyncTaskExecutor

。MVC Java配置和MVC命名空間也允許您注冊

CallableProcessingInterceptor

DeferredResultProcessingInterceptor

執行個體。

如果需要覆寫特定的預設逾時值

DeferredResult

,可以使用适當的類構造函數來實作。類似地,對于a

Callable

,可以将它包裝在一個

WebAsyncTask

并使用适當的類構造函數來自定義逾時值。類的構造函數

WebAsyncTask

也允許提供一個

AsyncTaskExecutor

18.3.5測試控制器

spring-test

子產品提供一流的支援,用于測試帶注釋的控制器。參見第11.6節“Spring MVC測試架構”。

18.4處理程式映射

在以前的Spring版本中,使用者需要

HandlerMapping

在Web應用程式上下文中定義一個或多個 bean,以将傳入的Web請求映射到适當的處理程式。通過引入注釋控制器,您通常不需要這樣做,因為它

RequestMappingHandlerMapping

@RequestMapping

自動在所有

@Controller

bean 上查找 注釋。但是,請記住,所有

HandlerMapping

擴充的類

AbstractHandlerMapping

都具有以下可用于自定義行為的屬性:

  • interceptors

    要使用的攔截器清單。

    HandlerInterceptor

    在 第18.4.1節“使用HandlerInterceptor攔截請求”中讨論。
  • defaultHandler

    當這個處理程式映射不會導緻一個比對的處理程式時,使用預設處理程式。
  • order

    基于order屬性的值(參見

    org.springframework.core.Ordered

    接口),Spring會排序上下文中可用的所有處理程式映射,并應用第一個比對處理程式。
  • alwaysUseFullPath

    如果

    true

    Spring使用目前Servlet上下文中的完整路徑來找到一個适當的處理程式。如果

    false

    (預設值),則使用目前Servlet映射中的路徑。例如,如果使用Servlet

    /testing/*

    并将

    alwaysUseFullPath

    屬性設定為true,

    /testing/viewPage.html

    則使用該屬性,而如果該屬性設定為false

    /viewPage.html

  • urlDecode

    預設為

    true

    ,從Spring 2.5開始。如果您喜歡比較編碼路徑,請将此标志設定為

    false

    。但是,

    HttpServletRequest

    始終以解碼形式公開Servlet路徑。請注意,與編碼路徑相比,Servlet路徑将不比對。

以下示例顯示如何配置攔截器:

<bean> 
	<bean  class = “org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping” > 
		<property  name = “interceptors” > 
			<bean  class = “example.MyInterceptor” /> 
		</ property> 
	</ bean> 
</ beans>      

18.4.1用HandlerInterceptor攔截請求

Spring的處理程式映射機制包括處理程式攔截器,當您希望将特定功能應用于某些請求時,例如,檢查主體,這是有用的。

位于處理程式映射中的攔截器必須

HandlerInterceptor

org.springframework.web.servlet

包中實作。這個接口定義了三個方法:

preHandle(..)

被稱為前被執行的實際處理程式;

postHandle(..)

被稱為後執行的處理程式; 并在完成請求完成後

afterCompletion(..)

調用。這三種方法應提供足夠的靈活性進行各種預處理和後處理。

preHandle(..)

方法傳回一個布爾值。您可以使用此方法來中斷或繼續處理執行鍊。當此方法傳回

true

時,處理程式執行鍊将繼續; 當它傳回false時,

DispatcherServlet

假定攔截器本身已經處理了請求(并且例如呈現适當的視圖),并且不會繼續執行其他攔截器和執行鍊中的實際處理程式。

攔截器可以使用

interceptors

屬性進行配置,該屬性存在于所有

HandlerMapping

類中

AbstractHandlerMapping

。這在下面的示例中顯示:

<bean> 
	<bean  id = “handlerMapping” 
			class = “org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping” > 
		<property  name = “interceptors” > 
			<list> 
				<ref  bean = “officeHoursInterceptor” /> 
			</ list> 
		</ property> 
	</ bean>

	<bean  id = “officeHoursInterceptor” 
			class = “samples.TimeBasedAccessInterceptor” > 
		<property  name = “openingTime”  value = “9” /> 
		<property  name = “closingTime”  value = “18” /> 
	</ bean> 
</ beans >      
包裝樣品;

public  class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {

	private  int openingTime;
	private  int closingTime;

	public  void setOpeningTime(int openingTime){
		 this .openingTime = openingTime;
	}

	public  void setClosingTime(int closingTime){
		 this .closingTime = closingTime;
	}

	public  boolean preHandle(HttpServletRequest request,HttpServletResponse response,
			對象處理程式)throws Exception {
		月曆cal = Calendar.getInstance();
		int hour = cal.get(HOUR_OF_DAY);
		if(openingTime <= hour && hour <closingTime){
			 return true;
		}
		response.sendRedirect(“http://host.com/outsideOfficeHours.html”);
		傳回假
	}
}      

該映射處理的任何請求都被截取

TimeBasedAccessInterceptor

。如果目前時間在辦公時間之外,使用者将被重定向到靜态HTML檔案,例如,您隻能在辦公時間内通路該網站。

《Spring 5 官方文檔》18. Web MVC 架構
當使用

RequestMappingHandlerMapping

實際處理程式時,

HandlerMethod

它的一個執行個體 辨別将被調用的特定控制器方法。

您可以看到,Spring擴充卡類

HandlerInterceptorAdapter

可以更容易地擴充

HandlerInterceptor

接口。

《Spring 5 官方文檔》18. Web MVC 架構
在上面的示例中,配置的攔截器将應用于使用注釋控制器方法處理的所有請求。如果要縮小攔截器應用的URL路徑,可以使用MVC命名空間或MVC Java配置,或聲明類型的bean執行個體

MappedInterceptor

。請參見第18.16.1節“啟用MVC Java配置或MVC XML命名空間”。

請注意,該

postHandle

方法

HandlerInterceptor

并不總是非常适用于

@ResponseBody

ResponseEntity

方法。在這種情況下

HttpMessageConverter

,在

postHandle

調用之前寫入并送出響應,這使得不可能更改響應,例如添加标題。相反,應用程式可以實作

ResponseBodyAdvice

并将其聲明為

@ControllerAdvice

bean或直接配置它

RequestMappingHandlerAdapter

18.5解決觀點

用于Web應用程式的所有MVC架構提供了一種解決視圖的方法。Spring提供視圖解析器,使您可以在浏覽器中渲染模型,而不需要将您視為特定的視圖技術。開箱即用,例如,Spring允許您使用JSP,FreeMarker模闆和XSLT視圖。請參見第19章,檢視技術對于如何整合并使用不同的視圖技術的讨論。

對于Spring處理視圖的方式來說重要的兩個接口是

ViewResolver

View

。所述

ViewResolver

提供視圖名稱和實際視圖之間的映射。該

View

接口解決了請求的準備,并将請求交給一種視圖技術。

18.5.1使用ViewResolver界面解析視圖

正如在讨論第18.3節,“實施控制器”,在Spring Web MVC架構控制器的所有處理方法必須解析為一個邏輯視圖名稱,明确地(例如,通過傳回

String

View

ModelAndView

)或隐式(即基于慣例)。Spring中的視圖由邏輯視圖名稱解析,并由視圖解析器解析。春天有不少視角解析器。這張表列出了大部分; 以下幾個例子。

表18.3。檢視解析器

視圖解析器 描述

AbstractCachingViewResolver

抽象視圖解析器緩存視圖。通常情況下,需要準備才能使用; 擴充此視圖解析器提供緩存。

XmlViewResolver

實作

ViewResolver

它接受使用與Spring的XML bean工廠相同的DTD使用XML編寫的配置檔案。預設配置檔案是

/WEB-INF/views.xml

ResourceBundleViewResolver

實作

ViewResolver

它使用bean定義

ResourceBundle

,由bundle基本名稱指定。通常,您可以在屬性檔案中定義bundle,該屬性檔案位于類路徑中。預設檔案名是

views.properties

UrlBasedViewResolver

簡單地實作

ViewResolver

了直接解析邏輯視圖名稱到URL的接口,而沒有明确的映射定義。如果您的邏輯名稱以直覺的方式與視圖資源的名稱比對,則這是适當的,而不需要任意映射。

InternalResourceViewResolver

友善的子類

UrlBasedViewResolver

支援

InternalResourceView

(實際上是Servlet和JSP)和子類,如

JstlView

TilesView

。您可以通過使用為此解析器生成的所有視圖指定視圖類

setViewClass(..)

。有關

UrlBasedViewResolver

詳細資訊,請參閱javadoc。

FreeMarkerViewResolver

它的便利子類

UrlBasedViewResolver

支援

FreeMarkerView

和自定義子類。

ContentNegotiatingViewResolver

實作

ViewResolver

根據請求檔案名或

Accept

頭解析視圖的界面。請參見第18.5.4節“ContentNegotiatingViewResolver”。

例如,使用JSP作為視圖技術,可以使用

UrlBasedViewResolver

。此視圖解析器将視圖名稱轉換為URL,并将請求轉交給RequestDispatcher以呈現視圖。

<bean  id = “viewResolver” 
		class = “org.springframework.web.servlet.view.UrlBasedViewResolver” > 
	<property  name = “viewClass”  value = “org.springframework.web.servlet.view.JstlView” /> 
	<property  name = “prefix”  value = “/ WEB-INF / jsp /” /> 
	<property  name = “suffix”  value = “.jsp” /> 
</ bean>      

test

以邏輯視圖名稱傳回時,此視圖解析器将請求轉發到

RequestDispatcher

将要發送的請求

/WEB-INF/jsp/test.jsp

當您在Web應用程式中組合不同的視圖技術時,可以使用

ResourceBundleViewResolver

<bean  id = “viewResolver” 
		class = “org.springframework.web.servlet.view.ResourceBundleViewResolver” > 
	<property  name = “basename”  value = “views” /> 
	<property  name = “defaultParentView”  value = “parentView” / > 
</ bean>      

ResourceBundleViewResolver

考察

ResourceBundle

确定了基本名字和它應該解決每個視圖,它使用屬性的值

[viewname].(class)

作為視圖類和屬性的值

[viewname].url

作為視圖的URL。示例可以在下一章中找到,涵蓋視圖技術。您可以看到,您可以識别父視圖,從屬性檔案中的所有視圖“擴充”。這樣,您可以指定預設視圖類。

《Spring 5 官方文檔》18. Web MVC 架構

AbstractCachingViewResolver

他們解析的緩存視圖執行個體的子類。緩存提高了某些視圖技術的性能。可以通過将

cache

屬性設定為關閉緩存

false

。此外,如果您必須在運作時重新整理某個視圖(例如,當FreeMarker模闆被修改時),則可以使用該

removeFromCache(String viewName, Locale loc)

方法。

18.5.2連結視圖解析器

Spring支援多個視圖解析器。是以,您可以連結解析器,并且在某些情況下例如覆寫特定視圖。您可以通過在應用程式上下文中添加多個解析器來連結視圖解析器,如有必要,可以通過設定

order

屬性來指定排序。記住,order屬性越高,視圖解析器在鍊中的位置越晚。

在以下示例中,視圖解析器由兩個解析器組成,一個

InternalResourceViewResolver

始終自動定位為鍊中的最後一個解析器,另一個

XmlViewResolver

用于指定Excel視圖。Excel不支援Excel視圖

InternalResourceViewResolver

<bean  id = “jspViewResolver”  class = “org.springframework.web.servlet.view.InternalResourceViewResolver” > 
	<property  name = “viewClass”  value = “org.springframework.web.servlet.view.JstlView” /> 
	<property  name = “prefix”  value = “/ WEB-INF / jsp /” /> 
	<property  name = “suffix”  value = “.jsp” /> 
</ bean>

<bean  id = “excelViewResolver”  class = “org.springframework.web.servlet.view.XmlViewResolver” > 
	<property  name = “order”  value = “1” /> 
	<property  name = “location”  value = “/ WEB- INF / views.xml“ /> 
</ bean>

<! -  in views.xml  - >

<bean> 
	<bean  name = “report”  class = “org.springframework.example.ReportExcelView” /> 
</ beans>      

如果一個特定的視圖解析器不會産生視圖,Spring會檢查其他視圖解析器的上下文。如果存在另外的視圖解析器,Spring會繼續檢查它們,直到視圖解決。如果沒有視圖解析器傳回一個視圖,Spring會抛出一個

ServletException

視圖解析器的合同指定視圖解析器可以傳回null以訓示無法找到視圖。然而,并不是所有的視圖解析器都這樣做,因為在某些情況下,解析器根本無法檢測視圖是否存在。例如,内部

InternalResourceViewResolver

使用

RequestDispatcher

,分派是确定JSP是否存在的唯一方法,但此操作隻能執行一次。對于

FreeMarkerViewResolver

其他一些人也是如此。檢查特定視圖解析器的javadoc以檢視是否報告不存在的視圖。是以,把一個

InternalResourceViewResolver

在鍊中比在鍊中的最後結果的其他地方沒有得到充分檢驗,因為

InternalResourceViewResolver

意志總是傳回一個視圖!

18.5.3重定向到視圖

如前所述,控制器通常傳回邏輯視圖名稱,視圖解析器解析為特定視圖技術。對于視圖技術如JSP,其通過servlet或JSP引擎處理,此分辨率通常是通過組合處理

InternalResourceViewResolver

InternalResourceView

,它發出一個内部正向或包括經由在Servlet API的

RequestDispatcher.forward(..)

方法或

RequestDispatcher.include()

方法。對于其他視圖技術,如FreeMarker,XSLT等,視圖本身将内容直接寫入響應流。

在呈現視圖之前,有時需要将HTTP重定向發回用戶端。這是可取的,例如,當一個控制器已經被調用了

POST

資料時,并且響應實際上是對另一個控制器的委派(例如,成功的表單送出)。在這種情況下,正常的内部向前将意味着另一個控制器也将看到相同的

POST

資料,如果它可能與其他預期資料混淆,這是潛在的問題。在顯示結果之前執行重定向的另一個原因是消除使用者多次送出表單資料的可能性。在這種情況下,浏覽器将首先發送一個初始的

POST

; 然後會收到重定向到其他URL的響應;

GET

最後浏覽器将為重定向響應中指定的URL執行後續操作。是以,從浏覽器的角度來看,目前頁面并不反映的結果

POST

,而是一個

GET

。最終的效果是使用者無法

POST

通過執行重新整理來意外重新獲得相同的資料。重新整理強制

GET

結果頁面a,而不是重新發送初始

POST

資料。

RedirectView的

作為控制器響應的結果強制重定向的一種方法是控制器建立并傳回Spring的執行個體

RedirectView

。在這種情況下,

DispatcherServlet

不使用普通視圖分辨機制。而是因為已經給了(重定向)視圖,

DispatcherServlet

簡單地訓示視圖來完成它的工作。将

RedirectView

依次調用

HttpServletResponse.sendRedirect()

發送一個HTTP重定向到用戶端浏覽器。

如果使用

RedirectView

并且視圖由控制器本身建立,則建議您将重定向URL配置為注入到控制器中,以使其不會被烘烤到控制器中,而是在上下文中配置視圖名稱。在一節“重定向:字首”有利于這種脫鈎。

将資料傳遞到重定向目标

預設情況下,所有模型屬性都被認為是重定向URL中的URI模闆變量。在剩餘的屬性中,原始類型或原始類型的集合/數組的那些屬性将自動附加為查詢參數。

如果為重定向準備了模型執行個體,則将原始類型屬性作為查詢參數附加可能是所需的結果。然而,在注釋控制器中,模型可能包含為渲染目的添加的附加屬性(例如下拉字段值)。為了避免這種屬性出現在URL中的可能性,一種

@RequestMapping

方法可以聲明一個類型的參數,

RedirectAttributes

并使用它來指定可供使用的确切屬性

RedirectView

。如果方法重定向,則使用内容

RedirectAttributes

。否則使用模型的内容。

RequestMappingHandlerAdapter

提供了一個名為标志

"ignoreDefaultModelOnRedirect"

,可以用來表示預設的内容

Model

,如果一個控制器方法重定向不應該被使用。相反,控制器方法應該聲明一個類型的屬性,

RedirectAttributes

或者如果它不這樣做,則不應該傳遞任何屬性

RedirectView

。MVC命名空間和MVC Java配置都将此标志設定

false

為保持向後相容性。但是,對于新的應用程式,我們建議将其設定為

true

請注意,當擴充重定向網址時,來自本請求的URI模闆變量将自動提供,并且不需要通過

Model

或不顯式添加

RedirectAttributes

。例如:

@PostMapping(“/ files / {path}”)
 public String upload(...){
	 // 
	傳回 “redirect:files / {path}” ;
}      

将資料傳遞到重定向目标的另一種方法是通過Flash屬性。與其他重定向屬性不同,Flash屬性儲存在HTTP會話中(是以不會出現在URL中)。有關詳細資訊,請參見第18.6節“使用Flash屬性”。

重定向:字首

雖然使用

RedirectView

工程正常,如果控制器本身建立

RedirectView

,則沒有避免控制器知道重定向發生的事實。這是非常不合時宜的事情,太緊密地結合在一起。控制器不應該真正關心響應如何處理。一般來說,它應該僅在注入到其中的視圖名稱的方式操作。

特殊的

redirect:

字首允許你完成這個。如果傳回具有字首的視圖名稱

redirect:

,則

UrlBasedViewResolver

(和所有子類)将會将其識别為需要重定向的特殊訓示。視圖名稱的其餘部分将被視為重定向網址。

淨效果與控制器傳回一樣

RedirectView

,但現在控制器本身可以簡單地按邏輯視圖名稱進行操作。一個邏輯視圖名稱,例如

redirect:/myapp/some/resource

将重定向到目前的Servlet上下文,而一個名稱

redirect:http://myhost.com/some/arbitrary/path

将重定向到絕對URL。

請注意,控制器處理程式使用注釋

@ResponseStatus

,注釋值優先于設定的響應狀态

RedirectView

轉發:字首

也可以使用

forward:

最終由子類決定的視圖名稱的特殊字首

UrlBasedViewResolver

。這将建立一個 視圖名稱

InternalResourceView

(其最終将

RequestDispatcher.forward()

圍繞其被視為URL)的視圖名稱。是以,這個字首對于

InternalResourceViewResolver

InternalResourceView

(對于JSP而言)不是有用的。但是,當您主要使用另一種視圖技術時,字首可能會有所幫助,但是仍然希望強制轉發由Servlet / JSP引擎處理的資源。(請注意,您也可以連結多個視圖解析器。)

redirect:

字首一樣,如果具有字首的視圖名稱

forward:

注入到控制器中,則控制器在處理響應方面沒有檢測到發生任何特殊事件。

18.5.4 ContentNegotiatingViewResolver

ContentNegotiatingViewResolver

不會解析視圖本身,而是委托給其他視圖解析器,選擇類似于用戶端請求的表示的視圖。用戶端可以從伺服器請求表示方式存在兩種政策:

  • 通常通過在URI中使用不同的檔案擴充名為每個資源使用不同的URI。例如,URI

    http://www.example.com/users/fred.pdf

    請求使用者fred的PDF表示,并

    http://www.example.com/users/fred.xml

    請求XML表示。
  • 使用相同的URI來為用戶端定位資源,但設定

    Accept

    HTTP請求标頭以列出它了解的媒體類型。例如,一個HTTP請求,

    http://www.example.com/users/fred

    其中一個

    Accept

    頭設定為

    application/pdf

    請求使用者fred的PDF表示,同時

    http://www.example.com/users/fred

    使用

    Accept

    頭設定來

    text/xml

    請求XML表示。這個政策被稱為 内容談判。
《Spring 5 官方文檔》18. Web MVC 架構

Accept

标題的一個問題是,不可能在HTML中的Web浏覽器中設定它。例如,在Firefox中,它被修改為:
接受:text / html,application / xhtml + xml,application / xml; q = 0.9,* / *; q = 0.8      
是以,在開發基于浏覽器的Web應用程式時,通常會看到每個表示使用不同的URI。

為了支援資源的多個表示,Spring提供了

ContentNegotiatingViewResolver

根據

Accept

HTTP請求的檔案擴充名或頭部來解析視圖。

ContentNegotiatingViewResolver

不執行視圖分辨率本身,而是委托給您通過bean屬性指定的視圖解析器的清單

ViewResolvers

ContentNegotiatingViewResolver

選擇一個合适的

View

通過比較與所述媒體類型(也被稱為媒體請求類型(一個或多個),以處理該請求

Content-Type

由支援)的

View

與每個其相關聯

ViewResolvers

View

具有相容性的清單中的第一個将表示

Content-Type

傳回給用戶端。如果鍊條不能提供相容的視圖,則會檢視

ViewResolver

通過

DefaultViews

屬性指定的視圖清單。後一個選項适用于

Views

可以呈現目前資源的适當表示的單例,而不管邏輯視圖名稱如何。的

Accept

報頭可以包括通配符,例如

text/*

,在這種情況下

View

,其内容類型是

text/xml

為相容的比對。

要支援基于檔案擴充名的視圖的自定義解析,請使用

ContentNegotiationManager

:請參見第18.16.6節“内容協商”。

以下是一個示例配置

ContentNegotiatingViewResolver

<bean  class = “org.springframework.web.servlet.view.ContentNegotiatingViewResolver” > 
	<property  name = “viewResolvers” > 
		<list> 
			<bean  class = “org.springframework.web.servlet.view.BeanNameViewResolver” /> 
			<bean  class = “org.springframework.web.servlet.view.InternalResourceViewResolver” > 
				<property  name = “prefix”  value = “/ WEB-INF / jsp /” /> 
				<property  name = “suffix” value = “.jsp” /> 
			</ bean> 
		</ list> 
	</ property> 
	<property  name = “defaultViews” > 
		<list> 
			<bean  class = “org.springframework.web.servlet.view.json.MappingJackson2JsonView” /> 
		</ list> 
	</ property> 
</ bean>web.servlet.view.json.MappingJackson2JsonView“ /> </ list> </ property> </ bean>web.servlet.view.json.MappingJackson2JsonView“ /> </ list> </ property> </ bean>

<bean  id = “content”  class = “com.foo.samples.rest.SampleContentAtomView” />      

InternalResourceViewResolver

搖桿視圖名稱和JSP頁面的翻譯,而

BeanNameViewResolver

傳回基于bean的名稱的視圖。(有關Spring如何查找和執行個體化視圖的更多詳細資訊,請參閱“ 使用ViewResolver界面解析視圖”。)在此示例中,該

content

bean是繼承的類,該類

AbstractAtomFeedView

傳回Atom RSS提要。有關建立Atom Feed表示的更多資訊,請參閱Atom視圖。

在上述配置中,如果使用擴充名進行請求

.html

,視圖解析器将查找與

text/html

媒體類型比對的視圖。在

InternalResourceViewResolver

提供了用于比對視圖

text/html

。如果請求是使用檔案擴充名

.atom

,視圖解析器将查找與

application/atom+xml

媒體類型相比對的視圖。該視圖由該

BeanNameViewResolver

映射提供給

SampleContentAtomView

如果傳回的視圖名稱是

content

。如果使用檔案擴充名進行請求

.json

,則無論視圖名稱如何,

MappingJackson2JsonView

将從

DefaultViews

清單中選擇執行個體。或者,用戶端請求可以在沒有檔案擴充名的情況下進行,但是将

Accept

标題設定為首選媒體類型,并且将發生對視圖請求的相同解析。

《Spring 5 官方文檔》18. Web MVC 架構
如果“ContentNegotiatingViewResolver”的ViewResolver清單未被明确配置,它會自動使用應用程式上下文中定義的任何ViewResolvers。

相應的控制器代碼傳回表單的URI

http://localhost/content.atom

http://localhost/content

應用

Accept

程式/ atom + xml 的頭部的Atom RSS提要 如下所示。

@Controller
 public  class ContentController {

	private List <SampleContent> contentList = new ArrayList <SampleContent>();

	@GetMapping(“/ content”)
	 public ModelAndView getContent(){
		ModelAndView mav = new ModelAndView();
		mav.setViewName(“content”);
		mav.addObject(“sampleContentList”,contentList);
		傳回 mav
	}

}      

18.6使用flash屬性

Flash屬性為一個請求存儲旨在用于另一個的屬性提供了一種方法。這是重定向時最常用的 – 例如 Post / Redirect / Get模式。閃存屬性在重定向(通常在會話中)之前臨時儲存,以便在重定向後立即對請求提供可用的請求。

Spring MVC有兩個主要的抽象支援Flash屬性。

FlashMap

用于儲存Flash屬性,

FlashMapManager

用于存儲,檢索和管理

FlashMap

執行個體。

Flash屬性支援始終是“開”的,不需要明确啟用,盡管如果不使用它,它不會導緻HTTP會話建立。在每個請求上都有一個“輸入”

FlashMap

,它具有從先前的請求傳遞的屬性(如果有的話)和

FlashMap

帶有屬性的“輸出” ,以儲存後續請求。這兩個

FlashMap

執行個體可以通過靜态方法在Spring MVC中從任何地方通路

RequestContextUtils

注釋控制器通常不需要

FlashMap

直接使用。相反,

@RequestMapping

方法可以接受類型的參數,

RedirectAttributes

并使用它來為重定向方案添加閃存屬性。添加的Flash屬性将

RedirectAttributes

自動傳播到“輸出”FlashMap。類似地,在重定向之後,來自“輸入”

FlashMap

的屬性将自動添加到

Model

為目标URL提供服務的控制器中。

比對請求到Flash屬性

閃存屬性的概念存在于許多其他Web架構中,并且已被證明有時暴露于并發問題。這是因為根據定義,flash屬性将被存儲直到下一個請求。然而,“下一個”請求可能不是預期的接收方,而是另一個異步請求(例如輪詢或資源請求),在這種情況下,閃存屬性過早地被删除。

為了減少此類問題的可能性,請使用目标重定向網址的路徑和查詢參數

RedirectView

自動“郵票”

FlashMap

執行個體。反過來,預設情況下

FlashMapManager

,當查詢“輸入”時,将該資訊與傳入請求相比對

FlashMap

這不能完全消除并發問題的可能性,但是仍然可以通過重定向URL中已經提供的資訊來大大減少它。是以,使用Flash屬性主要用于重定向方案。

18.7建構URI

Spring MVC提供了一種用于使用

UriComponentsBuilder

和建構和編碼URI的機制

UriComponents

例如,您可以擴充和編碼URI模闆字元串:

UriComponents uriComponents = UriComponentsBuilder.fromUriString(
		 “http://example.com/hotels/{hotel}/bookings/{booking}”).build();

URI uri = uriComponents.expand(“42”,“21”).encode()。toUri();      

請注意,這

UriComponents

是不可變的

expand()

encode()

如果需要,并且操作傳回新的執行個體。

您還可以使用各個URI元件進行擴充和編碼:

UriComponents uriComponents = UriComponentsBuilder.newInstance()
		.scheme(“http”). host(“example.com”).path(“/酒店/ {酒店} /預訂/ {預訂}”).build()
		.expand(“42”,“21”)
		.encode();      

在Servlet環境中,

ServletUriComponentsBuilder

子類提供靜态工廠方法從Servlet請求中複制可用的URL資訊:

HttpServletRequest request = ...

//重新使用host,scheme,port,path和query string 
//替換“accountId”查詢參數

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromRequest(request)
		.replaceQueryParam(“accountId”,“{id}”).build()
		.expand(“123”)
		.encode();      

或者,您可以選擇複制可用資訊的子集,直到并包括上下文路徑:

//重新使用主機,端口和上下文路徑
//将“/ accounts”附加到路徑

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromContextPath(request)
		.path(“/ accounts”).build()      

或者在

DispatcherServlet

按名稱(例如

/main/*

)映射的情況下,還可以包含servlet映射的文字部分:

//重新使用主機,端口,上下文路徑
//将servlet映射的文字部分附加到路徑
//将“/ accounts”附加到路徑

ServletUriComponentsBuilder ucb = ServletUriComponentsBuilder.fromServletMapping(request)
		.path(“/ accounts”).build()      

18.7.1建構控制器和方法的URI

Spring MVC還提供了一種建構控制器方法連結的機制。例如,給出:

@Controller 
@RequestMapping(“/ hotels / {hotel}”)
 public  class BookingController {

	@GetMapping(“/ bookings / {booking}”)
	 public String getBooking( @PathVariable Long booking){

	// ...
       }
}      

您可以通過名稱參考方法來準備連結:

UriComponents uriComponents = MvcUriComponentsBuilder
	.fromMethodName(BookingController 類,“getBooking” ,21).buildAndExpand(42);

URI uri = uriComponents.encode()。toUri();      

在上面的例子中,我們提供了實際的方法參數值,在這種情況下是長值21,用作路徑變量并插入到URL中。此外,我們提供了值42,以填充任何剩餘的URI變量,例如從類型級請求映射繼承的“hotel”變量。如果該方法有更多的參數,您可以為URL不需要的參數提供null。一般而言

@PathVariable

@RequestParam

參數與構造URL相關。

還有其他的使用方法

MvcUriComponentsBuilder

。例如,您可以使用類似于通過代理模拟測試的技術,以避免通過名稱引用控制器方法(示例假定靜态導入

MvcUriComponentsBuilder.on

):

UriComponents uriComponents = MvcUriComponentsBuilder
	.fromMethodCall(上(BookingController。類).getBooking(21))buildAndExpand(42);

URI uri = uriComponents.encode()。toUri();      

上面的例子使用靜态方法

MvcUriComponentsBuilder

。在内部,他們依靠

ServletUriComponentsBuilder

從目前請求的方案,主機,端口,上下文路徑和servlet路徑準備基本URL。這在大多數情況下運作良好,但有時可能不足。例如,您可能不在請求的上下文中(例如,準備連結的批處理),或者您可能需要插入路徑字首(例如,從請求路徑中删除并需要重新插入到連結中的區域設定字首)。

對于這種情況,您可以使用接受a

UriComponentsBuilder

使用基本URL 的靜态“fromXxx”重載方法 。或者您可以

MvcUriComponentsBuilder

使用基本URL 建立一個執行個體,然後使用基于執行個體的“withXxx”方法。例如:

UriComponentsBuilder base = ServletUriComponentsBuilder.fromCurrentContextPath()。path(“/ en”);
MvcUriComponentsBuilder builder = MvcUriComponentsBuilder.relativeTo(base);
builder.withMethodCall(上(BookingController。類).getBooking(21))buildAndExpand(42);

URI uri = uriComponents.encode()。toUri();      

18.7.2建構來自視圖的控制器和方法的URI

您還可以從JSP,Thymeleaf,FreeMarker等視圖中建構帶注釋控制器的連結。這可以使用

fromMappingName

方法,

MvcUriComponentsBuilder

其中指的是按名稱映射。

每個都會

@RequestMapping

根據類的大寫字母和完整的方法名稱配置設定一個預設名稱。例如,

getFoo

FooController

中的方法被配置設定名稱“FC#getFoo”。該政策可以通過建立一個執行個體

HandlerMethodMappingNamingStrategy

并将其插入到您中 來進行替換或定制

RequestMappingHandlerMapping

。預設政策實作也會檢視name屬性

@RequestMapping

,如果存在,則使用該屬性。這意味着如果配置設定的預設映射名稱與另一個沖突(例如重載方法),則可以在該目錄上明确指定一個名稱

@RequestMapping

《Spring 5 官方文檔》18. Web MVC 架構
配置設定的請求映射名稱在啟動時記錄在TRACE級别。

Spring JSP标簽庫提供了一個名為

mvcUrl

該函數的函數,可用于根據此機制準備到控制器方法的連結。

例如:

@RequestMapping(“/ people / {id} / addresses”)
 public  class PersonAddressController {

    @RequestMapping(“/ {country}”)
     public HttpEntity getAddress( @PathVariable String country){...}
}      

您可以從JSP準備一個連結,如下所示:

%@ taglib uri =“http://www.springframework.org/tags”prefix =“s”%>
...
<a href="${s:mvcUrl('PAC#getAddress').arg(0,'US').buildAndExpand('123')}" target="_blank" rel="external nofollow" >擷取位址</a>      

上述示例依賴于

mvcUrl

在Spring标簽庫(即META-INF / spring.tld)中聲明的JSP函數。對于更進階的案例(例如上一節所述的自定義基本URL),可以輕松地定義自己的函數或使用自定義标記檔案,以便使用

MvcUriComponentsBuilder

具有自定義基本URL 的特定執行個體。

18.8使用區域設定

Spring的大部分架構支援國際化,就像Spring Web MVC架構一樣。

DispatcherServlet

使您能夠使用用戶端的語言環境自動解析郵件。這是用

LocaleResolver

對象完成的。

當一個請求進來時,

DispatcherServlet

尋找一個區域設定解析器,如果它找到一個它試圖使用它來設定區域設定。使用該

RequestContext.getLocale()

方法,您可以随時檢索由語言環境解析器解析的區域設定。

除了自動區域設定解析之外,您還可以将攔截器附加到處理程式映射(參見第18.4.1節“攔截與HandlerInterceptor的請求”以擷取有關處理程式映射攔截器的更多資訊),以在特定情況下更改區域設定,例如,基于請求中的參數。

org.springframework.web.servlet.i18n

程式包中定義了語言環境解析器和攔截器, 并以正常方式在應用程式上下文中配置。以下是Spring中包含的區域解析器的選擇。

18.8.1擷取時區資訊

除了擷取客戶的區域設定之外,了解他們的時區通常也是有用的。該

LocaleContextResolver

界面提供了一個擴充

LocaleResolver

,允許解析器提供更豐富

LocaleContext

,可能包括時區資訊。

如果可用,

TimeZone

可以使用該

RequestContext.getTimeZone()

方法獲得 使用者。時區資訊将自動被Date / Time

Converter

Formatter

Spring注冊的對象使用

ConversionService

18.8.2 AcceptHeaderLocaleResolver

該語言環境解析器檢查

accept-language

用戶端發送的請求中的标題(例如,Web浏覽器)。通常此标題字段包含用戶端作業系統的區域設定。請注意,此解析器不支援時區資訊。

18.8.3 CookieLocaleResolver

這個本地化解析器檢查一個

Cookie

可能的用戶端中,看是否有

Locale

TimeZone

指定。如果是這樣,它使用指定的細節。使用此語言環境解析器的屬性,您可以指定cookie的名稱以及最大的年齡。在下面找到一個定義a的例子

CookieLocaleResolver

<bean  id = “localeResolver”  class = “org.springframework.web.servlet.i18n.CookieLocaleResolver” >

	<property  name = “cookieName”  value = “clientlanguage” />

	<! - 以秒為機關。如果設定為-1,則cookie不會持久化(在浏覽器關閉時删除) - > 
	<property  name = “cookieMaxAge”  value = “100000” />

</豆>      

表18.4。CookieLocaleResolver屬性

屬性 預設 描述
cookieName classname + LOCALE cookie的名稱
名cookieMaxAge Servlet容器預設 Cookie在用戶端上保持持續的最長時間。如果指定了-1,則cookie不會被持久化; 隻有用戶端關閉浏覽器才可用。
cookiePath / 将Cookie的可見性限制在您網站的某個部分。指定cookiePath時,cookie将隻對該路徑及其下方的路徑可見。

18.8.4 SessionLocaleResolver

SessionLocaleResolver

可以檢索

Locale

TimeZone

從可能與使用者的請求相關的會話。相反

CookieLocaleResolver

,該政策将本地選擇的區域設定存儲在Servlet容器中

HttpSession

。是以,這些設定對于每個會話都是臨時的,是以在每個會話終止時丢失。

請注意,與Spring Session項目之類的外部會話管理機制沒有直接關系。這

SessionLocaleResolver

将簡單地根據

HttpSession

目前值來評估和修改相應的屬性

HttpServletRequest

18.8.5 LocaleChangeInterceptor

您可以通過添加

LocaleChangeInterceptor

到其中一個處理程式映射來啟用更改區域設定(請參見第18.4節“處理程式映射”)。它将檢測請求中的一個參數并更改區域設定。它呼籲

setLocale()

LocaleResolver

上下文中也存在。以下示例顯示,對包含

*.view

名為的參數的所有資源的調用

siteLanguage

現在将更改語言環境。是以,例如,對以下URL的請求

http://www.sf.net/home.view?siteLanguage=nl

将會将站點語言更改為荷蘭語。

<bean  id = “localeChangeInterceptor” 
		class = “org.springframework.web.servlet.i18n.LocaleChangeInterceptor” > 
	<property  name = “paramName”  value = “siteLanguage” /> 
</ bean>

<bean  id = “localeResolver” 
		class = “org.springframework.web.servlet.i18n.CookieLocaleResolver” />

<bean  id = “urlMapping” 
		class = “org.springframework.web.servlet.handler.SimpleUrlHandlerMapping” > 
	<property  name = “interceptors” > 
		<list> 
			<ref  bean = “localeChangeInterceptor” /> 
		</ list> 
	</ property > 
	<property  name = “mappings” > 
		<value> /**/*.view=someController </ value> 
	</ property> 
</ bean>      

18.9使用主題

18.9.1主題概述

您可以應用Spring Web MVC架構主題來設定應用程式的整體外觀,進而增強使用者體驗。主題是影響應用程式視覺風格的靜态資源(通常是樣式表和圖像)的集合。

18.9.2定義主題

要在Web應用程式中使用主題,您必須設定接口的

org.springframework.ui.context.ThemeSource

實作。該

WebApplicationContext

接口擴充

ThemeSource

,但其代表職責的專用實作。預設情況下,委托将是

org.springframework.ui.context.support.ResourceBundleThemeSource

從類路徑根目錄加載屬性檔案的實作。要使用自定義

ThemeSource

實作或配置基本名稱字首

ResourceBundleThemeSource

,可以在應用程式上下文中使用保留名稱注冊一個bean

themeSource

。Web應用程式上下文将自動檢測具有該名稱的bean并使用它。

使用時

ResourceBundleThemeSource

,在一個簡單的屬性檔案中定義一個主題。屬性檔案列出構成主題的資源。這是一個例子:

=的styleSheet /主題/冷卻/ style.css中
背景= /主題/冷卻/ IMG / coolBg.jpg      

屬性的鍵是從視圖代碼引用主題元素的名稱。對于JSP,您通常使用與

spring:theme

标記非常相似的自定義标簽來執行此操作

spring:message

。以下JSP片段使用上一個示例中定義的主題來自定義外觀:

<%@  taglib  prefix = “spring”  uri = “http://www.springframework.org/tags” %> 
<html> 
	<head> 
		<link  rel = “stylesheet”  href = “<spring:theme code ='styleSheet '/>“  type = ”text / css“ /> 
	</ head> 
	<body  style = ”background = <spring:theme code ='background'/>“ >
		...
	</ body> 
</ html>      

預設情況下,

ResourceBundleThemeSource

使用空的基本名稱字首。是以,屬性檔案從類路徑的根目錄加載。是以,您可以将

cool.properties

主題定義放在類路徑的根目錄下,例如

/WEB-INF/classes

。它

ResourceBundleThemeSource

使用标準的Java資源包加載機制,允許主題的全面國際化。例如,我們可以有一個

/WEB-INF/classes/cool_nl.properties

引用一個特殊的背景圖像與荷蘭文本。

18.9.3主題解析器

定義主題後,如上一節所述,您決定使用哪個主題。該

DispatcherServlet

會尋找一個叫豆

themeResolver

,以找出

ThemeResolver

使用實施。主題解析器的工作方式與a的方式大緻相同

LocaleResolver

。它檢測到用于特定請求的主題,還可以更改請求的主題。以下主題解析器由Spring提供:

表18.5。ThemeResolver實作

描述

FixedThemeResolver

選擇一個固定的主題,使用

defaultThemeName

屬性設定。

SessionThemeResolver

主題維護在使用者的HTTP會話中。它隻需要為每個會話設定一次,但不會在會話之間持久化。

CookieThemeResolver

所選主題存儲在用戶端的cookie中。

Spring還提供了一個

ThemeChangeInterceptor

允許使用簡單請求參數對每個請求進行主題更改的功能。

18.10 Spring的多部分(檔案上傳)支援

18.10.1介紹

Spring的内置多部分支援處理Web應用程式中的檔案上傳。您可以

MultipartResolver

使用

org.springframework.web.multipart

包中定義的可插入對象來 啟用此multipart支援。Spring提供了一個

MultipartResolver

用于Commons FileUpload的實作,另一個用于Servlet 3.0 multipart請求解析。

預設情況下,Spring沒有多部門處理,因為一些開發人員想要自己處理多個部件。通過将多部分解析器添加到Web應用程式的上下文來啟用Spring multipart處理。檢查每個請求以檢視它是否包含多部分。如果沒有找到multipart,請求按預期方式繼續。如果在請求中找到一個multipart,

MultipartResolver

則使用在上下文中聲明的multipart 。之後,您的請求中的multipart屬性被視為任何其他屬性。

18.10.2使用Commons FileUpload的MultipartResolver

以下示例顯示如何使用

CommonsMultipartResolver

<bean  id = “multipartResolver” 
		class = “org.springframework.web.multipart.commons.CommonsMultipartResolver” >

	<! - 可用屬性之一; 最大檔案大小(以位元組為機關) - > 
	<property  name = “maxUploadSize”  value = “100000” />

</豆>      

當然,您還需要将适當的jar放在您的類路徑中,以使多部分解析器工作。在這種情況下

CommonsMultipartResolver

,您需要使用

commons-fileupload.jar

當Spring

DispatcherServlet

檢測到多部分請求時,它會激活已經在上下文中聲明的解析器,并交給請求。解析器然後将目前包裝

HttpServletRequest

MultipartHttpServletRequest

支援多部分檔案上傳的内容中。使用它

MultipartHttpServletRequest

,您可以擷取有關此請求所包含的多部分的資訊,實際上可以在控制器中自己通路多部分檔案。

18.10.3在Servlet 3.0中使用MultipartResolver

為了使用的Servlet 3.0基于多解析,您需要标記

DispatcherServlet

"multipart-config"

的部分

web.xml

,或用

javax.servlet.MultipartConfigElement

在程式設計的Servlet注冊,或在自定義Servlet類的情況下,可能與

javax.servlet.annotation.MultipartConfig

你的Servlet類注解。需要在Servlet注冊級别應用最大大小或存儲位置等配置設定,因為Servlet 3.0不允許從MultipartResolver完成這些設定。

一旦使用上述方法之一啟用了Servlet 3.0 multipart解析,您可以添加

StandardServletMultipartResolver

到Spring配置:

<bean  id = “multipartResolver” 
		class = “org.springframework.web.multipart.support.StandardServletMultipartResolver” > 
</ bean>      

18.10.4以表單處理檔案上傳

完成

MultipartResolver

工作後,請求像其他任何一樣處理。首先,建立一個帶有檔案輸入的表單,允許使用者上傳表單。編碼屬性(

enctype="multipart/form-data"

)允許浏覽器知道如何将表單編碼為多部分請求:

<html> 
	<head> 
		<title>上傳檔案請</ title> 
	</ head> 
	<body> 
		<h1>請上傳檔案</ h1> 
		<form  method = “post”  action = “/ form”  enctype = “multipart / form-data” > 
			<input  type = “text”  name = “name” /> 
			<input  type = “file”  name = “file” /> 
			<input  type = “submit”/> 
		</ form> 
	</ body> 
</ html>      

下一步是建立一個處理檔案上傳的控制器。該控制器非常類似于正常注釋

@Controller

,除了我們使用

MultipartHttpServletRequest

MultipartFile

在方法參數中:

@Controller
 public  class FileUploadController {

	@PostMapping(“/ form”)
	 public String handleFormUpload( @RequestParam(“name”) String name,
			 @RequestParam(“file”) MultipartFile檔案){

		if(!file.isEmpty()){
			 byte [] bytes = file.getBytes();
			//存儲位元組某處
			傳回 “redirect:uploadSuccess” ;
		}

		傳回 “redirect:uploadFailure” ;
	}

}      

注意

@RequestParam

方法參數如何映射到表單中聲明的​​輸入元素。在這個例子中,沒有什麼是完成的

byte[]

,但實際上你可以将它儲存在資料庫中,将它存儲在檔案系統上,等等。

當使用Servlet 3.0多部分解析時,您也可以使用

javax.servlet.http.Part

方法參數:

@Controller
 public  class FileUploadController {

	@PostMapping(“/ form”)
	 public String handleFormUpload( @RequestParam(“name”) String name,
			 @RequestParam(“file”)零件檔案){

		InputStream inputStream = file.getInputStream();
		//将上傳檔案的位元組存儲在某處

		傳回 “redirect:uploadSuccess” ;
	}

}      

18.10.5處理來自程式設計用戶端的檔案上傳請求

也可以在RESTful服務方案中從非浏覽器用戶端送出多部分請求。所有上述示例和配置也适用于此。然而,與通常送出檔案和簡單表單字段的浏覽器不同,程式設計用戶端還可以發送特定内容類型的更複雜資料,例如具有檔案的多部分請求,第二部分使用JSON格式的資料:

POST / someUrl
Content-Type:multipart / mixed

--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
内容處理:表單資料; NAME =“中繼資料”
Content-Type:application / json; 字元集= UTF-8
内容傳輸編碼:8bit

{
	“名稱”:“值”
}
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
内容處理:表單資料; NAME =“檔案的資料”; 檔案名= “file.properties”
Content-Type:text / xml
内容傳輸編碼:8bit
...檔案資料...      

您可以使用

@RequestParam("meta-data") String metadata

controller method參數通路名為“meta-data”的部分。但是,您可能更喜歡接受從請求部分正文中的JSON格式資料初始化的強類型對象,非常類似于

@RequestBody

在非幫助下将非多部分請求的正文轉換為目标對象的方式

HttpMessageConverter

您可以使用

@RequestPart

注釋而不是

@RequestParam

注釋用于此目的。它允許您通過

HttpMessageConverter

考慮多部分的

'Content-Type'

标題來傳遞特定多部分的内容:

@PostMapping(“/ someUrl”)
 public String onSubmit( @RequestPart(“meta-data”)MetaData中繼資料,
		@RequestPart(“file-data”)MultipartFile檔案){

	// ...

}      

注意如何

MultipartFile

使用

@RequestParam

@RequestPart

互換通路方法參數。但是,

@RequestPart("meta-data") MetaData

在這種情況下,該方法參數将被讀取為基于其

'Content-Type'

頭部的JSON内容,并在此幫助下進行轉換

MappingJackson2HttpMessageConverter

18.11處理例外

18.11.1 HandlerExceptionResolver

Spring

HandlerExceptionResolver

實作處理控制器執行期間發生的意外異常。一個

HandlerExceptionResolver

有點象異常映射的,你可以在Web應用程式描述符定義

web.xml

。但是,它們提供了一種更靈活的方法。例如,它們提供有關在抛出異常時正在執行哪個處理程式的資訊。此外,處理異常的程式設計方式可以在請求轉發到另一個URL之前提供更多的響應選項(與使用Servlet特定的異常映射相同的最終結果)。

除了實作

HandlerExceptionResolver

接口,這隻是一個實作

resolveException(Exception, Handler)

方法和傳回的問題

ModelAndView

,您還可以使用提供的

SimpleMappingExceptionResolver

或建立

@ExceptionHandler

方法。将

SimpleMappingExceptionResolver

讓您采取可能被抛出的異常的類名,并将它映射到視圖名。這在功能上等同于Servlet API的異常映射功能,但也可以從不同的處理程式實作更精細的異常映射。

@ExceptionHandler

另一方面,注釋可以用于應該調用來處理異常的方法。這樣的方法可以定義在本地内部,

@Controller

或者可以在

@Controller

類中定義時應用于許多類

@ControllerAdvice

。以下部分将對此進行更詳細的解釋。

18.11.2 @ExceptionHandler

HandlerExceptionResolver

接口和

SimpleMappingExceptionResolver

實作允許您在轉發到這些視圖之前将異常與聲明性地映射到特定視圖以及一些可選的Java邏輯。然而,在某些情況下,特别是在依賴于

@ResponseBody

方法而不是視圖分辨率的情況下,直接設定響應的狀态并可選地将錯誤内容寫入響應主體可能會更為友善。

你可以用

@ExceptionHandler

方法來做到這一點。當在控制器内聲明時,這種方法适用于由

@RequestMapping

該控制器(或其任何子類)的方法引發的異常。您也可以

@ExceptionHandler

@ControllerAdvice

類中聲明一個方法, 在這種情況下,它可以處理

@RequestMapping

來自多個控制器的方法的異常。下面是一個控制器局部

@ExceptionHandler

方法的例子 :

@Controller
 public  class SimpleController {

	// @RequestMapping方法省略...

	@ExceptionHandler(IOException.class)
	 public ResponseEntity <String> handleIOException(IOException ex){
		 // prepare responseEntity 
		return responseEntity;
	}

}      

@ExceptionHandler

值可以設定為一個異常類型的數組。如果抛出與清單中的一個類型比對的異常,

@ExceptionHandler

則将調用注釋與比對的方法。如果未設定注釋值,則使用列為方法參數的異常類型。

與使用

@RequestMapping

注釋注釋的标準控制器方法非常相似,方法的方法參數和傳回值

@ExceptionHandler

可以是靈活的。例如,

HttpServletRequest

可以在Servlet環境中通路。傳回類型可以是一個

String

,它被解釋為一個視圖名稱,一個

ModelAndView

對象,一個

ResponseEntity

或者你也可以添加

@ResponseBody

一個方法傳回值轉換為消息轉換器并寫入響應流。

18.11.3處理标準Spring MVC異常

Spring MVC可能會在處理請求時引發許多異常。根據需要,

SimpleMappingExceptionResolver

可以輕松地将任何異常映射到預設錯誤視圖。但是,在使用以自動方式解釋響應的用戶端時,您将需要在響應中設定特定的狀态代碼。根據引發的異常,狀态代碼可能會訓示用戶端錯誤(4xx)或伺服器錯誤(5xx)。

DefaultHandlerExceptionResolver

Spring MVC異常轉換為特定的錯誤狀态代碼。它預設注冊了MVC命名空間,MVC Java配置,還有

DispatcherServlet

(即不使用MVC命名空間或Java配置時)。下面列出了這個解析器處理的一些異常和相應的狀态代碼:

例外 HTTP狀态碼

BindException

400(不良要求)

ConversionNotSupportedException

500内部伺服器錯誤)

HttpMediaTypeNotAcceptableException

406(不可接受)

HttpMediaTypeNotSupportedException

415(不支援的媒體類型)

HttpMessageNotReadableException

400(不良要求)

HttpMessageNotWritableException

500内部伺服器錯誤)

HttpRequestMethodNotSupportedException

405(不允許方法)

MethodArgumentNotValidException

400(不良要求)

MissingPathVariableException

500内部伺服器錯誤)

MissingServletRequestParameterException

400(不良要求)

MissingServletRequestPartException

400(不良要求)

NoHandlerFoundException

錯誤(404)

NoSuchRequestHandlingMethodException

錯誤(404)

TypeMismatchException

400(不良要求)

DefaultHandlerExceptionResolver

通過設定響應的狀态透明地工作。但是,您的應用程式可能需要為每個錯誤響應添加開發人員友好的内容,例如提供REST API時,不會将任何錯誤内容寫入響應正文。你可以準備一個

ModelAndView

和渲染通過視圖解析錯誤内容-通過配置,即

ContentNegotiatingViewResolver

MappingJackson2JsonView

,等等。但是,您可能更喜歡使用

@ExceptionHandler

方法。

如果您喜歡通過

@ExceptionHandler

方法編寫錯誤内容,可以

ResponseEntityExceptionHandler

改為擴充 。這是提供處理标準Spring MVC異常和傳回

@ControllerAdvice

@ExceptionHandler

方法的類的友善基礎

ResponseEntity

。這允許您自定義響應并使用消息轉換器寫入錯誤内容。有關

ResponseEntityExceptionHandler

詳細資訊,請參閱 javadocs。

18.11.4 REST控制器異常處理

一個

@RestController

可以使用

@ExceptionHandler

傳回一個方法,

ResponseEntity

在響應的主體既提供響應狀态和錯誤的詳細資訊。這些方法也可以被添加到

@ControllerAdvice

用于子集或所有控制器的異常處理的類中。

一個常見的要求是在響應的正文中包含錯誤詳細資訊。Spring不會自動執行此操作(盡管Spring Boot),因為響應主體中的錯誤詳細資訊的表示是特定于應用程式的。

希望在響應體中實作具有錯誤詳細資訊的全局異常處理政策的應用程式應考慮擴充抽象基類

ResponseEntityExceptionHandler

,為Spring MVC引發的異常提供處理,并提供鈎子來自定義響應體以及處理其他異常。隻需将擴充類聲明為一個Spring bean并用它進行注釋

@ControllerAdvice

。有關詳細資訊,請參閱

ResponseEntityExceptionHandler

18.11.5使用@ResponseStatus注釋業務異常

可以注釋業務異常

@ResponseStatus

。當異常提出時,

ResponseStatusExceptionResolver

通過相應地設定響應的狀态來處理它。預設情況下,

DispatcherServlet

寄存器

ResponseStatusExceptionResolver

,它是可用。

18.11.6自定義預設Servlet容器錯誤頁面

當響應的狀态設定為錯誤狀态代碼并且響應的正文為空時,Servlet容器通常會呈現HTML格式的錯誤頁面。要自定義容器的預設錯誤頁面,可以在其中聲明一個

<error-page>

元素

web.xml

。直到Servlet 3,該元素必須映射到特定的狀态代碼或異常類型。從Servlet 3開始,不需要映射錯誤頁面,這意味着指定的位置定制了預設的Servlet容器錯誤頁面。

<error-page> 
	<location> / error </ location> 
</ error-page>      

請注意,錯誤頁面的實際位置可以是容器中的JSP頁面或其他一些URL,包括通過一種

@Controller

方法處理的頁面:

編寫錯誤資訊時,

HttpServletResponse

可通過控制器中的請求屬性通路狀态碼和設定的錯誤資訊 :

@Controller
 public  class ErrorController {

	@RequestMapping(path =“/ error”,produce = MediaType.APPLICATION_JSON_UTF8_VALUE)
	@ResponseBody
	 public Map <String,Object> handle(HttpServletRequest request){

		Map <String,Object> map = new HashMap <String,Object>();
		map.put(“status”,request.getAttribute(“javax.servlet.error.status_code”));
		map.put(“reason”,request.getAttribute(“javax.servlet.error.message”));

		傳回地圖;
	}

}      

或在JSP中:

<%@  page  contentType = “application / json”  pageEncoding = “UTF-8” %> 
{ 
	status:<% = request.getAttribute(“javax.servlet.error.status_code”) %>,
	reason:<% = request。 getAttribute(“javax.servlet.error.message”) %> 
}      

18.12網絡安全

在春季安全項目提供的功能,以防止惡意攻擊Web應用程式。請參閱 “CSRF保護”, “安全響應頭”以及 “Spring MVC內建”部分中的參考文檔。請注意,使用Spring Security來保護應用程式并不一定需要所有功能。例如,CSRF保護可以通過添加

CsrfFilter

和配置

CsrfRequestDataValueProcessor

來添加。參見 Spring MVC展示 示例。

另一個選擇是使用專門用于Web Security的架構。 HDIV是一個這樣的架構,并與Spring MVC內建。

18.13關于配置支援的公約

對于很多項目,堅持既定的約定和合理的預設值就是它們(項目)所需要的,而Spring Web MVC現在已經明确地支援約定的配置。這意味着如果您建立了一組命名約定等等,您可以大幅度減少設定處理程式映射,檢視解析器,

ModelAndView

執行個體等所需的配置量 。這對于快速原型,并且如果您選擇将其推向生産,還可以在代碼庫中提供一定程度的(始終如一的)一緻性。

公約超配置支援解決了MVC的三個核心領域:模型,視圖和控制器。

18.13.1 Controller ControllerClassNameHandlerMapping

ControllerClassNameHandlerMapping

班是一個

HandlerMapping

使用慣例來确定請求的URL和之間的映射實作

Controller

是要處理這些請求的情況。

考慮以下簡單的

Controller

實作。特别注意 課程名稱。

public  class  ViewShoppingCartController  implements Controller {

	public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response){
		 //實作對于這個例子來說不是很重要...
	}

}      

以下是相應的Spring Web MVC配置檔案的代碼段:

<bean  class = “org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping” />

<bean  id = “ viewShoppingCart ”class =“xyzViewShoppingCartController”>
	 <! - 根據需要注入依賴關系...  - > 
</ bean>      

ControllerClassNameHandlerMapping

找出所有的處理程式(或

Controller

在其應用上下文定義的)豆和剝離

Controller

掉,以限定其處理程式映射的名稱。是以,

ViewShoppingCartController

映射到

/viewshoppingcart*

請求URL。

我們再來看一些更多的例子,使中心思想變得熟悉。(注意URL中的全部小寫,與駱駝

Controller

類的類名相反)。

  • WelcomeController

    映射到

    /welcome*

    請求URL
  • HomeController

    映射到

    /home*

    請求URL
  • IndexController

    映射到

    /index*

    請求URL
  • RegisterController

    映射到

    /register*

    請求URL

MultiActionController

處理程式類的情況下,生成的映射稍微複雜一點。以下

Controller

示例中的名稱被假定為實作

MultiActionController

  • AdminController

    映射到

    /admin/*

    請求URL
  • CatalogController

    映射到

    /catalog/*

    請求URL

如果你按照你的命名的慣例

Controller

實作的

xxxController

,将

ControllerClassNameHandlerMapping

節省您定義和維護一個潛在的沉悶一長串

SimpleUrlHandlerMapping

(或類似的東西)。

ControllerClassNameHandlerMapping

類擴充

AbstractHandlerMapping

基類,是以你可以定義

HandlerInterceptor

執行個體和一切,就像你與許多其他

HandlerMapping

的實作。

18.13.2 ModelMap(ModelAndView)

ModelMap

班本質上是一種榮耀

Map

,可以使補充說,是要顯示(或上)一個對象

View

堅持一個共同的命名約定。考慮以下

Controller

實作; 注意對象被添加到

ModelAndView

沒有指定的任何關聯的名稱。

public  class DisplayShoppingCartController implements Controller {

	public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response){

		清單cartItems = //擷取CartItem對象的清單 
		User user = //讓使用者進行購物

		ModelAndView mav = new ModelAndView(“displayShoppingCart”); < - 邏輯視圖名稱

		mav.addObject(cartItems); < - 看ma,沒有名字,隻是對象
		mav.addObject(使用者);  - 再次!

		傳回 mav
	}
}      

ModelAndView

類使用一個

ModelMap

類,它是一個自定義的

Map

,可自動生成用于當對象被添加到它的對象的鍵實作。在标量對象的情況下,用于确定添加對象的名稱的政策是

User

使用對象類的短類名。以下示例是為放置到

ModelMap

執行個體中的标量對象生成的名稱。

  • x.y.User

    添加 的執行個體将生成名稱

    user

  • x.y.Registration

    添加 的執行個體将生成名稱

    registration

  • x.y.Foo

    添加 的執行個體将生成名稱

    foo

  • java.util.HashMap

    添加 的執行個體将生成名稱

    hashMap

    。在這種情況下,您可能想要明确說明名稱,因為

    hashMap

    它不直覺。
  • 添加

    null

    将導緻

    IllegalArgumentException

    被抛出。如果您要添加的對象(或對象)可能是

    null

    ,那麼您還需要明确說明名稱。

什麼,沒有自動多元化?

Spring Web MVC的正常配置支援不支援自動多元化。也就是說,你不能添加

List

Person

對象的

ModelAndView

,并有生成的名字會

people

這個決定是經過一番辯論,最終赢得了“最不起眼的原則”。

在添加一個

Set

或一個之後生成名稱的政策

List

是窺視集合,擷取集合中第一個對象的短類名稱,并将其

List

附加到名稱後面。這同樣适用于數組,盡管數組不需要窺視數組内容。幾個例子将使得集合名稱生成的語義更加清晰:

  • 添加

    x.y.User[]

    零個或多個

    x.y.User

    元素 的數組将生成名稱

    userList

  • 添加

    x.y.Foo[]

    零個或多個

    x.y.User

    元素 的數組将生成名稱

    fooList

  • 添加

    java.util.ArrayList

    一個或多個

    x.y.User

    元素的 A 将生成名稱

    userList

  • 添加

    java.util.HashSet

    一個或多個

    x.y.Foo

    元素的 A 将生成名稱

    fooList

  • 根本不會添加 一個空

    java.util.ArrayList

    (實際上,

    addObject(..)

    調用本質上是無操作的)。

18.13.3 View – RequestToViewNameTranslator

RequestToViewNameTranslator

接口确定的邏輯

View

當沒有這樣的邏輯視圖名稱被明确地提供的名稱。它隻有一個實作,

DefaultRequestToViewNameTranslator

類。

DefaultRequestToViewNameTranslator

請求的URL映射到邏輯視圖的名稱,與該實施例中:

public  class RegistrationController implements Controller {

	public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response){
		 //處理請求... 
		ModelAndView mav = new ModelAndView();
		//根據需要添加資料到模型... 
		return mav;
		//注意沒有設定View或邏輯視圖名稱
	}

}      
<?xml version =“1.0”encoding =“UTF-8”?> 
<beans  xmlns = “http://www.springframework.org/schema/beans” 
	xmlns:xsi = “http://www.w3.org / 2001 / XMLSchema-instance“ 
	xsi:schemaLocation = ”
		http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd“ >

	<! - 這個具有衆所周知的名稱的bean為我們生成視圖名稱 - > 
	<bean  id = “viewNameTranslator” 
			class = “org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator” />

	<bean  class = “xyRegistrationController” > 
		<! - 根據需要注入依賴項 - > 
	</ bean>

	<! - 将請求URL映射到控制器名稱 - > 
	<bean  class = “org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping” />

	<bean  id = “viewResolver”  class = “org.springframework.web.servlet.view.InternalResourceViewResolver” > 
		<property  name = “prefix”  value = “/ WEB-INF / jsp /” /> 
		<property  name = “suffix”  value = “.jsp” /> 
	</ bean>

</豆>      

注意在執行

handleRequest(..)

方法no

View

或邏輯視圖名稱是否被設定

ModelAndView

傳回的。該

DefaultRequestToViewNameTranslator

任務是 從請求的URL 生成邏輯視圖名稱。另外,在上述的情況下

RegistrationController

,這是在與結合使用

ControllerClassNameHandlerMapping

的一個請求的URL

http://localhost/registration.html

中的一個邏輯視圖名稱結果

registration

被生成的

DefaultRequestToViewNameTranslator

。該邏輯視圖名稱然後

/WEB-INF/jsp/registration.jsp

InternalResourceViewResolver

bean 解析為視圖 。

《Spring 5 官方文檔》18. Web MVC 架構
您不需要明确定義一個

DefaultRequestToViewNameTranslator

bean。如果您喜歡預設設定

DefaultRequestToViewNameTranslator

,可以依靠Spring Web MVC

DispatcherServlet

執行個體化此類的執行個體,如果未明确配置。

當然,如果您需要更改預設設定,那麼您需要明确配置自己的

DefaultRequestToViewNameTranslator

bean。有關可配置

DefaultRequestToViewNameTranslator

的各種屬性的詳細資訊,請查閱全面的 javadocs。

18.14 HTTP緩存支援

良好的HTTP緩存政策可以顯着提高Web應用程式的性能和客戶體驗。所述

'Cache-Control'

HTTP響應報頭主要是為這個負責,使用條件報頭,例如沿

'Last-Modified'

'ETag'

'Cache-Control'

HTTP響應頭勸告私有的高速緩存(如浏覽器),以及他們如何緩存進一步重用HTTP響應的公共高速緩存(例如代理)。

一個的ETag(實體标簽)是由HTTP / 1.1相容的Web用于在給定的URL來确定内容改變伺服器傳回的HTTP響應報頭中。它可以被認為是

Last-Modified

标題的更複雜的繼承者 。當伺服器傳回具有ETag頭的表示時,用戶端可以在标題中的後續GET中使用此

If-None-Match

頭。如果内容沒有改變,伺服器傳回

304: Not Modified

本節介紹在Spring Web MVC應用程式中配置HTTP緩存的不同選擇。

18.14.1緩存控制HTTP頭

Spring Web MVC支援許多用例和方式為應用程式配置“Cache-Control”标頭。雖然RFC 7234第5.2.2節 完全描述了标題及其可能的指令,但是有幾種方法可以解決最常見的情況。

Spring Web MVC在其幾個API中使用配置約定

setCachePeriod(int seconds)

  • -1

    值将不生成

    'Cache-Control'

    響應頭。
  • 一個 值,将使用防止緩存

    'Cache-Control: no-store'

    指令。
  • 一個

    n > 0

    值将緩存對于給定的響應

    n

    使用秒

    'Cache-Control: max-age=n'

    指令。

CacheControl

生成器類簡單地描述了可用的“緩存控制”指令,并使其更容易建立自己的HTTP緩存政策。一旦建構,一個

CacheControl

執行個體就可以被接受為幾個Spring Web MVC API中的參數。

//緩存一小時 - “Cache-Control:max-age = 3600” 
   CacheControl ccCacheOneHour = CacheControl.maxAge(1,TimeUnit.HOURS);

   //防止緩存 - “Cache-Control:no-store”
   CacheControl ccNoStore = CacheControl.noStore();

   //在公共和私有緩存中緩存十天,
   //公共緩存不應該轉換響應
   //“Cache-Control:max-age = 864000,public,no-transform” 
   CacheControl ccCustom = CacheControl.maxAge(10,TimeUnit 。天)
   									。.noTransform()cachePublic();      

18.14.2 HTTP緩存支援靜态資源

應使用适當的

'Cache-Control'

條件标題來提供靜态資源,以獲得最佳性能。 配置一個

ResourceHttpRequestHandler

用于提供靜态資源的功能不僅

'Last-Modified'

通過讀取檔案的中繼資料來定位

'Cache-Control'

頭檔案,而且還可以正确配置頭檔案。

您可以設定

cachePeriod

屬性

ResourceHttpRequestHandler

或使用

CacheControl

執行個體,該執行個體支援更具體的指令:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void addResourceHandlers(ResourceHandlerRegistry registry){
		registry.addResourceHandler(“/ resources / **”)
				.addResourceLocations(“/ public-resources /”)
				.setCacheControl(CacheControl.maxAge(1,TimeUnit.HOURS).cachePublic());
	}

}      

在XML中:

<mvc:resources  mapping = “/ resources / **”  location = “/ public-resources /” > 
	<mvc:cache-control  max-age = “3600”  cache-public = “true” /> 
</ mvc:resources >      

18.14.3支援控制器中的Cache-Control,ETag和Last-Modified響應頭

控制器可以支援

'Cache-Control'

'ETag'

和/或

'If-Modified-Since'

HTTP請求; 如果

'Cache-Control'

要在響應中設定标題,則建議這樣做。這涉及計算

long

給定請求的lastModified 和/或Etag值,将其與

'If-Modified-Since'

請求頭值進行比較,并可能傳回具有狀态代碼304(未修改)的響應。

如“使用HttpEntity”一節所述,控制器可以使用

HttpEntity

類型與請求/響應進行互動 。傳回的控制器

ResponseEntity

可以包括響應中的HTTP緩存資訊,如下所示:

@GetMapping(“/ book / {id}”)
 public ResponseEntity <Book> showBook( @PathVariable Long id){

	Book book = findBook(id);
	String version = book.getVersion();

	傳回 ResponseEntity
				。好()
				.cacheControl(CacheControl.maxAge(30,TimeUnit.DAYS))
				.eTag(version)// lastModified也可用
				。體(書);
}      

如果用戶端發送的條件标頭與控制器設定的緩存資訊比對,這樣做将不僅包括響應中的頭

'ETag'

'Cache-Control'

頭,還會将響應轉換

HTTP 304 Not Modified

為空體。

一種

@RequestMapping

方法也不妨支援相同的行為。這可以實作如下:

@RequestMapping
 public String myHandleMethod(WebRequest webRequest,Model model){

	long lastModified = // 1.應用程式特定的計算

	if(request.checkNotModified(lastModified)){
		 // 2.快捷方式退出 - 無需進一步處理必需
		傳回 null;
	}

	// 3.否則進一步請求處理,實際準備内容
	model.addAttribute(...);
	傳回 “myViewName” ;
}      

這裡有兩個關鍵元素:呼叫

request.checkNotModified(lastModified)

和傳回

null

。前者在傳回之前設定适當的響應狀态和标題

true

。後者與前者相結合,導緻Spring MVC不再進一步處理請求。

請注意,有3種變體:

  • request.checkNotModified(lastModified)

    與比較上次更改時間

    'If-Modified-Since'

    'If-Unmodified-Since'

    請求頭
  • request.checkNotModified(eTag)

    将eTag與

    'If-None-Match'

    請求标頭 進行比較
  • request.checkNotModified(eTag, lastModified)

    這兩者都意味着兩個條件都應該是有效的

當接收到條件

'GET'

/

'HEAD'

請求時,

checkNotModified

将檢查資源是否未被修改,如果是這樣,它将導緻

HTTP 304 Not Modified

響應。在有條件的

'POST'

/

'PUT'

/

'DELETE'

請求的情況下,

checkNotModified

将檢查資源是否尚未被修改,如果已經被修改,它将導緻

HTTP 409 Precondition Failed

響應以防止并發修改。

18.14.4淺層ETag支援

支援ETag由Servlet過濾器提供

ShallowEtagHeaderFilter

。它是一個簡單的Servlet過濾器,是以可以與任何Web架構結合使用。該

ShallowEtagHeaderFilter

濾波器産生所謂的淺ETag的(相對于深的ETag,稍後詳細說明)。該過濾器緩存呈現JSP(或其他内容)的内容,産生超過其MD5哈希,并傳回作為ETag頭在回應中。下一次用戶端發送對同一資源的請求時,它将使用該哈希作為該

If-None-Match

值。過濾器檢測到這一點,再次渲染視圖,并比較兩個散列。如果它們相等,

304

則傳回a。

請注意,此政策可節省網絡帶寬但不節省CPU,因為必須為每個請求計算完整的響應。控制器級别的其他政策(如上所述)可以節省網絡帶寬并避免計算。

此過濾器具有一個

writeWeakETag

參數,可将過濾器配置為寫入弱符号ETags,如RFC 7232第2.3節

W/"02a2d595e6ed9a0b24f027f2b63b134d6"

中所定義 。

您配置

ShallowEtagHeaderFilter

web.xml

<filter> 
	<filter-name> etagFilter </ filter-name> 
	<filter-class> org.springframework.web.filter.ShallowEtagHeaderFilter </ filter-class> 
	<! - 配置過濾器寫入弱ETag的可選參數
	<INIT-PARAM>
       	<PARAM名稱> writeWeakETag </ PARAM名稱>
       	<PARAM值>真</ PARAM值>
	</ INIT-param>
	- > 
</ filter>

<filter-mapping> 
	<filter-name> etagFilter </ filter-name> 
	<servlet-name> petclinic </ servlet-name> 
</ filter-mapping>      

或者在Servlet 3.0+環境中,

public  class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

	// ...

	@Override
	 protected Filter [] getServletFilters(){
		 return  new Filter [] { new ShallowEtagHeaderFilter()};
	}

}      

有關詳細資訊,請參見第18.15節“基于代碼的Servlet容器初始化”。

18.15基于代碼的Servlet容器初始化

在Servlet 3.0+環境中,您可以選擇以程式設計方式配置Servlet容器作為替代方法或與

web.xml

檔案組合使用。下面是一個注冊一個例子

DispatcherServlet

import org.springframework.web.WebApplicationInitializer;

public  class MyWebApplicationInitializer 實作 WebApplicationInitializer {

	@Override
	 public  void onStartup(ServletContext container){
		XmlWebApplicationContext appContext = new XmlWebApplicationContext();
		appContext.setConfigLocation(“/WEB-INF/spring/dispatcher-config.xml”);

		ServletRegistration.Dynamic注冊= container.addServlet(“dispatcher”,新的 DispatcherServlet(appContext));
		registration.setLoadOnStartup(1);
		registration.addMapping(“/”);
	}

}      

WebApplicationInitializer

是由Spring MVC提供的接口,可確定您的實作被檢測并自動用于初始化任何Servlet 3容器。

WebApplicationInitializer

命名 的抽象基類實作通過簡單地覆寫方法來指定servlet映射和配置的位置

AbstractDispatcherServletInitializer

更容易注冊 。

DispatcherServlet

DispatcherServlet

推薦使用基于Java的Spring配置的應用程式:

public  class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

	@Override
	 protected Class <?> [] getRootConfigClasses(){
		 return null;
	}

	@Override
	 protected Class <?> [] getServletConfigClasses(){
		 return  new Class [] {MyWebConfig。類 };
	}

	@Override
	 protected String [] getServletMappings(){
		 return  new String [] { “/” };
	}

}      

如果使用基于XML的Spring配置,您應該直接從

AbstractDispatcherServletInitializer

public  class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

	@Override
	 protected WebApplicationContext createRootApplicationContext(){
		 return null;
	}

	@Override
	 protected WebApplicationContext createServletApplicationContext(){
		XmlWebApplicationContext cxt = new XmlWebApplicationContext();
		cxt.setConfigLocation(“/WEB-INF/spring/dispatcher-config.xml”);
		傳回 cxt;
	}

	@Override
	 protected String [] getServletMappings(){
		 return  new String [] { “/” };
	}

}      

AbstractDispatcherServletInitializer

還提供了一種友善的方法來添加

Filter

執行個體并讓它們自動映射到

DispatcherServlet

public  class MyWebAppInitializer extends AbstractDispatcherServletInitializer {

	// ...

	@Override
	 protected Filter [] getServletFilters(){
		 return  new Filter [] { new HiddenHttpMethodFilter(), new CharacterEncodingFilter()};
	}

}      

每個過濾器根據具體類型添加預設名稱并自動映射到

DispatcherServlet

提供單一位置的

isAsyncSupported

受保護方法

AbstractDispatcherServletInitializer

可以在

DispatcherServlet

映射到它的所有過濾器上啟用異步支援。預設情況下,該标志設定為

true

最後,如果需要進一步自定義

DispatcherServlet

自身,可以覆寫該

createDispatcherServlet

方法。

18.16配置Spring MVC

第18.2.1節“WebApplicationContext中的特殊Bean類型”和第18.2.2節“預設DispatcherServlet配置”解釋了Spring MVC的特殊bean以及該使用的預設實作

DispatcherServlet

。在本節中,您将了解配置Spring MVC的兩種其他方法。即MVC Java配置和MVC XML命名空間。

MVC Java配置和MVC命名空間提供了類似的預設配置,可以覆寫

DispatcherServlet

預設配置。目标是使大多數應用程式不必建立相同的配置,并提供更進階别的構造,用于配置作為簡單起始點的Spring MVC,并且需要很少或根本沒有底層配置的知識。

您可以根據自己的喜好選擇MVC Java配置或MVC命名空間。另外,您将在下面進一步看到,使用MVC Java配置,可以更容易地檢視底層配置,以及直接對建立的Spring MVC bean進行細粒度的自定義。但是讓我們從一開始就開始。

18.16.1啟用MVC Java Config或MVC XML命名空間

要啟用MVC Java配置,請将注釋添加

@EnableWebMvc

到您的一個

@Configuration

類中:

@Configuration 
@EnableWebMvc
 public  class WebConfig {

}      

要在XML中實作相同的使用

mvc:annotation-driven

DispatcherServlet上下文中的元素(如果您沒有定義DispatcherServlet上下文,則在根上下文中):

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

	<MVC:注釋驅動/>

</豆>      

在上述寄存器一

RequestMappingHandlerMapping

,一個

RequestMappingHandlerAdapter

,和

ExceptionHandlerExceptionResolver

在支援帶注釋控制器方法的處理請求(等等)使用注釋諸如

@RequestMapping

@ExceptionHandler

和其他。

它還支援以下功能:

  1. 除了用于資料綁定的JavaBeans PropertyEditor之外,還可以 通過ConversionService執行個體進行Spring 3樣式類型轉換。
  2. 支援格式使用數字字段

    @NumberFormat

    通過注釋

    ConversionService

  3. 支援的格式

    Date

    Calendar

    Long

    ,和喬達時間使用的字段

    @DateTimeFormat

    注解。
  4. 支援驗證

    @Controller

    輸入

    @Valid

    ,如果JSR-303提供程式存在于類路徑中。
  5. HttpMessageConverter

    支援

    @RequestBody

    方法參數和

    @ResponseBody

    方法傳回值

    @RequestMapping

    @ExceptionHandler

    方法。

    這是由mvc設計的HttpMessageConverters的完整清單:annotation-driven:

    1. ByteArrayHttpMessageConverter

      轉換位元組數組。
    2. StringHttpMessageConverter

      轉換字元串。
    3. ResourceHttpMessageConverter

      轉換為/從

      org.springframework.core.io.Resource

      為所有媒體類型。
    4. SourceHttpMessageConverter

      轉換到/從a

      javax.xml.transform.Source

    5. FormHttpMessageConverter

      将表單資料轉換為/從a轉換

      MultiValueMap<String, String>

    6. Jaxb2RootElementHttpMessageConverter

      将Java對象轉換為/從XML中添加 – 如果存在JAXB2,并且類别路徑中不存在Jackson 2 XML擴充名。
    7. MappingJackson2HttpMessageConverter

      轉換為/從JSON中添加,如果傑克遜2存在于類路徑。
    8. MappingJackson2XmlHttpMessageConverter

      轉換為/從XML中添加,如果 Jackson 2 XML擴充存在于類路徑中。
    9. MappingJackson2SmileHttpMessageConverter

      轉換為/從微笑(二進制JSON) – 添加如果 傑克遜2微笑擴充 存在于類路徑。
    10. MappingJackson2CborHttpMessageConverter

      轉換為/從CBOR – 添加如果 傑克遜2 CBOR擴充 存在于類路徑。
    11. AtomFeedHttpMessageConverter

      轉換Atom Feed – 如果羅馬存在于類路徑中則添加。
    12. RssChannelHttpMessageConverter

      轉換RSS提要 – 如果羅馬存在于類路徑中,則會添加。

有關如何自定義這些預設轉換器的更多資訊,請參見第18.16.12節“消息轉換器”。

《Spring 5 官方文檔》18. Web MVC 架構
使用

ObjectMapper

建立的執行個體建立 Jackson JSON和XML轉換器

Jackson2ObjectMapperBuilder

,以提供更好的預設配置。此建構器使用以下指令自定義Jackson的預設屬性:
  1. DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES

    被禁用。
  2. MapperFeature.DEFAULT_VIEW_INCLUSION

    被禁用。
如果在類路徑中檢測到它們,它也會自動注冊以下衆所周知的子產品:
  1. jackson-datatype-jdk7:支援Java 7類型

    java.nio.file.Path

  2. jackson-datatype-joda:支援Joda-Time類型。
  3. jackson-datatype-jsr310:支援Java 8 Date&Time API類型。
  4. jackson-datatype-jdk8:支援其他Java 8類型

    Optional

18.16.2定制提供的配置

要定制Java中的預設配置,您隻需實作該

WebMvcConfigurer

接口,或者更有可能擴充該類

WebMvcConfigurerAdapter

并覆寫所需的方法:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	//覆寫配置方法...

}      

要自定義預設配置,

<mvc:annotation-driven/>

檢查它支援哪些屬性和子元素。您可以檢視 Spring MVC XML模式或使用IDE的代碼完成功能來發現哪些屬性和子元素可用。

18.16.3轉換和格式化

預設情況下,已安裝格式化程式

Number

Date

類型,包括對

@NumberFormat

@DateTimeFormat

注釋的支援。如果Joda時間存在于類路徑上,則還将完全支援Joda Time格式化庫。要注冊自定義格式化程式和轉換器,請覆寫該

addFormatters

方法:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void addFormatters(FormatterRegistry registry){
		 //添加格式化程式和/或轉換器
	}

}      

在MVC命名空間

<mvc:annotation-driven>

中,添加相同的預設值。注冊自定義格式化器和轉換器隻需提供一個

ConversionService

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

	<mvc:annotation-driven  conversion-service = “conversionService” />

	<豆 ID = “conversionService” 
			類 = “org.springframework.format.support.FormattingConversionServiceFactoryBean” > 
		<屬性 名 = “轉換器” > 
			<設定> 
				<豆 類 = “org.example.MyConverter” /> 
			</設定> 
		< / property> 
		<property  name = “formatters” > 
			<set> 
				<bean  class = “org.example.MyFormatter” /> 
				<bean  class = “org.example。MyAnnotationFormatterFactory“ /> 
			</ set> 
		</ property> 
		<property  name = ”formatterRegistrars“ > 
			<set> 
				<bean  class = ”org.example.MyFormatterRegistrar“ /> 
			</ set> 
		</ property> 
	</ bean>

</豆>      
《Spring 5 官方文檔》18. Web MVC 架構
參見5.6.4節,“FormatterRegistrar SPI”和

FormattingConversionServiceFactoryBean

關于何時使用FormatterRegistrars更多的資訊。

18.16.4驗證

Spring提供了一個驗證器接口,可用于在應用程式的所有層中進行驗證。在Spring MVC中,您可以将其配置為用作全局

Validator

執行個體,以在遇到

@Valid

@Validated

控制器方法參數時使用,和/或

Validator

通過

@InitBinder

方法作為控制器中的本地 使用。可以組合全局和本地驗證器執行個體以提供複合驗證。

Spring還支援JSR-303 / JSR-349 Bean驗證,通過

LocalValidatorFactoryBean

它可以将Spring

org.springframework.validation.Validator

界面适應Bean驗證

javax.validation.Validator

合同。這個類可以插入Spring MVC作為下面描述的全局驗證器。

預設情況下,通過在類路徑中檢測到一個Bean驗證提供程式(如Hibernate Validator)時,可以在Spring MVC中使用

@EnableWebMvc

<mvc:annotation-driven>

自動注冊Bean驗證支援

LocalValidatorFactoryBean

《Spring 5 官方文檔》18. Web MVC 架構
有時,将

LocalValidatorFactoryBean

注入到控制器或其他類中是很友善的。最簡單的方法是聲明自己的

@Bean

,并且标記它,

@Primary

以避免與MVC Java配置提供的沖突。如果你喜歡使用MVC的Java的配置之一,你需要重寫

mvcValidator

的方法

WebMvcConfigurationSupport

,并聲明明确回報的方法

LocalValidatorFactory

,而不是

Validator

。有關 如何切換擴充提供的配置的資訊,請參見第18.16.13節“使用MVC Java Config進行進階定制”。

或者,您可以配置自己的全局

Validator

執行個體:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public Validator getValidator(); {
		 //傳回“全局”驗證器
	}

}      

和XML:

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

	<mvc:annotation-driven  validator = “globalValidator” />

</豆>      

要将全局和本地驗證結合起來,隻需添加一個或多個本地驗證器:

@Controller
 public  class MyController {

	@InitBinder
	 protected  void initBinder(WebDataBinder binder){
		binder.addValidators(new FooValidator());
	}

}      

使用這個最小配置,任何時候遇到一個

@Valid

@Validated

方法參數,它将被配置的驗證器驗證。任何驗證違規将自動

BindingResult

作為方法參數可通路的錯誤公開,并且也可以在Spring MVC HTML視圖中呈現。

18.16.5攔截器

您可以配置

HandlerInterceptors

WebRequestInterceptors

應用于所有傳入的請求或限制在特定的URL路徑模式。

在Java中注冊攔截器的示例:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void addInterceptors(InterceptorRegistry registry){
		registry.addInterceptor(new LocaleInterceptor());
		registry.addInterceptor(new ThemeInterceptor())。addPathPatterns(“/ **”).excludePathPatterns(“/ admin / **”);
		registry.addInterceptor(new SecurityInterceptor())。addPathPatterns(“/ secure / *”);
	}

}      

而在XML中使用

<mvc:interceptors>

元素:

<mvc:interceptors> 
	<bean  class = “org.springframework.web.servlet.i18n.LocaleChangeInterceptor” /> 
	<mvc:interceptor> 
		<mvc:mapping  path = “/ **” /> 
		<mvc:exclude-mapping  path = “/ admin / **” /> 
		<bean  class = “org.springframework.web.servlet.theme.ThemeChangeInterceptor” /> 
	</ mvc:interceptor> 
	<mvc:interceptor> 
		<mvc:mapping  path = “/ secure / “ /> 
		<bean  class = ”org.example.SecurityInterceptor“/> 
	</ mvc:interceptor> 
</ mvc:interceptors>      

18.16.6 Content Negotiation

You can configure how Spring MVC determines the requested media types from the request. The available options are to check the URL path for a file extension, check the “Accept” header, a specific query parameter, or to fall back on a default content type when nothing is requested. By default the path extension in the request URI is checked first and the “Accept” header is checked second.

The MVC Java config and the MVC namespace register

json

,

xml

,

rss

,

atom

by default if corresponding dependencies are on the classpath. Additional path extension-to-media type mappings may also be registered explicitly and that also has the effect of whitelisting them as safe extensions for the purpose of RFD attack detection (see the section called “Suffix Pattern Matching and RFD” for more detail).

Below is an example of customizing content negotiation options through the MVC Java config:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
		configurer.mediaType("json", MediaType.APPLICATION_JSON);
	}
}      

In the MVC namespace, the

<mvc:annotation-driven>

element has a

content-negotiation-manager

attribute, which expects a

ContentNegotiationManager

that in turn can be created with a

ContentNegotiationManagerFactoryBean

:

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>

<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
	<property name="mediaTypes">
		<value>
			json=application/json
			xml=application/xml
		</value>
	</property>
</bean>      

If not using the MVC Java config or the MVC namespace, you’ll need to create an instance of

ContentNegotiationManager

and use it to configure

RequestMappingHandlerMapping

for request mapping purposes, and

RequestMappingHandlerAdapter

and

ExceptionHandlerExceptionResolver

for content negotiation purposes.

Note that

ContentNegotiatingViewResolver

now can also be configured with a

ContentNegotiationManager

, so you can use one shared instance throughout Spring MVC.

In more advanced cases, it may be useful to configure multiple

ContentNegotiationManager

instances that in turn may contain custom

ContentNegotiationStrategy

implementations. For example you could configure

ExceptionHandlerExceptionResolver

with a

ContentNegotiationManager

that always resolves the requested media type to

"application/json"

. Or you may want to plug a custom strategy that has some logic to select a default content type (e.g. either XML or JSON) if no content types were requested.

18.16.7 View Controllers

This is a shortcut for defining a

ParameterizableViewController

that immediately forwards to a view when invoked. Use it in static cases when there is no Java controller logic to execute before the view generates the response.

An example of forwarding a request for

"/"

to a view called

"home"

in Java:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void addViewController(ViewControllerRegistry registry){
		registry.addViewController(“/”).setViewName(“home”);
	}

}      

而且在XML中使用相同的

<mvc:view-controller>

元素:

<mvc:view-controller  path = “/”  view-name = “home” />      

18.16.8檢視解決方案

MVC配置簡化了視圖解析器的注冊。

以下是一個Java配置示例,它使用FreeMarker HTML模闆配置内容協商視圖分辨率,并将Jackson作為

View

JSON渲染的預設值:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void configureViewResolvers(ViewResolverRegistry registry){
		registry.enableContentNegotiation(new MappingJackson2JsonView());
		registry.jsp();
	}

}      

和XML一樣:

<mvc:view-resolvers> 
	<mvc:content-negotiation> 
		<mvc:default-views> 
			<bean  class = “org.springframework.web.servlet.view.json.MappingJackson2JsonView” /> 
		</ mvc:default-views> 
	</ mvc:content-negotiation> 
	<mvc:jsp /> 
</ mvc:view-resolvers>      

不過請注意,FreeMarker,Tiles,Groovy Markup和腳本模闆也需要配置底層視圖技術。

MVC命名空間提供專用元素。例如與FreeMarker:

<mvc:view-resolvers> 
	<mvc:content-negotiation> 
		<mvc:default-views> 
			<bean  class = “org.springframework.web.servlet.view.json.MappingJackson2JsonView” /> 
		</ mvc:default-views> 
	</ mvc:content-negotiation> 
	<mvc:freemarker  cache = “false” /> 
</ mvc:view-resolvers>

<mvc:freemarker-configurer> 
	<mvc:template-loader-path  location = “/ freemarker” /> 
</ mvc:freemarker-configurer>      

在Java配置中,隻需添加相應的“Configurer”bean:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void configureViewResolvers(ViewResolverRegistry registry){
		registry.enableContentNegotiation(new MappingJackson2JsonView());
		。registry.freeMarker()高速緩存(假);
	}

	@Bean
	 public FreeMarkerConfigurer freeMarkerConfigurer(){
		FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
		configurer.setTemplateLoaderPath(“/ WEB-INF /”);
		return configurer;
	}

}      

18.16.9資源服務

此選項允許在特定URL模式之後的靜态資源請求由位置

ResourceHttpRequestHandler

清單中的任何一個

Resource

提供。這提供了一種友善的方式來從除Web應用程式根以外的位置(包括類路徑上的位置)提供靜态資源。該

cache-period

屬性可用于設定遠期未來的到期标頭(1年是優化工具的推薦,如Page Speed和YSlow),以便用戶端更有效地利用它們。處理程式也正确地評估

Last-Modified

标題(如果存在),以便适當地

304

傳回狀态代碼,避免用戶端已經緩存的資源的不必要的開銷。例如,

/resources/**

public-resources

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void addResourceHandlers(ResourceHandlerRegistry registry){
		registry.addResourceHandler(“/ resources / **”).addResourceLocations(“/ public-resources /”);
	}

}      

和XML一樣:

<mvc:resources  mapping = “/ resources / **”  location = “/ public-resources /” />      

為了在未來1年的時間内為這些資源提供服務,以確定最大限度地利用浏覽器緩存并減少浏覽器發出的HTTP請求:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void addResourceHandlers(ResourceHandlerRegistry registry){
		registry.addResourceHandler(“/資源/ **”).addResourceLocations(“/公共資源/”).setCachePeriod(31556926);
	}

}      

在XML中:

<mvc:resources  mapping = “/ resources / **”  location = “/ public-resources /”  cache-period = “31556926” />      

有關詳細資訊,請參閱靜态資源的HTTP緩存支援。

mapping

屬性必須是可以被使用的螞蟻圖案

SimpleUrlHandlerMapping

,并且

location

屬性必須指定一個或多個有效的資源目錄位置。可以使用逗号分隔的值清單來指定多個資源位置。指定的位置将按照指定的順序檢查是否存在任何給定請求的資源。例如,要啟用來自Web應用程式根目錄和類路徑

/META-INF/public-web-resources/

中任何jar中已知路徑 的資源的使用,請執行以下操作:

@EnableWebMvc 
@Configuration
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void addResourceHandlers(ResourceHandlerRegistry registry){
		registry.addResourceHandler(“/ resources / **”)
				.addResourceLocations(“/”,“classpath:/ META-INF / public-web-resources /”);
	}

}      

在XML中:

<mvc:resources  mapping = “/ resources / **”  location = “/,classpath:/ META-INF / public-web-resources /” />      

當部署新版本的應用程式時可能會更改的資源時,建議您将版本字元串合并到用于請求資源的映射模式中,以便您可以強制用戶端請求新部署的應用程式資源版本。版本化URL的支援内置在架構中,可以通過在資源處理程式上配置資源鍊來啟用。該鍊由

ResourceResolver

一個或多個

ResourceTransformer

執行個體之後的一個執行個體組成。他們一起可以提供任意解決和資源轉型。

内置

VersionResourceResolver

可配置不同的政策。例如,

FixedVersionStrategy

可以使用屬性,日期或其他作為版本。A

ContentVersionStrategy

使用從資源的内容計算的MD5哈希(稱為“指紋識别”URL)。請注意,

VersionResourceResolver

在服務資源時,會自動将解析的版本字元串用作HTTP ETag标頭值。

ContentVersionStrategy

是一個很好的預設選擇,除非不能使用(例如使用JavaScript子產品加載器)的情況。您可以針對不同的模式配置不同的版本政策,如下所示。請記住,計算基于内容的版本是昂貴的,是以在生産中應該啟用資源鍊緩存。

Java配置示例

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void addResourceHandlers(ResourceHandlerRegistry registry){
		registry.addResourceHandler(“/ resources / **”)
				.addResourceLocations(“/ public-resources /”)
				.resourceChain(真).addResolver(
					new VersionResourceResolver()。addContentVersionStrategy(“/ **”));
	}

}      

XML示例:

<MVC:資源 映射 = “/資源/ **”  位置 = “/公共資源/” > 
	<MVC:資源鍊> 
		<MVC:資源高速緩存/> 
		<MVC:解析器> 
			<MVC:版本-解析器> 
				<mvc:content-version-strategy  patterns = “/ **” /> 
			</ mvc:version-resolver> 
		</ mvc:resolvers> 
	</ mvc:resource-chain> 
</ mvc:resources>      

為了使上述工作,應用程式還必須使用版本來呈現URL。最簡單的方法是配置

ResourceUrlEncodingFilter

其中包含響應并覆寫其

encodeURL

方法。這将在JSP,FreeMarker以及調用響應

encodeURL

方法的任何其他視圖技術中起作用 。或者,應用程式還可以直接注入和使用

ResourceUrlProvider

bean,該bean将自動使用MVC Java配置和MVC命名空間聲明。

還支援Webjars

WebJarsResourceResolver

,當

"org.webjars:webjars-locator"

庫位于類路徑時,Webjars會自動注冊。該解析器允許資源鍊從HTTP GET請求中解析版本不可知庫

"GET /jquery/jquery.min.js"

将傳回資源

"/jquery/1.2.0/jquery.min.js"

。它也可以通過在模闆中重寫資源URL來實作

<script src="/jquery/jquery.min.js"/> → <script src="/jquery/1.2.0/jquery.min.js"/>

18.16.10回退在“預設”Servlet服務資源

這允許映射

DispatcherServlet

到“/”(進而覆寫容器的預設Servlet的映射),同時仍允許靜态資源請求由容器的預設Servlet處理。它

DefaultServletHttpRequestHandler

使用“/ **”的URL映射和相對于其他URL映射的最低優先級來配置。

該處理程式将所有請求轉發到預設Servlet。是以,重要的是按照所有其他URL的順序保持最後

HandlerMappings

。如果您使用

<mvc:annotation-driven>

或者如果您正在設定自己的自定義

HandlerMapping

執行個體,請確定将其

order

屬性設定為低于該值的值

DefaultServletHttpRequestHandler

,否則将是這種情況

Integer.MAX_VALUE

要使用預設設定啟用該功能,請使用:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

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

}      

或在XML中:

<MVC:預設servlet的處理程式/>      

覆寫“/”Servlet映射的注意事項是,

RequestDispatcher

預設的Servlet必須通過名稱而不是路徑檢索。該

DefaultServletHttpRequestHandler

會嘗試自動檢測在啟動時容器中的預設的Servlet,使用大多數主要的Servlet容器(包括軟體Tomcat,Jetty的GlassFish,JBoss和樹脂中,WebLogic和WebSphere)已知名稱的清單。如果預設的Servlet已經使用不同的名稱自定義配置,或者如果使用了預設Servlet名稱未知的其他Servlet容器,那麼必須明确地提供預設的Servlet名稱,如下例所示:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

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

}      

或在XML中:

<mvc:default-servlet-handler  default-servlet-name = “myCustomDefaultServlet” />      

18.16.11路徑比對

這允許自定義與URL映射和路徑比對相關的各種設定。有關各個選項的詳細資訊,請檢視 PathMatchConfigurer API。

以下是Java配置中的一個示例:

@Configuration 
@EnableWebMvc
 public  class WebConfig extends WebMvcConfigurerAdapter {

	@Override
	 public  void configurePathMatch(PathMatchConfigurer configurer){
		配置者
		    .setUseSuffixPatternMatch(真)
		    .setUseTrailingSlashMatch(假)
		    .setUseRegisteredSuffixPatternMatch(真)
		    .setPathMatcher(antPathMatcher())
		    .setUrlPathHelper(urlPathHelper());
	}

	@Bean
	 public UrlPathHelper urlPathHelper(){
	     // ...
	}

	@Bean
	 public PathMatcher antPathMatcher(){
	     // ...
	}

}      

和XML一樣,使用

<mvc:path-matching>

元素:

<mvc:annotation-driven>
    <mvc:path-matching
        suffix-pattern="true"
        trailing-slash="false"
        registered-suffixes-only="true"
        path-helper="pathHelper"
        path-matcher="pathMatcher"/>
</mvc:annotation-driven>

<bean id="pathHelper" class="org.example.app.MyPathHelper"/>
<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>      

18.16.12消息轉換器

如果要替換由Spring MVC建立的預設轉換器,或者 如果您隻想自定義它們或将額外的轉換器添加到預設轉換器,

HttpMessageConverter

則可以通過重寫Java配置來實作 定制。

configureMessageConverters()

extendMessageConverters()

以下是使用自定義

ObjectMapper

而不是預設值添加Jackson JSON和XML轉換器的示例 :

@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
				.indentOutput(true)
				.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
				.modulesToInstall(new ParameterNamesModule());
		converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
		converters.add(new MappingJackson2XmlHttpMessageConverter(builder.xml().build()));
	}在此示例中,         Jackson2ObjectMapperBuilder                用于為兩者建立通用配置,         MappingJackson2HttpMessageConverter                并         MappingJackson2XmlHttpMessageConverter                啟用縮進,自定義日期格式以及 jackson-module-parameter-name的注冊 ,以增加對通路參數名稱的支援(Java 8中添加的功能)。         ngJackson2XmlHttpMessageConverter                 with indentation enabled, a customized date format and the registration of jackson-module-parameter-names that adds support for accessing parameter names (feature added in Java 8).
      
《Spring 5 官方文檔》18. Web MVC 架構
使用Jackson XML支援啟用縮進功能需要

woodstox-core-asl

除依賴之外

jackson-dataformat-xml

其他有趣的傑克遜子產品可用:

  1. jackson-datatype-money:支援

    javax.money

    類型(非官方子產品)
  2. jackson-datatype-hibernate:支援Hibernate的特定類型和屬性(包括延遲加載方面)

也可以在XML中執行相同的操作:

<mvc:annotation-driven> 
    <mvc:message-converters> 
        <bean  class = “org.springframework.http.converter.json.MappingJackson2HttpMessageConverter” > 
            <property  name = “objectMapper”  ref = “objectMapper” /> 
        </ bean> 
        <bean  class = “org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter” > 
            <property  name = “objectMapper”  ref = “xmlMapper” /> 
        </ bean> 
    </ mvc:message-converters> 
</ mvc:注解驅動>

<bean  id = “objectMapper”  class = “org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean” 
      p:indentOutput = “true” 
      p:simpleDateFormat = “yyyy-MM-dd” 
      p:modulesToInstall = “com.fasterxml.jackson .module.paramnames.ParameterNamesModule“ />

<bean  id = “xmlMapper”  parent = “objectMapper”  p:createXmlMapper = “true” />      

18.16.13使用MVC Java Config進行進階定制

從上述示例可以看出,MVC Java配置和MVC命名空間提供了不需要深入了解為您建立的基礎bean的更進階别的構造。相反,它可以幫助您專注于您的應用程式需求。但是,在某些時候,您可能需要更細緻的控制,或者您可能隻想了解底層配置。

更精細控制的第一步是檢視為您建立的基礎bean。在MVC Java配置中,您可以看到javadoc和其中的

@Bean

方法

WebMvcConfigurationSupport

。此類中的配置通過注釋自動導入

@EnableWebMvc

。其實如果你打開

@EnableWebMvc

你可以看到

@Import

聲明。

更精細控制的下一步是定制一個在其中建立的bean之一

WebMvcConfigurationSupport

或可能提供您自己的執行個體的屬性。這需要兩件事情 – 删除

@EnableWebMvc

注釋,以防止導入,然後從

DelegatingWebMvcConfiguration

一個子類 擴充

WebMvcConfigurationSupport

。這是一個例子:

@Configuration
 public  class WebConfig extends DelegatingWebMvcConfiguration {

	@Override
	 public  void addInterceptors(InterceptorRegistry registry){
		 // ...
	}

	@Override 
	@Bean
	 public RequestMappingHandlerAdapter requestMappingHandlerAdapter(){
		 //建立或讓“超級”建立擴充卡
		//然後自定義其屬性之一
	}

}      
《Spring 5 官方文檔》18. Web MVC 架構
應用程式應該隻有一個配置擴充

DelegatingWebMvcConfiguration

或單個

@EnableWebMvc

注釋類,因為它們都注冊了相同的底層bean。以這種方式修改bean不會阻止您使用本節前面顯示的任何更進階别的構造。

WebMvcConfigurerAdapter

子類和

WebMvcConfigurer

實作仍在使用中。

18.16.14使用MVC命名空間進行進階自定義

對您建立的配置的細粒度控制對于MVC命名空間來說有點困難。

如果您确實需要這樣做,而不是複制其提供的配置,請考慮配置一個

BeanPostProcessor

檢測要按類型自定義的bean,然後根據需要修改其屬性。例如:

@Component
 public  class MyPostProcessor實作 BeanPostProcessor {

	public Object postProcessBeforeInitialization(Object bean,String name)throws BeansException {
		 if(Bean instanceof RequestMappingHandlerAdapter){
			 //修改擴充卡的屬性
		}
	}

}      

請注意,

MyPostProcessor

需要将其包含在其中

<component scan/>

以便檢測到它,或者如果您喜歡,可以使用XML bean聲明明确聲明它。

原創文章,轉載請注明: 轉載自并發程式設計網 – ifeve.com本文連結位址: 《Spring 5 官方文檔》18. Web MVC 架構