- 1WEB 基础HTTP / Browser / WebServer静态页面写死,人人看到一样
- 2Servlet手写 if-else 分发不可扩展,无生命周期/并发管理
- 3JSP:参数散字符串参数散成一堆 String,取值靠字段名硬记
- 3JSP:scriptlet 塞逻辑scriptlet 把逻辑塞进页面,代码与 HTML 糊在一起
- 3JavaBean:数据对象化对象全靠 new、层层硬依赖
- 4Spring IoCWeb 路由仍手写 web.xml/if-else、手动取参绑定,展示/业务/数据访问没分开
- 5MVC · SpringMVC数据在库里,访问是重复样板 + 拼串有注入风险
- 6MySQLJava 连库要手写五步,连接与资源管理全手动
- 7JDBCSQL 与 Java 混写、结果集逐行手映射、没有动态 SQL
- 8MyBatis四份配置 + web.xml 装配繁琐,部署要外部 Tomcat
- 9SpringBoot链尾 · 不考核
MVC 模式 · SpringMVC
MVC 模式 · SpringMVC
目标:掌握 SpringMVC 请求处理流程与 Controller 开发,能完成 CRUD 小项目。
本模块在 IoC/DI 之上引入 MVC 框架:DispatcherServlet 统一调度、Controller 处理请求、ViewResolver 渲染视图。以真实工程
GuestBookSpringMVC为样板,拆解「表单提交 → Controller → Model → JSP 回显」的完整闭环。
一、MVC 设计模式
MVC(Model-View-Controller)把「一次请求的处理」拆成三种职责,各管一段:
- Model:数据——业务对象与属性;
- View:视图——JSP 用 EL
${...}从 Model 取值渲染; - Controller:控制——
@RequestMapping方法处理请求、决定返回哪个 View。
SpringMVC 是 MVC 在 Web 层的落地:Controller 由
@Controller标注,DispatcherServlet 负责统一调度。
落到工程里,MVC 进一步对应三层架构——表示层(Controller/View)、业务逻辑层(Service)、数据访问层(DAO)。下面交互组件逐层看每层「只干自己的事」:
接收请求、渲染视图、展示数据——只负责「跟用户打交道」
@Controller + @RequestMapping + JSP(EL ${...})
@RequestMapping("/hello.do")
public ModelAndView hello() {
return new ModelAndView("hello", "message", msg);
}请求自上而下穿过三层(Controller → Service → DAO),数据自下而上回到 View——每层只干自己的事,互不越界。
二、请求处理五步流程
客户端请求 → DispatcherServlet → HandlerMapping 找 Controller → Controller 返回 ModelAndView → ViewResolver 渲染视图。下面交互实验逐步看这条链路(对照 GuestBookSpringMVC):
交互实验:DispatcherServlet 分发五步时序(SpringMVCFlowDiagram)
先选一个 URL,再点「下一步」,看请求如何从浏览器一路走到 JSP 渲染。对照真实工程 GuestBookSpringMVC。
客户端请求 —— 负责组件 浏览器
用户访问某个 .do 地址,HTTP 请求到达服务器
web.xml 把所有 *.do 交给 DispatcherServlet;spring-mvc.xml 里
<context:component-scan>自动发现 @Controller,RequestMappingHandlerMapping负责 URL→方法映射。
三、@RequestMapping 与 HandlerMapping
@Controller 类里的每个 @RequestMapping("...") 方法都是一个 handler。请求进来,HandlerMapping 按 URL 找到命中的方法:
交互实验:URL → @RequestMapping 命中(HandlerMappingDemo)
输入一个 URL(或点下面的预设),看 RequestMappingHandlerMapping 命中哪个 Controller 方法。支持 {占位符} 路径变量匹配。
| @RequestMapping | 方法 | Controller |
|---|---|---|
| /hello.do | helloWorld(HttpSession) | HelloWorldController |
| /login.do | login(request, User user, Model model, session) | HelloWorldController |
| /logout.do | logout(HttpSession) | HelloWorldController |
| /user/{id}.do | getUser(@PathVariable Long id) | UserController(教学示例) — {id} 为路径变量,如 /user/42.do → id=42 |
精确路径优先;含 {...} 的映射按「任意非 / 片段」匹配,如 /user/42.do 命中 /user/{id}.do(id=42)。无匹配通常返回 404。
支持精确路径(/hello.do)与路径变量占位符(
/user/{id}.do→@PathVariable)。
四、数据传递:Model / ModelAndView / JSP EL
Controller 把数据放进 Model,ViewResolver 渲染的 JSP 用 EL 取出来:
交互实验:Model → JSP EL 数据流(ModelDataFlow)
选一个请求,点「下一步」,看 Controller 放进 Model 的数据如何被 JSP 用 EL 取出来渲染。
① Controller(放)
model.addAttribute("user", user);
return new ModelAndView("words", "message", message);② Model / ModelMap(持有)
- user : User(对象)
- message : String
③ JSP(EL 取)
- <h3>${message}</h3>
- 当前用户:${user.username}
Model 是「本次请求」的数据容器:Controller 放、JSP 取,请求结束即失效;而 HttpSession 跨多次请求存活。要让用户「下次进来还记得」,得把对象同时放进 session(如本工程 login 里 session.setAttribute)。
new ModelAndView("hello", "message", msg)= 逻辑视图名 hello + 属性 message;JSP 里${message}取值。要跨请求记住用户,还得session.setAttribute。
五、spring-mvc.xml 与 web.xml
- web.xml:注册 DispatcherServlet,把 *.do 交给它(前端控制器);
- spring-mvc.xml:
<context:component-scan base-package="com.un.controller"/>—— 自动发现 @Controller;viewResolver(UrlBasedViewResolver):prefix=/WEB-INF/jsp/、suffix=.jsp,把逻辑视图名拼成实际 JSP;RequestMappingHandlerMapping/RequestMappingHandlerAdapter:URL→方法映射 + 调用方法。
思考题
- DispatcherServlet、HandlerMapping、ViewResolver 各自负责什么?为什么需要「前端控制器」统一入口?
@RequestMapping写在类上和方法上有什么区别?- Model 与 HttpSession 的作用域有何不同?何时该用哪个?
new ModelAndView("hello", "message", msg)三个参数各是什么含义?- ViewResolver 的 prefix/suffix 如何把逻辑视图名拼成实际 JSP 路径?
学习小测验
学习小测验
DispatcherServlet 的作用是( )
SpringMVC 请求处理五步的正确顺序是( )
@RequestMapping 的作用是( )
HandlerMapping 的职责是( )
ViewResolver(视图解析器)的作用是( )
Model / ModelMap 的作用是( )
JSP 里 ${message} 的取值来源是( )
new ModelAndView("hello", "message", msg) 的含义是( )
在 MVC 三层架构里,「业务规则、事务边界」应放在哪一层?
数据访问层(DAO)的职责是( )