当前位置: 首页 > 知识库问答 >
问题:

在springboot中用多个字段搜索并实现分页

南宫星波
2023-03-14

我有以下的请求给管理员和管理员

@PostMapping 
public responseDto search(@RequestBody SearchUserRequestDto request){
    userService.search(request);
}
java prettyprint-override">public class SearchUserRequestDto {

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

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

示例:如果firstName是“john”,lastName是“smith”,其余字段为空,那么我必须在存储库中搜索firstName是“john”,lastName是“smith”的所有记录(不是或)

我还必须为响应执行分页

我是Spring靴新手,有人能建议我怎么做吗?

共有2个答案

巢德华
2023-03-14

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

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

考虑<代码>用户< /代码>对象

public class User{
  String firstName;
  String lastName;
}

假设我们有一个UserController来处理User资源的REST请求。此控制器将带有UserSearchCriteria的请求转换为Spring数据页面

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=misa

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数据项目的一部分。在我的项目中,我让排序和分页存在于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使用SpecificationAPI动态地将搜索添加到JPA调用中,我发现这比直接使用CriteriaAPI更简洁。

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调用传递的params(UserSearchSpeation上的属性),并动态地构建数据库调用的限制。最后,我选择将每个谓词放在一起,但是您可以在这里做任何您想做的事情。您还可以检查相等而不是like,大于/小于等。

最后,请注意,此规范传递到UserService.findAllUser方法中的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这样的数据存储库中扩展某些接口。Spring数据可以处理引擎盖下的其他数据。重要的是要注意PagingAndSortingRepository的扩展,它处理分页和排序方面,以及JpaSpecificationExecutor的扩展,它接受规范对象并生成正确的查询。

这看起来像是很多代码,但随着代码库的增长,这对我来说扩展得非常好。一旦有了规范,就可以轻松地向搜索条件对象添加新字段,并通过检查新字段和创建谓词在规范中添加新限制。

宦正诚
2023-03-14

正如@mandar dharurkar所建议的,你可以使用org。springframework。数据领域可分页,但对于条件搜索,您可以使用以下内容:,

@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);
 类似资料:
  • 问题内容: 我正在使用最新版本的elasticsearch-php以及最新版本的MongoDB和ElasticSearch。 我需要对可以包含一个或多个值的多个字段进行搜索。例: country_code应为NL,BE或DE,并且类别应包含AA01,BB01,CC02或ZZ11 我以为我会按照以下方式解决它(PHP): 但是结果甚至还不能接近我期望返回的数据。 有时 $ countries 和/或

  • 问题内容: 现在,我有一个通过KeyReleased事件实现的搜索textField,当我开始键入“ Andrew”中的“ An”时,并在我准确键入(caseSensitive)我要输入的名称后,找不到/更新jTable。找。 因此,我想要从该站点实现Filtering方法,但是我遇到了很大的问题。在执行以下操作并删除了“旧的” KeyReleased事件之后,当我在文本字段“ txt_searc

  • 问题内容: 我第一次使用Postgresql,并且试图在我的网站中创建一个搜索引擎。我有这张桌子: 然后我为表的每个字段创建了一个索引(这是正确的方法吗?或者我可以为所有字段创建一个索引?): 现在,如果我想在每个索引中搜索一个单词,SQL查询是什么? 我尝试了这个,它的工作原理: 是否存在更好的方法来做到这一点?我可以搜索多个吗?我的一个朋友提出了一个解决方案,但这是针对MySQL数据库的: P

  • 问题内容: 我正在构建一个简单的 搜索 算法,我想 用空格 打破我的 字符串 ,并在其上搜索数据库,如下所示: 这可能吗? 问题答案: 是的,您可以使用SQL 运算符来搜索多个绝对值: 如果要使用,则需要改为使用: 使用(如您所尝试的)要求所有条件为真,使用至少需要一个条件为真。

  • 如果我想搜索那些名字中包含巴黎的地方,我会做以下操作: 这样我就能看到所有有巴黎这个名字的地方。 然而,我如何能够搜索到其他标准的地方,如 null 在Cloud Firestore中这甚至是可能的吗?如果没有的话,有没有其他方法可以做到这一点?

  • 我有一个如下的模型: 它填充了一些数据: 我需要合并/加入一个集合(不是queryset): 所以基本上,当我用这个元组列表搜索这个模型时,第0行和第2行应该返回。 目前,我的解决方法是将 读取到数据帧中,并与元组列表进行合并,并将 ID 传递给 。我还尝试迭代列表并在每个元组上调用 但它非常慢。这个清单相当大。 当我尝试按照当前答案的建议链接Q时,它抛出了一个OperationalError(太