Spring 的 ResponseEntity 包装器使用详解

简介

Spring 中,ResponseEntityHTTP 响应的包装器。它允许自定义响应的各个方面:

  • HTTP 状态码

  • 响应主体

  • HTTP 请求头

使用 ResponseEntity 允许完全控制 HTTP 响应,并且它通常用于 RESTful Web 服务中从控制器方法返回响应。

基本语法

java 复制代码
ResponseEntity<T> response = new ResponseEntity<>(body, headers, status);
  • T:响应主体的类型

  • body:想要作为响应主体发送的对象(如果不想返回主体,则可以为空)

  • headers:想要包含的任何其他 HTTP 请求头

  • status:HTTP 状态代码(如 HttpStatus.OK、HttpStatus.CREATED等)

示例用法

基本用法:返回简单响应
java 复制代码
@RestController
@RequestMapping("/api/posts")
public class PostController {

    @GetMapping("/{id}")
    public ResponseEntity<Post> getPost(@PathVariable Long id) {
        Post post = postService.findById(id);
        if (post != null) {
            return new ResponseEntity<>(post, HttpStatus.OK);  // 200 OK
        } else {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);  // 404 Not Found
        }
    }
}
返回带有请求头的 ResponseEntity
java 复制代码
@GetMapping("/custom-header")
public ResponseEntity<String> getWithCustomHeader() {
    HttpHeaders headers = new HttpHeaders();
    headers.add("Custom-Header", "CustomValue");

    return new ResponseEntity<>("Hello with custom header!", headers, HttpStatus.OK);
}
返回具有创建状态的 ResponseEntity

创建新资源时,通常希望返回 201 Created 状态代码

java 复制代码
@PostMapping("/create")
public ResponseEntity<Post> createPost(@RequestBody Post post) {
    Post createdPost = postService.save(post);
    URI location = ServletUriComponentsBuilder.fromCurrentRequest()
            .path("/{id}")
            .buildAndExpand(createdPost.getId())
            .toUri();

    return ResponseEntity.created(location).body(createdPost);
}
返回没有内容的 ResponseEntity

当成功处理一个请求但不需要返回任何内容(例如,一个 DELETE 请求)时,可以使用 204 No Content

java 复制代码
@DeleteMapping("/{id}")
public ResponseEntity<Void> deletePost(@PathVariable Long id) {
    boolean isDeleted = postService.delete(id);
    if (isDeleted) {
        return new ResponseEntity<>(HttpStatus.NO_CONTENT);  // 204 No Content
    } else {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);   // 404 Not Found
    }
}
使用带有异常处理的 ResponseEntity

可以在全局异常处理程序或控制器中使用 ResponseEntity 来处理异常

java 复制代码
@ExceptionHandler(PostNotFoundException.class)
public ResponseEntity<String> handlePostNotFound(PostNotFoundException ex) {
    return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
使用 Map 返回 ResponseEntity(例如,对于 JSON 响应)
java 复制代码
@GetMapping("/user/{id}")
public ResponseEntity<Map<String, Object>> getUser(@PathVariable Long id) {
    Map<String, Object> response = new HashMap<>();
    User user = userService.findById(id);

    if (user != null) {
        response.put("status", "success");
        response.put("data", user);
        return new ResponseEntity<>(response, HttpStatus.OK);
    } else {
        response.put("status", "error");
        response.put("message", "User not found");
        return new ResponseEntity<>(response, HttpStatus.NOT_FOUND);
    }
}
具有泛型类型的 ResponseEntity
java 复制代码
@GetMapping("/posts/{id}")
public ResponseEntity<Post> getPostById(@PathVariable Long id) {
    Post post = postService.findById(id);
    if (post != null) {
        return ResponseEntity.ok(post);  // 200 OK with Post object as body
    }
    return ResponseEntity.status(HttpStatus.NOT_FOUND).build();  // 404 Not Found with no body
}

// ResponseEntity.ok(post) 是 new ResponseEntity<>(post, HttpStatus.OK) 的简写
返回验证错误的 ResponseEntity
java 复制代码
@PostMapping("/validate")
public ResponseEntity<Map<String, String>> validateUser(@RequestBody User user, BindingResult result) {
    if (result.hasErrors()) {
        Map<String, String> errorResponse = new HashMap<>();
        result.getFieldErrors().forEach(error -> errorResponse.put(error.getField(), error.getDefaultMessage()));
        return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST);  // 400 Bad Request
    }
    userService.save(user);
    return new ResponseEntity<>(HttpStatus.CREATED);  // 201 Created
}
使用统一的响应对象
  • 定义统一响应对象
java 复制代码
public class ApiResponse<T> {

