Spring Boot 中修改 HTTP 响应状态码(即 `response.status`)可以通过以下几种方式实现

以下是不同场景下的具体方法:


方法 1:直接使用 @ResponseStatus 注解

在 Controller 方法或异常类上使用 @ResponseStatus 注解,直接指定返回的状态码。

场景示例:固定返回指定状态码
java 复制代码
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {
    // 成功创建资源时返回 201
    @PostMapping("/create")
    @ResponseStatus(HttpStatus.CREATED) // 状态码 201
    public String createResource() {
        return "Resource created";
    }
}

方法 2:动态返回 ResponseEntity 对象

通过 ResponseEntity 对象在代码中动态控制状态码,适用于需要根据业务逻辑返回不同状态码的场景。

场景示例:根据条件返回不同状态码
java 复制代码
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {
    @GetMapping("/user/{id}")
    public ResponseEntity<String> getUser(@PathVariable Long id) {
        if (id == 1) {
            return ResponseEntity.ok("User found"); // 默认 200
        } else {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).body("User not found"); // 404
        }
    }
}

方法 3:通过全局异常处理统一修改状态码

使用 @ControllerAdvice@ExceptionHandler 拦截异常并统一设置状态码。

场景示例:资源不存在时返回 404
java 复制代码
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import javax.persistence.EntityNotFoundException;

@ControllerAdvice
public class GlobalExceptionHandler {
    // 捕获 EntityNotFoundException 并返回 404
    @ExceptionHandler(EntityNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public String handleEntityNotFound() {
        return "Resource not found";
    }
}

方法 4:直接操作 HttpServletResponse

在 Controller 方法中注入 HttpServletResponse 对象,直接设置状态码。

场景示例:手动设置状态码
java 复制代码
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {
    @GetMapping("/manual")
    public String manualStatus(HttpServletResponse response) {
        response.setStatus(HttpStatus.ACCEPTED.value()); // 状态码 202
        return "Status manually set";
    }
}

常见场景与状态码对照表

场景 推荐状态码 说明
成功 200 OK 默认成功状态码
创建资源成功 201 Created 配合 @PostMapping 使用
请求参数错误 400 Bad Request 客户端请求错误
未授权访问 401 Unauthorized 需要身份验证
禁止访问 403 Forbidden 无权限访问资源
资源不存在 404 Not Found 请求的资源不存在
服务器内部错误 500 Internal Error 未捕获的异常导致服务器错误

注意事项

  1. 优先级问题
    ResponseEntity 的优先级高于 @ResponseStatus,如果二者同时存在,以 ResponseEntity 为准。

  2. 直接操作 HttpServletResponse 的限制

    如果在设置状态码后修改响应体,可能导致 IllegalStateException,建议优先使用 Spring 提供的抽象(如 ResponseEntity)。

  3. 全局异常处理的覆盖范围

    通过 @ControllerAdvice 可以统一处理所有 Controller 抛出的异常,适合集中管理错误状态码。


通过上述方法,你可以根据具体场景灵活控制 HTTP 响应的状态码。推荐优先使用 ResponseEntity@ResponseStatus 保持代码简洁。

以下是结合自定义返回工具类与 Spring Boot 状态码控制的详细方案,提供代码示例和分步说明:


1. 定义统一返回结果工具类

java 复制代码
public class ApiResponse<T> {
    private int code;       // 业务状态码(非 HTTP 状态码)
    private String message; // 提示信息
    private T data;         // 返回数据

    // 快速创建成功响应(静态工厂方法)
    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<>(200, "Success", data);
    }

    // 快速创建失败响应(链式调用支持)
    public static ApiResponse<Void> failure(int code, String message) {
        return new ApiResponse<>(code, message, null);
    }

    public ApiResponse<T> code(int code) {
        this.code = code;
        return this;
    }

    public ApiResponse<T> message(String message) {
        this.message = message;
        return this;
    }

    // 构造方法、Getter 省略...
}

2. 与状态码控制方法结合使用

