Spring REST api - 外键 ID 而不是整个对象
Spring REST api - foreign key ID instead of entire object
我的 REST api GET 方法返回的 Json 有问题。
这就是我的实体的样子:
@Entity
public class Employee {
...
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "department_id", nullable = true)
private Department department;
}
@Entity
public class Department {
...
@OneToMany(mappedBy = "department", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JsonBackReference
private Set<Employee> employees;
}
这是我得到的答案,当我试图通过其 ID 获取员工时:
{
"id": 1,
"surname": "smith",
"department": {
"id": 1,
"name": "HR",
"room": "13"
}
}
现在,我只想获取简单的 ID:"department_id": 1
,,而不是整个 Department 对象,但我不知道该怎么做。
第二个问题:REST api中这种情况下的good practise
是什么?我应该保持原样吗?只公开 id(我问你怎么做);或者使用 DTO 而根本不显示它?
此外,无论如何我要添加_链接到这个用户的部门,在这种情况下我认为只留下 id 应该没问题(如果我错了请告诉我)。
期待您的回答!
一个好的做法是定义一个 DTO 来表示您的 API 公开的数据。
这应该与您的域(员工)分离,因为它将为您提供更大的灵活性,就像您想要实现的那样。
class EmployeeDTO extends RepresentationModel {
private long id;
private String surname;
private long departmentId;
// getters and setters
}
这应该有效。当然,您需要将 Employee 实体映射到 EmployeeDTO。 RepresentationModel 包含您希望用于 HATEOAS 的 _links 属性(例如,查看
https://www.baeldung.com/spring-hateoas-tutorial)
关于从您的数据库中公开 ID,我认为不这样做的一个很好的理由是您免费提供了有关您的数据库大小的信息,而这可能是您不希望的。甚至可以从中获得更多信息。
在这里您可以找到关于该主题的很好的讨论:
Exposing database IDs - security risk?
我建议看一下 UUID,它是一个通用的唯一字母数字标识符,不会公开有关您的数据的信息。
关于 UUID 的更多信息:https://www.baeldung.com/java-uuid
@JsonIgnoreProperties
要在不更改任何实现的情况下仅获取部门 ID,您可以使用 @JsonIgnoreProperties({"name", "room"})
如下
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "department_id", nullable = true)
@JsonIgnoreProperties({"name", "room"})
private Department department;
这将响应以下
[
{
"id": 1,
"surname": "smith",
"department": {
"id": 1
}
}
]
您可能还想探索实现相同目的的其他方法here
最佳实践
我们永远不应该公开和 return 我们的模态和实体作为对 API 的响应。我们可以创建 DTOs/DAOs 来接收和传输对象和数据。您还可以使用 mappers 将 entity 转换为 DTO 并将 DTO 转换为 entity。
在 DTO 的情况下,您可以只包含部门 ID,并且可以在需要时使用存储库获取对象。
我的 REST api GET 方法返回的 Json 有问题。
这就是我的实体的样子:
@Entity
public class Employee {
...
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "department_id", nullable = true)
private Department department;
}
@Entity
public class Department {
...
@OneToMany(mappedBy = "department", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JsonBackReference
private Set<Employee> employees;
}
这是我得到的答案,当我试图通过其 ID 获取员工时:
{
"id": 1,
"surname": "smith",
"department": {
"id": 1,
"name": "HR",
"room": "13"
}
}
现在,我只想获取简单的 ID:"department_id": 1
,,而不是整个 Department 对象,但我不知道该怎么做。
第二个问题:REST api中这种情况下的good practise
是什么?我应该保持原样吗?只公开 id(我问你怎么做);或者使用 DTO 而根本不显示它?
此外,无论如何我要添加_链接到这个用户的部门,在这种情况下我认为只留下 id 应该没问题(如果我错了请告诉我)。
期待您的回答!
一个好的做法是定义一个 DTO 来表示您的 API 公开的数据。 这应该与您的域(员工)分离,因为它将为您提供更大的灵活性,就像您想要实现的那样。
class EmployeeDTO extends RepresentationModel {
private long id;
private String surname;
private long departmentId;
// getters and setters
}
这应该有效。当然,您需要将 Employee 实体映射到 EmployeeDTO。 RepresentationModel 包含您希望用于 HATEOAS 的 _links 属性(例如,查看 https://www.baeldung.com/spring-hateoas-tutorial)
关于从您的数据库中公开 ID,我认为不这样做的一个很好的理由是您免费提供了有关您的数据库大小的信息,而这可能是您不希望的。甚至可以从中获得更多信息。
在这里您可以找到关于该主题的很好的讨论: Exposing database IDs - security risk?
我建议看一下 UUID,它是一个通用的唯一字母数字标识符,不会公开有关您的数据的信息。 关于 UUID 的更多信息:https://www.baeldung.com/java-uuid
@JsonIgnoreProperties
要在不更改任何实现的情况下仅获取部门 ID,您可以使用 @JsonIgnoreProperties({"name", "room"})
如下
@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "department_id", nullable = true)
@JsonIgnoreProperties({"name", "room"})
private Department department;
这将响应以下
[
{
"id": 1,
"surname": "smith",
"department": {
"id": 1
}
}
]
您可能还想探索实现相同目的的其他方法here
最佳实践
我们永远不应该公开和 return 我们的模态和实体作为对 API 的响应。我们可以创建 DTOs/DAOs 来接收和传输对象和数据。您还可以使用 mappers 将 entity 转换为 DTO 并将 DTO 转换为 entity。
在 DTO 的情况下,您可以只包含部门 ID,并且可以在需要时使用存储库获取对象。