【问题标题】:Searching with mutliple fields and implementing pagination in springboot在spring boot中搜索多个字段并实现分页
【发布时间】:2020-04-27 21:33:48
【问题描述】:

我有以下 requestDto 和控制器

@PostMapping 
public responseDto search(@RequestBody SearchUserRequestDto request){
    userService.search(request);
}
public class SearchUserRequestDto {

    private Long userId;
    private String firstName;
    private String lastName;
    private String role;
    private String userType;
}

我想用上面 Dto 中不为空的字段搜索用户存储库。

示例:如果 firstName 是 "john" 并且 lastName 是 "smith" 并且其余字段为空,那么我必须在存储库中搜索所有记录 WHERE firstName is "john" AND lastName is "smith"(不是

我还必须为响应实现分页

我是 spring-boot 新手,谁能建议我怎么做?

【问题讨论】:

标签: java spring spring-boot


【解决方案1】:

正如@mandar-dharurkar 所建议的,您可以使用 org.springframework.data.domain.Pageable 但对于条件搜索,您可以使用以下内容,

@Query("SELECT u FROM User u WHERE (:name is null or u.name = :name) and (:lastname is null"
  null + " or u.lastname= :lastname)")
Page<User> search(@Param("name") String name, @Param("lastname") String lastname, Pageable pageable);

【讨论】:

    【解决方案2】:

    如果您使用 JPA,我建议使用 Spring Data JPASpecification API。当我最初查看 Spring Boot 和 Spring Data 时,我看到推广的唯一真正的方法是 Spring Data Rest,这对我来说太神奇了。

    我个人喜欢让控制器调用服务上的方法(可重用的业务逻辑层,基本上是外观模式)。这些服务最终调用 Spring Data 存储库。

    考虑一个User 对象

    public class User{
      String firstName;
      String lastName;
    }
    

    假设我们有一个UserController 处理我们对User 资源的REST 请求。此控制器将带有 UserSearchCriteria 的请求转换为 Spring Data Page&lt;User&gt;

    import org.springframework.data.domain.Page;
    
    public class UserController{
    
      @Autowired
      UserService userService;
    
      @RequestMapping(path = "/users", method = RequestMethod.GET)
      Page<User> getAll(HttpServletRequest request, UserSearchCriteria searchCriteria){
         return userService.findAllUsers(searchCriteria);
      }
    }
    

    UserSearchCriteria 是您的客户端将作为查询参数传递的搜索参数类型,例如 GET /users?firstName=mista&amp;lastName=henry,它们会自动映射到 UserSearchCriteria 字段。

    import org.springframework.data.domain.Sort;
    import org.springframework.data.domain.PageRequest;
    public class UserSearchCriteria {
        UserSearchCriteria(){
            super();
            sort = "lastName";
        }
        Integer size;
        Integer page;
        String sort;
        String sortDir;
    
        String firstName;
        String lastName;
        Sort buildSort(){
            return new Sort(new Sort.Order(Sort.Direction.ASC, sort).ignoreCase());
        }
        PageRequest toPageRequest(){
            if(size == null){
                size = Integer.MAX_VALUE; // may or may not be a good idea for your usecase
            }
            return new PageRequest(page, size, buildSort());
        }
    }
    

    PageRequestSort 是 Spring Data 项目的一部分。在我的项目中,我让排序和分页存在于AbstractSearchCriteria 对象中,以便于重用,我的所有搜索条件都扩展了,但如上所示更简单。

    UserService 层,我将委托给我的存储库(我还可以检查访问要求、设置默认值等。

    import org.springframework.data.domain.Page;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.annotation.Transactional;
    
    @Component
    @Transactional
    public class UserService{
    
      @Autowired
      UserRepository userRepository;
    
      Page<User> findAllUsers(UserSearchCriteria userSearchCriteria){
        if(userSearchCriteria == null){
          userSearchCriteria = new UserSearchCriteria();
        }
        return userRepository.findAll(UserSearchSpecification.findByCriteria(userSearchCriteria), userSearchCriteria.toPageRequest());
      }
    }
    

    UserSearchSpecification 使用Specification API 将搜索动态添加到您的JPA 调用中,我发现这比直接使用Criteria API 更简洁。

    import org.springframework.data.jpa.domain.Specification;
    import javax.persistence.criteria.CriteriaBuilder;
    import javax.persistence.criteria.CriteriaQuery;
    import javax.persistence.criteria.Expression;
    import javax.persistence.criteria.Predicate;
    import javax.persistence.criteria.Root;
    import javax.persistence.criteria.Subquery;
    public class UserSearchSpecification{
    
      public static Specification<User> findByCriteria(final UserSearchCriteria searchCriteria){
        return new Specification<User>() {
    
          @Override
          Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            List<Predicate> predicates = new ArrayList<Predicate>();
    
            // if firstName in criteria, do an uppercase prefix match
            if(searchCriteria.firstName != null){
              predicates.add(
                cb.like(
                  cb.upper(root.get("firstName")),
                  "%" + searchCriteria.lastName.toUpperCase()
                )
              );
            }
    
            // if lastName in criteria, do an uppercase prefix match
            if(searchCriteria.lastName != null){
              predicates.add(
                cb.like(
                  cb.upper(root.get("lastName")),
                  "%" + searchCriteria.lastName.toUpperCase()
                )
              );
            }
            if(predicates.size() > 0){
              return cb.and(predicates.toArray());
            }else{
              return null;
            }
          }
        }
      }
    }
    

    这使您可以轻松地检查来自 rest 调用的传入参数(UserSearchSpecification 上的属性)并动态建立数据库调用的限制。最后,我选择将每个谓词and 放在一起,但你可以在这里做任何你想做的事情。您还可以检查相等而不是喜欢、大于/小于等。

    最后,请注意此规范在UserService.findAllUsers 方法中传递给UserRepository。这是一个 Spring Data 存储库:

    import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    import org.springframework.data.repository.PagingAndSortingRepository;
    
    public interface UserRepository extends PagingAndSortingRepository<User, Long>, JpaSpecificationExecutor<User>{
    
    }
    

    在 Spring Data 中,您通常只需要在像这里这样的接口中扩展某些存储库。 Spring Data 可以在后台处理其余部分。重要的是要注意PagingAndSortingRepository 的扩展,它处理分页和排序方面以及JpaSpecificationExecutor,它采用Specification 对象并生成正确的查询。

    这可能看起来像很多代码,但随着代码库的增长,这对我来说扩展得非常好。制定规范后,您可以轻松地向 SearchCriteria 对象添加新字段,并通过检查新字段并创建 Predicate 在规范中添加新限制。

    【讨论】:

    • 谢谢。根据您在 cmets 中 @MarkHunt 提供的答案和链接,我能够做到并且它正在工作
    猜你喜欢
    • 1970-01-01
    • 2018-07-13
    • 1970-01-01
    • 2019-01-30
    • 2023-01-26
    • 2018-07-25
    • 2015-04-16
    • 2019-08-11
    • 1970-01-01
    相关资源
    最近更新 更多