繼續《Spring in Action》學習筆記系列,本篇聚焦 Spring MVC 控制器類型擴展、多視圖解析器鏈配置、國際化視圖解析與統一異常處理機制。
標準 Controller 介面為單例(Singleton),多線程共享實例,請求參數只能通過方法參數傳遞。ThrowawayController 介面標記原型作用域(singleton="false"),每次請求新建實例,可直接用實例欄位綁定表單數據,類似 Struts 2 / WebWork Action 模式。
<bean name="/throwaway" class="com.example.MyThrowawayController" singleton="false"/>
需註冊 ThrowawayControllerHandlerAdapter 讓 DispatcherServlet 識別:
<bean class="org.springframework.web.servlet.mvc.throwaway.ThrowawayControllerHandlerAdapter"/>
若同時使用單例與原型控制器,需額外註冊 SimpleControllerHandlerAdapter(實測預設 ControllerHandlerAdapter 亦可共存,版本差異)。
| 解析器 | 適用場景 | 核心配置 |
|---|---|---|
| InternalResourceViewResolver | JSP/Velocity 等模板,最常用 | prefix=/WEB-INF/jsp/, suffix=.jsp, viewClass=JstlView |
| BeanNameViewResolver | 視圖作為 Spring Bean 管理(如 PDF/Excel 生成類) | bean name = 邏輯視圖名 |
| XmlViewResolver | 視圖定義獨立 XML,便於模組化 | location=/WEB-INF/views.xml |
| ResourceBundleViewResolver | 國際化視圖:不同 Locale 解析到不同視圖實現 | basename=views(讀取 views.properties, views_zh_CN.properties 等) |
<bean id="viewResolver" 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>
指定 JstlView 可正確暴露 JSTL 所需的請求屬性(javax.servlet.jsp.jstl.fmt.localizationContext 等)。
# views.properties (預設)
reportView.class=com.example.PdfReportView
# views_en_US.properties
reportView.class=com.example.ExcelReportView
# views_de_DE.properties
reportView.class=org.springframework.web.servlet.view.JstlView
reportView.url=/WEB-INF/jsp/report.jsp
同一邏輯視圖名 reportView,中文用戶看 PDF,美國用戶下載 Excel,德國用戶看 JSP 頁面——零代碼修改實現區域化呈現。
同時註冊多個解析器時,DispatcherServlet 按 order 屬性(實作 Ordered 介面)從小到大嘗試。注意:Spring 1.2.x InternalResourceViewResolver 未實作 Ordered,無法設 order;Spring 2.0+ 已支援。若無 order,按 Bean 定義順序。
<bean id="xmlViewResolver" class="...XmlViewResolver" p:order="1" p:location="/WEB-INF/views.xml"/>
<bean id="internalViewResolver" class="...InternalResourceViewResolver" p:order="2" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>
先嘗試 XML 定義的視圖(如 PDF/Excel),找不到再 fallback 到 JSP。
Spring 1.x spring.tld 需配合 JSTL 使用,綁定極繁瑣:
<spring:bind path="user.name">
<input name="<c:out value='${status.expression}'/>" value="<c:out value='${status.value}'/>">
<c:forEach items="${status.errorMessages}" var="err"><c:out value="${err}"/></c:forEach>
</spring:bind>
強烈建議升級 Spring 2.x 使用 spring-form.tld(<form:input path="name"/>),或將 2.x 表單標籤移植到 1.x 專案。
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.Exception">friendlyError</prop>
<prop key="com.example.BusinessException">businessError</prop>
<prop key="org.springframework.dao.DataAccessException">dataError</prop>
</props>
</property>
<property name="defaultErrorView" value="systemError"/>
<property name="exceptionAttribute" value="ex"/> <!-- 預設暴露異常到模型 -->
</bean>
控制器拋出異常 → ExceptionResolver 匹配映射 → 邏輯視圖名 → 視圖解析器 → 錯誤頁面。支援多異常類型差異化處理,exceptionAttribute 可在錯誤頁面取得異常物件顯示詳情。