前后端分离下,Spring Boot 请求从发起到响应的完整执行流程

以下是前后端分离架构下,Spring Boot 请求从发起到响应的完整执行流程,结合你提出的所有问题,按真实执行顺序和职责链条重新整理所有核心概念、结构、关键类、数据转换点和典型代码示例:


一、前端发起请求(步骤1-2)

关键组件:React/Vue + Axios + JSON

axios.get('/api/users', { headers: { Authorization: 'Bearer xxx' } });
  • 不会包含 JSON body(因 GET 请求规范所限)

  • 请求参数以 query param 附带,如 /api/users?active=true


二、后端接收请求与过滤(步骤3)

关键组件:Spring Security Filter Chain

public class JwtAuthenticationFilter extends OncePerRequestFilter {protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {String header = request.getHeader("Authorization");String token = header != null && header.startsWith("Bearer ") ? header.substring(7) : null;if (token != null && jwtUtil.validate(token)) {Authentication auth = jwtUtil.getAuthentication(token);SecurityContextHolder.getContext().setAuthentication(auth);}chain.doFilter(request, response);}
}
  • JWT 验证只发生在 Filter 中,不会进入 Controller 就已判定是否通过

  • 验证通过后构造 Authentication 对象放入 SecurityContext


三、DispatcherServlet 分发请求(步骤4)

核心作用:统一接收请求,协调执行链

  • DispatcherServlet 并不执行具体处理,只负责流程编排


四、HandlerMapping 确定 Handler(步骤5)

RequestMappingHandlerMapping:匹配@Controller + @RequestMapping 控制器方法
  • 负责查找哪个 Controller 的哪个方法应该处理这个请求

  • 构建好 HandlerExecutionChain(包含拦截器)


五、HandlerAdapter 调用处理器(步骤6)

RequestMappingHandlerAdapter:负责调用注解控制器方法
  • supports(Object handler) 方法确认适配器是否支持此处理器

  • 参数解析、类型转换、方法调用都由它完成


六、Controller 执行业务分发(步骤7)

@RestController
@RequestMapping("/api/users")
public class UserController {@Autowiredprivate UserService userService;@GetMappingpublic ResponseEntity<List<UserDto>> getUsers() {List<UserDto> list = userService.getAllUsers();return ResponseEntity.ok(list);}
}
  • Controller 不应处理认证逻辑,而是专注于业务与 DTO 构造

  • 使用 ResponseEntity 是为了更灵活控制 HTTP 状态码与头部


七、Service 层执行业务逻辑(步骤8)

@Service
public class UserServiceImpl implements UserService {public List<UserDto> getAllUsers() {List<User> entities = userRepository.findAll();return entities.stream().map(this::toDto).toList();}private UserDto toDto(User user) {return new UserDto(user.getId(), user.getName(), user.getEmail());}
}
  • 接收 Entity 对象 → 转换为 DTO(数据传输对象)

  • 不应返回 ResponseEntity,这保持了关注点分离


八、Repository 访问数据库(步骤9-11)

@Repository
public interface UserRepository extends JpaRepository<User, Long> {List<User> findByActiveTrue();
}@Entity
@Table(name = "users")
public class User {@Idprivate Long id;private String name;private String email;
}
  • DAO 实质上是 Repository 接口本身(即 Data Access Object)

  • Entity 是 ORM 框架(JPA/Hibernate)使用的 Java → 表 的映射结构

  • 从数据库返回的是 Entity 实例,非 DTO,非 DAO


九、响应流程(步骤12-17)

数据返回结构:

步骤返回对象类型
12Repository → ServiceEntity 实体类
13Service → ControllerDTO(如 UserDto)
14Controller → HandlerAdapterResponseEntity 或直接 DTO
15HandlerAdapter → DispatcherServlet包装为 ModelAndView(内部结构)
17DispatcherServlet → 前端JSON 数据(通过 HttpMessageConverter 序列化)

十、常见问题澄清汇总

❓JWT是谁生成的?前端能编辑它吗?

  • ❌ 前端不能生成 JWT,必须由后端签名生成

  • ✅ JWT 中的 claim 字段(sub/iss/exp)由后端控制

❓为什么需要 Authentication?不能直接验证放行?

  • ✅ 因为权限注解(如 @PreAuthorize)等依赖 SecurityContextHolder 中的 Authentication 对象

