目录
2. DispatcherServlet 接收请求(服务员接单)
3. HandlerAdapter 调用 Controller(服务员传达厨师)
引言:以下我将MVC的底层各个流程比作一个餐厅的运作流程,这样便于我们理解。
一、基于餐厅比喻的代码示例 ,帮助你理解各组件间的协作关系
1. DispatcherServlet 配置(服务员)
// 在web.xml中配置DispatcherServlet(SpringBoot中自动配置)
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml</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>
2. HandlerMapping 配置(菜单索引)
<!-- spring-mvc.xml 配置HandlerMapping -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
3. Controller 实现(厨师)
@Controller
@RequestMapping("/food")
public class FoodController {
@Autowired
private FoodService foodService; // 厨房(Service层)
// 处理 "/food/123" 请求(宫保鸡丁)
@GetMapping("/{id}")
public ModelAndView getFood(@PathVariable("id") Long id) {
// 从厨房获取菜品(调用Service)
Food food = foodService.getFoodById(id);
// 返回视图名称和数据(餐盘+菜品)
ModelAndView mav = new ModelAndView("foodDetail");
mav.addObject("food", food);
return mav;
}
}
4. Service 层(厨房)
@Service
public class FoodServiceImpl implements FoodService {
@Autowired
private FoodRepository foodRepository; // 食材库(DAO)
@Override
public Food getFoodById(Long id) {
// 从食材库获取食材,制作菜品
return foodRepository.findById(id)
.orElseThrow(() -> new RuntimeException("菜品不存在"));
}
}
5. ViewResolver 配置(餐桌索引)
<!-- spring-mvc.xml 配置ViewResolver -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
6. View 视图(餐桌)
<!-- /WEB-INF/views/foodDetail.jsp -->
<html>
<head>
<title>${food.name}</title>
</head>
<body>
<h1>菜品详情:${food.name}</h1>
<p>价格:${food.price} 元</p>
<p>配料:${food.ingredients}</p>
<img src="${food.imageUrl}" alt="${food.name}">
</body>
</html>
7. 客户端请求流程(顾客点餐)
顾客请求:访问
http://localhost:8080/food/123
DispatcherServlet 接收到请求,通过
RequestMappingHandlerMapping
找到FoodController.getFood()
方法。Controller 调用
FoodService
获取菜品数据。Controller 返回
ModelAndView("foodDetail", {food: 宫保鸡丁})
。DispatcherServlet 通过
InternalResourceViewResolver
解析视图为/WEB-INF/views/foodDetail.jsp
。JSP 将菜品数据渲染为 HTML 响应给客户端。
二、SpringMVC 底层原理与餐厅运作流程的类比
SpringMVC 是一个基于 MVC 模式的 Web 框架,其核心是 DispatcherServlet (中央调度器),负责协调请求的处理流程。这个过程可以类比为餐厅的运作:
1. 客户端请求(顾客点餐)
- 顾客(客户端)进入餐厅(Web 应用),向服务员(DispatcherServlet)点餐(发送请求)。
- 示例:顾客说:“我要一份宫保鸡丁!”(对应 URL 请求 /food/123)。
2. DispatcherServlet 接收请求(服务员接单)
- 服务员(DispatcherServlet)收到订单后,首先查看菜单索引(HandlerMapping),确定由哪位厨师(Controller)负责制作这道菜。
- HandlerMapping:将 URL 请求映射到具体的 Controller 方法。
- 示例:菜单显示 “宫保鸡丁 → 川菜厨师”。
3. HandlerAdapter 调用 Controller(服务员传达厨师)
- 服务员(DispatcherServlet)通过对讲机(HandlerAdapter)通知川菜厨师(Controller)制作宫保鸡丁。
- HandlerAdapter:负责调用 Controller 方法并获取返回值。
- 示例:服务员说:“厨师,麻烦做一份宫保鸡丁!”
4. Controller 处理请求(厨师做菜)
- 川菜厨师(Controller)根据订单(请求参数),从厨房(Service/DAO)获取食材(数据),制作宫保鸡丁(处理业务逻辑)。
- Controller:处理请求,调用 Service 层获取数据,并返回一个视图名称(如 foodDetail)和模型数据(如菜品详情)。
- 示例:厨师从冰箱取鸡肉、花生,烹饪后装盘。
5. ModelAndView 返回结果(厨师上菜)
- 厨师(Controller)将做好的菜(Model 数据)放在餐盘(ViewName)上,交给服务员(DispatcherServlet)。
- ModelAndView:包含视图名称和模型数据。
- 示例:厨师说:“宫保鸡丁做好了,放在 3 号桌对应的餐盘上!”
6. ViewResolver 解析视图(服务员找餐桌)
- 服务员(DispatcherServlet)根据餐盘编号(ViewName),通过餐桌索引(ViewResolver)找到对应的餐桌(View)。
- ViewResolver:将视图名称映射到具体的视图实现(如 JSP、Thymeleaf)。
- 示例:服务员查看索引表:“3 号桌 → 大厅东侧靠窗位置”。
7. View 渲染数据(摆盘上菜)
- 服务员(DispatcherServlet)将菜(Model 数据)摆放在指定餐桌(View)上,顾客(客户端)看到最终的菜品(HTML 页面)。
- View:将模型数据填充到模板中,生成 HTML 响应。
- 示例:服务员把宫保鸡丁放在餐桌上,顾客看到色香味俱全的菜品。
- 示例:服务员把宫保鸡丁放在餐桌上,顾客看到色香味俱全的菜品。
总结对比表
请求处理流程图

通过这个餐厅类比,你可以直观理解 SpringMVC 的核心流程: 中央调度、请求分发、业务处理、视图渲染。
这种设计模式让 Web 应用的职责分离,代码更易维护和扩展。