企業級 Spring MVC 配置遠超 Hello World。本文提供一份生產就緒的 spring-mvc.xml 全量樣例,涵蓋組件掃描、多視圖解析、Freemarker/JSP、攔截器鏈、消息轉換器、統一異常處理、靜態資源、DBCP 數據源、JdbcTemplate、聲明式事務、SpringContextHolder 工具類,並附關鍵點註釋。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="https://www.springframework.org/schema/tx"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:mvc="https://www.springframework.org/schema/mvc"
xsi:schemaLocation="
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd
https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 1. 組件掃描:Controller、Service、Component 等 -->
<context:component-scan base-package="com.xxx,com.xxx.session,com.xxx.xxx" />
<!-- 2. 多視圖解析器:同項目同時支持 JSP + Freemarker -->
<bean class="com.xxx.core.web.MixedViewResolver">
<property name="resolvers">
<map>
<entry key="jsp">
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
</entry>
<entry key="ftl">
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="cache" value="true"/>
<property name="contentType" value="text/html;charset=UTF-8"/>
<property name="exposeSpringMacroHelpers" value="true"/>
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView"/>
<property name="requestContextAttribute" value="rc"/>
</bean>
</entry>
</map>
</property>
</bean>
<!-- 3. Freemarker 配置 -->
<bean id="freeMarkerConfigurer" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/ftl/"/>
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">5</prop>
<prop key="default_encoding">UTF-8</prop>
<prop key="locale">zh_CN</prop>
</props>
</property>
</bean>
<!-- 4. 攔截器鏈(順序即執行順序) -->
<bean id="logNDCInteceptor" class="com.xxx.core.web.LogNDCInteceptor"/>
<bean id="myPermissionsInteceptor" class="com.xxx.userplatform.mvc.MyPermissionsInteceptor"/>
<bean id="myRequestHelperInteceptor" class="com.xxx.core.web.MyRequestHelperInteceptor"/>
<bean id="myUserInfoInteceptor" class="com.xxx.userplatform.mvc.MyUserInfoInteceptor"/>
<!-- 5. 註解映射 + 攔截器注入 -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<ref bean="logNDCInteceptor"/> <!-- 1. 日誌 MDC -->
<ref bean="myRequestHelperInteceptor"/> <!-- 2. 請求輔助 -->
<ref bean="myPermissionsInteceptor"/> <!-- 3. 權限校驗 -->
<ref bean="myUserInfoInteceptor"/> <!-- 4. 用戶信息注入 -->
</list>
</property>
</bean>
<!-- 6. 註解適配器 + 消息轉換器(支援 JSON、XML、文件、字節流等) -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="byteArray_hmc"/> <!-- byte[] -->
<ref bean="string_hmc"/> <!-- String -->
<ref bean="resource_hmc"/> <!-- Resource -->
<ref bean="source_hmc"/> <!-- XML Source -->
<ref bean="xmlAwareForm_hmc"/> <!-- XML 表單 -->
<ref bean="jaxb2RootElement_hmc"/> <!-- JAXB2 -->
<ref bean="jackson_hmc"/> <!-- JSON (Jackson) -->
</list>
</property>
</bean>
<bean id="byteArray_hmc" class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean id="string_hmc" class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean id="resource_hmc" class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
<bean id="source_hmc" class="org.springframework.http.converter.xml.SourceHttpMessageConverter"/>
<bean id="xmlAwareForm_hmc" class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"/>
<bean id="jaxb2RootElement_hmc" class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean id="jackson_hmc" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
<!-- 7. 統一異常處理 -->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">
redirect:/uploadError.jsp
</prop>
</props>
</property>
<property name="defaultErrorView" value="forward:/error.jsp"/>
<property name="defaultStatusCode" value="200"/>
<property name="warnLogCategory" value="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"/>
</bean>
<!-- 8. 靜態資源訪問(不經 DispatcherServlet) -->
<mvc:default-servlet-handler/>
<!-- 9. 數據源 (DBCP) -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@192.168.3.141:1521:xxx"/>
<property name="username" value="xxxdb"/>
<property name="password" value="xxxdb"/>
<property name="initialSize" value="2"/>
<property name="maxActive" value="10"/>
<property name="maxIdle" value="10"/>
<property name="maxWait" value="1000"/>
<property name="poolPreparedStatements" value="true"/>
</bean>
<!-- JNDI 數據源備選 -->
<!-- <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/xxx"/> </bean> -->
<!-- 10. JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 11. 事務管理器 + 註解驅動 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<!-- 12. SpringContextHolder:靜態獲取 Bean -->
<bean class="com.xxxxx.SpringContextHolder" lazy-init="false"/>
</beans>
| 模塊 | 核心作用 | 注意事項 |
|---|---|---|
| MixedViewResolver | 根據返回視圖名後綴(.jsp/.ftl)動態選擇解析器 | 需自定義實現 ViewResolver 接口,委派給對應 resolver |
| 攔截器順序 | 日誌 → 請求輔助 → 權限 → 用戶信息 | 權限攔截器依賴用戶信息,必須在後;preHandle 返回 false 終止鏈 |
| 消息轉換器順序 | 按列表順序嘗試匹配 | Jackson 放最後避免誤吞其他類型;Spring 4.1+ 建議用 RequestMappingHandlerAdapter + HttpMessageConverters 自動配置 |
| SimpleMappingExceptionResolver | 異常類名映射視圖 | 僅處理 Controller 拋出異常;Filter/攔截器異常需 HandlerExceptionResolver 鏈或 @ControllerAdvice |
| mvc:default-servlet-handler | 將靜態資源請求轉發給容器默認 Servlet | 需容器支援;Spring Boot 以 ResourceHttpRequestHandler 替代 |
| DBCP 連接池 | 基礎連接池,生產建議換 HikariCP | 配置 validationQuery、testOnBorrow 防連接失效 |
| tx:annotation-driven | 啟用 @Transactional | proxy-target-class="true" 強制 CGLIB 代理,支援非接口類 |
| SpringContextHolder | 非 Spring 管理類(工具類、監聽器)靜態獲取 Bean | 實現 ApplicationContextAware,慎用防止循環依賴 |
AnnotationMethodHandlerAdapter,改用 RequestMappingHandlerMapping + RequestMappingHandlerAdapter(自動註冊)。@EnableWebMvc + WebMvcConfigurer Java Config 替代,零 XML。spring.datasource.hikari.*)。@RestControllerAdvice + @ExceptionHandler 返回標準 JSON 錯誤碼。這份配置樣例承載了傳統 Spring MVC 項目十年的最佳實踐沉澱,理解每個 Bean 的職責與協作,是向架構師邁進的必修課。