❓HandlerMapping vs HandlerAdapter 为什么都要有?

组件功能是否必须
HandlerMapping确定哪个 Controller 处理请求
HandlerAdapter执行该 Controller 的方法
  • 二者实现了解耦:DispatcherServlet 不直接依赖 Controller 类型

  • 实际开发可以注册自定义 Mapping/Adapter

❓ResponseEntity vs DTO vs ResponseObject 区别?

类型

定义

用途

DTO

纯Java对象,字段只为数据交换

Service 返回给 Controller

ResponseEntity

Spring类,用于封装响应状态、头、体

Controller 返回给框架

自定义 ResponseObject

如 ApiResponse,封装统一格式

可选嵌入于 ResponseEntity 中

不是必须使用 ResponseEntity,直接返回 DTO,Spring 也会自动序列化


建议实践结构总结

前端请求 → Filter链认证(JWT) → DispatcherServlet协调 → HandlerMapping确定Controller
→ HandlerAdapter调用Controller方法 → Controller调用Service → Service调用Repository
→ Repository返回Entity → Service转换为DTO → Controller包装为ResponseEntity
→ 返回给前端(JSON)


✅ 先明确三个概念:

注解

用于

描述

@ExceptionHandler

控制器或异常处理类中的方法

声明某个方法用来处理特定类型异常

@ControllerAdvice

类级别

用于集中定义所有控制器的全局异常处理

@RestControllerAdvice

@ControllerAdvice + @ResponseBody

自动将返回值作为JSON响应


✅ 情况分类:异常处理的三个层级

异常发生层

谁处理

示例

Controller层内部异常

当前 Controller 类中的 @ExceptionHandler@ControllerAdvice

请求参数缺失、非法访问

Service层抛出业务异常

交由 Controller 接收并传播给 @ControllerAdvice

用户名重复、余额不足

Repository层抛出数据访问异常

Service 可以选择 catch/转义,也可以上抛

JPA抛出 DataIntegrityViolationException

❓1. “用了@ExceptionHandler,为什么还需要@ControllerAdvice?”

  • @ExceptionHandler 是方法级,@ControllerAdvice 是全局级的,集中管理多个Controller的异常处理 。所以两者不是“互相替代”,而是范围不同:ControllerAdvice 是容器,ExceptionHandler 是容器里的处理器方法


❓2. 那为什么还说“Controller处理Service抛出的异常”?“Controller处理Service异常”指的是:“异常发生于Service层,但由Controller层抛出并触发了统一异常处理机制”。


✅ 代码级举例(完整调用链)

➤ 1. 自定义异常类:

➤ 2. Service层抛出异常:

➤ 3. Controller调用Service:

➤ 4. 全局异常处理器:

