介绍
假设在带有Spring Data Rest模块的Spring Boot应用程序中,有两个主要实体(例如Student
和LegalGuardian
)。它们通过Guardianship
由嵌入式ID(例如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, setters, equals and hashCode
}
}
对于所有这些实体,存在单独的存储库:
StudentRepository : JpaRepository<Student, Long>
,LegalGuardianRepository : JpaRepository<LegalGuardian, Long>
和GuardianshipRepository : JpaRepository<Guardianship, Guardianship.GuardianshipId>
要查询单个Guardianship
S的GuardianshipRepository
通过REST的ID,也是一个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",
"_links" : {
"self" : {
"href" : "http://localhost:8080/guardianships/1_2"
},
"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",
"new" : false
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/guardianships/1_2"
},
"guardianship" : {
"href" : "http://localhost:8080/guardianships/1_2"
}
}
}
举一个完整的例子,我创建了一个可执行的示例项目。
经过一些搜索,我发现了两种将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"
}
}
}
优点:
带有:
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",
"_links" : {
"self" : {
"href" : "http://localhost:8080/guardianships/1_2"
},
"guardianship" : {
"href" : "http://localhost:8080/guardianships/1_2"
}
}
}
优点:
带有:
guardianshipId
链接周围的-wrapper)编辑
对于方式二:要公开所有使用嵌入式(复合)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);
}
});
}
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句