一次点击到底发生了什么?Java 全栈请求从浏览器到 MySQL 的完整链路

学习 Java 全栈时,我们往往会分别接触 Vue、HTTP、Nginx、Spring Boot、Spring MVC、Controller、Service、MyBatis、MySQL、Redis、消息队列等技术。真正困难的并不是记住这些名词,而是理解它们在一个真实项目中如何连接。本文沿着一次真实用户操作,把“打开网站”和“调用后端 API”两条链路串起来:从浏览器、网络、Nginx、Tomcat、Spring MVC,到 Controller、Service、MyBatis、JDBC、MySQL,再返回 Vue 页面;同时把 Redis、MQ、WebSocket、定时任务、安全、事务、异常处理与可观察性放回它们真正所在的位置。

1. 为什么要从“一次请求”重新理解 Java 全栈

很多 Java 学习路线最后会变成一串技术名词:

Java
Spring Boot
Spring MVC
MyBatis
MySQL
Redis
Nginx
Vue
MQ
...

每一个名词单独看都认识,但真正进入项目后,经常会遇到三个问题:

  1. 它位于整条链路的哪里?
  2. 它在这里解决什么问题?
  3. 它的上游和下游分别是谁?

如果只记住:

Vue → Spring Boot → MySQL

这个模型太粗。

如果只记住:

Controller → Service → Mapper

它又只覆盖了 Java 后端内部的一小段。

一个更接近真实工程的视角应该是:

用户
 ↓
浏览器 / 前端
 ↓
网络与 HTTP
 ↓
Nginx / Web Server
 ↓
Tomcat / Servlet
 ↓
Spring MVC
 ↓
Controller / Service / Mapper
 ↓
MyBatis / JDBC
 ↓
MySQL
 ↓
结果返回浏览器

而在这条主链周围,还存在三类能力:

支线能力:Redis / MQ / WebSocket / Spring Task / 第三方服务
横切能力:Security / Validation / Transaction / AOP / Exception / Observability
工程外围:Maven / Git / Test / Linux / Docker / CI/CD / Deployment

所以全文只做三件事:

  • 纵向看链路:请求是怎么走的。
  • 横向看层级:每一层有哪些技术。
  • 横切看能力:哪些机制会跨越多个层。

2. 先分清两件事:打开网站 ≠ 调用后端 API

这是理解整条链路的第一步。

用户第一次在地址栏输入:

https://example.com/admin/employee

和页面已经打开之后点击:

“保存员工”

虽然都会发生网络通信,但它们属于两个不同阶段。

2.1 阶段 A:网站是怎样打开的

为了看清主干,下面先忽略 DNS 缓存、连接复用、CDN、HTTP/2 多路复用等优化细节,并以常见的 HTTP/1.1 或 HTTP/2 over TCP 为例。HTTP/3 使用 QUIC,底层连接过程会有所不同。

用户输入 URL
    ↓
浏览器解析 URL
    ↓
DNS:域名 → IP
    ↓
建立连接
    ↓
HTTPS 场景进行 TLS 握手
    ↓
发送 HTTP Request
    ↓
Nginx / Web Server
    ↓
HTML / CSS / JavaScript / 图片
    ↓
浏览器解析与执行
    ↓
Vue 应用启动
    ↓
页面展示

这一阶段解决的是:

网站页面从哪里来,以及浏览器如何把资源组装成用户看到的页面。

| 层次 | 主要知识点 | 在这里的作用 | | -------- | -------------------------------------------- | -------------------------------- | | 浏览器 | URL、Cache、Cookie、DevTools | 接收用户输入、加载并展示页面 | | 网络 | DNS、IP、Port、TCP / QUIC | 找到服务器并建立通信通道 | | 安全 | TLS、HTTPS、Certificate | 加密通信并验证服务端身份 | | Web 通信 | HTTP Request / Response、Header、Status Code | 定义浏览器与服务器的数据交换方式 | | 网关 | Nginx / CDN / Load Balancer | 静态资源、反向代理、HTTPS 入口等 | | 前端 | HTML、CSS、JavaScript、Vue | 构建最终用户界面 |

需要注意两点:

  • Nginx 是常见生产部署节点,不是 Spring MVC 的组成部分,也不是所有项目必须经过的节点。
  • TLS 可能在 CDN、负载均衡器或 Nginx 处终止,不一定一直进入 Spring Boot 应用。

