文章目录
- 1. **DispatcherServlet**
- 2. **HandlerMapping**
- 3. **HandlerAdapter**
- 4. **Controller**
- 5. **ModelAndView**
- 6. **ViewResolver**
- 7. **View**
- 工作流程
- 配置方式
- XML 配置
- Java 配置
- 最佳实践
- 示例项目
- 项目目录结构
- 控制器 (`HelloWorldController.java`)
- 服务层 (`HelloWorldService.java`)
- 视图 (`hello.jsp`)
- 配置文件 (`application.properties`)
- 全局异常处理 (`GlobalExceptionHandler.java`)
1. DispatcherServlet
DispatcherServlet
是 Spring MVC 的前端控制器,它负责接收所有的 HTTP 请求,并将请求分发到相应的处理器。它是整个 Spring MVC 框架的核心组件。
- 初始化:
DispatcherServlet
在启动时会初始化一系列的组件,如HandlerMapping
、HandlerAdapter
、ViewResolver
等。 - 请求处理:接收到请求后,
DispatcherServlet
会通过HandlerMapping
找到合适的处理器,然后通过HandlerAdapter
调用处理器方法。
2. HandlerMapping
HandlerMapping
负责将请求映射到处理器。Spring MVC 提供了多种 HandlerMapping
实现,包括:
- RequestMappingHandlerMapping:基于
@RequestMapping
注解进行请求映射。 - BeanNameUrlHandlerMapping:基于 Bean 名称进行请求映射。
- SimpleUrlHandlerMapping:基于 URL 模式进行请求映射。
3. HandlerAdapter
HandlerAdapter
负责调用处理器方法。Spring MVC 提供了多种 HandlerAdapter
实现,包括:
- RequestMappingHandlerAdapter:支持基于
@RequestMapping
注解的方法调用。 - HttpRequestHandlerAdapter:支持
HttpRequestHandler
接口的方法调用。
4. Controller
控制器是处理请求的主要组件。在 Spring MVC 中,控制器类通常使用 @Controller
注解标记,并且方法上使用 @RequestMapping
或其派生注解(如 @GetMapping
, @PostMapping
)来指定处理哪些请求。
5. ModelAndView
ModelAndView
对象用于封装模型数据和视图信息。控制器方法可以返回 ModelAndView
对象,其中包含模型数据和视图名称。
6. ViewResolver
视图解析器负责将逻辑视图名称解析为具体的视图对象。常用的视图解析器有:
- InternalResourceViewResolver:用于 JSP 视图。
- ThymeleafViewResolver:用于 Thymeleaf 视图。
- FreeMarkerViewResolver:用于 FreeMarker 视图。
7. View
视图负责渲染最终的页面,展示给用户。视图可以是 JSP、FreeMarker、Thymeleaf 等模板引擎生成的页面。
工作流程
- 客户端发送请求:客户端(如浏览器)发送 HTTP 请求到服务器。
- 请求到达 DispatcherServlet:请求被
DispatcherServlet
捕获。 - HandlerMapping 定位处理器:
DispatcherServlet
使用HandlerMapping
查找处理请求的控制器方法。 - HandlerAdapter 调用处理器:
DispatcherServlet
使用HandlerAdapter
调用控制器方法。 - 控制器处理请求:控制器方法处理请求,返回
ModelAndView
对象。 - ViewResolver 解析视图:
DispatcherServlet
使用ViewResolver
将逻辑视图名称解析为具体的视图对象。 - 视图渲染:视图对象渲染最终的页面,并返回给客户端。
配置方式
XML 配置
传统的 Spring MVC 配置通常是通过 XML 文件完成的。以下是一个简单的 XML 配置示例:
<!-- web.xml -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- dispatcher-servlet.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 扫描 Controller -->
<context:component-scan base-package="com.example.controller" />
<!-- 启用 MVC 注解驱动 -->
<mvc:annotation-driven />
<!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
Java 配置
现代的 Spring MVC 项目通常使用 Java 配置。以下是一个简单的 Java 配置示例:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@ComponentScan(basePackages = "com.example.controller")
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
最佳实践
- 分层设计:将应用分为控制器层、服务层和数据访问层,保持各层职责清晰。
- 异常处理:使用
@ControllerAdvice
和@ExceptionHandler
注解来集中处理异常。 - 数据验证:使用 JSR-303 标准的数据验证框架(如 Hibernate Validator)来验证请求参数。
- 国际化:使用 Spring 的国际化支持来提供多语言界面。
- 安全性:使用 Spring Security 来保护应用的安全性。
- 性能优化:合理使用缓存、异步处理等技术来提升应用性能。
示例项目
假设我们有一个简单的 Spring Boot 项目,使用 Spring MVC 构建一个基本的 Web 应用程序。
项目目录结构
src/main/java
│── com.example
│ └── controller
│ └── HelloWorldController.java
│── com.example.service
│ └── HelloWorldService.java
│── com.example.repository
│ └── HelloWorldRepository.java
└── Application.java
src/main/resources
│── static
│── templates
│── application.properties
控制器 (HelloWorldController.java
)
package com.example.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import com.example.service.HelloWorldService;
@Controller
public class HelloWorldController {
@Autowired
private HelloWorldService helloWorldService;
@GetMapping("/hello")
public String hello(Model model) {
String message = helloWorldService.getMessage();
model.addAttribute("message", message);
return "hello"; // 返回视图名称
}
}
服务层 (HelloWorldService.java
)
package com.example.service;
import org.springframework.stereotype.Service;
@Service
public class HelloWorldService {
public String getMessage() {
return "Hello, Spring MVC!";
}
}
视图 (hello.jsp
)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>
配置文件 (application.properties
)
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
全局异常处理 (GlobalExceptionHandler.java
)
package com.example.controller;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ModelAndView handleException(Exception ex) {
ModelAndView modelAndView = new ModelAndView("error");
modelAndView.addObject("errorMessage", ex.getMessage());
return modelAndView;
}
}