场景 1:固定状态码 + 统一数据结构(@ResponseStatus)
java 复制代码
@PostMapping("/users")
@ResponseStatus(HttpStatus.CREATED) // 强制 HTTP 201
public ApiResponse<User> createUser(@RequestBody User user) {
    User savedUser = userService.save(user);
    return ApiResponse.success(savedUser)
                     .message("User created successfully");
}
场景 2:动态状态码 + 统一数据结构(ResponseEntity)
java 复制代码
@GetMapping("/products/{id}")
public ResponseEntity<ApiResponse<Product>> getProduct(@PathVariable Long id) {
    return productService.findById(id)
        .map(product -> 
            ResponseEntity.ok(ApiResponse.success(product)) // HTTP 200
        )
        .orElseGet(() -> 
            ResponseEntity.status(HttpStatus.NOT_FOUND)
                          .body(ApiResponse.failure(404, "Product not found"))
        );
}

3. 全局异常处理统一包装结果

java 复制代码
@ControllerAdvice
public class GlobalExceptionHandler {

    // 处理业务异常(HTTP 400 + 自定义错误码)
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ApiResponse<Void>> handleBusinessException(BusinessException ex) {
        return ResponseEntity.badRequest() // HTTP 400
            .body(ApiResponse.failure(ex.getCode(), ex.getMessage()));
    }

    // 处理资源不存在(HTTP 404)
    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ApiResponse<Void>> handleResourceNotFound(ResourceNotFoundException ex) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(ApiResponse.failure(404, ex.getMessage()));
    }

    // 兜底异常处理(HTTP 500)
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiResponse<Void>> handleGlobalException(Exception ex) {
        return ResponseEntity.internalServerError()
            .body(ApiResponse.failure(500, "Internal server error"));
    }
}

4. 进阶工具类(支持链式设置 HTTP 状态码)

java 复制代码
public class ApiResponseBuilder<T> {
    private HttpStatus httpStatus = HttpStatus.OK; // 默认 200
    private ApiResponse<T> apiResponse;

    private ApiResponseBuilder(ApiResponse<T> apiResponse) {
        this.apiResponse = apiResponse;
    }

    public static <T> ApiResponseBuilder<T> success(T data) {
        return new ApiResponseBuilder<>(ApiResponse.success(data));
    }

    public ApiResponseBuilder<T> httpStatus(HttpStatus status) {
        this.httpStatus = status;
        return this;
    }

    public ResponseEntity<ApiResponse<T>> build() {
        return ResponseEntity.status(httpStatus).body(apiResponse);
    }
}

// 使用示例
@PostMapping("/orders")
public ResponseEntity<ApiResponse<Order>> createOrder() {
    Order newOrder = orderService.create();
    return ApiResponseBuilder.success(newOrder)
                           .httpStatus(HttpStatus.CREATED) // 设置 HTTP 201
                           .build();
}

5. 关键注意事项

  1. 明确区分两类状态码

    • HTTP 状态码:描述网络请求结果(200/404/500)
    • 业务状态码:描述业务逻辑结果(如 1001=库存不足)
  2. 推荐优先级

    • 优先使用 ResponseEntity 控制 HTTP 状态码
    • 使用工具类封装业务状态码
  3. 保持响应结构一致性

    json 复制代码
    // 成功示例
    {
      "code": 200,
      "message": "Success",
      "data": { "id": 1, "name": "test" }
    }
    
    // 错误示例(HTTP 404)
    {
      "code": 40401,
      "message": "Product not found",
      "data": null
    }

通过这种方式,您既可以精准控制 HTTP 协议层的状态码,又能通过工具类统一业务响应格式,同时保持代码的高度可维护性。

相关推荐
是三好1 小时前
并发容器(Collections)
java·多线程·juc
jian110581 小时前
java项目实战、pom.xml配置解释、pojo 普通java对象
java·开发语言·python
述雾学java1 小时前
Spring Boot是什么?MybatisPlus常用注解,LambdaQueryWrapper常用方法
java·spring boot·后端
jinhuazhe20131 小时前
maven 3.0多线程编译提高编译速度
java·maven
xosg2 小时前
HTMLUnknownElement的使用
java·前端·javascript
forestsea2 小时前
Java虚拟机面试题:内存管理(上)
java·开发语言
yueyekkx2 小时前
Ubuntu24.04 LTS安装java8、mysql8.0
java·mysql·ubuntu
若水uy3 小时前
静态分配动态绑定
java
程序员buddha3 小时前
SpringBoot多环境配置文件切换
java·spring boot·后端
Java小白笔记3 小时前
IDEA中创建SpringBoot项目没有Java8
java·spring boot·intellij-idea