图1.png

3. 阶段 B:用户点击按钮后,一次 API 请求怎样走完整条链

页面已经展示后,用户点击“登录”“保存”“查询”“下单”等按钮,才进入典型的业务请求链。

把它压缩成一条主干:

User
 ↓
DOM Event
 ↓
Vue / JavaScript
 ↓
Axios / Fetch
 ↓
HTTP Request(JSON / Query / Form 等)
 ↓
Nginx
 ↓
Tomcat / Servlet Filter Chain
 ↓
Spring MVC / DispatcherServlet
 ↓
Controller
 ↓
Service
 ↓
Mapper / MyBatis
 ↓
JDBC / DataSource / Connection Pool
 ↓
MySQL
 ↓
Result
 ↓
VO / Result<T>
 ↓
JSON
 ↓
HTTP Response
 ↓
Axios / Fetch
 ↓
Vue State
 ↓
DOM Update
 ↓
User

这就是全文的纵向脊柱。

它是一条“典型请求链”,不是所有请求都会经过所有节点:

  • 本地开发可能没有 Nginx;
  • 命中 Redis 后可能不访问 MySQL;
  • 某些接口只做计算,不访问数据库;
  • Result<T> 是很多项目采用的统一响应包装,并不是 Spring MVC 强制要求;
  • MQ、WebSocket、Spring Task 属于支线或其他触发模型,而不是普通同步 HTTP 请求的固定节点。

图二.png

4. 把整条主链压缩成七层

主链虽然很长,但按职责可以压缩成七个层次。

| 层次 | 代表技术 | 核心职责 | | ------------------- | --------------------------------------- | ---------------------------------------- | | ① 用户与前端 | HTML / CSS / JavaScript / Vue / Axios | 收集用户操作、组织页面、调用 API | | ② 网络与 Web 通信 | DNS / TCP / TLS / HTTP / RESTful | 找到服务端、建立通信、定义 API 交互方式 | | ③ 网关入口 | Nginx | 静态资源、反向代理、负载均衡、HTTPS 入口 | | ④ Java Web Runtime | Spring Boot / Tomcat / Servlet / Filter | 让 HTTP 请求进入 Java Web 运行环境 | | ⑤ Web 与业务 | Spring MVC / Controller / Service | 请求映射、参数接收、业务处理 | | ⑥ 持久化 | Mapper / MyBatis / JDBC / HikariCP | 把 Java 数据访问转化为数据库操作 | | ⑦ 数据层 | MySQL / InnoDB | 执行 SQL 并持久化核心业务数据 |

这里有一个容易混淆的点:

RESTful 是 API 设计风格,不是 TCP、TLS 这类网络协议。

把它放在这一层,是因为它参与“前后端如何表达资源和操作”的 API 契约设计。

5. 用户与前端层:把人的操作变成一次 API 调用

前端并不只是“把页面做得好看”,它是业务请求的起点。

  • HTML / CSS / JavaScript:分别负责页面结构、视觉表现和交互行为。
  • Vue:组织组件、状态与界面更新。
  • Axios / Fetch:发送 HTTP 请求并接收响应。
  • Vue Router:管理单页应用中的客户端路由。
  • Pinia:管理跨组件共享的前端状态。

一次典型操作可以压缩成:

用户点击按钮
 ↓
DOM Event
 ↓
Vue 方法
 ↓
JavaScript Object
 ↓
Axios / Fetch
 ↓
HTTP Request

从这里开始,用户界面中的一次操作已经变成网络可以传输的数据。

6. 网络与 HTTP:让浏览器和服务器真正“说上话”

前端构造好请求后,需要经过网络到达服务器。

  • DNS:把域名解析到可访问的地址。
  • IP / Port:定位目标主机与具体服务。
  • TCP:为 HTTP/1.1、HTTP/2 等提供可靠字节流传输。
  • TLS / HTTPS:提供加密、完整性保护与服务端身份验证。
  • HTTP:规定 Request / Response 的消息结构和语义。
  • RESTful:使用资源、URI、HTTP Method 等组织 API 的一种常见设计风格。

这一层不负责业务,它负责:

