架構圖解
Client Request
↓
DispatcherServlet (前端控制器)
↓
HandlerMapping → Controller → ModelAndView
↓
ViewResolver → View (JSP/Thymeleaf/JSON)
↓
Response
web.xml 核心配置
<web-app version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-context.xml</param-value> <!-- Spring 根容器 -->
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/springmvc.xml</param-value> <!-- Web 容器 -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern> <!-- 攔截所有請求 -->
</servlet-mapping>
<!-- Log4j 配置 -->
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/classes/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
</web-app>
關鍵點解析
- 雙容器架構:
ContextLoaderListener 啟動根容器(Service、DAO、DataSource);DispatcherServlet 啟動 Web 容器(Controller、ViewResolver、Interceptor)。Web 容器可訪問根容器 Bean,反之不可。
url-pattern>/ vs /*:/ 不攔截 JSP,交由容器默認 Servlet 處理;/* 會攔截 JSP 導致 404。
load-on-startup>1:容器啟動時即初始化 DispatcherServlet,減少首請求延遲。
springmvc.xml (Web 容器配置)
<beans>
<!-- 只掃描 @Controller,避免重複掃描 Service -->
<context:component-scan base-package="com.cn.my">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<mvc:annotation-driven/> <!-- 請求參數綁定、JSON 轉換、校驗等 -->
<mvc:resources mapping="/resource/**" location="/resource/"/> <!-- 靜態資源 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
application-context.xml (根容器配置)
<beans>
<!-- 掃描非 @Controller 組件 -->
<context:component-scan base-package="com.cn.my">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 數據源 + JdbcTemplate -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
Controller 開發範例
@Controller
@RequestMapping("/my/*")
public class MyController {
@Autowired private CourseServiceInter csi;
@RequestMapping("my")
public String method(HttpServletRequest request, @RequestParam("courseId") String courseId) {
csi.findCourse(courseId);
return "success"; // 邏輯視圖名
}
@RequestMapping("my2/{courseId}/{name}")
public String method2(@PathVariable("courseId") String courseId, @PathVariable("name") String name) {
csi.findCourse(courseId + " " + name);
return "success";
}
}
@RequestMapping 類上定義基礎路徑,方法上定義子路徑。
@RequestParam 綁定查詢參數 ?courseId=xxx。
@PathVariable 綁定 REST 風格路徑變量 /my2/123/abc。
- 返回
String 視為邏輯視圖名,經 ViewResolver 解析為 /WEB-INF/jsp/success.jsp。
常見坑點避雷
- 雙容器掃描包重疊 → Bean 重複創建、事務失效。根容器排除 @Controller,Web 容器只掃描 @Controller。
- 靜態資源 404 → 缺少
<mvc:resources> 或 configurer.enable()。
- 中文亂碼 → 添加
CharacterEncodingFilter 到 web.xml(需在其他 Filter 之前)。
- JSP 無法訪問 → 放在
/WEB-INF/jsp/ 目錄下,防止直接 URL 訪問。