Spring MVC 的核心知识点梳理

作者:huohuopro日期:2026/5/11

MVC 是什么

MVC 不是 Spring 发明的,而是一种设计模式,目的是“解耦”。

  • M(Model,模型):数据 + 业务逻辑。比如 Teacher 类,TeacherService
  • V(View,视图):展示数据的界面。比如 JSP、Thymeleaf 模板,或者是现代返回 JSON 的前端页面。
  • C(Controller,控制器):接收用户请求,调用 Model,最后选择 View 来展示。

流程:用户点击一个链接 → Controller 拿到请求 → 调 Service 拿到数据(Model)→ 把数据交给 View 渲染 → 返回 HTML 给浏览器。

Spring MVC 就是把这个流程在 Java Web 环境里落地的一套框架。

核心组件与处理流程

Spring MVC 最核心的就是一个 前端控制器(Front Controller)——DispatcherServlet

组件作用常见实现
DispatcherServlet统一入口,调度一切Spring 提供,我们只需配置
HandlerMapping根据请求 URL 找到对应的处理器RequestMappingHandlerMapping
HandlerAdapter执行找到的处理器(Controller 方法)RequestMappingHandlerAdapter
HandlerInterceptor拦截器,在处理方法前后做增强自定义
ViewResolver根据视图名找到真正的视图文件InternalResourceViewResolver (JSP)
HandlerExceptionResolver处理异常ExceptionHandlerExceptionResolver

一个请求的完整生命周期(回顾前面讲过的流程图):

  1. 请求到达 DispatcherServlet
  2. DispatcherServletHandlerMapping:谁处理这个 URL?
  3. HandlerMapping 返回一个 HandlerExecutionChain(包含 Controller 方法 + 一堆拦截器)。
  4. DispatcherServletHandlerAdapter:谁能执行这个 Controller 方法?
  5. HandlerAdapter 执行具体方法(期间会做参数绑定、类型转换、校验等)。
  6. 方法返回 ModelAndView(或 @ResponseBody 直接返回数据)。
  7. 若有视图名,ViewResolver 解析出真正的 JSP 等视图。
  8. 渲染视图,响应给浏览器。

Controller 与注解:从入门到精通

@Controller & @RestController

1@Controller  // 声明这是一个控制器类,方法通常返回视图名
2public class TeacherController { ... }
3
4@RestController  // = @Controller + @ResponseBody,所有方法默认返回 JSON
5public class TeacherRestController { ... }
6

@RequestMapping 及衍生注解

1@RequestMapping("/teacher")   // 类级别映射
2public class TeacherController {
3
4    @RequestMapping(value = "/list", method = RequestMethod.GET)
5    public String list() { ... }  // 等价于 @GetMapping("/list")
6}
7

@GetMapping@PostMapping@PutMapping@DeleteMapping 等都是 @RequestMapping 的快捷方式。

参数绑定注解(重点对比)

注解从哪里拿数据示例
@RequestParamURL 问号后的参数或表单数据?name=Tom → @RequestParam("name") String name
@PathVariableURI 路径中的占位符/teacher/{id} → @PathVariable("id") Long id
@RequestBody请求体中的 JSON/XMLPOST 的 JSON {"name":"Tom"} 自动转成 Teacher 对象
@ModelAttribute① 从 Model 中取;② 把参数绑定到对象常用于表单提交自动封装对象,
@RequestHeader请求头@RequestHeader("User-Agent") String ua
@CookieValueCookie@CookieValue("JSESSIONID") String sid

把参数自动封装成对象

Spring 可以直接将表单字段或 JSON 映射成一个 Java Bean。

表单提交示例

1<form action="/teacher/save" method="post">
2    <input name="name"/>     <!-- Teacher.name -->
3    <input name="age"/>      <!-- Teacher.age -->
4    <input type="submit"/>
5</form>
6
1@PostMapping("/teacher/save")
2public String save(@ModelAttribute Teacher teacher) {
3    // teacher 对象已被自动填充 name  age
4    teacherService.save(teacher);
5    return "redirect:/teacher/list";
6}
7

底层原理:DataBinder + BeanWrapper 负责属性拷贝。

自定义类型转换器:String → Date

很多时候,请求参数是 String,但你想转成 DateLocalDate 或自定义类型。

Spring 内置的转换器和格式化器

  • Converter<S, T>:源类型 → 目标类型,如 StringToDateConverter
  • Formatter:专为字符串和对象互转设计,支持国际化,适合 String <-> Date

自定义一个 String → Date 的 Converter 示例

1@Component
2public class StringToDateConverter implements Converter<String, Date> {
3    private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
4
5    @Override
6    public Date convert(String source) {
7        try {
8            return format.parse(source);
9        } catch (ParseException e) {
10            throw new IllegalArgumentException("日期格式必须为 yyyy-MM-dd");
11        }
12    }
13}
14

在 Spring Boot 中,只需让它被容器管理(@Component)就会自动注册到转换器链。
在传统 Spring MVC XML 中,需要配置 FormattingConversionServiceFactoryBean

