Spring 嵌入式实体的数据剩余投影
Spring Data Rest projection for Embedded Entities
假设我有以下实体:
@Entity
public class Registration {
@ManyToOne
private Student student;
//getters, setters
}
@Entity
public class Student {
private String id;
private String userName;
private String name;
private String surname;
//getters, setters
}
@Projection(name="minimal", types = {Registration.class, Student.class})
public interface RegistrationProjection {
String getUserName();
Student getStudent();
}
我正在尝试创建以下 JSON 表示,因此当我使用 http://localhost:8080/api/registrations?projection=minimal
时,我不需要所有用户数据:
{
"_links": {
"self": {
"href": "http://localhost:8080/api/registrations{?page,size,sort,projection}",
}
},
"_embedded": {
"registrations": [
{
"student": {
"userName": "user1"
}
}
],
"_links": {
"self": {
"href": "http://localhost:8080/api/registrations/1{?projection}",
}
}
}
}
然而,我创建的投影出现异常(它在没有 getUserName() 语句的情况下工作。显然我以错误的方式定义了接口...但是这样做的正确方法是什么?
编辑:例外情况如下
Invalid property 'userName' of bean class [com.test.Registration]:
Could not find field for property during fallback access! (through reference chain: org.springframework.hateoas.PagedResources["_embedded"]
->java.util.UnmodifiableMap["registrations"]->java.util.ArrayList[0]->org.springframework.data.rest.webmvc.json.["content"]
->$Proxy119["userName"])</div></body></html>
如例外所述,userName
不是 Registration
实体的成员。这就是它失败的原因。但我想你已经明白了。
首先,如果您只是想为 Registration
公开其投影,您应该首先更改以下行:
@Projection(name="minimal", types = {Registration.class, Student.class})
通过设置 types = {Registration.class, Student.class}
,您要求 Spring Data Rest 在 Registration.class
和 Student.class
上应用投影。这可能会导致一些问题,因为根据类型的不同,您不应该拥有相同的 member/methods。实际上 types
必须有一个共同的祖先。
否则,对于主要问题,您应该尝试 virtual projections 以下方法(我没有尝试您的示例,但我希望它应该有效):
@Projection(name="minimal", types = {Registration.class})
public interface RegistrationProjection {
@Value("#{target.getStudent().getUserName()}")
String getUserName();
}
我不知道你是否熟悉SPeL但是前面的代码只是创建了一个getUserName
就像this.getStudent().getUserName()
因为target
绑定在实例对象上(参见文档)。
假设我有以下实体:
@Entity
public class Registration {
@ManyToOne
private Student student;
//getters, setters
}
@Entity
public class Student {
private String id;
private String userName;
private String name;
private String surname;
//getters, setters
}
@Projection(name="minimal", types = {Registration.class, Student.class})
public interface RegistrationProjection {
String getUserName();
Student getStudent();
}
我正在尝试创建以下 JSON 表示,因此当我使用 http://localhost:8080/api/registrations?projection=minimal
时,我不需要所有用户数据:
{
"_links": {
"self": {
"href": "http://localhost:8080/api/registrations{?page,size,sort,projection}",
}
},
"_embedded": {
"registrations": [
{
"student": {
"userName": "user1"
}
}
],
"_links": {
"self": {
"href": "http://localhost:8080/api/registrations/1{?projection}",
}
}
}
}
然而,我创建的投影出现异常(它在没有 getUserName() 语句的情况下工作。显然我以错误的方式定义了接口...但是这样做的正确方法是什么?
编辑:例外情况如下
Invalid property 'userName' of bean class [com.test.Registration]:
Could not find field for property during fallback access! (through reference chain: org.springframework.hateoas.PagedResources["_embedded"]
->java.util.UnmodifiableMap["registrations"]->java.util.ArrayList[0]->org.springframework.data.rest.webmvc.json.["content"]
->$Proxy119["userName"])</div></body></html>
如例外所述,userName
不是 Registration
实体的成员。这就是它失败的原因。但我想你已经明白了。
首先,如果您只是想为 Registration
公开其投影,您应该首先更改以下行:
@Projection(name="minimal", types = {Registration.class, Student.class})
通过设置 types = {Registration.class, Student.class}
,您要求 Spring Data Rest 在 Registration.class
和 Student.class
上应用投影。这可能会导致一些问题,因为根据类型的不同,您不应该拥有相同的 member/methods。实际上 types
必须有一个共同的祖先。
否则,对于主要问题,您应该尝试 virtual projections 以下方法(我没有尝试您的示例,但我希望它应该有效):
@Projection(name="minimal", types = {Registration.class})
public interface RegistrationProjection {
@Value("#{target.getStudent().getUserName()}")
String getUserName();
}
我不知道你是否熟悉SPeL但是前面的代码只是创建了一个getUserName
就像this.getStudent().getUserName()
因为target
绑定在实例对象上(参见文档)。