使用Spring Data的每个人都面临这样的情况:您拥有一个用于处理实体的存储库,并且您想编写一种通用的find方法,以通过用户可以在搜索表单上设置或跳过的一组参数进行搜索。 Spring Data中find方法的基本实现仅在考虑所有参数的情况下查找实体,而不允许您按有限的集合进行搜索。 我找到了解决此问题的方法,并创建了一个OpenSource库以在其他项目中快速使用。
为了理解这些问题,让我们想象一下,我们正在创建一个简单的笔记本应用程序,在其中定义一个实体-具有字段id,firstName,lastName,phoneNumber的Person。
人.java@Entity @Data @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(of = "id") public class Person { @Id private Long id; private String firstName; private String lastName; private String phoneNumber; }
假设我们必须通过名字,姓氏和电话号码的一部分或这些参数的任意组合进行搜索,并且希望搜索方法不考虑值为空的参数。 要解决此问题,可以采取几种方法:
- 通过SQL直接与数据库一起使用,在服务中创建一个将动态生成SQL查询的方法。 像
动态查询 Iterable<Person> find(String firstName, String lastName, String phoneNumber) { List<String> where = new ArrayList(); List params = new ArrayList(); if(firstName != null) { params.add(firstName); where.add("first_name = ?"); } if(lastName != null) { params.add(lastName); where.add("last_name = ?"); } if(phoneNumber != null) { params.add(phoneNumber); where.add("phone_number = ?"); } String sql = "SELECT * FROM person " + (where.isEmpty() ? "" : " WHERE " + String.join(" AND ", where));
- 将Query注释用于带有参数检查为null的搜索方法。
@查询 @Query("SELECT p FROM Person p " + "WHERE " + "(firstName = :firstName or :firstName is null) and " + "(lastName = :lastName or :lastName is null) and " + "(phoneNumber = :phoneNumber or :phoneNumber is null)" ) Iterable<Person> find( @Param("firstName") String firstName, @Param("lastName") String lastName, @Param("phoneNumber") String phoneNumber );
- 为所有可能的参数组合创建搜索方法,并在检查参数为null之后调用所需的方法。
很多查找方法 @Repository public interface PersonRepo extends PagingAndSortingRepository<Person, Long> {
我不会分析每种方法的优缺点,它们是显而易见的。 我只是说,我选择了第三个选项,并为参数组合的每个变体添加了搜索方法,并创建了一个使用注释处理器机制的OpenSource库,并在编译阶段为您完成了所有工作。 要使用它,您必须连接该库(请参见
https://github.com/ukman/kolobok或
https://mvnrepository.com/artifact/com.github.ukman/kolobok的最新版本)。
<dependency> <groupId>com.github.ukman</groupId> <artifactId>kolobok</artifactId> <version>0.1.2</version> <scope>compile</scope> </dependency>
然后,您需要标记该方法,该方法应使用@FindWithOptionalParams注释以新方式工作。
@Repository public interface PersonRepo extends PagingAndSortingRepository<Person, Long> { @FindWithOptionalParams Iterable<Person> findByFirstNameAndLastNameAndPhoneNumberContains(String firstName, String lastName, String number); }
库本身将生成所有搜索方法和默认实现,并检查参数是否为null并调用所需的方法。
PS:在注释中写下其他注释可以简化您使用Spring的工作,也许我也会添加它们。