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 协议层的状态码,又能通过工具类统一业务响应格式,同时保持代码的高度可维护性。

相关推荐
永卿0015 分钟前
设计模式-责任链模式
java·设计模式·责任链模式
hello 早上好9 分钟前
深入解析AOP调用链:递归与责任链模式的协同实现
java·责任链模式
wangmengxxw19 分钟前
Spring-常用注解
java·数据库·spring·注解
籍籍川草27 分钟前
JVM指针压缩的那些事
java·开发语言·jvm
艾莉丝努力练剑36 分钟前
【C/C++】类和对象(上):(一)类和结构体,命名规范——两大规范,新的作用域——类域
java·c语言·开发语言·c++·学习·算法
myNameGL1 小时前
下载一个JeecgBoot-master项目 导入idea需要什么操作启动项目
java·ide·intellij-idea
Emotion亦楠1 小时前
Java 学习笔记:常用类、String 与日期时间处理
java·笔记·学习
郝学胜-神的一滴2 小时前
Spring Boot Actuator 保姆级教程
java·开发语言·spring boot·后端·程序人生
jiangxia_10243 小时前
面试系列:什么是JAVA并发编程中的JUC并发工具类
java·后端
草莓爱芒果3 小时前
Spring Boot中使用Bouncy Castle实现SM2国密算法(与前端JS加密交互)
java·spring boot·算法