    private String status;
    private String message;
    private T data;
    private ErrorDetails error;

    // Constructor for success response
    public ApiResponse(String status, String message, T data) {
        this.status = status;
        this.message = message;
        this.data = data;
    }

    // Constructor for error response
    public ApiResponse(String status, String message, ErrorDetails error) {
        this.status = status;
        this.message = message;
        this.error = error;
    }

    // Getters and setters
}

class ErrorDetails {
    private String timestamp;
    private int status;
    private String error;
    private String path;

    // Getters and setters
}
  • 在控制器方法中使用统一响应
java 复制代码
@GetMapping("/posts/{id}")
public ResponseEntity<ApiResponse<Post>> getPostById(@PathVariable Long id) {
    Post post = postService.findById(id);
    if (post != null) {
        ApiResponse<Post> response = new ApiResponse<>(
            "success", 
            "Post retrieved successfully", 
            post
        );
        return new ResponseEntity<>(response, HttpStatus.OK);
    } else {
        return getErrorResponse(HttpStatus.NOT_FOUND, "Post not found", "/api/posts/" + id);
    }
}
java 复制代码
private ResponseEntity<ApiResponse<Post>> getErrorResponse(HttpStatus status, String message, String path) {
    ErrorDetails errorDetails = new ErrorDetails();
    errorDetails.setTimestamp(LocalDateTime.now().toString());
    errorDetails.setStatus(status.value());
    errorDetails.setError(status.getReasonPhrase());
    errorDetails.setPath(path);

    ApiResponse<Post> response = new ApiResponse<>(
        "error",
        message,
        errorDetails
    );

    return new ResponseEntity<>(response, status);
}

响应数据结构示例

  • Success
json 复制代码
{
  "status": "success",
  "message": "Post retrieved successfully",
  "data": {
    "id": 1,
    "title": "Hello World",
    "content": "This is my first post"
  }
}
  • Error
json 复制代码
{
  "status": "error",
  "message": "Post not found",
  "error": {
    "timestamp": "2025-02-07T06:43:41.111+00:00",
    "status": 404,
    "error": "Not Found",
    "path": "/api/posts/1"
  }
}
  • 使用 @ControllerAdvice 全局统一处理异常
java 复制代码
@ControllerAdvice
public class GlobalExceptionHandler {

    // Handle all exceptions
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ApiResponse<Object>> handleGeneralException(Exception ex) {
        ErrorDetails errorDetails = new ErrorDetails();
        errorDetails.setTimestamp(LocalDateTime.now().toString());
        errorDetails.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        errorDetails.setError("Internal Server Error");
        errorDetails.setPath("/api/posts");

        ApiResponse<Object> response = new ApiResponse<>("error", ex.getMessage(), errorDetails);
        return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

常用的 HTTP 状态码

  • HttpStatus.OK:200 OK

  • HttpStatus.CREATED:201 Created

  • HttpStatus.NO_CONTENT:204 No Content

  • HttpStatus.BAD_REQUEST:400 Bad Request

  • HttpStatus.UNAUTHORIZED:401 Unauthorized

  • HttpStatus.FORBIDDEN:403 Forbidden

  • HttpStatus.NOT_FOUND:404 Not Found

  • HttpStatus.INTERNAL_SERVER_ERROR:500 Internal Server Error

相关推荐
Query*3 分钟前
Java 设计模式——代理模式:从静态代理到 Spring AOP 最优实现
java·设计模式·代理模式
梵得儿SHI4 分钟前
Java 反射机制深度解析:从对象创建到私有成员操作
java·开发语言·class对象·java反射机制·操作类成员·三大典型·反射的核心api
JAVA学习通8 分钟前
Spring AI 核心概念
java·人工智能·spring·springai
望获linux10 分钟前
【实时Linux实战系列】实时 Linux 在边缘计算网关中的应用
java·linux·服务器·前端·数据库·操作系统
绝无仅有18 分钟前
面试真实经历某商银行大厂数据库MYSQL问题和答案总结(二)
后端·面试·github
绝无仅有20 分钟前
通过编写修复脚本修复 Docker 启动失败(二)
后端·面试·github
..Cherry..22 分钟前
【java】jvm
java·开发语言·jvm
老K的Java兵器库31 分钟前
并发集合踩坑现场:ConcurrentHashMap size() 阻塞、HashSet 并发 add 丢数据、Queue 伪共享
java·后端·spring
冷冷的菜哥1 小时前
go邮件发送——附件与图片显示
开发语言·后端·golang·邮件发送·smtp发送邮件
向葭奔赴♡1 小时前
Spring Boot 分模块:从数据库到前端接口
数据库·spring boot·后端