Skip to content

REST 接口开发

一、统一返回结构(先定义好)

前端约定 code / message / data,后端先定义一个通用返回类:

java
package com.mall.common;

import lombok.Data;

@Data
public class Result<T> {
    private Integer code;      // 0 成功,非 0 失败
    private String message;
    private T data;

    public static <T> Result<T> ok(T data) {
        Result<T> r = new Result<>();
        r.setCode(0);
        r.setMessage("success");
        r.setData(data);
        return r;
    }

    public static <T> Result<T> fail(String message) {
        Result<T> r = new Result<>();
        r.setCode(500);
        r.setMessage(message);
        return r;
    }
}

二、第一个 Controller

java
package com.mall.controller;

import com.mall.common.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController                    // 返回 JSON 的 Controller
@RequestMapping("/api/hello")      // 统一前缀
public class HelloController {

    @GetMapping("/world")
    public Result<String> hello() {
        return Result.ok("Hello Full Stack!");
    }
}

重启后访问 http://localhost:8080/api/hello/world

json
{ "code": 0, "message": "success", "data": "Hello Full Stack!" }

三、注解与参数绑定(重点)

后端接收前端参数有几种方式,必须分清:

① 路径参数 @PathVariable(REST 风格)

java
@GetMapping("/product/{id}")
public Result<Product> getById(@PathVariable Long id) {
    return Result.ok(productService.getById(id));
}

② 查询参数 @RequestParam(?keyword=手机)

java
@GetMapping("/product/list")
public Result<Page<Product>> list(
        @RequestParam(required = false) String keyword,
        @RequestParam(defaultValue = "1") Integer page,
        @RequestParam(defaultValue = "10") Integer size) {
    return Result.ok(productService.list(keyword, page, size));
}

③ JSON 请求体 @RequestBody(POST 的数据)

java
@PostMapping("/order")
public Result<Order> create(@RequestBody OrderCreateDTO dto) {
    return Result.ok(orderService.create(dto));
}

④ 请求头 @RequestHeader

java
@GetMapping("/user/info")
public Result<UserVO> userInfo(@RequestHeader("Authorization") String token) {
    return Result.ok(userService.info(token));
}

四、@RequestMapping 与 HTTP 方法

java
@RestController
@RequestMapping("/api/cart")     // 类上定义资源前缀
public class CartController {

    @GetMapping                    // GET /api/cart   查
    public Result<List<CartItemVO>> list() { ... }

    @PostMapping                   // POST /api/cart  增
    public Result<Void> add(@RequestBody CartAddDTO dto) { ... }

    @PatchMapping("/{id}")         // PATCH /api/cart/{id}  局部改
    public Result<Void> updateCount(@PathVariable Long id,
                                    @RequestBody CartUpdateDTO dto) { ... }

    @DeleteMapping("/{id}")        // DELETE /api/cart/{id}  删
    public Result<Void> remove(@PathVariable Long id) { ... }
}

五、DTO 与 VO:别让实体裸奔

为什么要 DTO/VO

直接把 Product 实体返回给前端,会把 deletedstock 等敏感/多余字段暴露出去。企业规范是:

  • DTO:接收前端入参(只含需要的字段 + 校验注解)
  • VO:返回给前端的数据(按需裁剪、组合字段)
java
// dto/OrderCreateDTO.java —— 接收前端入参
@Data
public class OrderCreateDTO {
    @NotNull(message = "商品不能为空")
    private List<Long> cartIds;
    @NotBlank(message = "收货地址不能为空")
    private String address;
}
java
// vo/ProductVO.java —— 返回给前端
@Data
public class ProductVO {
    private Long id;
    private String name;
    private BigDecimal price;
    private Integer stock;
    private String image;
    private String categoryName;   // 从分类表 join 出来
}

六、分页接口(MyBatis-Plus 的 Page)

java
@GetMapping("/product/list")
public Result<IPage<ProductVO>> list(@RequestParam(defaultValue = "1") Integer page,
                                     @RequestParam(defaultValue = "10") Integer size) {
    Page<Product> p = new Page<>(page, size);
    IPage<Product> result = productMapper.selectPage(p, new LambdaQueryWrapper<>());
    // 组装成 Page<ProductVO> 返回
    return Result.ok(productService.pageVO(p));
}

前端拿到的结构(与 TS 里的 PageResult<T> 对应):

json
{
  "code": 0,
  "records": [ { "id": 1, "name": "手机" } ],
  "total": 120,
  "size": 10,
  "current": 1
}

七、验收

用 Postman / Apifox 测试:

GET http://localhost:8080/api/hello/world      → code=0
GET http://localhost:8080/api/product/list?page=1&size=10
POST http://localhost:8080/api/cart  body: {"productId":1,"count":2}

本章核心

记住四件事:Result 统一返回、@GetMapping 等四个注解、DTO 接收 / VO 返回、分页用 Page。后面所有接口都是这个套路。

基于 MIT 协议发布,可自由学习与修改