跳到主要内容
Java Web 基础:Spring Web MVC 核心解析 | 极客日志
Java java
Java Web 基础:Spring Web MVC 核心解析 Java Web 开发演进从原生 Servlet 到 Spring Boot,重点解析 Spring Web MVC 的核心注解与参数绑定机制。文章涵盖 Tomcat 容器原理、Servlet 生命周期、以及 @RequestMapping、@RequestBody 等关键注解的实战用法,帮助开发者理解 MVC 模式在 Spring 中的具体落地与常见坑点。
Elasticer 发布于 2026/3/29 0 浏览Java Web 基础:Spring Web MVC 核心解析
1. 前置知识
1.1 Tomcat
Tomcat 是一个开源的轻量级 Web 服务器和 Servlet 容器。它实现了 Java EE 规范的核心功能,常用于部署和运行 Java Web 应用程序。简单来说,Tomcat 就是一个严格遵循 Servlet 规范、可以独立安装运行的 Java Web 服务器 。
核心功能
Servlet 容器 :支持 Servlet 的执行,处理 HTTP 请求和响应。
Web 服务器 :提供静态资源(如 HTML)的访问能力,支持基本的 HTTP 服务。
目录结构
bin:存放可执行文件,如 startup.bat。
conf:存放配置文件。
lib:存放 Tomcat 运行所需的 jar 文件。
logs:存储日志文件。
temp:存放临时文件,如上传的文件或缓存数据。
webapps:默认 web 应用部署目录。
work:服务器的工作目录,存放运行时生成的临时文件。
1.2 Servlet
1.2.1 定义
Servlet 是 Java 语言编写的、运行在服务器端的程序,它遵循一套标准的 API 规范。Tomcat 是这套规范的一个具体实现/容器,并提供了让 Servlet 与前端交互的运行时环境。
1.2.2 快速上手
创建一个基础的 Servlet 项目通常包含以下步骤:
在 IDE 中创建 Maven 项目。
在 pom.xml 中添加 servlet 依赖(置于 <project> 标签下)。
<dependencies >
<dependency >
<groupId > jakarta.servlet</groupId >
<artifactId > jakarta.servlet-api</artifactId >
<version > 6.1.0</version >
<scope > provided</scope >
</ >
dependency
</dependencies >
在 main 路径下创建 webapp/Web-INF/web.xml,配置应用信息。
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app >
<display-name > Archetype Created Web Application</display-name >
</web-app >
编写 Servlet 类,继承 HttpServlet 并重写方法。
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/method")
public class MethodServlet extends HttpServlet {
@Override
protected void doPost (HttpServletRequest req, HttpServletResponse resp) throws IOException {
System.out.println("doPost" );
resp.setContentType("text/html; charset=utf-8" );
resp.getWriter().write("doPost" );
}
@Override
protected void doPut (HttpServletRequest req, HttpServletResponse resp) throws IOException {
System.out.println("doPut" );
resp.setContentType("text/html; charset=utf-8" );
resp.getWriter().write("doPut" );
}
@Override
protected void doDelete (HttpServletRequest req, HttpServletResponse resp) throws IOException {
System.out.println("doDelete" );
resp.setContentType("text/html; charset=utf-8" );
resp.getWriter().write("doDelete" );
}
}
1.2.3 生命周期 Servlet 生命周期由 Web 容器(如 Tomcat)管理,包含加载、初始化、处理请求和销毁 四个阶段。每个阶段对应特定的方法调用,开发者可通过重写这些方法实现自定义逻辑。
类加载 :Web 容器通过类加载器加载 Servlet 类(通常首次请求触发或容器启动时预加载),字节码文件被加载到内存但未实例化。
实例化 :确认 Servlet 类成功加载后立刻执行,在整个 Web 容器中每种 Servlet 类只会有一个实例化对象。
初始化 :Web 容器调用刚刚创建好的 Servlet 实例的 init(ServletConfig config) 方法。在整个 Servlet 实例的生命周期中仅调用一次,主要作用是读取配置和资源加载。若初始化失败,抛出 ServletException,Servlet 不会被加入可用队列。
处理请求 :Web 容器为每个请求创建线程,调用 service(ServletRequest req, ServletResponse res) 方法。service() 方法根据 HTTP 请求类型(get/post)调用 doGet() 或 doPost()。
销毁 :Web 容器调用 destroy() 方法,Servlet 实例被标记为垃圾回收。
2. Spring Boot Servlet 是 Java EE 规范中处理 Web 请求的核心组件,但随着应用复杂度提升,直接手写 Servlet 显得笨重。Spring 框架通过一系列抽象和扩展,简化了企业级应用开发。
我们可以用一个形象的比喻来理解演进过程:建造一座房子 。
3. Spring Web MVC
3.1 概述 Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,并从一开始就在 Spring 框架中。正式名称'Spring Web MVC',来自其源模块的名称(spring-webmvc),但它通常被称为'Spring MVC'。
MVC(Model-View-Controller)模式最初由 Trygve Reenskaug 于 1978 年提出,核心思想是将应用程序的逻辑分为三个独立组件:
Model :处理数据逻辑和业务规则。
View :负责数据展示和用户界面。
Controller :接收用户输入并协调 Model 与 View 的交互。
Spring MVC 是 MVC 模式在 Spring 框架中的具体化,同时扩展了传统 MVC 的功能以适应现代 Web 开发需求。
3.2 必需工具 开发过程中,我们通常需要借助一些辅助工具来提升效率:
Postman :主要用于 API 的开发和测试。提供一个用户友好的界面,支持发送 HTTP 请求、管理请求历史、自动化测试以及团队协作。
Fiddler :网络调试代理工具,用于监控和分析 HTTP/HTTPS 流量。它可以捕获设备与服务器之间的所有请求和响应,支持修改请求、重放请求以及性能分析。
3.3 RequestMapping 这是 Spring MVC 中最核心、最基础的注解之一,用于将 HTTP 请求映射到具体的方法上。
注解级别 :类 + 方法
作为类注解 :可以为整个类提供一个统一的 url 前缀(可有可无)。
作为方法注解 :指定该方法负责处理哪个 url 的请求(强制要求)。
@RequestMapping("/HelloController")
@RestController
public class HelloController {
@RequestMapping(value = "/hello", method = RequestMethod.GET, produces = "application/json")
public String hello () {
return "{\"Hello\" : World}" ;
}
@RequestMapping("/receiveAge1")
public String receiveAge1 (Integer age) {
return "接收到参数 age:" + age;
}
@RequestMapping("/receiveAge2")
public String receiveAge2 (int age) {
return "接收到参数 age:" + age;
}
@RequestMapping("/receiveArray")
public String receiveArray (String[] array) {
return "接收到参数 array:" + Arrays.toString(array);
}
@RequestMapping("/receivePerson")
public String receivePerson (Person person) {
return "接收到参数 person:" + person;
}
}
3.4 RequestBody 作用是将 HTTP 请求体中的 json 数据绑定到 Java 对象(方法注解)。
@RequestMapping("/receivePerson")
public String receivePerson (@RequestBody Person person) {
return "接收到参数 person:" + person;
}
3.5 RequestParam 这是 Spring MVC 框架中从 HTTP 请求中提取参数/查询字符串 的注解,主要用于将请求参数绑定到控制器方法的参数上。
@RequestMapping("/receiveRename")
public String receiveRename (@RequestParam(value = "name", required = false) String userName) {
return "接收到参数 name:" + userName;
}
注意 :需要接收多个同名参数 时(如 param=value1¶m=value2),直接绑定到 List 类型需通过该注解明确声明。
在 Spring MVC 中,参数绑定机制对集合类型 和数组类型 的处理存在差异:
使用 ArrayList<String> 作为方法参数时,必须显式添加 @RequestParam 注解。原因如下:
默认绑定规则 :Spring 默认将单个请求参数的值绑定到简单类型(如 String、int)或单个对象。对于集合类型,框架无法自动推断是否需要将多个同名参数合并为集合。
需要明确指示 :@RequestParam 注解会告知 Spring 将同名请求参数的值收集到一个集合中。
数组(如 String[])无需 @RequestParam 注解即可正确接收。原因是 Spring 对数组类型有原生支持,能自动将多个同名请求参数值绑定到数组。这是框架的默认行为,无需额外配置。
@RequestMapping("/receiveList1")
public String receiveList1 (ArrayList<String> list) {
return "接收到参数 list:" + list;
}
@RequestMapping("/receiveList2")
public String receiveList2 (@RequestParam(required = false) ArrayList<String> list) {
return "接收到参数 list:" + list;
}
@RequestMapping("/receiveList3")
public String receiveList3 (List<String> list) {
return "接收到参数 list:" + list;
}
后端报错 :java.lang.IllegalStateException: No primary or single unique constructor found for interface java.util.List。
receiveList3 方法使用 List<String> 接口类型而非具体实现类。Spring 虽然支持接口类型参数绑定,但需要满足特定条件:必须配合 @RequestParam 注解使用,不能直接使用未注解的接口类型参数。
报错根本原因 :Spring 尝试实例化 List 接口失败(接口不可实例化)。
3.6 PathVariable 作用是从 URL 路径中提取变量值并绑定到方法的参数上。
@RequestMapping("/receivePath/{article}/{blog}")
public String receivePath (@PathVariable(value = "article", required = false) Integer title,
@PathVariable(value = "blog", required = false) String content) {
return "接收到参数 article:" + title + " blog:" + content;
}
3.7 RequestPart 作用用于处理 HTTP 请求中的 multipart/form-data 类型数据,通常用于文件上传或同时上传文件和其他表单字段的场景。
@RequestMapping("/receiveFile")
public String receiveFile (@RequestPart(value = "file", required = false) MultipartFile imgFile,
@RequestParam(value = "userName", required = false) String name) {
return "用户:" + name + ",接收到文件:" + imgFile.getOriginalFilename();
}
3.8 Controller & ResponseBody & RestController
Controller
作用 :是 Spring MVC 中的核心注解,用于标记一个类作为 Web 请求的处理器(声明一个类是一个 Spring MVC 控制器),负责处理 HTTP 请求并返回视图。
注解级别 :类
ResponseBody
作用 :指示方法返回值应直接写入 HTTP 响应体,而非通过视图解析器渲染。
注解级别 :类 + 方法
@RequestMapping("/ControllerResponse")
@Controller
public class ControllerResponse {
@RequestMapping("/HTMLView")
public String HTMLView () {
return "/show.html" ;
}
@ResponseBody
@RequestMapping("/HTMLData")
public String HTMLData () {
return "/show.html" ;
}
}
RestController
作用 :是 Spring MVC 中的一个组合注解,它结合了 @Controller 和 @ResponseBody 的功能,标记的类所有方法返回值默认直接作为 HTTP 响应体(JSON/XML 等格式),无需额外视图渲染。
注解级别 :类
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online