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 的核心知识点梳理》 是转载文章,点击查看原文


相关推荐


精准医学的数据平台化与Python编程实战(中)
Allen_Lyb2026/5/1

第五章:高性能数据处理与分析 5.1 使用Pandas进行临床数据清洗与特征工程 import pandas as pd import numpy as np from sklearn.impute import SimpleImputer from sklearn.preprocessing import StandardScaler, OneHotEncoder # 加载模拟临床数据 df = pd.read_csv('clinical_cohort.csv') # 处理缺失值 nu


每天刷十几个平台的热榜太累了?我用一个页面全部搞定
扑克中的黑桃A2026/4/22

这里写目录标题 前言1.什么是DailyHot?2.在飞牛OS上部署DailyHot3.docker部署DailyHot4.使用DailyHot5.安装cpolar内网穿透6.配置公网地址7.保留固定公网地址总结 前言 每天看热点,你要打开几个 App? 微博、知乎、Hacker News、V2EX、豆瓣、少数派……每个平台都有热榜,每个平台都得点进去刷一遍。等把这些都刷完,半个小时过去了,真正有用的信息反而被稀释了。 而且还有个更现实的问题——你在公司想看看知乎热榜发生了啥,


LangGraph 入门到精通0x02:基础 API (二)
chaors2026/4/14

前言 今天继续学习一些 LangGraph 常用到的基础 API。废话少说上干货。 .点语法 Graph 的创建可以使用看着更简洁的 .语法。 graph = ( StateGraph(State) .add_node(a) .add_node(b) .add_edge(START, "a") .add_edge("a", "b") .add_edge("b", END) .compile() ) 步骤序列 StateGraph(St


你的 Android App 可能白白损失了 35% 的性能——R8 全模式配置详解
陆业聪2026/4/6

字节跳动的工程师优化启动速度时,可能花了数周分析 trace、改代码;Monzo 的团队却只改了一行配置,性能指标全线提升了 35%。这不是段子,是 Google 官方 blog 2026 年 3 月底发出来的案例。 问题来了:你的项目,是不是也开着 R8,但根本没用对? R8 到底做了什么——大多数人理解是错的 很多人对 R8 的理解停留在「代码混淆 + 压缩」。打开 minifyEnabled true,觉得任务完成了。 但 R8 实际上分两种工作模式: • 兼容模式(Compatibili


核心概念层——深入理解 Agent 是什么
想打游戏的程序猿2026/3/28

1 Agent vs ChatBot:从根本上理解区别 1.1 一个直观的例子 假设你对 AI 说:"帮我分析一下我们公司上周的销售数据,找出表现最好的产品,并给团队发一封总结邮件"。 ChatBot 的反应: ChatBot: "要分析销售数据,你可以按以下步骤操作: 1. 打开数据库,执行 SQL 查询获取上周的销售记录 2. 使用 Excel 或 Python 进行数据汇总 3. 找出销售额最高的产品 4. 撰写邮件总结发送给团队 你需要我帮你写 SQL 查询语句吗?" → ChatB


配置钉钉龙虾OpenClaw机器人调用OpenMetadata
光于前裕于后2026/3/20

目录 一、前言1️⃣钉钉(DingTalk)2️⃣OpenClaw3️⃣OpenMetadata4️⃣MCP(Model Context Protocol) 二、安装OpenClaw三、配置OpenClaw钉钉机器人四、调用OpenMetadata MCP 一、前言 先介绍下这四个工具/协议的定位与核心能力,本文将从零开始配置。 1️⃣钉钉(DingTalk) 阿里巴巴旗下的企业协作平台,2014年上线,是中国市场份额最大的企业即时通讯与办公套件之一。 核心能


10分钟搭建 Windows + WSL + Codex环境
Lei_official2026/3/12

并不是 AI 替代人,而是会用 AI 的人替代不会用 AI 的人。 我的大模型使用历程 从2023年秋季,我开始使用对话型的大模型,提升工作和学习的效率,以及回答一些生活上的常识问题。最开始是 ChatGPT 的免费版本,随着使用频率提高,慢慢会遇到问答超过上限的情况。随后便开通了Plus订阅直至今日。期间也曾使用过 Deepseek、Gemini、Minimax 等等,不过最主要的仍然是 ChatGPT,个人感觉它在回答的质量、速度、上下文方面体验最好。 在这段历程里,网页对话型 的 AI


MySQL中 SHOW FULL PROCESSLIST` 输出中 `State` 列的所有可能值
左Python右Java2026/3/4

SHOW FULL PROCESSLIST输出中State` 列的所有可能值,以及这些值代表的含义,这能帮你精准判断数据库连接的状态(包括锁相关、执行状态等)。 一、State 列核心分类及含义 State 列描述了当前线程正在执行的操作状态,不同状态对应不同的数据库行为,以下是最常见且实用的分类(按场景划分): 1. 锁相关状态(排查锁表核心) 这是你最关心的锁表相关状态,直接反映锁等待 / 阻塞: 状态值含义Waiting for t


326. Java Stream API - 实现自定义的 toList() 与 toSet() 收集器
yaoxin5211232026/2/23

文章目录 326. Java Stream API - 实现自定义的 `toList()` 与 `toSet()` 收集器📦 实现一个自定义 `toList()` 收集器🚀 使用我们的 `ToList` 收集器🔄 将其改造成 `toSet()` 收集器✅ 修改 1:使用 `HashSet` 作为容器✅ 修改 2:声明该收集器是无序的 🧪 `ToSet` 收集器完整实现示例🎯 总结一下关键点🧠 小贴士 326. Java Stream API - 实现自定义的 toL


Kafka 生产者与消费者配置详解
倚肆2026/2/15

Kafka 生产者与消费者配置详解 一、DefaultKafkaProducerFactory 生产者配置详解 配置项示例值作用说明调优建议ProducerConfig.BOOTSTRAP_SERVERS_CONFIG"localhost:9092"Kafka 集群地址列表,生产者通过此地址发现集群。配置多个地址(用逗号分隔)以提高可用性。ProducerConfig.KEY_SERIALIZER_CLASS_CONFIGStringSerializer.class消息键的序列化器。键用于分区

首页编辑器站点地图

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

Copyright © 2026 聚合阅读