前后端分离下,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 {
    @Autowired
    private UserService userService;

    @GetMapping
    public 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 {
    @Id
    private Long id;
    private String name;
    private String email;
}
  • DAO 实质上是 Repository 接口本身(即 Data Access Object)

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

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


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

数据返回结构:

步骤 返回对象 类型
12 Repository → Service Entity 实体类
13 Service → Controller DTO(如 UserDto)
14 Controller → HandlerAdapter ResponseEntity 或直接 DTO
15 HandlerAdapter → DispatcherServlet 包装为 ModelAndView(内部结构)
17 DispatcherServlet → 前端 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 结构
ModelAndView Spring MVC 内部统一封装结构
JWT JSON Web Token,认证令牌,由后端生成
Authentication Spring Security 中用于表示认证用户的对象
SecurityContextHolder 保存当前请求上下文的认证信息
@PreAuthorize 方法级授权注解,执行方法前做权限判断

相关推荐
陈震_几秒前
在 Java 中调用 ChatGPT API 并实现流式接收(Server-Sent Events, SSE)
java·开发语言·chatgpt·sse·流式
Anarkh_Lee19 分钟前
图解JVM - 24.使用OQL语言查询对象信息
java·jvm·后端
Anarkh_Lee21 分钟前
图解JVM - 19.JVM监控及诊断工具-命令行篇
java·jvm·后端
嘵奇22 分钟前
Spring Boot内嵌服务器全解析:Tomcat vs Jetty vs Undertow 选型指南
服务器·spring boot·tomcat
写bug写bug28 分钟前
Java 中的 Lambda
java·后端
写bug写bug30 分钟前
一文速通 Spring Boot 常用注解,建议收藏!
java·spring boot·面试
雷渊32 分钟前
redis为什么设计单线程的?
java·后端·面试
雷渊34 分钟前
redis的集群模式分析
java·后端·面试
点纭1 小时前
JBDC Java数据库连接(1)
java·数据库·oracle
kill bert1 小时前
Java八股文背诵 第六天 pring MVC spring Boot Java 新特性
java·spring boot·mvc