使用场景

1@GetMapping("/teacher/search")
2public String searchByDate(@RequestParam("date") Date date) {
3    // /teacher/search?date=2025-01-01  date 直接转换好
4}
5

如果转换失败,会抛出 TypeMismatchException,我们可以用异常处理来统一返回友好信息。

拦截器(Interceptor)和过滤器(Filter)

两者都可以在请求前后做手脚,但层级不同。

对比维度Filter(过滤器)Interceptor(拦截器)
归属Servlet 规范,Java EESpring MVC 框架
作用范围能拦截所有进入 Servlet 的请求(包括静态资源)只能拦截进到 Spring MVC 的请求(DispatcherServlet 处理)
是否能用 Spring Bean不能直接注入(可以迂回)可以正常注入其他 Bean
执行顺序先经过 Filter,再进 DispatcherServlet在 DispatcherServlet 之后,Controller 方法之前
典型场景字符编码、跨域、权限安全检查登录检查、日志记录、性能监控、用户权限补充

定义拦截器示例

1@Component
2public class LoginInterceptor implements HandlerInterceptor {
3    @Override
4    public boolean preHandle(HttpServletRequest request, 
5                             HttpServletResponse response, 
6                             Object handler) {
7        // 检查 session 中是否有用户
8        if (request.getSession().getAttribute("user") == null) {
9            response.sendRedirect("/login");
10            return false;  // 不放行
11        }
12        return true;
13    }
14}
15

注册拦截器

1@Configuration
2public class WebConfig implements WebMvcConfigurer {
3    @Autowired
4    private LoginInterceptor loginInterceptor;
5
6    @Override
7    public void addInterceptors(InterceptorRegistry registry) {
8        registry.addInterceptor(loginInterceptor)
9                .addPathPatterns("/teacher/**")   // 要拦截的
10                .excludePathPatterns("/teacher/login"); // 排除的
11    }
12}
13

异常处理:优雅地给前端报错

还记得我们之前聊过的“异常和错误”吗?常用的处理方式是:

局部异常处理

1@Controller
2public class TeacherController {
3    @ExceptionHandler(TeacherNotFoundException.class)
4    public String handleNotFound(TeacherNotFoundException ex, Model model) {
5        model.addAttribute("msg", ex.getMessage());
6        return "error/404";   // 返回错误视图
7    }
8}
9

全局异常处理(推荐)

1@ControllerAdvice
2public class GlobalExceptionHandler {
3
4    @ExceptionHandler(MethodArgumentNotValidException.class)
5    @ResponseStatus(HttpStatus.BAD_REQUEST)
6    @ResponseBody
7    public Map<String, String> handleValidation(MethodArgumentNotValidException ex) {
8        // 返回校验失败信息,如 {"name":"不能为空"}
9        ...
10    }
11
12    @ExceptionHandler(Exception.class)
13    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
14    @ResponseBody
15    public Map<String, String> handleGeneral(Exception ex) {
16        return Map.of("error", "服务器内部错误");
17    }
18}
19

Spring MVC 的核心知识点梳理》 是转载文章,点击查看原文


相关推荐


Git Worktree: AI 编程 Agent 并行开发的秘密武器
陈佬昔编程人生2026/5/1

你在 AI 编程工具里开发一个新功能,突然产品过来让修复一个紧急 bug。于是你开了两个 AI Agent: Agent A:在 feature/new-dashboard 上写新功能 Agent B:在 fix/login-bug 上修一个登录 Bug 你心想:"两个 Agent 同时干活,效率翻倍。" 但三分钟后你回到编辑器,看到的是一幅这样的画面: app/ ├── dashboard.tsx ← Agent A 刚改了这里,但没写完 ├── login.tsx ←


我把 Hermes 里的模型几乎测了一遍,得出一个很扎心的结论:越贵的,往往越强
孟健AI编程2026/4/23

大家好,我是孟健。 这几周我在 Hermes 里来回切了很多模型。真跑下来,我越来越确认一件事:模型的水平,很多时候早就写在价格里了。把性价比榜倒过来看,八九不离十就是质量排行。 这不是 benchmark 结论。 是我把 Hermes 当生产底座,拿它去跑多 Agent、长流程、代码任务、资料整理之后,交出来的体感排序。 01 先给排序:贵,很多时候不是乱贵 先看这张图。 图里是按价格排的:便宜的在前,贵的在后。 但我这轮实际测下来,如果你把它倒过来看,它反而更像质量榜。 我的主观体感


c++从入门到跑路——string类
小肝一下2026/4/14

c++从入门到跑路——string类 1.为什么学习string类? 1.1 C语言中的字符串 C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列 的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户 自己管理,稍不留神可能还会越界访问。 1.2 两个面试题(暂不做讲解) 把字符串转换成整数_牛客题霸_牛客网 415. 字符串相加 - 力扣(LeetCode) 在OJ中,有关字符串的题目基本以stri


