跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Java Web 开发基础:Spring Web MVC 核心注解详解

Spring Web MVC 基于 Servlet 构建,是 Java Web 开发的核心框架。内容涵盖 Servlet 生命周期、Spring Boot 简化配置的优势,以及 @RequestMapping、@RequestBody、@RequestParam 等关键注解的参数绑定规则。通过对比传统 Servlet 开发与 Spring 开发的差异,帮助开发者理解 MVC 模式在实际项目中的应用,解决参数接收、文件上传及视图渲染等常见问题。

樱花落尽发布于 2026/4/11更新于 2026/5/2517 浏览
Java Web 开发基础:Spring Web MVC 核心注解详解

1. 前置知识

1.1 Tomcat

Tomcat 是一个开源的轻量级 Web (HTTP) 服务器和 Servlet 容器。它实现了 Java Servlet 等 Java EE 规范的核心功能,常用于部署和运行 Java Web 应用程序。换言之,Tomcat 就是一个严格遵循 Servlet 规范开发出来的、可以独立安装和运行的 Java Web 服务器/Servlet 容器。

核心功能:

  • 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 API 示范

创建项目时,通常需要在 IDE(如 IDEA)中配置 Maven 依赖。

(1) pom.xml 配置

<dependencies>
    <dependency>
        <groupId>jakarta.servlet</groupId>
        <artifactId>jakarta.servlet-api</artifactId>
        <!-- servlet 依赖版本应与 jdk 和 tomcat 的版本相匹配 -->
        <version>6.1.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

(2) web.xml 配置 在 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>

(3) Servlet 代码示例 这里演示如何继承 HttpServlet 并重写方法以处理不同 HTTP 请求:

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 {
    // 接收 method=post 的请求
    @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");
    }

    // 接收 method=put 的请求
    @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");
    }

    // 接收 method=delete 的请求
    @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)管理,包含加载、初始化、处理请求和销毁四个阶段。每个阶段对应特定的方法调用,开发者可通过重写这些方法实现自定义逻辑。

  1. 类加载:Web 容器通过类加载器加载 Servlet 类(通常首次请求触发或容器启动时预加载),字节码文件被加载到内存但未实例化。
  2. 实例化:确认 Servlet 类成功加载后立刻执行,在整个 Web 容器中每种 Servlet 类只会有一个实例化对象。
  3. 初始化:Web 容器调用刚刚创建好的 Servlet 实例的 init(ServletConfig config) 方法,在整个 servlet 实例的生命周期中仅调用一次,主要作用是读取配置和资源加载。若初始化失败,抛出 ServletException,Servlet 不会被加入可用队列。
  4. 处理请求:Web 容器为每个请求创建线程,调用 service(ServletRequest req, ServletResponse res) 方法。service() 方法根据 HTTP 请求类型(get/post)调用 doGet() 或 doPost()。
  5. 销毁:Web 容器调用 destroy() 方法,Servlet 实例被标记为垃圾回收。

2. Spring Boot

Servlet 是 Java EE 规范中处理 Web 请求的核心组件,但随着应用复杂度提升,直接使用 Servlet 显得笨重。Spring 框架通过一系列抽象和扩展,简化了企业级应用开发。

我们可以用一个形象的比喻来理解演进过程:建造一座房子。

第一阶段:Servlet 时代 - 自己烧砖砌墙

  • 目标:建造一个能遮风挡雨的房子(一个能处理 HTTP 请求的 Web 应用)。
  • 工作状态:材料是泥土(Java 语言)和水(JVM)。你需要自己烧制砖块(编写 Servlet 类),只有简单的泥瓦刀(Servlet API)。
  • 过程:为每一面墙、每一扇门都亲手烧制一块特定的砖;亲自规划每块砖的位置(在 web.xml 中配置大量的 <servlet> 和 <servlet-mapping>);在每个 Servlet 的 doGet/doPost 方法中手动解析参数、处理业务、组装 HTML。
  • 核心特点:高度灵活但极其繁琐,大量重复性劳动,难以维护,依赖外部容器。

第二阶段:Spring 时代 - 使用预制件和设计图纸

  • 目标:用更高效、更标准化的方式建造一个结构更好、更易扩展的房子。
  • 核心创新:聘请一位神奇的管家(IoC 容器)。不再亲自'砌砖'(用 new 实例化对象),只需告诉管家你需要什么(用 @Autowired 声明依赖)。管家会自动把预制件(Bean)按照图纸(配置)组装好,送到你手上(依赖注入 DI)。
  • 过程:一个总大门(DispatcherServlet),所有访客(请求)都先到这里;接待员根据访客需求,呼叫房子里对应的专业房间(@Controller 中的方法)来接待。
  • 核心特点:解耦,专业化(AOP 像装修队一样统一安装中央空调),效率提升,但配置复杂。

