我可以创建一个通用的 @Query 来检测 URL 中的哪些参数不为空,并仅使用 Spring 进行搜索吗?

Can I create a generic @Query that detects which parameters from URL are not null and make a search only by them with Spring?

我能否创建一个通用的 @Query 来检测 URL 中的哪些参数不为空,并仅通过它们进行搜索,而不是为每个参数与 Spring 框架组合创建一个方法?

例如:我的URL中有两个参数;我只想进行一个查询,从我的 URL 中检测非空参数并将它们传递给我的查询,忽略空值(而不是为不同的参数组合创建大量 if/else 和不同的查询) .

我创建了这段代码,其中 return 是一个基于用户在 URL 中传递的 NOT-NULL 参数的国家/地区列表。因为我有 4 个参数,所以所有的可能性都会导致 16 个不同的查询(因为我还有一个 findAll 方法,当没有定义参数时它会带来所有结果),而且一直创建它们很无聊。

我的控制器:

@RequestMapping(value = "/countries", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity listCountries(
        @RequestParam(value = "name", required = false) String name,
        @RequestParam(value = "twoLetterCode", required = false) String twoLetterCode,
        @RequestParam(value = "threeLetterCode", required = false) String threeLetterCode,
        @RequestParam(value = "nameInPortuguese", required = false) String nameInPortuguese) {
    try {

        List<Country> countryList = null;

        @Autowired
        private CountryRepository countryRepository;

        if (name != null && !name.isEmpty() && !name.equals("")) {
            if (twoLetterCode != null && !twoLetterCode.isEmpty() && !twoLetterCode.equals("")) {
                if (threeLetterCode != null && !threeLetterCode.isEmpty() && !threeLetterCode.equals("")) {
                    if (nameInPortuguese != null && !nameInPortuguese.isEmpty() && !nameInPortuguese.equals("")) {
                        countryList = countryRepository.findByNameTwoLetterCodeThreeLetterCodeNameInPortuguese(name, twoLetterCode, threeLetterCode, nameInPortuguese);
                    } else {
                        countryList = countryRepository.findByNameTwoLetterCodeThreeLetterCode(name, twoLetterCode, threeLetterCode);
                    }
                } else {
                    if (nameInPortuguese != null && !nameInPortuguese.isEmpty() && !nameInPortuguese.equals("")) {
                        countryList = countryRepository.findByNameTwoLetterCodeNameInPortuguese(name, twoLetterCode, nameInPortuguese);
                    } else {
                        countryList = countryRepository.findByNameTwoLetterCode(name, twoLetterCode);
                    }
                }
            } else {
                if (threeLetterCode != null && !threeLetterCode.isEmpty() && !threeLetterCode.equals("")) {
                    if (nameInPortuguese != null && !nameInPortuguese.isEmpty() && !nameInPortuguese.equals("")) {
                        countryList = countryRepository.findByNameThreeLetterCodeNameInPortuguese(name, threeLetterCode, nameInPortuguese);
                    } else {
                        countryList = countryRepository.findByNameThreeLetterCode(name, threeLetterCode);
                    }
                } else {
                    if (nameInPortuguese != null && !nameInPortuguese.isEmpty() && !nameInPortuguese.equals("")) {
                        countryList = countryRepository.findByNameNameInPortuguese(name, nameInPortuguese);
                    } else {
                        countryList = countryRepository.findByName(name);
                    }
                }
            }
        } else {
            if (twoLetterCode != null && !twoLetterCode.isEmpty() && !twoLetterCode.equals("")) {
                if (threeLetterCode != null && !threeLetterCode.isEmpty() && !threeLetterCode.equals("")) {
                    if (nameInPortuguese != null && !nameInPortuguese.isEmpty() && !nameInPortuguese.equals("")) {
                        countryList = countryRepository.findByTwoLetterCodeThreeLetterCodeNameInPortuguese(twoLetterCode, threeLetterCode, nameInPortuguese);
                    } else {
                        countryList = countryRepository.findByTwoLetterCodeThreeLetterCode(twoLetterCode, threeLetterCode);
                    }
                } else {
                    if (nameInPortuguese != null && !nameInPortuguese.isEmpty() && !nameInPortuguese.equals("")) {
                        countryList = countryRepository.findByTwoLetterCodeNameInPortuguese(twoLetterCode, nameInPortuguese);
                    } else {
                        countryList = countryRepository.findByTwoLetterCode(twoLetterCode);
                    }
                }
            } else {
                if (threeLetterCode != null && !threeLetterCode.isEmpty() && !threeLetterCode.equals("")) {
                    if (nameInPortuguese != null && !nameInPortuguese.isEmpty() && !nameInPortuguese.equals("")) {
                        countryList = countryRepository.findByThreeLetterCodeNameInPortuguese(threeLetterCode, nameInPortuguese);
                    } else {
                        countryList = countryRepository.findByThreeLetterCode(threeLetterCode);
                    }
                } else {
                    if (nameInPortuguese != null && !nameInPortuguese.isEmpty() && !nameInPortuguese.equals("")) {
                        countryList = countryRepository.findByNameInPortuguese(nameInPortuguese);
                    } else {
                        countryList = countryRepository.findAll();
                    }
                }
            }
        }


        if (countryList != null && !countryList.isEmpty()) {
            List<CountryDTO> dtosList = modelMapper.map(countryList, new TypeToken<CountryDTO>() {}.getType());
            return ResponseEntity(dtosList, HttpStatus.OK);
        } else {
            return ResponseEntity.status(HttpStatus.OK).body(new EmptySerializableClass());
        }

    } catch (Exception e) {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
    }

}

我的仓库:

@Query("SELECT c FROM Country c WHERE c.name LIKE :name")
public List<Country> findByName(@Param("name") String name);

@Query("SELECT c FROM Country c WHERE c.twoLetterCode LIKE :twoLetterCode")
public List<Country> findByTwoLetterCode(@Param("twoLetterCode") String twoLetterCode);

@Query("SELECT c FROM Country c WHERE c.threeLetterCode LIKE :threeLetterCode")
public List<Country> findByThreeLetterCode(@Param("threeLetterCode") String threeLetterCode);

@Query("SELECT c FROM Country c WHERE c.nameInPortuguese LIKE :nameInPortuguese")
public List<Country> findByNameInPortuguese(@Param("nameInPortuguese") String nameInPortuguese);

@Query("SELECT c FROM Country c WHERE c.name LIKE :name AND c.twoLetterCode LIKE :twoLetterCode")
public List<Country> findByNameTwoLetterCode(@Param("name") String name, @Param("twoLetterCode") String twoLetterCode);

@Query("SELECT c FROM Country c WHERE c.name LIKE :name AND c.threeLetterCode LIKE :threeLetterCode")
public List<Country> findByNameThreeLetterCode(@Param("name") String name, @Param("threeLetterCode") String threeLetterCode);

@Query("SELECT c FROM Country c WHERE c.name LIKE :name AND c.nameInPortuguese LIKE :nameInPortuguese")
public List<Country> findBynameInPortuguese(@Param("name") String name, @Param("nameInPortuguese") String nameInPortuguese);

@Query("SELECT c FROM Country c WHERE c.twoLetterCode LIKE :twoLetterCode AND c.threeLetterCode LIKE :threeLetterCode)")
public List<Country> findByTwoLetterCodeThreeLetterCode(@Param("twoLetterCode") String twoLetterCode, @Param("threeLetterCode") String threeLetterCode);

@Query("SELECT c FROM Country c WHERE c.twoLetterCode LIKE :twoLetterCode AND c.nameInPortuguese LIKE :nameInPortuguese")
public List<Country> findByTwoLetterCodeNameInPortuguese(@Param("twoLetterCode") String twoLetterCode, @Param("nameInPortuguese") String nameInPortuguese);

@Query("SELECT c FROM Country c WHERE c.threeLetterCode LIKE :threeLetterCode AND c.nameInPortuguese LIKE :nameInPortuguese")
public List<Country> findByThreeLetterCodeNameInPortuguese(@Param("threeLetterCode") String threeLetterCode, @Param("nameInPortuguese") String nameInPortuguese);

@Query("SELECT c FROM Country c WHERE c.name LIKE :name AND c.twoLetterCode LIKE :twoLetterCode AND c.threeLetterCode LIKE :threeLetterCode)")
public List<Country> findByNameTwoLetterCodeThreeLetterCode(@Param("name") String name, @Param("twoLetterCode") String twoLetterCode, @Param("threeLetterCode") String threeLetterCode);

@Query("SELECT c FROM Country c WHERE c.name LIKE :name AND c.twoLetterCode LIKE :twoLetterCode AND c.nameInPortuguese LIKE :nameInPortuguese")
public List<Country> findByNameTwoLetterCodeNameInPortuguese(@Param("name") String name, @Param("twoLetterCode") String twoLetterCode, @Param("nameInPortuguese") String nameInPortuguese);

@Query("SELECT c FROM Country c WHERE c.name LIKE :name AND c.threeLetterCode LIKE :threeLetterCode AND c.nameInPortuguese LIKE :nameInPortuguese")
public List<Country> findByNameThreeLetterCodeNameInPortuguese(@Param("name") String name, @Param("threeLetterCode") String threeLetterCode, @Param("nameInPortuguese") String nameInPortuguese);

@Query("SELECT c FROM Country c WHERE c.twoLetterCode LIKE :twoLetterCode AND c.threeLetterCode LIKE :threeLetterCode AND c.nameInPortuguese LIKE :nameInPortuguese")
public List<Country> findByTwoLetterCodeThreeLetterCodeNameInPortuguese(@Param("twoLetterCode") String twoLetterCode, @Param("threeLetterCode") String threeLetterCode, @Param("nameInPortuguese") String nameInPortuguese);

@Query("SELECT c FROM Country c WHERE c.name LIKE :name AND c.twoLetterCode LIKE :twoLetterCode AND c.threeLetterCode LIKE :threeLetterCode AND c.nameInPortuguese LIKE :nameInPortuguese")
public List<Country> findByNameTwoLetterCodeThreeLetterCodeNameInPortuguese(@Param("name") String name, @Param("twoLetterCode") String twoLetterCode, @Param("threeLetterCode") String threeLetterCode, @Param("nameInPortuguese") String nameInPortuguese);

@Query("SELECT c FROM Country c")
public List<Country> findAll();

所以,我想你们明白我的问题是什么了。与其创建数百万 if/else 和数以千计的查询来处理 URL 调用中定义的非空参数,有没有办法在 Spring 框架上 - 甚至在 JPA/Hibernate 上- 只编写一个查询来检测那些非空参数并通过它们进行搜索(如果所有参数都为空,那么只有 return 所有结果)?

你不能用 @Query 注释来做。 但是您可以使用示例查询或规范查询。

使用示例查询,您可以创建目标实体 Country 的实例,其中包含过滤值作为属性,null 包含不应被过滤的那些值。 还提供一个 ExampleMatcher 来控制应该使用哪种比较(相等、包含、不区分大小写等)。

See the documentation for details

更灵活的是规范,您可以使用 JPA 条件 API 或使用 Querydsl 以编程方式构造 where 条件。

Again the documentation describes the details.

感谢大家,但我能做到!就这么简单:

@Query("SELECT c FROM Country c WHERE (:name is null or c.name LIKE :name)"
+ " AND (:twoLetterCode is null or c.twoLetterCode LIKE :twoLetterCode)"
+ " AND (:threeLetterCode is null or c.threeLetterCode LIKE :threeLetterCode)"
+ " AND (:nameInPortuguese is null or c.nameInPortuguese LIKE :nameInPortuguese)")

public List<Country> findCountries(
@Param("name") String name, 
@Param("twoLetterCode") String twoLetterCode,
@Param("threeLetterCode") String threeLetterCode,
@Param("nameInPortuguese") String nameInPortuguese);