火爆全网的Seedance2.0 十万人排队,我2分钟就用上了
AI袋鼠帝2026/4/6

大家好,我是袋鼠帝。 之前我在B站看到一位AI视频创作者分享他的工作流。不可否认,那套流程做出来的视频确实很专业,画面精美,运镜流畅。但是,看完我只觉得头皮发麻。 原文档找不到了,我记得他先是用Gemini写剧本,接着用NanoBanana跑画面,然后再去另外的配音平台搞音频,中间穿插着使用ComfyUI来控制视频、图片生成。 ComfyUI这玩意儿我以前也折腾过几次,连线复杂就算了,每个节点的各种配置参数直接给我整懵逼了,我感觉比当初学敲代码还难,后面就再也没碰过了。 然后整个流程的最后一步,


Vue项目打包为WAR文件部署Tomcat完整指南
蒙眼过河2026/3/28

Vue项目打包为WAR文件部署Tomcat完整指南 前言 在Vue项目开发完成后,通常我们会将打包后的静态文件部署到Nginx等静态服务器上。但在某些企业环境中,我们需要将Vue项目部署到Tomcat这样的Java应用服务器中。本文将详细介绍如何将Vue项目的打包文件转换为标准的WAR包,以便部署到Tomcat服务器。 为什么需要将Vue打包为WAR包? 企业规范要求:很多企业使用统一的Tomcat应用服务器集群统一管理:便于与后端Java应用统一部署和管理历史遗留系统:部分老系统架构需


Django 基础入门教程(第四篇):Form组件、Auth认证、Cookie/Session与中间件
冉成未来2026/3/20

在前三篇中,我们完成了 Django 的环境搭建、模型设计、视图模板、Admin 后台以及 ORM 高级查询。本篇将带你深入 Django 的用户交互与安全机制:Form 组件、Auth 认证系统、Cookie/Session 和中间件。学完本篇,你将能够处理复杂的表单验证、实现用户注册登录、管理用户会话,并理解 Django 的请求/响应处理流程。 第一部分:Django Form 组件 1.1 为什么需要 Form 组件? 在 Web 开发中,处理表单是常见且复杂的任务。你需要:


AI时代的数据对比:DBA还需要盯着屏幕看差异吗?
NineData2026/3/12

当 AI 已经能写 SQL、辅助诊断、生成代码时,很多企业的数据对比却还停留在相对原始的阶段:任务跑完,DBA 需要面对动辄上百张表的差异报告,逐行核对的工作量极大。 这种场景在迁移、同步、数据备份演练里并不少见,到了国产化迁移场景下更是被进一步放大。数据库从 Oracle 迁到达梦、从 MySQL 迁到人大金仓,变化的不只是运行环境,更是数据库内核、数据类型、字符集规则和兼容语义。DBA 担心的往往不是任务失败,而是任务看起来已经完成,业务流量切换之后才发现数据并不一致。 AI 时代的数据对


ubuntu应用深度守护
字节逆旅2026/3/4

二、 定位分析:抽丝剥茧 1. 系统日志中的“启动死循环” 输入sudo grep "linux-myApp" /var/log/syslog调取 syslog 发现,系统曾多次尝试自动拉起应用,但均告失败。 报错核心:Exec binary ... does not exist: No such file or directory。 结论:系统预设的自动启动路径与实际安装路径不匹配,导致应用在服务器重启后无法“回家”。 2. 定位原因 上面的日志内容意味着我的应用可能已经被卸载、被移动了位


【C++】整数类型(Integer Types)避雷指南与正确使用姿势
PAK向日葵2026/2/24

背景 C++继承自C语言。作为一门以零开销抽象为主要特征的底层语言,不同于Python或JavaScript等高抽象层次的语言,C++拥有一套较为完整、但又包含有一定历史包袱的内建整数类型。 在实际开发中,如果对C++内建整数类型的机制不熟悉,或者不遵循一定的使用规范,则非常容易引入难以排查和调试的Bug。因此学习了解C++中内建整数类型的特性,以及一套行之有效的使用规范,是非常有必要的。 内建整数类型的坑 or 历史包袱 C++ 标准没有规定具体位数 虽然在实际实践中,我们知道在x64平台,对


百度 APP 正式接入 OpenClaw,所有人限时免费!
苍何2026/2/15

这是苍何的第 495 篇原创! 大家好,我是苍何。 最近被 OpenClaw 刷屏了吧? 3 周时间 GitHub Star 干到 19 万,比当年 DeepSeek 还猛。 我也发了好几篇文章了,然后还开源了个知识库,你别说,还挺多人用的。 基本上接入 QQ、微信、飞书、discord 等都写的比较全了。 但是说实话,OpenClaw 的部署使用过程并不算丝滑。 买服务器、配环境、装依赖,光是部署就需要折腾大半天。 好不容易跑起来了,还得通过 Telegram 来发指令。 就,怎么说呢,能用

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 XYZ博客