让客户端和服务端可以按照约定完成一次可靠、可理解的 Web 通信。

7. Nginx:生产环境常见的系统入口

在很多生产架构里,浏览器不会直接访问 Spring Boot 应用端口,而是先到达 Nginx、云负载均衡器或其他网关节点。

Nginx 常见职责包括:

  • 静态资源服务;
  • 反向代理;
  • HTTPS 入口;
  • 负载均衡;
  • 压缩、缓存和部分访问控制能力。

可以把它简化理解为:

Browser
   ↓
Nginx
   ├── Static Assets
   └── /api/* → Spring Boot

因此:

Nginx 是常见的系统入口,而不是 Spring MVC 内部组件。

8. Spring Boot、Tomcat 与 Servlet:请求进入 Java 世界

这三个概念经常一起出现,但职责不同。

  • Spring Boot:负责应用启动、自动配置、依赖整合和运行环境装配。
  • Tomcat:常见的 Servlet 容器,接收 Web 请求并驱动 Servlet 请求处理。
  • Servlet / Filter:Java Web 中处理请求、响应和过滤链的基础规范。

可以把关系简化为:

JVM
└── Spring Boot Application
      └── Embedded Tomcat
            └── Servlet / Filter
                  └── Spring MVC

所以:

Spring Boot 更像整个 Java Web 应用的启动与装配环境,而不是一次请求必须依次经过的“业务中转站”。

9. Spring MVC:把 HTTP 请求找到对应的 Controller

Spring MVC 在整条链路中的核心作用可以压缩成一句话:

把 HTTP Request 映射到对应的 Handler / Controller 方法,再把 Java 返回值转换成 HTTP Response。

总览层面认识这些节点就足够了:

HTTP Request
 ↓
Servlet Filter
 ↓
DispatcherServlet
 ↓
HandlerMapping
 ↓
Handler / Interceptors
 ↓
HandlerAdapter
 ↓
Parameter Binding / HttpMessageConverter / Jackson
 ↓
Controller
 ↓
Return Value Processing
 ↓
HTTP Response

它们的职责可以快速记成:

  • DispatcherServlet:Spring MVC 的 Front Controller,负责统一调度。
  • HandlerMapping:根据请求找到对应 Handler,并关联相应 Interceptor。
  • Interceptor:在 MVC Handler / Controller 前后执行统一处理。
  • HandlerAdapter:让 DispatcherServlet 能以统一方式调用不同类型的 Handler。
  • 参数绑定 / HttpMessageConverter / Jackson:把 HTTP 中的数据转成 Java 参数,或把 Java 返回值转成响应体。
  • 异常解析机制:把请求处理过程中的异常转换成合适的错误响应。

这里不继续追踪框架内部类层级,因为那属于 Spring MVC 专题,而不是全链路地图的主角。

图三.png

10. Java 后端主干:Controller → Service → Mapper

Spring MVC 完成请求映射后,真正进入我们编写的应用代码。

Controller
   ↓
Service
   ↓
Mapper

10.1 Controller:Web 接口层

作用:接收参数、调用业务、返回响应。

常见注解:

@RestController
@RequestMapping
@GetMapping / @PostMapping / @PutMapping / @DeleteMapping
@RequestBody / @RequestParam / @PathVariable
@Valid / @Validated

基本规范:

Controller 尽量只做“接收 → 调用 → 返回”,复杂业务规则交给 Service。

10.2 Service:业务层

作用:承载业务规则,组织一个完整业务过程。

常见内容:

@Service
@Transactional
DTO → Entity
Entity → VO
Business Logic

基本规范:

Service 关注业务过程与事务边界,不关心 HTTP 细节,也不承担 SQL 映射职责。

10.3 Mapper:数据访问层

作用:负责应用程序与数据库之间的数据访问。

以 MyBatis 为例,常见内容:

@Mapper
Mapper Interface
Mapper XML / SQL Annotation
#{ } 参数绑定
resultType / resultMap
Dynamic SQL

基本规范:

Mapper 负责数据访问,不负责业务规则。

11. DTO、Entity、VO:同一份业务数据在不同边界上的表达

三层架构不仅在传递“值”,也在不断改变数据的表达形式。

一种常见建模方式是:

Frontend JSON
  ↓
DTO:接收请求数据
  ↓
Controller / Service
  ↓
Entity:业务 / 持久化实体
  ↓
Mapper / Database

Database
  ↓
Entity
  ↓
Service
  ↓
VO:组织前端需要的数据
  ↓
Result<T>(可选的统一响应包装)
  ↓
JSON Response

真正需要掌握的是边界意识:

  • DTO:常用于输入或跨层传输;
  • Entity:常用于表达业务实体或持久化数据;
  • VO:常用于面向前端输出;
  • Result<T>:很多项目用它统一包装 code / message / data,但它是项目约定,不是 Spring 强制模型。

这些并不是不可改变的硬规则。不同项目可以有不同命名和建模方式,但“不要让所有边界无条件共用同一个对象”的工程思想很重要。

12. IoC / DI 在哪里:它不是请求节点,而是应用的组织方式

在代码里:

Controller 需要 Service
Service 需要 Mapper

这些对象通常不会由业务代码到处手动 new,而是由 Spring Container 管理和装配。

Class
 ↓
Spring Container
 ↓
Bean
 ↓
Dependency Injection
 ↓
Controller / Service / Mapper 协作

常见相关注解包括:

@Component
@RestController
@Service
@Repository
@Configuration
@Bean
@Autowired

现代 Spring 项目通常更偏向 Constructor Injection;当类只有一个构造器时,也不一定需要显式写 @Autowired。

因此:

IoC / DI 更适合画在三层架构背后的“组织层”,而不是强行插入一次请求的运行箭头中。

图四.png

13. Mapper 到 MySQL 之间,还有一条持久化链

Mapper → MySQL 是教学上的压缩写法。

在典型 MyBatis 项目中,更接近:

Service
 ↓
Mapper Interface
 ↓
MyBatis
 ↓
JDBC
 ↓
DataSource / Connection Pool(常见如 HikariCP)
 ↓
JDBC Driver
 ↓
MySQL Server
 ↓
InnoDB

每个节点只需要一句话理解:

  • MyBatis:根据 Mapper 映射定位并执行 SQL,把参数交给 JDBC,并把结果集映射回 Java 对象。
  • JDBC:Java 访问关系型数据库的标准 API。
  • DataSource / Connection Pool:管理和复用数据库连接,避免每次请求都重新建立数据库连接。
  • JDBC Driver:实现 JDBC 调用与 MySQL 通信之间的具体适配。
  • MySQL Server:接收 SQL,并完成解析、优化和执行等工作。
  • InnoDB:MySQL 常用的默认存储引擎,负责索引、数据页、事务和并发控制等核心能力。

为了理解项目位置,可以把数据库内部进一步抽象为:

SQL
 ↓
Parser / Optimizer / Executor
 ↓
InnoDB
 ↓
Index / Buffer Pool / Data Page

因此我们平时学习的索引、B+Tree、事务、MVCC、锁、Redo / Undo Log、Buffer Pool,并不是项目之外的一套孤立知识,而是位于整条链最后的“数据库内部”。

图五.png

14. 另一条隐藏主线:数据本身一直在“变形”

如果前面的主链关注“请求经过谁”,还有另一条同样重要的链关注:

同一份业务信息,在不同系统边界上以什么形式存在。

一次典型的数据变化可以抽象成:

用户输入
 ↓
DOM / Form Data
 ↓
JavaScript Object
 ↓
JSON
 ↓
HTTP Request Body
 ↓
DTO
 ↓
Entity
 ↓
SQL Parameters
 ↓
Database Row
 ↓
Entity
 ↓
VO / Result<T>
 ↓
JSON
 ↓
JavaScript Object
 ↓
Vue State
 ↓
DOM
 ↓
用户看到结果

当然,并不是所有接口都会完整经历这组转换。

例如:

  • GET 查询可能没有 JSON Request Body;
  • Service 可能直接返回 DTO / projection;
  • 项目也可能不用统一 Result<T>;
  • ORM / 持久化方案不同,对象边界也会不同。

但这条数据线揭示了一个很重要的事实:

DTO、Entity、VO、JSON、SQL、Database Row,本质上是在描述同一份业务信息跨越不同边界时的不同表达形式。

图六.png

15. 主链之外:企业项目为什么会出现 Redis、MQ、WebSocket、Task

到这里,同步主链已经完整:

Browser → Java Backend → Database → Browser

但真实业务不会只有同步 CRUD,因此还会出现一些支线能力。

它们很重要,却不是每个请求都必经。

15.1 Redis:缓存支线

以典型的读取型 Cache-Aside 为例:

Service
 ↓
Redis
 ├─ Hit  → Return
 └─ Miss → MySQL → Cache Redis → Return

作用: 缓存热点数据,减少重复数据库访问,提高读取性能。

常见关联知识:

TTL
Spring Cache
Cache Aside
缓存穿透 / 击穿 / 雪崩
数据一致性
分布式锁

缓存更新策略与一致性方案会随业务而变化,因此“数据库更新后一定怎样写 Redis”不能用一条规则概括。

15.2 MQ:异步支线

Business Event
 ↓
Producer
 ↓
Message Broker / Queue / Topic
 ↓
Consumer

作用: 把适合异步执行的工作从同步请求中拆出去,用于解耦、削峰和后台处理。

常见技术:

RabbitMQ
Kafka
RocketMQ

常见关联知识:

Producer / Consumer
Queue / Topic
ACK
Retry
Dead Letter
Idempotency
消息可靠性

15.3 WebSocket:实时通信支线

Browser ←──── Persistent Bidirectional Connection ────→ Server

作用: 建立持续的双向通信通道,使服务器可以主动向客户端推送实时消息。

常见场景:

来单提醒
聊天
实时状态
通知
数据大屏

15.4 Spring Task:时间驱动入口

并不是所有业务都从用户 HTTP Request 开始。

Clock / Scheduler
 ↓
@Scheduled
 ↓
Service

作用: 按时间规则自动触发业务逻辑。

常见场景:

超时订单
日报
数据清理
定时通知

15.5 第三方 API / OSS:跨系统能力

Service
 ↓
HTTP Client / SDK
 ↓
External Service

作用: 让自己的系统接入支付、微信登录、短信、地图、对象存储等外部能力。

图七.png

16. 横切整条链路的能力

还有一类能力很特殊:它们不属于某一个固定业务节点,而是会覆盖一段甚至整条链路。

| 横切能力 | 主要作用 | 常见实现 | | ------------------------------ | ------------------------------------ | -------------------------------------------- | | Authentication / Authorization | 判断“你是谁、你能做什么” | Spring Security、JWT、RBAC | | Validation | 在核心业务执行前校验输入 | Bean Validation、@Valid、@Validated | | Transaction | 让一组数据库操作按事务边界提交或回滚 | @Transactional、TransactionManager | | AOP | 对 Spring Bean 方法统一增强 | Logging、Audit、Transaction 等 | | Exception Handling | 把异常统一转换成 API 错误响应 | @RestControllerAdvice、@ExceptionHandler | | Observability | 记录、测量并追踪运行过程 | Logging、Metrics、Tracing |

16.1 Filter、Interceptor、AOP 的位置区别

与其背定义,不如直接看它们在哪一层。

HTTP Request
 ↓
Filter                ← Servlet 层
 ↓
DispatcherServlet
 ↓
Interceptor           ← Spring MVC 层
 ↓
Controller / Service
 ↓
AOP Proxy             ← Spring Bean 方法层

可以快速记成:

  • Filter:包围 Servlet 请求链;
  • Interceptor:包围 Spring MVC Handler / Controller;
  • AOP:增强 Spring Bean 方法调用。

在完整的 Spring Security Servlet 架构中,安全处理通常建立在 Servlet Filter Chain 之上。

事务则通常在 Service 业务边界开启,通过同一个事务上下文覆盖后续一组数据库操作;从概念图上可以画成包围 Service → Mapper → Database Operation 的事务范围,但真正的数据库事务最终落实在数据库连接和数据库引擎上。

图八.png

17. 从代码到线上:工程能力包围整个项目

一次 HTTP Request 的运行流程,并不等于完整的软件工程。

一个项目还需要从“能运行”继续走向“可构建、可测试、可部署、可观察、可维护”。

| 工程域 | 代表技术 | 作用 | | --------------- | ----------------------------------------------- | -------------------- | | Build | Maven、Dependency、Multi-module、JAR | 依赖管理、构建与打包 | | Version Control | Git、Branch、Merge、GitHub / Gitee | 代码版本与协作 | | API & Test | OpenAPI / Swagger、Apifox、Postman、JUnit | 接口文档、测试与联调 | | Runtime | JVM、Linux、Process、Port、Environment Variable | 提供真实运行环境 | | Deployment | Nginx、JAR、Docker | 部署与运行应用 | | Delivery | CI/CD | 自动构建、测试与发布 | | Production | Logging、Metrics、Tracing、Backup | 线上观测、维护与恢复 |

其中 Docker、CI/CD 等都不是 Java 项目运行的必要条件,它们属于现代工程中常见的交付方案。

18. 最终把所有内容压缩成一张 Java 全栈地图

到这里,可以把全文重新组织成一棵树:

Java 全栈项目
│
├── 用户与前端
│   ├── Browser / URL
│   ├── HTML / CSS / JavaScript / DOM
│   └── Vue / Axios / Router / Pinia
│
├── 网络与 Web 通信
│   ├── DNS / IP / Port
│   ├── TCP / QUIC
│   ├── TLS / HTTPS
│   └── HTTP / RESTful API
│
├── 网关
│   └── Nginx / Load Balancer / CDN
│
├── Java Web Runtime
│   ├── Spring Boot
│   ├── Tomcat
│   └── Servlet / Filter
│
├── Spring MVC
│   ├── DispatcherServlet
│   ├── HandlerMapping / HandlerAdapter
│   ├── Interceptor
│   ├── Parameter Binding
│   ├── HttpMessageConverter / Jackson
│   └── Exception Handling
│
├── Application Code
│   ├── Controller
│   ├── Service
│   ├── Mapper
│   ├── DTO / Entity / VO
│   └── IoC / DI / AOP / Transaction
│
├── Persistence
│   ├── MyBatis
│   ├── JDBC
│   └── DataSource / Connection Pool
│
├── Data
│   ├── MySQL / InnoDB
│   └── Redis
│
├── Async / Realtime / Scheduled
│   ├── MQ
│   ├── WebSocket
│   └── Spring Task
│
├── Cross-cutting
│   ├── Spring Security / JWT / RBAC
│   ├── Validation
│   ├── Exception
│   └── Logging / Metrics / Tracing
│
└── Engineering
    ├── Maven
    ├── Git
    ├── OpenAPI / Apifox
    ├── JUnit
    ├── Linux
    ├── Docker
    ├── CI/CD
    └── Deployment / Monitoring

这张树真正想表达的不是“还要背这么多名词”,而是:

每一种技术都有自己的位置。只要知道当前位于哪一层,就能顺着上下游继续理解整个系统。

图9.png

19. 回到最开始的问题:一次点击,到底发生了什么?

现在再回到最开始的那次点击。

用户看到的可能只是:

点击“保存”

系统看到的却是:

用户操作
 ↓
前端事件
 ↓
JavaScript 数据
 ↓
HTTP Request
 ↓
网络传输
 ↓
Nginx
 ↓
Tomcat / Servlet
 ↓
Spring MVC
 ↓
Controller
 ↓
Service
 ↓
Mapper / MyBatis
 ↓
JDBC
 ↓
MySQL
 ↓
结果返回
 ↓
JSON
 ↓
Vue State
 ↓
DOM 更新
 ↓
用户看到新的页面状态

与此同时,系统还可能:

  • 先从 Redis 获取缓存;
  • 把业务事件投递给 MQ;
  • 通过 WebSocket 主动推送实时消息;
  • 由 Spring Task 在没有用户请求时触发后台任务;
  • 通过 Spring Security 完成认证与授权;
  • 用事务保证一组数据库操作的一致性;
  • 通过统一异常处理返回稳定的 API 错误结构;
  • 用 Logging、Metrics、Tracing 观察一次请求从进入到结束的全过程。

这就是 Java 全栈真正有意思的地方:

看似分散的框架、协议、中间件和工程工具,其实都在为同一个业务系统的不同边界负责。

以后再遇到一个新技术,不妨先问三个问题:

  1. 它位于整条链的哪里?
  2. 它在这里解决什么问题?
  3. 它的上游和下游分别是谁?

当这三个问题能够回答出来,Java 全栈就不再是一堆孤立名词,而是一张可以在脑中自由移动的工程地图。