Angular 正确地使用链接对象对支柱进行编组
TL;博士强> 在Angular 2.x+Spring Data REST+Spring Boot 1.4应用程序中,如何定义Spring可以将哪些JSON对象引用解析到域模型中 详细信息 例如,如果一本食谱包含同时创建的Angular 正确地使用链接对象对支柱进行编组,angular,typescript,spring-data-rest,angular2-forms,Angular,Typescript,Spring Data Rest,Angular2 Forms,TL;博士 在Angular 2.x+Spring Data REST+Spring Boot 1.4应用程序中,如何定义Spring可以将哪些JSON对象引用解析到域模型中 详细信息 例如,如果一本食谱包含同时创建的标签和配方,并且每个配方都引用了一个或多个标签,则表示形式可能如下所示: book: { title: 'Cook book', labels:[{ <--- array index used in labelRef below name
标签
和配方
,并且每个配方
都引用了一个或多个标签
,则表示形式可能如下所示:
book: {
title: 'Cook book',
labels:[{ <--- array index used in labelRef below
name: 'fruit',
description: 'Recipe with fruit.'
},{
name: 'vegetable',
description: 'Recipe with vegetables.'
},{
name: 'fish',
description: 'Recipe with fish.'
}],
recipes:[{
title: 'Sweet corn and onion salad',
description: 'Simple, quick, and refreshing corn salad',
labels: [{
labelRef: 1 <--- using array index as reference
}]
}]
}
Spring数据JPA+Lombok标签中的中端表示法
@Data
@Entity
@Table(name = "LABEL")
public class Label {
@Id
@Column(nullable = false)
private Long id;
private String name = "";
private String description = "";
@ManyToOne(optional=false)
@JoinColumn(name="book_id")
private Book book;
}
@Data
@Entity
@Table(name = "RECIPE")
public class Recipe {
@Id
@Column(nullable = false)
private Long id;
private String title = "";
private String description = "";
@OneToMany(cascade={CascadeType.ALL}, mappedBy="book", orphanRemoval=true)
@Column(nullable = false)
private List<Label> labels = new ArrayList<>();
@ManyToOne(optional=false)
@JoinColumn(name="book_id")
private Book book;
}
@Data
@Entity
@Table(name = "BOOK")
public class Book {
@Id
@Column(nullable = false)
private Long id;
private String title = "";
@OneToMany(cascade={CascadeType.ALL}, mappedBy="book", orphanRemoval=true)
@Column(nullable = false)
private Set<Label> labels = new HashSet<>();
@OneToMany(cascade={CascadeType.ALL}, mappedBy="book", orphanRemoval=true)
@Column(nullable = false)
private List<Recipe> recipes = new ArrayList<>();
}
配方
:
@Data
@Entity
@Table(name = "LABEL")
public class Label {
@Id
@Column(nullable = false)
private Long id;
private String name = "";
private String description = "";
@ManyToOne(optional=false)
@JoinColumn(name="book_id")
private Book book;
}
@Data
@Entity
@Table(name = "RECIPE")
public class Recipe {
@Id
@Column(nullable = false)
private Long id;
private String title = "";
private String description = "";
@OneToMany(cascade={CascadeType.ALL}, mappedBy="book", orphanRemoval=true)
@Column(nullable = false)
private List<Label> labels = new ArrayList<>();
@ManyToOne(optional=false)
@JoinColumn(name="book_id")
private Book book;
}
@Data
@Entity
@Table(name = "BOOK")
public class Book {
@Id
@Column(nullable = false)
private Long id;
private String title = "";
@OneToMany(cascade={CascadeType.ALL}, mappedBy="book", orphanRemoval=true)
@Column(nullable = false)
private Set<Label> labels = new HashSet<>();
@OneToMany(cascade={CascadeType.ALL}, mappedBy="book", orphanRemoval=true)
@Column(nullable = false)
private List<Recipe> recipes = new ArrayList<>();
}
书籍
在@RepositoryRestController
中正确地取消标记:
@Slf4j
@RepositoryRestController
public class BookRespositoryRestController {
private final BookRepository bookRepository;
private final LabelRepository labelRepository;
@RequestMapping(method = RequestMethod.POST,value = "/books")
public @ResponseBody PersistentEntityResource post(@RequestBody Book book,
PersistentEntityResourceAssembler assembler) {
Book entity = processPost(book);
return assembler.toResource(entity);
}
配方标签除外(因为域模型不知道labelRef
)
那么,如何在Angular TypeScript应用程序中构造一个合适的
labelRef
,以便书籍
也对每个配方
对象中的标签
链接进行封送处理?TL;博士强>
不幸的是,它还不受支持。但是,您可以通过一些自定义代码添加支持
细节
有两个基本问题需要解决:定义JSON对象引用;对客户端JSON对象引用进行编码,对服务器端JSON对象引用进行解码
对JSON对象的引用
有许多关于“标准”JSON引用的建议(例如,请参见“”),但截至2017年,还没有“标准”
多个请求
如果可以拆分请求,请首先提交引用的对象,然后使用唯一的相对服务器端路径作为对对象的引用:
/labels/1: {
name: 'fruit',
description: 'Recipe with fruit.'
}
/labels/2: {
name: 'vegetable',
description: 'Recipe with vegetables.'
}
/labels/3: {
name: 'fish',
description: 'Recipe with fish.'
}
然后,第二个请求使用服务器端路径:
recipes:[{
title: 'Sweet corn and onion salad',
description: 'Simple, quick, and refreshing corn salad',
labels: [{
label: '/labels/1'
}]
}]
SpringDataREST不需要任何自定义代码就支持此模型(尽管您可能需要在更复杂的模型中修补任何双向指针)
单一请求
如果需要使用单个请求,请选择JSON对象引用模型并相应地对引用进行编码。在服务器端,使用自定义代码对数据进行反整理/反序列化
Spring数据REST支持。或者,数据传输对象可以执行去marhalling
我使用了JSONPath并向服务器端的数据传输对象添加了反序列化程序:
book: {
title: 'Cook book',
labels:[{
name: 'fruit',
description: 'Recipe with fruit.'
},{
name: 'vegetable',
description: 'Recipe with vegetables.'
},{
name: 'fish',
description: 'Recipe with fish.'
}],
recipes:[{
title: 'Sweet corn and onion salad',
description: 'Simple, quick, and refreshing corn salad',
labels: [{
label: '$..labels[1]' <--- using JSONPath reference
}]
}]
}
书籍:{
标题:“烹饪书”,
标签:[{
名称:'水果',
描述:“水果食谱。”
},{
名称:'蔬菜',
描述:“蔬菜食谱。”
},{
名字:‘鱼’,
描述:“鱼的食谱。”
}],
食谱:[{
标题:“甜玉米洋葱沙拉”,
描述:“简单、快速、清爽的玉米沙拉”,
标签:[{
label:“$…labels[1]”尝试将JSON对象直接转换为持久性实体可能不是一个好主意;为什么不引入一个知道如何将一个转换为另一个的中间层呢?根据设计,Spring Data REST完成了大部分工作,@jornsharpe,(尽管我必须在processPost
中修补一些对象引用,以便正确保存实体).我可以创建一个BookJson
Java对象,它具有labelRef
数组,并以这种方式进行修补,但SDR的目的似乎是要能够做到,如果它在Angular forms端正确编码的话……但这可能要求太高了?我能看到的唯一方法是使用自定义Jackson反序列化器或将帖子拆分为两个请求,即一个用于保存初始的book+标签。然后,您可以使用指向现有标签的正确链接发布食谱。@AlanHay--在我的示例中,将其拆分为两个请求是可行的,但在引发问题的模型中,我无法这样做。我将很快为我实施的解决方案撰写一份答案。