如何解决如何将联接表中嵌入式ID的关系公开为与Spring Data Rest的链接
简介
假设在带有Spring Data Rest模块的Spring Boot应用程序中,有两个主要实体(例如Student
和LegalGuardian
)。它们通过由嵌入式ID(例如Guardianship
)标识的“关联实体”(例如GuardianshipId
)加入。此外,此嵌入的ID包含与两个主要实体的关系(不是主要实体的ID,即实体本身)。
// The Main entities
@Entity
public class Student extends AbstractPersistable<Long> {
private String name;
@OnetoMany(mappedBy = "guardianshipId.student")
private List<Guardianship> guardianships;
// getters and setters
}
@Entity
public class LegalGuardian extends AbstractPersistable<Long> {
private String name;
@OnetoMany(mappedBy = "guardianshipId.legalGuardian")
private List<Guardianship> guardianships;
// getters and setters
}
// The association entity
@Entity
public class Guardianship implements Serializable {
@EmbeddedId
private GuardianshipId guardianshipId;
private String name;
// getters,setters,equals and hashCode
@Embeddable
public static class GuardianshipId implements Serializable {
@ManyToOne
private Student student;
@ManyToOne
private LegalGuardian legalGuardian;
// getters,equals and hashCode
}
}
对于所有这些实体,都有单独的存储库:
-
StudentRepository : JpaRepository<Student,Long>
, -
LegalGuardianRepository : JpaRepository<LegalGuardian,Long>
和 -
GuardianshipRepository : JpaRepository<Guardianship,Guardianship.GuardianshipId>
要通过REST通过ID查询Guardianship
中的单个GuardianshipRepository
,还实现了BackendIdConverter
(因此,该ID类似于 {studentId} _ {legalGuardianId} )。
如果请求关联实体的存储库,则默认情况下,嵌入式id本身(及其属性)未序列化,因此响应如下所示:
$ curl "http://localhost:8080/guardianships/1_2"
{
"name" : "Cool father","_links" : {
"self" : {
"href" : "http://localhost:8080/guardianships/1_2"
},"guardianship" : {
"href" : "http://localhost:8080/guardianships/1_2"
}
}
}
问题/问题
需要做些什么,以便响应包括与包含在嵌入ID中的实体的链接,链接,如下所示:
$ curl "http://localhost:8080/guardianships/1_2"
{
"name" : "Cool father","guardianship" : {
"href" : "http://localhost:8080/guardianships/1_2"
},"student" : {
"href" : "http://localhost:8080/guardianships/1_2/student"
},"legalGuardian" : {
"href" : "http://localhost:8080/guardianships/1_2/legalGuardian"
}
}
}
(天真无味)尝试/尝试
第一个想法是通过委派嵌入的id来使嵌套关系可访问:
@Entity
public class Guardianship implements Serializable {
@EmbeddedId
private GuardianshipId guardianshipId;
public Student getStudent() { return guardianshipId.getStudent(); }
public LegalGuardian getLegalGuardian() { return guardianshipId.getLegalGuardian(); }
// the same as before
}
但是,这两个实体都已完全序列化,响应如下所示:
$ curl "http://localhost:8080/guardianships/1_2"
{
"name" : "Cool father","student" : {
"name" : "Hans","new" : false
},"legalGuardian" : {
"name" : "Peter","guardianship" : {
"href" : "http://localhost:8080/guardianships/1_2"
}
}
}
举一个完整的例子,我创建了一个可执行文件sample project。
解决方法
经过一些搜索,我发现了两种将ID关系公开为链接的可能方法:
1。提供RepresentationModelProcessor
通过实施RepresentationModelProcessor
,我可以向响应表示添加自定义链接。
@Component
public class GuardianshipProcessor
implements RepresentationModelProcessor<EntityModel<Guardianship>> {
@Autowired
private RepositoryEntityLinks repositoryEntityLinks;
@Override
public EntityModel<Guardianship> process(EntityModel<Guardianship> model) {
Link studentLink = repositoryEntityLinks.linkToItemResource(Student.class,model.getContent().getGuardianshipId().getStudent().getId());
model.add(studentLink);
Link legalGuardianLink = repositoryEntityLinks.linkToItemResource(LegalGuardian.class,model.getContent().getGuardianshipId().getLegalGuardian().getId());
model.add(legalGuardianLink);
return model;
}
}
$ curl "http://localhost:8080/guardianships/1_2"
{
"name" : "Cool father","_links" : {
"self" : {
"href" : "http://localhost:8080/guardianships/1_2"
},"guardianship" : {
"href" : "http://localhost:8080/guardianships/1_2"
},"student" : {
"href" : "http://localhost:8080/students/1"
},"legalGuardian" : {
"href" : "http://localhost:8080/legalGuardians/2"
}
}
}
Pro:
- 完全匹配所需的响应表示形式
Con:
- 更多的关联类导致
RepresentationModelProcessor
的更多实现或多或少都相同
2。配置RepositoryRestConfiguration
以公开ID的
默认情况下,Spring Data Rest不公开ID,尽管该主题是关于嵌入式ID的,但它们也是ID。这种行为是可以逐级配置的。
@Configuration
public class RepositoryConfig implements RepositoryRestConfigurer {
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(Guardianship.class);
}
}
$ curl "http://localhost:8080/guardianships/1_2"
{
"guardianshipId" : {
"_links" : {
"student" : {
"href" : "http://localhost:8080/students/1"
},"legalGuardian" : {
"href" : "http://localhost:8080/legalGuardians/2"
}
}
},"name" : "Cool father","guardianship" : {
"href" : "http://localhost:8080/guardianships/1_2"
}
}
}
Pro:
- 较少的“实现”
Con:
- (以这种形式)与原始所需的响应表示形式不完全匹配(请参见链接周围的
guardianshipId
包装器)
修改
方法二:公开使用嵌入式(复合)id的实体的所有ID,如下所示:
@Configuration
public class RepositoryRestConfig implements RepositoryRestConfigurer {
@Autowired
Repositories repositories;
@Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
repositories.forEach(repository -> {
Field embeddedIdField =
ReflectionUtils.findField(repository,new AnnotationFieldFilter(EmbeddedId.class));
if (embeddedIdField != null) {
config.exposeIdsFor(repository);
}
});
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。