Spring Boot RESTful API 的层设计及其实体映射

Posted

技术标签:

【中文标题】Spring Boot RESTful API 的层设计及其实体映射【英文标题】:Design of the layers of a Spring Boot RESTful API and its entities mapping 【发布时间】:2020-08-09 10:14:12 【问题描述】:

自从我使用 Spring Boot 从头开始​​开发我的第一个 RESTful API 以来,我一直在思考我的服务器的架构。 我正在使用 Hibernate,并使用 Hibernate/JPA 注释创建了几个实体及其关系,但是,我不确定是否应该将这些实体用作业务模型,因为它们对于 Hibernate 推荐的额外字段是“脏的”。

This is my tentative REST API layered architecture

这是一个直接取自 Hibernate 文档的示例。

@Entity(name = "Person")
public static class Person implements Serializable 

    @Id
    @GeneratedValue
    private Long id;

    @NaturalId
    private String registrationNumber;

    @OneToMany(
        mappedBy = "person",
        cascade = CascadeType.ALL,
        orphanRemoval = true
    )
    private List<PersonAddress> addresses = new ArrayList<>();

    // ...

    public void addAddress(Address address) 
        PersonAddress personAddress = new PersonAddress( this, address );
        addresses.add( personAddress );
        address.getOwners().add( personAddress );
    

    public void removeAddress(Address address) 
        PersonAddress personAddress = new PersonAddress( this, address );
        address.getOwners().remove( personAddress );
        addresses.remove( personAddress );
        personAddress.setPerson( null );
        personAddress.setAddress( null );
    


@Entity(name = "PersonAddress")
public static class PersonAddress implements Serializable 

    @Id
    @ManyToOne
    private Person person;

    @Id
    @ManyToOne
    private Address address;

    // ...


@Entity(name = "Address")
public static class Address implements Serializable 

    @Id
    @GeneratedValue
    private Long id;

    private String street;

    @Column(name = "`number`")
    private String number;

    private String postalCode;

    @OneToMany(
        mappedBy = "address",
        cascade = CascadeType.ALL,
        orphanRemoval = true
    )
    private List<PersonAddress> owners = new ArrayList<>();

    // ....

我的意思是,如果我要制作一个类图,它看起来不会与这些实体完全一样,因为您必须为 Hibernate 完成一些条件,以便它可以使用 ORM 将它们映射到表。例如,在假设的类图中,Person 将有一个 Address 列表,而不是 Hibernate 在这种情况下建议的 PersonAddress 列表(用于映射性能)。

我的问题是我是否应该将Person 模型分成两个独立的实体,一个用于业务逻辑层(服务),一个用于数据访问层(存储库)。就个人而言,我认为这不是问题,因为 Hibernate 帮助我忽略了所有的表创建,但也许这不是一个好习惯,我应该将它分成两个不同的实体。

【问题讨论】:

【参考方案1】:

一般来说,我使用 API 模型和实体模型。 api模型用于在服务之间交换数据,实体对象用于持久化数据。这使您的架构更加灵活。如果您的业务逻辑中的某些内容发生更改,实体不会自动受到影响。此外,有时您通过客户端获取数据并且不想公开整个数据库对象。因此,您可以只提供您需要的字段并在实体对象中完成其余部分。这也是静态代码分析 sonaqube 推荐的。

【讨论】:

【参考方案2】:

您所指的是持久性模型和业务/域模型之间的分裂,这很常见。人们通常将此称为 DTO 方法。 这种方法有很多好处,如果你实施得当,几乎没有缺点。

可以使用Blaze-Persistence Entity-Views 有效地实现它,这是一个位于 JPA/Hibernate 之上的库,它将透明地为您处理所有获取。查看spring data integration,它可以让您快速入门,或者通过archetype 试用示例项目以感受其中的好处。

【讨论】:

以上是关于Spring Boot RESTful API 的层设计及其实体映射的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot构建RESTful API与单元测试

Spring Boot构建RESTful API

Spring Boot - Restful API

??????spring boot??????restful api

Spring Boot整合Swagger2构建RESTful API

使用 RESTful 登录 API 验证我的 Spring Boot 应用程序