📜  如何在 Spring Boot 中实现一对多映射?(1)

📅  最后修改于: 2023-12-03 15:08:48.193000             🧑  作者: Mango

如何在 Spring Boot 中实现一对多映射?

在数据库中,一对多映射通常表示为一个表中的多个行与另一个表中的一个单独行之间的关系。在 Spring Boot 中,可以使用 JPA 来实现一对多映射。本篇文章将介绍如何在 Spring Boot 中实现一对多映射。

准备工作

在开始之前,需要确保已经完成以下准备工作:

  • 安装并配置好 MySQL 数据库以及相应的数据库管理工具,比如 HeidiSQL。
  • 创建一个 Spring Boot 项目。
  • 添加 Spring Boot Data JPA 和 MySQL 相关依赖。
数据库设置

在 MySQL 数据库中,一对多映射通常通过在一个表中保存另一个表的外键来实现。

假设有两个表,一个是“订单”表(orders),另一个是“订单项”表(order_items)。一个订单可能对应多个订单项,因此“订单项”表需要保存“订单”的外键。以下是这两个表的创建语句:

CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `customer_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `order_items` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `price` float DEFAULT NULL,
  `order_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_ORDER_ITEMS_ORDERS` (`order_id`),
  CONSTRAINT `FK_ORDER_ITEMS_ORDERS` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
实体类定义

在 Spring Boot 中使用 JPA 实现一对多映射,需要定义两个实体类,一个是“订单”实体类,另一个是“订单项”实体类。

首先是“订单”实体类定义:

@Entity
@Table(name = "orders")
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String customerName;
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> orderItems;
    // ... constructor, getters and setters
}

这里使用了 JPA 中的 @OneToMany 注解来表示一对多的关系。其中 mappedBy 属性表示关系的被维护方是“订单项”实体类,它的属性名为“order”(即“订单”实体类中的 List<OrderItem> orderItems 属性),cascade 属性表示级联操作(在这里是所有操作),表示当对一个“订单”实体类执行操作时,它所关联的“订单项”实体类也会执行同样的操作。

接下来是“订单项”实体类定义:

@Entity
@Table(name = "order_items")
public class OrderItem {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private Float price;
    @ManyToOne
    @JoinColumn(name = "order_id")
    private Order order;
    // ... constructor, getters and setters
}

这里使用了 JPA 中的 @ManyToOne 注解来表示多对一的关系。其中 @JoinColumn 注解表示关联的外键名,它指向“订单”实体类中的 id 属性。

数据访问层

在 Spring Boot 中,数据访问层通常使用 Repository 来实现。可以定义两个 Repository 接口,分别对应“订单”和“订单项”实体类。

首先是“订单” Repository 定义:

public interface OrderRepository extends JpaRepository<Order, Long> {
}

这里使用了 Spring Data JPA 提供的 JpaRepository 接口,它提供了基本的 CRUD(Create, Read, Update, Delete)操作。

然后是“订单项” Repository 定义:

public interface OrderItemRepository extends JpaRepository<OrderItem, Long> {
}
服务层和控制层

在服务层和控制层中,可以直接调用 Repository 中提供的方法来实现业务逻辑。

以下是针对“订单”实体类的服务层和控制层的定义:

@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;
    public List<Order> findAll() {
        return orderRepository.findAll();
    }
    public Order save(Order order) {
        return orderRepository.save(order);
    }
}

@RestController
public class OrderController {
    @Autowired
    private OrderService orderService;
    @GetMapping("/orders")
    public List<Order> findAll() {
        return orderService.findAll();
    }
    @PostMapping("/orders")
    public Order save(@RequestBody Order order) {
        return orderService.save(order);
    }
}

以下是针对“订单项”实体类的服务层和控制层的定义:

@Service
public class OrderItemService {
    @Autowired
    private OrderItemRepository orderItemRepository;
    public List<OrderItem> findAll() {
        return orderItemRepository.findAll();
    }
    public OrderItem save(OrderItem orderItem) {
        return orderItemRepository.save(orderItem);
    }
}

@RestController
public class OrderItemController {
    @Autowired
    private OrderItemService orderItemService;
    @GetMapping("/orderItems")
    public List<OrderItem> findAll() {
        return orderItemService.findAll();
    }
    @PostMapping("/orderItems")
    public OrderItem save(@RequestBody OrderItem orderItem) {
        return orderItemService.save(orderItem);
    }
}
测试

完成以上所有工作后,启动 Spring Boot 应用程序,使用 curl 或 Postman 等工具调用相关接口,测试一下。以下是一些参考命令:

查找所有订单
$ curl http://localhost:8080/orders
[{"id":1,"customerName":"Alice","orderItems":[{"id":1,"name":"Item1","price":10.0},{"id":2,"name":"Item2","price":20.0}]},{"id":2,"customerName":"Bob","orderItems":[{"id":3,"name":"Item3","price":30.0}]}]
保存一个订单
$ curl -X POST http://localhost:8080/orders -d '{"customerName": "Charlie", "orderItems": [{"name": "Item4", "price": 40.0}, {"name": "Item5", "price": 50.0}]}'
{"id":3,"customerName":"Charlie","orderItems":[{"id":4,"name":"Item4","price":40.0,"order_id":3},{"id":5,"name":"Item5","price":50.0,"order_id":3}]}
查找所有订单项
$ curl http://localhost:8080/orderItems
[{"id":1,"name":"Item1","price":10.0,"order_id":1},{"id":2,"name":"Item2","price":20.0,"order_id":1},{"id":3,"name":"Item3","price":30.0,"order_id":2},{"id":4,"name":"Item4","price":40.0,"order_id":3},{"id":5,"name":"Item5","price":50.0,"order_id":3}]
保存一个订单项
$ curl -X POST http://localhost:8080/orderItems -d '{"name": "Item6", "price": 60.0, "order": {"id": 1}}'
{"id":6,"name":"Item6","price":60.0,"order_id":1}
总结

使用 JPA 可以很方便地实现在 Spring Boot 中的一对多映射。只需定义好实体类和 Repository,即可完成基本的 CRUD 操作。在实际项目中,可以根据需要添加更多的业务逻辑和数据校验。