文档站点
Skip to content

响应 ​

Laravel 里 return response()->json($data) 或 return $data;Spring Boot 的 @RestController 让「返回对象 = 自动 JSON」,再用 ResponseEntity 精细控制状态码和响应头。

最基本的响应:返回对象即 JSON ​

java
@GetMapping("/posts/{id}")
public Post show(@PathVariable Long id) {
    return service.get(id);
}

@RestController 下,返回值会被 HttpMessageConverter 自动序列化为 JSON 并返回 200。Post 的 getter 有哪些字段,JSON 里就有哪些字段。

TIP

@RestController = @Controller + 方法上的 @ResponseBody。用了它,方法返回值就不是「视图名」,而是「响应体」。

控制状态码和响应头:ResponseEntity ​

Laravel 用 response()->json($data, 201);Spring 用 ResponseEntity:

java
@PostMapping("/posts")
public ResponseEntity<Post> store(@Valid @RequestBody PostDto dto) {
    Post post = service.create(dto);
    return ResponseEntity
            .status(HttpStatus.CREATED)          // 201
            .header("X-Post-Id", post.getId().toString())
            .body(post);
}

常用构建器:

java
return ResponseEntity.ok(post);                          // 200
return ResponseEntity.status(201).body(post);            // 201 + body
return ResponseEntity.noContent().build();               // 204,无 body
return ResponseEntity.badRequest().build();              // 400
return ResponseEntity.notFound().build();                // 404
return ResponseEntity.ok()
        .contentType(MediaType.APPLICATION_JSON)
        .header("X-Custom", "v1")
        .body(post);

推荐写法

  • 成功且有数据:返回对象本身(Post),或 ResponseEntity.ok(post) 自定义响应头
  • 创建成功:ResponseEntity.status(201).body(...)
  • 无内容:ResponseEntity.noContent().build()
  • 出错:不要在控制器里 return 400/500,应该 throw 异常交给全局处理器(见 异常处理)

设置 HTTP 状态码的三种方式 ​

方式写法场景
返回对象 + @ResponseStatus@ResponseStatus(HttpStatus.CREATED)固定状态码
ResponseEntityResponseEntity.status(201)动态状态码 + 自定义头
抛异常 + @ResponseStatus自定义异常上标注业务异常
java
@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/posts")
public Post store(@Valid @RequestBody PostDto dto) {
    return service.create(dto);
}

JSON 输出定制 ​

字段改名 ​

java
@Data
public class Post {
    @JsonProperty("post_id")
    private Long id;
}

输出:{ "post_id": 1 }。

忽略字段 ​

java
@Data
public class User {
    private Long id;
    @JsonIgnore
    private String passwordHash;    // 响应里不输出
}

日期格式 ​

yaml
spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: Asia/Shanghai

TIP

给实体直接加 @JsonIgnore 会同时影响入参序列化,容易踩坑。更干净的做法是用 DTO 分别定义入参/出参结构,见 JPA 序列化与 DTO。

统一响应包装:和 Laravel 一样的套路 ​

很多团队喜欢统一的 {code, message, data} 结构,就像 Laravel 里自定义 ApiResponse:

java
@Data
public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;

    public static <T> ApiResponse<T> ok(T data) {
        return of(0, "ok", data);
    }

    public static <T> ApiResponse<T> of(int code, String message, T data) {
        ApiResponse<T> r = new ApiResponse<>();
        r.code = code;
        r.message = message;
        r.data = data;
        return r;
    }
}

控制器统一返回:

java
@GetMapping("/posts")
public ApiResponse<List<Post>> index() {
    return ApiResponse.ok(service.list());
}

两种风格二选一

  1. 裸数据:直接返回 Post,状态码表达语义(REST 风格,前后端约定好)
  2. 包装数据:统一 {code,message,data},状态码永远是 200 团队里必须统一。本教程示例两种都会出现,实际项目选一种定下来。

返回文件下载 ​

java
@GetMapping("/download/{fileId}")
public ResponseEntity<Resource> download(@PathVariable Long fileId) {
    Resource resource = fileStorage.load(fileId);
    return ResponseEntity.ok()
            .header(HttpHeaders.CONTENT_DISPOSITION,
                    "attachment; filename=\"" + resource.getFilename() + "\"")
            .contentType(MediaType.APPLICATION_OCTET_STREAM)
            .body(resource);
}

重定向 ​

java
@GetMapping("/old-url")
public ResponseEntity<Void> redirect() {
    return ResponseEntity.status(HttpStatus.MOVED_PERMANENTLY)
            .location(URI.create("/posts"))
            .build();
}

响应对照速查 ​

需求LaravelSpring Boot
JSON 数据return $posts;return posts;
自定义状态码response()->json($d, 201)ResponseEntity.status(201).body(d)
无内容response()->noContent()ResponseEntity.noContent().build()
定制响应头response()->header('X-Foo','1')ResponseEntity.ok().header("X-Foo","1").body(d)
输出字段改名$resource->toArray()@JsonProperty("xxx")
隐藏字段$hidden@JsonIgnore
下载response()->download($path)返回 ResponseEntity<Resource>

接下来:请求与响应之间,如何做横切逻辑 —— 中间件(Interceptor / Filter)。

面向 PHP / Laravel 开发者的 Spring Boot 中文文档