Spring-boot、one-to-many 关系处于同一 object(parent 和子女)
Spring-boot, one-to-many relationship in the same object (parent & childrens)
在我的 spring-boot 项目中,我想创建具有 parent 和 children 值的 object "Menu":
- 菜单可以有 一个 parent 元素
- 菜单可以有 一个或多个 childrens 元素
实体 Menu.java
@Entity
@Data @AllArgsConstructor @NoArgsConstructor
public class Menu implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany
private List<Menu> childrens;
@ManyToOne
private Menu parent;
}
MenuDAO.java
@RepositoryRestResource
public interface MenuDAO extends JpaRepository<Menu, Long> {
}
DemoApplication.java 为使用 CommandLine Runner 进行测试添加数据:
- 菜单 1 (parent)
- 子菜单 1(children 属于 菜单 1)
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
@Autowired
MenuDAO menuDAO;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
Menu m1 = menuDAO.save(new Menu(null,"Menu1",null,null));
Menu m2 = menuDAO.save(new Menu(null,"Sub-Menu1",null,m1));
}
}
但是当我通过 rest 服务调用获取 parent 元素时,我得到了这个结果 http://localhost:9090/menus/1:
{
"name" : "Menu1",
"_links" : {
"self" : {
"href" : "http://localhost:9090/menus/1"
},
"menu" : {
"href" : "http://localhost:9090/menus/1"
},
"childrens" : {
"href" : "http://localhost:9090/menus/1/childrens"
},
"parent" : {
"href" : "http://localhost:9090/menus/1/parent"
}
}
}
但我的要求是获取以下 JSON 格式的数据:
{
"name" : "Menu1",
"childrens" : [{
"name" : "Menu2"
}],
"parent" : NULL,
"_links" : {
"self" : {
"href" : "http://localhost:9090/menus/1"
},
"menu" : {
"href" : "http://localhost:9090/menus/1"
},
"childrens" : {
"href" : "http://localhost:9090/menus/1/childrens"
},
"parent" : {
"href" : "http://localhost:9090/menus/1/parent"
}
}
}
有什么建议吗?
阅读 Spring 数据 REST 参考指南
的文档后,我终于有了答案
Spring Data REST 呈现您导出的域模型的默认视图。但如果出于各种原因我们可能需要更改该模型的视图,我们可以使用预测和摘录来提供简化和简化的资源视图。
在我的例子中,第一步是创建我的实体 Prejection 界面 Menu 并选择我想在 JSON响应。
@Projection(name = "MenuProjection", types = Menu.class)
public interface MenuProjection {
Long getId();
String getName();
Menu getParent();
List<Menu> getChildrens();
}
第二步是添加属性 excerptProjection of RepositroyRestRessource annotation with Menu.Class 我的 MenuRepository 界面中的值。
@RepositoryRestResource(excerptProjection = MenuProjection.class)
JSON 之前的响应
{
"_embedded" : {
"menus" : [ {
"name" : "cat_test1",
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus/1"
},
"menu" : {
"href" : "http://localhost:9292/menus/1"
},
"parent" : {
"href" : "http://localhost:9292/menus/1/parent"
},
"pages" : {
"href" : "http://localhost:9292/menus/1/pages"
},
"children" : {
"href" : "http://localhost:9292/menus/1/children"
}
}
}, {
"name" : "cat_test2",
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus/2"
},
"menu" : {
"href" : "http://localhost:9292/menus/2"
},
"parent" : {
"href" : "http://localhost:9292/menus/2/parent"
},
"pages" : {
"href" : "http://localhost:9292/menus/2/pages"
},
"children" : {
"href" : "http://localhost:9292/menus/2/children"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus{?page,size,sort}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:9292/profile/menus"
},
"search" : {
"href" : "http://localhost:9292/menus/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}
JSON 投影
{
"_embedded" : {
"menus" : [ {
"name" : "cat_test1",
"parent" : null,
"id" : 1,
"childrens" : [ {
"name" : "cat_test2"
} ],
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus/1"
},
"menu" : {
"href" : "http://localhost:9292/menus/1{?projection}",
"templated" : true
},
"childrens" : {
"href" : "http://localhost:9292/menus/1/childrens{?projection}",
"templated" : true
},
"parent" : {
"href" : "http://localhost:9292/menus/1/parent{?projection}",
"templated" : true
},
"pages" : {
"href" : "http://localhost:9292/menus/1/pages"
}
}
}, {
"name" : "cat_test2",
"parent" : {
"name" : "cat_test1",
},
"id" : 2,
"childrens" : [ ],
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus/2"
},
"menu" : {
"href" : "http://localhost:9292/menus/2{?projection}",
"templated" : true
},
"childrens" : {
"href" : "http://localhost:9292/menus/2/childrens{?projection}",
"templated" : true
},
"parent" : {
"href" : "http://localhost:9292/menus/2/parent{?projection}",
"templated" : true
},
"pages" : {
"href" : "http://localhost:9292/menus/2/pages"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus{?page,size,sort,projection}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:9292/profile/menus"
},
"search" : {
"href" : "http://localhost:9292/menus/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}
因此,使用 Spring 数据投影,我们可以在实体资源中包含数据字段。
在我的 spring-boot 项目中,我想创建具有 parent 和 children 值的 object "Menu":
- 菜单可以有 一个 parent 元素
- 菜单可以有 一个或多个 childrens 元素
实体 Menu.java
@Entity
@Data @AllArgsConstructor @NoArgsConstructor
public class Menu implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany
private List<Menu> childrens;
@ManyToOne
private Menu parent;
}
MenuDAO.java
@RepositoryRestResource
public interface MenuDAO extends JpaRepository<Menu, Long> {
}
DemoApplication.java 为使用 CommandLine Runner 进行测试添加数据:
- 菜单 1 (parent)
- 子菜单 1(children 属于 菜单 1)
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
@Autowired
MenuDAO menuDAO;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
Menu m1 = menuDAO.save(new Menu(null,"Menu1",null,null));
Menu m2 = menuDAO.save(new Menu(null,"Sub-Menu1",null,m1));
}
}
但是当我通过 rest 服务调用获取 parent 元素时,我得到了这个结果 http://localhost:9090/menus/1:
{
"name" : "Menu1",
"_links" : {
"self" : {
"href" : "http://localhost:9090/menus/1"
},
"menu" : {
"href" : "http://localhost:9090/menus/1"
},
"childrens" : {
"href" : "http://localhost:9090/menus/1/childrens"
},
"parent" : {
"href" : "http://localhost:9090/menus/1/parent"
}
}
}
但我的要求是获取以下 JSON 格式的数据:
{
"name" : "Menu1",
"childrens" : [{
"name" : "Menu2"
}],
"parent" : NULL,
"_links" : {
"self" : {
"href" : "http://localhost:9090/menus/1"
},
"menu" : {
"href" : "http://localhost:9090/menus/1"
},
"childrens" : {
"href" : "http://localhost:9090/menus/1/childrens"
},
"parent" : {
"href" : "http://localhost:9090/menus/1/parent"
}
}
}
有什么建议吗?
阅读 Spring 数据 REST 参考指南
的文档后,我终于有了答案
Spring Data REST 呈现您导出的域模型的默认视图。但如果出于各种原因我们可能需要更改该模型的视图,我们可以使用预测和摘录来提供简化和简化的资源视图。
在我的例子中,第一步是创建我的实体 Prejection 界面 Menu 并选择我想在 JSON响应。
@Projection(name = "MenuProjection", types = Menu.class)
public interface MenuProjection {
Long getId();
String getName();
Menu getParent();
List<Menu> getChildrens();
}
第二步是添加属性 excerptProjection of RepositroyRestRessource annotation with Menu.Class 我的 MenuRepository 界面中的值。
@RepositoryRestResource(excerptProjection = MenuProjection.class)
JSON 之前的响应
{
"_embedded" : {
"menus" : [ {
"name" : "cat_test1",
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus/1"
},
"menu" : {
"href" : "http://localhost:9292/menus/1"
},
"parent" : {
"href" : "http://localhost:9292/menus/1/parent"
},
"pages" : {
"href" : "http://localhost:9292/menus/1/pages"
},
"children" : {
"href" : "http://localhost:9292/menus/1/children"
}
}
}, {
"name" : "cat_test2",
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus/2"
},
"menu" : {
"href" : "http://localhost:9292/menus/2"
},
"parent" : {
"href" : "http://localhost:9292/menus/2/parent"
},
"pages" : {
"href" : "http://localhost:9292/menus/2/pages"
},
"children" : {
"href" : "http://localhost:9292/menus/2/children"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus{?page,size,sort}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:9292/profile/menus"
},
"search" : {
"href" : "http://localhost:9292/menus/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}
JSON 投影
{
"_embedded" : {
"menus" : [ {
"name" : "cat_test1",
"parent" : null,
"id" : 1,
"childrens" : [ {
"name" : "cat_test2"
} ],
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus/1"
},
"menu" : {
"href" : "http://localhost:9292/menus/1{?projection}",
"templated" : true
},
"childrens" : {
"href" : "http://localhost:9292/menus/1/childrens{?projection}",
"templated" : true
},
"parent" : {
"href" : "http://localhost:9292/menus/1/parent{?projection}",
"templated" : true
},
"pages" : {
"href" : "http://localhost:9292/menus/1/pages"
}
}
}, {
"name" : "cat_test2",
"parent" : {
"name" : "cat_test1",
},
"id" : 2,
"childrens" : [ ],
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus/2"
},
"menu" : {
"href" : "http://localhost:9292/menus/2{?projection}",
"templated" : true
},
"childrens" : {
"href" : "http://localhost:9292/menus/2/childrens{?projection}",
"templated" : true
},
"parent" : {
"href" : "http://localhost:9292/menus/2/parent{?projection}",
"templated" : true
},
"pages" : {
"href" : "http://localhost:9292/menus/2/pages"
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://localhost:9292/menus{?page,size,sort,projection}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:9292/profile/menus"
},
"search" : {
"href" : "http://localhost:9292/menus/search"
}
},
"page" : {
"size" : 20,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}
因此,使用 Spring 数据投影,我们可以在实体资源中包含数据字段。