Java Spring REST API 处理许多可选参数 [英] Java Spring REST API Handling Many Optional Parameters

查看:23
本文介绍了Java Spring REST API 处理许多可选参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在搞一个 Spring Boot REST API 项目以用于教学目的.我有一个相当大的表,其中 22 列加载到 MySQL 数据库中,并试图让用户能够按多列过滤结果(在本示例中假设为 6).

I'm currently messing around with a Spring Boot REST API project for instructional purposes. I have a rather large table with 22 columns loaded into a MySQL database and am trying to give the user the ability to filter the results by multiple columns (let's say 6 for the purposes of this example).

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

I am currently extending a Repository and have initialized methods such as findByParam1 and findByParam2 and findByParam1OrderByParam2Desc and etc. and have verified that they are working as intended. My question to you guys is the best way to approach allowing the user the ability to leverage all 6 optional RequestParams without writing a ridiculous amount of conditionals/repository method variants. For example, I want to give the user the ability to hit url home/get-data/ to get all results, home/get-data?param1=xx to filter based on param1, and potentially, home/get-data?param1=xx&param2=yy...&param6=zz to filter on all the optional parameters.

作为参考,这是我的控制器的相关块的样子(大致).

For reference, here is what the relevant chunk of my controller looks like (roughly).

@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 等于我要过滤的字段/列的数量.有没有更好的方法来处理这个问题,也许我正在就地"过滤存储库,这样我就可以在检查地图以查看用户确实填充了哪些过滤器时简单地过滤就地"?

My issue so far is that the way I am proceeding about this means that I will basically need n! amount of methods in my repository to support this functionality with n equalling the amount of fields/columns I want to filter on. Is there a better way to approach handling this, perhaps where I am filtering the repository 'in-place' so I can simply filter 'in-place' as I check the Map to see what filters the user did indeed populate?

所以我目前正在实施一个可能与 J. West 下面的评论有关的hacky"解决方案.我假设用户将在请求 URL 中指定所有 n 个参数,如果他们不指定(例如,他们指定 p1-p4 但不指定 p5 和 p6),我生成的 SQL 只将语句与 LIKE '%' 匹配未包含的参数.它看起来像......

So I'm currently implementing a 'hacky' solution that might be related to J. West's comment below. I assume that the user will be specifying all n parameters in the request URL and if they do not (for example, they specify p1-p4 but not p5 and p6) I generate SQL that just matches the statement to LIKE '%' for the non-included params. It would look something like...

@Query("select u from User u where u.p1 = :p1 and u.p2 = :p2 ... and u.p6 = :p6") 
List<User> findWithComplicatedQueryAndSuch;

在控制器中,我会检测映射中的 p5 和 p6 是否为空,如果是,只需将它们更改为字符串 '%'.我确信有一种更精确和直观的方法可以做到这一点,尽管我还没有找到任何类似的东西.

and in the Controller, I would detect if p5 and p6 were null in the Map and if so, simply change them to the String '%'. I'm sure there is a more precise and intuitive way to do this, although I haven't been able to find anything of the sort yet.

推荐答案

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

You can do this easily with a JpaSpecificationExecutor and a custom Specification: https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/

我会将 HashMap 替换为包含所有可选 get 参数的 DTO,然后基于该 DTO 构建规范,显然您也可以保留 HashMap 并基于它构建规范.

I would replace the HashMap with a DTO containing all optional get params, then build the specifications based on that DTO, obviously you can also keep the HashMap and build the specification based on it.

基本上:

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
}

和控制器:

@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>
{
}

只是一个改编自公司代码的简单例子,你懂的!

Just a quick example adapted from company code, you get the idea!

这篇关于Java Spring REST API 处理许多可选参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