Java Spring REST API处理许多可选参数

pur*_*doo 6 java mysql rest spring-data-jpa spring-boot

我目前正忙着使用Spring Boot REST API项目进行教学.我有一个相当大的表,其中22列被加载到MySQL数据库中,我试图让用户能够按多列过滤结果(假设这个例子的目的是6).

我目前正在扩展一个Repository并初始化了一些方法,例如findByParam1和findByParam2以及findByParam1OrderByParam2Desc等,并且已经验证它们是按预期工作的.我向你们提出的问题是最好的方法,允许用户能够利用所有6个可选的RequestParams,而无需编写大量的条件/存储库方法变体.例如,我想让用户能够点击url home/get-data /获取所有结果,home/get-data?param1 = xx根据param1进行过滤,可能还有home/get-data?param1 = xx¶m2 = yy ...¶m6 = zz来过滤所有可选参数.

作为参考,这是我的控制器的相关块(粗略地).

@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();
}
Run Code Online (Sandbox Code Playgroud)

到目前为止我的问题是我正在进行的这种方式意味着我基本上需要n!我的存储库中用于支持此功能的方法数量,n等于我要过滤的字段/列数量.有没有更好的方法来处理这个问题,也许我正在过滤存储库'就地'所以我可以简单地过滤'就地',因为我检查地图以查看用户确实填充了哪些过滤器?

编辑:所以我现在正在实施一个'hacky'解决方案,可能与J. West的评论有关.我假设用户将在请求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;
Run Code Online (Sandbox Code Playgroud)

在Controller中,我会检测地图中p5和p6是否为空,如果是,则只需将它们更改为字符串'%'即可.我确信有更精确和直观的方法来做到这一点,虽然我还没有找到任何类型的东西.

dav*_*v1d 6

您可以使用JpaSpecificationExecutor和自定义轻松完成此操作Specification:https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/

我会用包含所有可选get参数的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
}
Run Code Online (Sandbox Code Playgroud)

和控制器:

@RequestMapping(value = "/{ticket}/count", method = RequestMethod.GET)
public long getItemsCount(
    @PathVariable String ticket,
    VehicleFilter filter,
    HttpServletRequest request
) throws Exception
{
    return vehicleService.getCount(filter);
}
Run Code Online (Sandbox Code Playgroud)

服务:

@Override
public long getCount(VehicleFilter filter)
{
    return vehicleRepository.count(filter);
}
Run Code Online (Sandbox Code Playgroud)

库:

@Repository
public interface VehicleRepository extends JpaRepository<Vehicle, Integer>, JpaSpecificationExecutor<Vehicle>
{
}
Run Code Online (Sandbox Code Playgroud)

只是一个根据公司代码改编的简单示例,您就会明白!