出于教学目的,我目前正在处理一个 Spring Boot REST API 项目。我有一个相当大的表,其中有 22 列加载到 MySQL 数据库中,我试图让用户能够按多列过滤结果(在本示例中假设为 6)。
我目前正在扩展一个存储库,并已初始化方法,例如 findByParam1 和 findByParam2 以及 findByParam1OrderByParam2Desc 等,并已验证它们是否按预期工作。我想问你们的问题是最好的方法是让用户能够利用所有 6 个可选的 RequestParam,而无需编写大量的条件/存储库方法变体。例如,我想让用户能够点击 url home/get-data/ 获取所有结果,home/get-data?param1=xx 以基于 param1 进行过滤,并且可能, home/get-data?param1=xx¶m2=yy...¶m6=zz 过滤所有可选参数。
作为引用,下面是我的 Controller 的相关部分(大致)。
@RequestMapping(value = "/get-data", method = RequestMethod.GET)
public List<SomeEntity> getData(@RequestParam Map<String, String> params) {
String p1 = params.get("param1");
if(p1 != null) {
return this.someRepository.findByParam1(p1);
}
return this.someRepository.findAll();
}
到目前为止,我的问题是我处理这件事的方式意味着我基本上需要 n!我的存储库中支持此功能的方法数量 n 等于我要过滤的字段/列的数量。有没有更好的方法来处理这个问题,也许我正在“就地”过滤存储库,这样我就可以简单地“就地”过滤,因为我检查 map 以查看用户确实填充了哪些过滤器?
编辑:所以我目前正在实现一个可能与 J. West 下面的评论相关的“hacky”解决方案。我假设用户将在请求 URL 中指定所有 n 个参数,如果他们不指定(例如,他们指定 p1-p4 但不指定 p5 和 p6),我生成的 SQL 只匹配语句到 LIKE '%'非包含参数。它看起来像……
@Query("select u from User u where u.p1 = :p1 and u.p2 = :p2 ... and u.p6 = :p6")
List<User> findWithComplicatedQueryAndSuch;
在 Controller 中,我会检测映射中的 p5 和 p6 是否为空,如果是,只需将它们更改为字符串“%”。我确信有一种更精确、更直观的方法可以做到这一点,尽管我还没有找到任何类似的方法。
最佳答案
您可以使用 JpaSpecificationExecutor
和自定义 Specification
轻松完成此操作:https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
我会用包含所有可选获取参数的 DTO 替换 HashMap,然后基于该 DTO 构建规范,显然您也可以保留 HashMap 并基于它构建规范。
基本上:
public class VehicleFilter implements Specification<Vehicle>
{
private String art;
private String userId;
private String vehicle;
private String identifier;
@Override
public Predicate toPredicate(Root<Vehicle> root, CriteriaQuery<?> query, CriteriaBuilder cb)
{
ArrayList<Predicate> predicates = new ArrayList<>();
if (StringUtils.isNotBlank(art))
{
predicates.add(cb.equal(root.get("art"), art));
}
if (StringUtils.isNotBlank(userId))
{
predicates.add(cb.equal(root.get("userId"), userId));
}
if (StringUtils.isNotBlank(vehicle))
{
predicates.add(cb.equal(root.get("vehicle"), vehicle));
}
if (StringUtils.isNotBlank(identifier))
{
predicates.add(cb.equal(root.get("identifier"), fab));
}
return predicates.size() <= 0 ? null : cb.and(predicates.toArray(new Predicate[predicates.size()]));
}
// getter & setter
}
和 Controller :
@RequestMapping(value = "/{ticket}/count", method = RequestMethod.GET)
public long getItemsCount(
@PathVariable String ticket,
VehicleFilter filter,
HttpServletRequest request
) throws Exception
{
return vehicleService.getCount(filter);
}
服务:
@Override
public long getCount(VehicleFilter filter)
{
return vehicleRepository.count(filter);
}
存储库:
@Repository
public interface VehicleRepository extends JpaRepository<Vehicle, Integer>, JpaSpecificationExecutor<Vehicle>
{
}
只是一个根据公司代码改编的简单示例,您明白了!
关于Java Spring REST API 处理许多可选参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41068956/