自定义数据源 25.02
当您的数据存储在应用程序之外 - 在REST API、数据库或外部服务中 - 您需要创建自定义的存储库实现。DelegatingRepository 类通过允许您提供函数而非实现一个完整的类,使这一过程变得简单。
DelegatingRepository 的工作原理
DelegatingRepository 是一个具体类,扩展了 AbstractQueryableRepository。您不需要实现抽象方法,而是在构造函数中提供三个函数:
DelegatingRepository<User, UserFilter> repository = new DelegatingRepository<>(
// 1. 查找函数 - 返回过滤/排序/分页数据
criteria -> userService.findUsers(criteria),
// 2. 计数函数 - 返回过滤器的总数
criteria -> userService.countUsers(criteria),
// 3. 通过键查找函数 - 通过ID返回单个实体
userId -> userService.findById(userId)
);
每个函数都有特定的用途:
查找函数接收一个 RepositoryCriteria 对象,其中包含:
getFilter()- 您的自定义过滤器对象(类型参数F)getOffset()和getLimit()- 用于分页getOrderCriteria()- 排序规则的列表
该函数必须返回一个符合条件的实体流 Stream<T>。如果没有找到匹配项,流可以为空。
计数函数也接收条件,但通常只使用过滤部分。它返回匹配实体的总数,忽略分页。这用于UI组件显示总结果或计算页面。
通过键查找函数接收一个实体键(通常是ID)并返回一个 Optional<T>。如果实体不存在,返回 Optional.empty()。
REST API 示例
在与REST API集成时,您需要将存储库条件转换为HTTP请求参数。首先,定义一个与您的API查询能力匹配的过滤器类:
public class UserFilter {
private String department;
private String status;
// getters and setters...
}
此过滤器类表示您的API接受的搜索参数。存储库将在应用过滤时将此类的实例传递给您的函数。
创建一个存储库,其中的函数将条件转换为API调用:
DelegatingRepository<User, UserFilter> apiRepository = new DelegatingRepository<>(
// 查找用户
criteria -> {
Map<String, String> params = buildParams(criteria);
List<User> users = restClient.get("/users", params);
return users.stream();
},
// 计数用户
criteria -> {
Map<String, String> filterParams = buildFilterParams(criteria.getFilter());
return restClient.getCount("/users/count", filterParams);
},
// 通过ID查找
userId -> restClient.getById("/users/" + userId)
);
buildParams() 方法将从条件中提取值并转换为查询参数,如 ?department=Sales&status=active&offset=20&limit=10。您的REST客户端随后执行实际的HTTP请求并反序列化响应。
数据库示例
数据库集成遵循类似的模式,但将条件转换为SQL查询。关键区别在于处理SQL生成和参数绑定:
DelegatingRepository<Customer, CustomerFilter> dbRepository = new DelegatingRepository<>(
// 根据过滤器、排序、分页查询
criteria -> {
String sql = buildQuery(criteria);
return jdbcTemplate.queryForStream(sql, rowMapper);
},
// 计数匹配的记录
criteria -> {
String countSql = buildCountQuery(criteria.getFilter());
return jdbcTemplate.queryForObject(countSql, Integer.class);
},
// 通过主键查找
customerId -> {
String sql = "SELECT * FROM customers WHERE id = ?";
return jdbcTemplate.queryForObject(sql, rowMapper, customerId);
}
);
buildQuery() 方法将构建类似于以下的SQL:
SELECT * FROM customers
WHERE status = ? AND region = ?
ORDER BY created_date DESC, name ASC
LIMIT ? OFFSET ?