有没有一种方法可以为 Spring Data 中的特殊查询构建自定义存储库方法,该方法接受多个且连接的搜索字符串,这意味着需要在一个数据库字段中找到所有这些字符串?
以这个例子为例,只接受一个字符串:
import java.util.List;
import org.jean.dossier.model.entities.Contact;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ContactRepository extends JpaRepository<Contact, Long> {
List<Contact> findTop10ByNameContainingOrderByName(String name);
}
在这里,我实质上选择了 contact.name 参数中具有
name
变量内容的所有联系人。我还按名称对结果进行排序,并将输出限制为 10 行。
此搜索仅使用一个参数
name
,即“alfonso”来查找所有名为“alfonso”的联系人。不过,我想要实现的是使用多个字符串进行相同的搜索。
示例:我提供字符串“al”和“du”。查询的可能结果是:
我认为更改上述方法的正确方法如下:
列表 findTop10ByNameContainingOrderByName(String[] name);
有什么办法可以做到吗?
显然我正在寻找的东西在 Spring Data 中是不可能的。因此,我的构建有点不同,但仍然达到了我的结果。也许还有另一个人面临着和我一样的问题,所以希望通过这种方式我可以提供一个可能的解决方案。
我向 ContactRepository 添加了一个新的
findAll()
方法,接受规范(用于名称字段的字符串限制)和可分页(用于限制输出行的数量):
import org.jean.dossier.model.entities.Contact;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ContactRepository extends JpaRepository<Contact, Long> {
Page<Contact> findAll(Specification<Contact> spec, Pageable pageable);
}
为了调用此存储库方法,我创建了一个新服务,在其中准备查询:
import java.util.ArrayList;
import java.util.List;
import org.jean.dossier.data.ContactRepository;
import org.jean.dossier.model.entities.Contact;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import jakarta.persistence.criteria.Predicate;
@Service
public class ContactService {
@Autowired
private ContactRepository contactRepository;
private final Logger logger = LoggerFactory.getLogger(ContactService.class);
public List<Contact> findFirst10ByMultipleStrings(String... searchStrings) {
this.logger.info("Find contacts using multiple strings.");
// Sort by attribute "name" ascending.
Sort sort = Sort.by(Sort.Direction.ASC, "name");
// Limit to the first 10 lines.
Pageable pageable = PageRequest.of(0, 10, sort);
Page<Contact> resultPage = this.contactRepository.findAll(createSpecification(searchStrings), pageable);
return resultPage.getContent();
}
private Specification<Contact> createSpecification(String... searchStrings) {
this.logger.info("Create specification for query.");
return (root, query, criteriaBuilder) -> {
List<Predicate> predicates = new ArrayList<>();
for (String searchString : searchStrings) {
predicates.add(criteriaBuilder.like(root.get("name"), "%" + searchString + "%"));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
}
}
最终,从控制器调用它变得很容易:
@Autowired
private ContactService contactService;
List<Contact> contacts = this.contactService.findFirst10ByMultipleStrings(name.split(" "));