考虑到PetClinic Res API的经典示例,我有2个REST调用:
第一次调用返回所有所有者(详细信息),第二次返回特定所有者的详细信息。
在两种情况下,每个所有者对象都包含所有者基本详细信息以及宠物列表,每个 pet 进一步包含访问 >
如果我想返回没有宠物的所有者列表并访问我的 findAll (第一个API)调用的详细信息以及第二次调用的完整详细信息,那是最好的方法?
我已经研究了自定义序列化程序的实现,但是我不想将其应用于实体级别。如果我使用杰克逊手动准备JSON,它仍然会进行数据库调用!我基本上是想避免在进行第一次REST调用
时不必要的数据库获取答案 0 :(得分:1)
您需要将数据库对象与返回的对象分开。由于宠物位于LAZY OneToMany关联的后面,因此当您在findAll中获得列表时,它们将不会被获取...但是当您将实体对象传递到Serailizing库中时,它们将被获取,(大概)将调用给定对象的每个getter
因此,现在您要么以某种方式修改序列化过程,以使其不会调用错误的getter并触发提取...,或者您使一个映射器将实体转换为仅具有所需字段的DTO,然后对其进行序列化。您可以使用现有的映射库来简化该过程(即mapstruct)。
您甚至可以将这些DTO用作API模型的应用程序的适当部分-将前端API与数据库分离,以便您可以更轻松地对其进行外观更改(不存储在数据库中的字段,不存储在数据库中的重命名)破坏您的JPQL,也许会生成文档)
答案 1 :(得分:0)
如果您确实想这样做,我认为您需要返回Object而不是确切的Owner实体。 并且,如果您也希望DB层也高效(仅获取所需的属性),则应创建一个函数,该函数接受一个List,该List包含所需的属性,并且该函数将返回Object然后将其发送给您的API。 因此,在您的情况下,将是这样。
//DAO
public List<Object> findAll(List<String> fieldsNeeded) {
String hql = "SELECT ";
for (String field: fieldsNeeded) {
hql += field + " ";
}
hql += "FROM //your table name";
// create query and all those stuff;
// return the result
}
//controller
@GetMapping("/petclinic/owners")
public List<Object> getOwners(//your parameters) {
// (lets skip service layer)
// then you need to prepare the list of needed properties
// including checking if the properties do exsit in the table etc...
// which also returns an object;
List<String> fieldsNeeded = new ArrayList<String>();
// add all the fieldnames;
return ownerDao.findAll(fieldsNeeded);
}
此外,如果您有一个包含大量属性的巨大表,则应使用StringBuilder中的.append()函数更改该“ hql + = ...”,并且如果所需的属性量太大,则您相反,应该告诉函数不要获取通过的属性,而不要获取未通过的属性。
所以我只是发现您实际上无法使用REST返回对象。 因此,如果您需要发送jsut一个对象,我建议您做的是在获得DAO层的结果后,在Service层中添加一个注入步骤,将Object中的所有字段设置为Entity,它应该可以工作很好。