Spring Data Rest 是非常快捷的实现 Rest API 的一个方案。但是,其中也有很多的坑需要处理。下面就记录下遇到的坑和处理方案:
有外键的对象如何添加/关联对象的 POST 数据格式是怎样的
假如有如下两个实体类,一个代表班级,一个代表学生,存在学生到班级的多对一单向映射:
@Entity
public class Clazz {
private String id;
// ......
}
@Entity
public class Student {
private String id;
private Clazz clazz;
// ......
@ManyToOne
@JoinColumn(name = "clazzId")
public Clazz getClazz() {
return this.clazz;
}
// ......
}
使用 Spring Data Rest 添加 student 中 class 的正确格式是:
{
// ......
"clazz": "http://localhost:8080/api/clazzes/8a818fee5667b764015667ba27520002"
// ......
}
也就是说,应该提交对应 clazz 的 link。
如何选择性的展开外键对应的对象
Spring Data Rest 的外键全部都是以 link 的方式给出,这样的方式在某些情况下很难以使用。比如,依然采用上一节的学生和班级实体,如果每个学生对应的班级都用 link 给出,那就意味着显示一个学生列表时每显示一条记录就要发一次请求以获取学生对应的班级。这样编程显然是一种灾难。那么,在返回的数据中直接嵌入 clazz 对象是合理的。Spring Data Rest 提供了这样的机制来完成这种需求,那就是投影(projection)和摘录(excerpt)。
为了让学生列表直接携带班级信息,可以采用如下实现:
@Projection(name = "inlineClazz", types = { Clazz.class })
interface InlineClazz {
// 这里写你要暴露的 class 字段的 getter 方法
Clazz getClazz(); // 这句话会让 clazz 信息以内嵌(inline)的方式出现在学生的信息中
}
@RepositoryRestResource(excerptProjection = InlineClazz.class)
interface StudentRepository extends CrudRepository<Student, String> {}
一次性获取多个特定对象
例如,用一组 ID 获取一组题目的 ID 用以生成作业,可以用下面的方式实现:
@Query("from Problem p where (p.id in (:ids))")
List<Problem> fetchByIds(@Param("ids") List<String> ids);
用下面的方式获取数据:
http://localhost:8080/rest/problems/search/fetchByIds?ids=62183,72111
这样就可以一次性取得 ID 为 62183 和 72111 的题目数据。