@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(UserAlreadyExistsException.class)public ResponseEntity<ApiError> handleUserExists(UserAlreadyExistsException ex) {ApiError error = new ApiError(409, ex.getMessage());return ResponseEntity.status(HttpStatus.CONFLICT).body(error);}@ExceptionHandler(Exception.class)public ResponseEntity<ApiError> handleOther(Exception ex) {ApiError error = new ApiError(500, \"Internal server error\");return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);}
}

✅ 小结(极简结论):

问题结论
@ExceptionHandler@ControllerAdvice 冲突吗?❌ 不冲突,前者方法级,后者类级,全局异常需要配合使用
Controller是否“处理”Service抛出的异常?✅ 表面上Controller收到异常,实则由 @ControllerAdvice 捕获
实际开发该怎么用?✅ 建议所有 Controller 异常集中交由 @RestControllerAdvice 来统一处理

✅ 一、前后端通信中的数据结构与序列化处理

1. 前端发送 GET 请求 /api/users,不做 JSON 清洗吗?后端收到的是什么?直接处理 JSON 吗?

  • ✅ GET 请求不会带有 JSON 请求体(规范禁止),数据清洗体现在构造 Query 参数(如 /api/users?active=true)。

  • ✅ 后端不会处理 JSON,而是通过 @RequestParam 解析 URL 查询参数。

  • ✅ JSON 序列化只发生在 POST/PUT 请求体响应数据 中。


2. JSON 序列化 / 反序列化发生在哪一步?DispatcherServlet 负责吗?

  • ✅ 反序列化(JSON → Java)发生在 HandlerAdapter 调用 Controller 方法前

  • ✅ 序列化(Java → JSON)发生在 Controller 方法返回后

  • DispatcherServlet 不负责 JSON 处理,它只负责请求转发。

  • ✅ JSON 的处理由 HttpMessageConverter(默认使用 Jackson)完成。


✅ 二、DAO / DTO 的职责与流程中的定位

3. 什么是 DAO 和 DTO?图中的第 12~14 步分别返回的是什么?

  • ✅ DAO(Data Access Object)是用于封装数据库访问逻辑的接口,如 UserRepository extends JpaRepository

  • ✅ DTO(Data Transfer Object)是前后端或多层之间传递数据的载体,如 UserDto

  • 图中:

    • 第12步:DAO 返回的是实体类(Entity);

    • 第13步:Service 转换为 DTO,返回给 Controller;

    • 第14步:Controller 使用 ResponseEntity<DTO> 作为响应,框架底层封装为 ModelAndView


4. ResponseEntity 和 Model 有什么区别?第 15 步为什么是 ModelAndView?

  • ResponseEntity 用于前后端分离,返回完整 JSON 响应;

  • Model 是传统 MVC 模式中用于传数据给视图模板的结构;

  • ModelAndView 是 Spring MVC 底层用于封装所有结果的统一结构(即使你返回的是 ResponseEntity,框架也封装为 ModelAndView(null, body))。

  • ✅ 前后端分离时,开发者只用 ResponseEntity,无需直接接触 ModelAndView


✅ 三、Spring Security 中的 JWT 验证机制

5. JWT 验证流程在 Spring Boot 中是怎样的?在哪一层?

  • ✅ JWT 验证发生在 FilterChain 阶段,通常在 OncePerRequestFilter 中实现;

  • ✅ 验证步骤:

    • 从请求 Header 获取 Authorization: Bearer <token>

    • 验证签名、结构、过期时间;

    • 解析生成 Authentication

    • 设置到 SecurityContextHolder

    • 放行到 DispatcherServlet;

  • ❌ DispatcherServlet 和 Handler 不参与认证,只接收已验证请求。


6. JWT 是由前端编辑生成的吗?字段如 iss、sub、exp、roles 是前端决定的吗?

  • ❌ JWT 不能由前端生成;

  • ✅ JWT 是后端使用密钥生成的,包含的字段完全由后端控制;

  • ✅ 前端只是接收、存储并在请求中携带;

  • JWT 示例字段如 sub: userId, exp: timestamp, roles: ["ADMIN"] 都由后端代码设置。


7. 为什么 JWT 验证完还要构建 Authentication 对象?不能直接转发请求吗?

  • ✅ 构建 Authentication 的目的是让 Spring Security 安全机制生效:

    • 权限判断(如 @PreAuthorize)依赖 SecurityContext

    • 日志、审计、日志追踪、用户上下文等都依赖它;

  • ❌ 如果跳过该步骤,系统将视为匿名用户,请求将不具备认证身份。


✅ 四、Spring Security 的方法级授权机制

8. @PreAuthorize 注解用在哪些类?在哪一步执行?为什么叫 Pre?看起来像是在认证前

  • @PreAuthorize 用于 Controller 或 Service 方法上,限制某角色、用户是否能执行该方法;

  • ✅ 执行时机是 在方法体执行之前,不是在登录认证之前;

  • ✅ 所谓“Pre”指的是在方法调用前进行权限判断

  • ✅ 注解本质通过 AOP 拦截方法,依赖于 Authentication 已存在(由 Filter 中设置);

  • ❌ 如果没有 Authentication@PreAuthorize 判断失效,默认拒绝访问。

用法:

@PreAuthorize("hasRole('ADMIN')")
public void deleteUser(Long id) { ... }@PreAuthorize("#userId == authentication.name")
public void updateUser(Long userId, UserDto dto) { ... }

✅ 总结关键词表

关键词解释
DTO传输数据结构体,跨层/跨系统使用
DAO数据访问接口,用于封装数据库操作
ResponseEntity用于返回 JSON 响应体的 Spring 结构
ModelAndViewSpring MVC 内部统一封装结构
JWTJSON Web Token,认证令牌,由后端生成
AuthenticationSpring Security 中用于表示认证用户的对象
SecurityContextHolder保存当前请求上下文的认证信息
@PreAuthorize方法级授权注解,执行方法前做权限判断

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/75729.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于sklearn实现文本摘要思考

和各位小伙伴分享一下使用sklearn进行文本摘要的思考。 第一版本 原理 提取式文本摘要的基本原理是&#xff1a; 将文本分割成句子 计算每个句子的重要性(权重) 选择权重最高的几个句子组成摘要 常用的句子权重计算方法&#xff1a; TF-IDF&#xff1a;基于词频-逆文档频…

OpenHarmony子系统开发 - DFX(三)

OpenHarmony子系统开发 - DFX&#xff08;三&#xff09; 五、HiTraceMeter开发指导 HiTraceMeter概述 简介 HiTraceMeter在OpenHarmony中&#xff0c;为开发者提供业务流程调用链跟踪的维测接口。通过使用该接口所提供的功能&#xff0c;可以帮助开发者迅速获取指定业务流…

2025年 能够有效提升AI的生成质量和逻辑严谨性 的通用型系统提示

以下是三个经过精心设计的通用型系统提示&#xff08;System Prompt&#xff09;&#xff0c;能够有效提升AI的生成质量和逻辑严谨性&#xff0c;适用于各类对话、分析和创作场景&#xff1a; Prompt 1 - 专家级分步验证模式 你是一个具备跨领域知识整合能力的超级AI&#xff…

python爬虫:小程序逆向实战教程

根据我之前发表的文章&#xff0c;我们进行延伸实战https://blog.csdn.net/weixin_64809364/article/details/146981598?spm1001.2014.3001.5501 1. 想要爬取什么小程序&#xff0c;我们进行搜索 2. 找到我们vx小程序的文件地址&#xff0c;我们就可以进行破解 破解步骤强看…

C语言变长数组(VLA)详解:灵活处理动态数据的利器

引言 在C语言中&#xff0c;传统的数组大小必须在编译时确定&#xff0c;这限制了程序处理动态数据的灵活性。C99标准引入的变长数组&#xff08;Variable-Length Array, VLA&#xff09; 打破了这一限制&#xff0c;允许数组长度在运行时动态确定。本文将深入解析VLA的语法、…

串口数据转换为IP数据

串口数据转换为IP数据是一种常见的通信技术,用于将传统的串行设备(如传感器、控制器等)接入现代的IP网络。以下是详细介绍: 1. 转换原理 串口数据转换为IP数据的过程涉及硬件和软件的结合,核心是将串行数据封装为TCP/IP或UDP/IP数据包,通过网络传输。具体步骤如下: 硬…

client-go如何监听自定义资源

如何使用 client-go 监听自定义资源 在 Kubernetes 中使用 client-go 监听自定义资源&#xff08;Custom Resource&#xff0c;简称 CR&#xff09;需要借助 Dynamic Client 或 Custom Informer&#xff0c;因为 client-go 的标准 Clientset 只支持内置资源&#xff08;如 Pod…

C++软件开发架构

文章目录 1.全局消息通信MsgHandler.h单元测试(QTest)MsgHandlerUnitTest.hMsgHandlerUnitTest.cpp 2.实例间通信InstMsgHandler.h单元测试InstMsgHandlerUnitTest.hInstMsgHandlerUnitTest.cpp 1.全局消息通信 1. 适用于类与类单个对象实例之间的通信&#xff0c;多个对象需要…

AI Agent设计模式一:Chain

概念 &#xff1a;线性任务流设计 ✅ 优点&#xff1a;逻辑清晰易调试&#xff0c;适合线性处理流程❌ 缺点&#xff1a;缺乏动态分支能力 from typing import TypedDictfrom langgraph.graph import StateGraph, END# 定义后续用到的一些变量 class CustomState(TypedDict):p…

Git三剑客:工作区、暂存区、版本库深度解析

一、引言&#xff1a;为什么需要理解Git的核心区域&#xff1f; 作为开发者&#xff0c;Git是日常必备的版本控制工具。但你是否曾因以下问题感到困惑&#xff1f; 修改了文件&#xff0c;但 git status 显示一片混乱&#xff1f; git add 和 git commit 到底做了什么&#x…

Python数据类型-list

列表(List)是Python中最常用的数据类型之一&#xff0c;它是一个有序、可变的元素集合。 1. 列表基础 创建列表 empty_list [] # 空列表 numbers [1, 2, 3, 4, 5] # 数字列表 fruits [apple, banana, orange] # 字符串列表 mixed [1, hello, 3.14, True] # 混合类型…

Keepalive+LVS+Nginx+NFS高可用项目

项目架构 分析 主机规划 主机系统安装应用网络IPclientredhat 9.5无NAT172.25.250.115/24lvs-masterrocky 9.5ipvsadm&#xff0c;keepalivedNAT172.25.250.116/24 VIP 172.25.250.100/32lvs-backuprocky 9.5ipvsadm&#xff0c;keepalivedNAT172.25.250.117/24 VIP 172.25.2…

【视觉与语言模型参数解耦】为什么?方案?

一些无编码器的MLLMs统一架构如Fuyu&#xff0c;直接在LLM内处理原始像素&#xff0c;消除了对外部视觉模型的依赖。但是面临视觉与语言模态冲突的挑战&#xff0c;导致训练不稳定和灾难性遗忘等问题。解决方案则是通过参数解耦方法解决模态冲突。 在多模态大语言模型&#xf…

AI比人脑更强,因为被植入思维模型【43】蝴蝶效应思维模型

giszz的理解&#xff1a;蝴蝶效应我们都熟知&#xff0c;就是说一个微小的变化&#xff0c;能带动整个系统甚至系统的空间和时间的远端&#xff0c;产生巨大的链式反应。我学习后的启迪&#xff0c;简单的说&#xff0c;就是不要忽视任何微小的问题&#xff0c;更多时候&#x…

AI 数理逻辑基础之统计学基本原理(上)

目录 文章目录 目录统计学统计学基本概念描述性统计数据可视化图表工具 汇总统计统计数据的分布情况&#xff1a;中位数、众数、平均值统计数据的离散程度&#xff1a;极差、方差、标准差、离散系数 相关分析Pearson 线性关系相关系数Spearman 单调关系相关系数 回归分析回归模…

无招回归阿里

这两天&#xff0c;无招回归阿里的新闻被刷屏了。无招创业成立的两氢一氧公司无招的股份也被阿里收购&#xff0c;无招以这种姿态回归阿里&#xff0c;并且出任钉钉的 CEO。有人说&#xff0c;这是对 5 年前“云钉一体”战略的纠偏。现在确实从云优先到 AI 优先&#xff0c;但云…

算法题(114):矩阵距离

审题&#xff1a; 本题需要我们找出所有0距离最近的1的曼哈顿距离 思路&#xff1a; 方法一&#xff1a;多源bfs 分析曼哈顿距离&#xff1a; 求法1&#xff1a;公式法&#xff0c;带入题目公式&#xff0c;利用|x1-x2||y1-y2|求出 求法2&#xff1a;曼哈顿距离就是最短距离 本…

LLM 性能优化有哪些手段?

LLM(大语言模型)性能优化是一个多维度、多层次的系统工程,涉及从提示工程到模型微调,从推理加速到系统架构优化等多个方面。以下是当前主流的优化手段及其技术细节: 一、提示工程(Prompt Engineering) 提示工程是优化LLM性能最直接、成本最低的方法,适用于快速原型开发…

群体智能避障革命:RVO算法在Unity中的深度实践与优化

引言&#xff1a;游戏群体移动的挑战与进化 在《全面战争》中万人战场恢弘列阵&#xff0c;在《刺客信条》闹市里人群自然涌动&#xff0c;这些令人惊叹的场景背后&#xff0c;都离不开一个关键技术——群体动态避障。传统路径规划算法&#xff08;如A*&#xff09;虽能解决单…

I.MX6ULL 交叉编译环境配置与使用

一、什么是交叉编译 我们一般开发程序在自己的电脑上开发&#xff0c;运行的时候将程序烧录到板子运行。但我们的开发平台是X86架构&#xff0c;而I.MX6ULL是ARM架构&#xff0c;所以需要一个在 X86 架构的 PC 上运行&#xff0c;可以编译 ARM 架构代码的 GCC 编译器&#xff0…