Spring Boot 1.0.0正式发布于 2014 年 4 月 1 日,标志着该框架的首次稳定版本发布。基于 Spring Framework 4 设计,显著减少了开发者的配置工作量,彻底消除了 Spring 的配置地狱。

  • 约定大于配置:约定了默认配置。
  • Start 机制:是一种依赖管理机制,每个 Starter 包含特定功能所需的依赖库和自动配置类,开发者只需引入对应 Starter 即可快速启用功能模块。
  • 嵌入式容器:内置了 Tomcat 等嵌入式容器,无需部署 war 文件到外部容器,直接运行即可启动应用。

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 年在施乐帕克研究中心提出,目的是为 Smalltalk 编程语言设计用户界面。其核心思想是将应用程序的逻辑分为三个独立组件:

  • 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 {
    // 0. 不接收参数
    // 作为 方法注解 时,@RequestMapping(value = "/hello", method = RequestMethod.GET) 等同于 @GetMapping(value = "/hello")
    // 设置返回的响应是 json 格式,produces = "application/json"
    @RequestMapping(value = "/hello", method = RequestMethod.GET, produces = "application/json")
    public String hello() {
        return "{\"Hello\" : World}";
    }

    // 1. 一个参数
    @RequestMapping("/receiveAge1")
    // 不传参或者传递的参数名不匹配时默认为 null
    public String receiveAge1(Integer age) {
        return "接收到参数 age:" + age;
    }

    @RequestMapping("/receiveAge2")
    // 不传参或者传递的参数名不匹配时尝试设置为 null,但 int 无法被设置为 null,所以抛出 IllegalStateException
    public String receiveAge2(int age) {
        return "接收到参数 age:" + age;
    }

    // 2. 接收数组
    @RequestMapping("/receiveArray")
    public String receiveArray(String[] array) {
        return "接收到参数 array:" + Arrays.toString(array);
    }

    // 3. 接收对象,需要保证传递的参数名称和数量与 Java 对象保持一致
    @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&param=value2),直接绑定到 List 类型需通过该注解明确声明。

在 Spring MVC 中,参数绑定机制对集合类型和数组类型的处理存在差异:

  1. ArrayList:必须显式添加 @RequestParam 注解。默认绑定规则下,Spring 无法自动推断是否需要将多个同名参数合并为集合,需要明确指示。
  2. String[]:无需 @RequestParam 注解即可正确接收。Spring 对数组类型有原生支持,能自动将多个同名请求参数值绑定到数组。
  3. List:如果直接使用接口类型而非具体实现类,会报错 java.lang.IllegalStateException: No primary or single unique constructor found for interface java.util.List。Spring 虽然支持接口类型参数绑定,但需要满足特定条件:必须配合 @RequestParam 注解使用,不能直接使用未注解的接口类型参数。
@RequestMapping("/receiveList1")
public String receiveList1(ArrayList<String> list) {
    // 返回的 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;
}

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 请求的处理器,负责处理 HTTP 请求并返回视图。
  • ResponseBody:指示方法返回值应直接写入 HTTP 响应体,而非通过视图解析器渲染。
  • RestController:是 Spring MVC 中的一个组合注解,它结合了 @Controller 和 @ResponseBody 的功能,标记的类所有方法返回值默认直接作为 HTTP 响应体(JSON/XML 等格式),无需额外视图渲染。
@RequestMapping("/ControllerResponse")
@Controller
public class ControllerResponse {
    // 返回视图
    @RequestMapping("/HTMLView")
    public String HTMLView() {
        return "/show.html";
    }

    // 返回数据
    @ResponseBody
    @RequestMapping("/HTMLData")
    public String HTMLData() {
        return "/show.html";
    }
}

目录

  1. 1. 前置知识
  2. 1.1 Tomcat
  3. 1.2 Servlet
  4. 1.2.1 定义
  5. 1.2.2 API 示范
  6. 1.2.3 生命周期
  7. 2. Spring Boot
  8. 3. Spring Web MVC
  9. 3.1 概述
  10. 3.2 必需工具
  11. 3.3 RequestMapping
  12. 3.4 RequestBody
  13. 3.5 RequestParam
  14. 3.6 PathVariable
  15. 3.7 RequestPart
  16. 3.8 Controller & ResponseBody & RestController
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • C++ 搜索引擎实战:日志宏封装与 Server 交互逻辑
  • Stable Diffusion XL 1.0 灵感画廊镜像部署与使用指南
  • Web 打印控件 Lodop 快速入门与使用指南
  • 在嵌入式中实现 O(1) 的字符串 Switch-Case (编译期哈希)
  • 基于 Rust 与 DeepSeek V3.2 构建高性能插件化 LLM 应用框架
  • 灵感画廊实战:用“梦境描述”替代 Prompt 提升 AI 绘画质感
  • 开源自主可控的 AI+ 无人机一体化平台及多行业应用场景
  • C++ 类型转换避坑指南:从基础到四种核心强制转换方式
  • Stable Diffusion v1.5 GPU 能效比分析:每瓦特算力生成图像实测
  • 2025 AI 产业全景深度解析与未来趋势洞察
  • LeetCode 92 链表区间反转:递归实现与哨兵技巧详解
  • 字节开源 DeerFlow 2.0:重构 Super Agent 运行时基础设施
  • 数据结构入门:链表分类详解与带头双向循环链表初始化
  • Stable Diffusion 1.5 皮革服装 LoRA 镜像部署指南
  • C# 荣获 2023 年度编程语言奖,TIOBE 2024 年 1 月排行榜解读
  • 黑客技术入门指南:编程语言与操作系统选择建议
  • LeetCode 原地复写零:双指针与逆向填充 O(n) 时间 O(1) 空间解法
  • Java 25 虚拟线程核心优化与使用
  • LeetCode 712. 两个字符串的最小 ASCII 删除和:状态压缩优化
  • 旋转排序数组二分查找解法:LeetCode 33 题实战

相关免费在线工具

  • 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