简体   繁体   English

在 Spring Boot 中使用查询参数的最佳方式

[英]Best way to use query params in Spring Boot

I have my JPA repository in place in code which is having multiple findByColumn method for fast lookup.我在代码中有我的 JPA 存储库,它有多个 findByColumn 方法用于快速查找。

and few findBy clause with multiple columns like findByColumn1AndColumn2AndColumn3 and many more like or combination of multiple columns like mentioned.很少有像 findByColumn1AndColumn2AndColumn3 这样的多列的 findBy 子句,还有更多像提到的多列或多列的组合。

My question is currently I expect my client to use just one endpoint for all the select/fetch operation which expect the RequestParam for each column and if he does not enter any expected column value on the request endpoint I set default as "NA" and I use if clause to identified all the incoming fields params and then call the respected repository endpoint.我的问题是目前我希望我的客户只对所有选择/获取操作使用一个端点,这些操作期望每一列的 RequestParam,如果他没有在请求端点上输入任何预期的列值,我将默认设置为“NA”,然后我使用 if 子句来识别所有传入的字段参数,然后调用受尊重的存储库端点。

I problem is now due to adding multiple new columns in the same endpoint request my if clause if become craze and I am confident enough code will not be user friendly for other team member to read.我现在的问题是由于在同一个端点中添加多个新列请求我的 if 子句如果变得狂热,我相信足够的代码不会对其他团队成员阅读友好。

Can anyone suggestion how to achieve this dynamic query part on the spring boot app.任何人都可以建议如何在 Spring Boot 应用程序上实现这个动态查询部分。

My Controller Code snippet look like this:我的控制器代码片段如下所示:

@GetMapping("/getdata")
public ResponseEntity<Page<PojoTbl>> getDataFromDB(
        @PageableDefault(page = 0, size = 20) @SortDefault.SortDefaults({
                @SortDefault(sort = "id", direction = Sort.Direction.DESC) }) Pageable pageable,
        @RequestParam(value = "col1", required = false, defaultValue = "NA") String col1,
        @RequestParam(value = "col2", required = false, defaultValue = "NA") String col2,
        @RequestParam(value = "col3", required = false, defaultValue = "NA") String col3,
        @RequestParam(value = "col4", required = false, defaultValue = "NA") String col4,
        @RequestParam(value = "col5", required = false, defaultValue = "NA") String col5,
        @RequestParam(value = "col6", required = false, defaultValue = "NA") String col6,
        @RequestParam(value = "col7", required = false, defaultValue = "NA") String col7,
        @RequestParam(value = "col8", required = false, defaultValue = "NA") String col8,
        @RequestParam(value = "id", required = false) Long id) {

    Page<PojoTbl> selectedRecords = myService.findDataFromDB(col1,
            col2, col3, col4, col5, col6, col7, id,
            col8, pageable);

    return ResponseEntity.ok(selectedRecords);

}

Back-end service layer for the same look like this:后端服务层同样看起来像这样:

public Page<PojoTbl> findDataFromDB(String col1, String col2,
        String col3, String col4, String col5, String col6,
        String col7, Long id, String col8, Pageable pageable) {

    Page<PojoTbl> selectedRecords = null;

    if (col1.equals("NA") && col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findAll(pageable);

    } else if (col1.equals("NA") && col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && col5.equals("NA") && !col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findBycol8IgnoreCase(col8, pageable);

    } else if (!col1.equals("NA") && col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findBycol1IgnoreCase(col1, pageable);

    } else if (col1.equals("NA") && col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && !col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findBycol5IgnoreCase(col5, pageable);

    } else if (col1.equals("NA") && !col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findBycol2IgnoreCase(col2, pageable);

    } else if (col1.equals("NA") && col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && !col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findBycol6IgnoreCase(col6, pageable);

    } else if (col1.equals("NA") && col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && col6.equals("NA") && !col7.equals("NA")
            && Objects.isNull(id) && col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findBycol7IgnoreCase(col7, pageable);

    } else if (col1.equals("NA") && col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && col6.equals("NA") && col7.equals("NA")
            && !Objects.isNull(id) && col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findById(id, pageable);

    } else if (!col1.equals("NA") && !col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findBycol1Andcol2IgnoreCase(col1, col2,
                pageable);

    } else if (!col1.equals("NA") && !col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && !col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findBycol1Andcol2Andcol5IgnoreCase(col1,
                col2, col5, pageable);


    } else if (!col1.equals("NA") && !col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && !col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository.findBycol1Andcol2Andcol6IgnoreCase(col1,
                col2, col6, pageable);

    } else if (!col1.equals("NA") && !col2.equals("NA") && col3.equals("NA")
            && col4.equals("NA") && !col6.equals("NA") && !col7.equals("NA")
            && Objects.isNull(id) && col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository
                .findBycol1Andcol2Andcol6Andcol7IgnoreCase(col1, col2,
                        col6, col7, pageable);

    } else if (!col1.equals("NA") && !col2.equals("NA") && !col3.equals("NA")
            && !col4.equals("NA") && !col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && !col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository
                .findBycol1Andcol2Andcol3Andcol4Andcol6IgnoreCase(
                        col1, col2, col3, col4, col6, pageable);

    } else if (!col1.equals("NA") && !col2.equals("NA") && !col3.equals("NA")
            && !col4.equals("NA") && col6.equals("NA") && col7.equals("NA")
            && Objects.isNull(id) && !col5.equals("NA") && col8.equals("NA")) {

        selectedRecords = tableJpaRepository
                .findBycol1Andcol2Andcol3Andcol4Andcol5IgnoreCase(
                        col1, col2, col3, col4, col5, pageable);

    }
    return selectedRecords;

}

See the complexity i have created in the service layer, this will going to create problem in future release as code looks messy due to many check in single if statement.看看我在服务层创建的复杂性,这将在未来的版本中产生问题,因为由于许多检查单个 if 语句,代码看起来很混乱。

Hope someone can guide me on the best practices which can reduce the code complexity here.希望有人可以指导我了解可以降低代码复杂性的最佳实践。

Though you can use specification as you were suggested in comments, you can try a custom query with @Query annotation.尽管您可以按照评论中的建议使用规范,但您可以尝试使用@Query注释进行自定义查询

public interface PersonRepository extends JpaRepository<PojoTbl, Integer> {

    @Query("select p from PojoTbj p where " + 
        "(p.col1 like ?1 or ?1 is null) and " +
        "(p.col2 like ?2 or ?2 is null) and " +
        "(p.col3 like ?3 or ?3 is null) and " +
        "(p.id = ?4 or id is null)"
    )
    Page<PojoTbl> findByParams(String param1, String param2, String param3, Long id, Pageable pageable)

}

Using conditions like ?1 is null allows you to pass null for params you don't want to use in the query.使用?1 is null类的条件允许您为不想在查询中使用的参数传递null So you don't need "NA" value anymore.所以你不再需要"NA"值了。

public ResponseEntity<Page<PojoTbl>> getDataFromDB(
        @PageableDefault(page = 0, size = 20) @SortDefault.SortDefaults({
                @SortDefault(sort = "id", direction = Sort.Direction.DESC) }) Pageable pageable,
        @RequestParam(required = false) String col1,
        @RequestParam(required = false) String col2,
        @RequestParam(required = false) String col3,
        @RequestParam(value = "id", required = false, defaultValue=null) Long id) {

    Page<PojoTbl> selectedRecords = myService.findDataFromDB(col1,
            col2, col3, id, pageable);

    return ResponseEntity.ok(selectedRecords);

}

@Query accepts any valid JPQL query. @Query接受任何有效的 JPQL 查询。 That means you can use any JPQL functions with it.这意味着您可以使用任何 JPQL 函数。 For example if you need to ignore case you can use upper function:例如,如果您需要忽略大小写,您可以使用upper函数:

@Query("select p from PojoTbj p where " + 
    "(upper(p.col1) like upper(?1) or ?1 is null))

By your repository methods I understand you are doing basic findBy for the fields that are available.通过您的存储库方法,我了解到您正在对可用字段进行基本的findBy

Take a look at Query by Example (QBE) : documentation查看示例查询 (QBE)文档

Essentially you are filling all the present fields to the entity and ask for an Example type back.本质上,您正在向实体填充所有现有字段并要求返回示例类型。

Although this approach helps the dynamic nature of your case it comes with some limitations as are described in the documentation link above.虽然这种方法有助于您的案例的动态性质,但它有一些限制,如上面的文档链接中所述。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM