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

如何在Java中使用Criteria API进行动态搜索?

施德运
2023-03-14

我想在Java中用标准API进行动态搜索。

在我写的代码中,我们需要用JSON编写url栏中的每个实体。我不想写“普拉卡”。

网址:

这里我们需要写出每个实体,即使我们只搜索一个实体。类型实体,它应该为空。

我的代码如下。假设有多个实体,我想做的是使用它想要搜索的单个实体进行搜索。正如你在照片中看到的,我不想写一个我不需要的实体。你能帮我做什么吗?

我在存储库中的代码

public interface CityRepository extends JpaRepository<City, Integer> , JpaSpecificationExecutor<City> {

}

我的服务代码

@Service
public class CityServiceImp implements CityService{


private static final String CITY = "city";
private static final String PLAKA = "plaka";

@Override
public List<City> findCityByNameAndPlaka(String cityName, int plaka) {
    GenericSpecification genericSpecification = new GenericSpecification<City>();
    if (!cityName.equals("_"))
        genericSpecification.add(new SearchCriteria(CITY,cityName, SearchOperation.EQUAL));
    if (plaka != -1)
        genericSpecification.add(new SearchCriteria(PLAKA,plaka, SearchOperation.EQUAL));

    return cityDao.findAll(genericSpecification);
}

@Autowired
CityRepository cityDao;

我在控制器中的代码

@RestController
@RequestMapping("api/city")
public class CityController {

@Autowired
private final CityService cityService;

public CityController(CityService cityService) {
    this.cityService = cityService;


@GetMapping("/query")
public List<City> query(@RequestParam String city, @RequestParam String plaka){

    String c = city;
    int p;

    if (city.length() == 0)
        c = "_";

    if (plaka.length() == 0) {
        p = -1;
    }
    else
        p = Integer.parseInt(plaka);

    return cityService.findCityByNameAndPlaka(c,p);
}

SearchCriteria中的我的代码

public class SearchCriteria {

private String key;
private Object value;
private SearchOperation operation;

public SearchCriteria(String key, Object value, SearchOperation operation) {
    this.key = key;
    this.value = value;
    this.operation = operation;
}

public String getKey() {
    return key;
}

public Object getValue() {
    return value;
}

public SearchOperation getOperation() {
    return operation;
}

GenericSpecification中的我的代码

public class GenericSpecification<T> implements Specification<T> {

private List<SearchCriteria> list;

public GenericSpecification() {
    this.list = new ArrayList<>();
}

public void add(SearchCriteria criteria){
    list.add(criteria);
}

@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {

    List<Predicate> predicates = new ArrayList<>();

    for (SearchCriteria criteria : list) {
        if (criteria.getOperation().equals(SearchOperation.GREATER_THAN)) {
            predicates.add(builder.greaterThan(
                    root.get(criteria.getKey()), criteria.getValue().toString()));
        } else if (criteria.getOperation().equals(SearchOperation.LESS_THAN)) {
            predicates.add(builder.lessThan(
                    root.get(criteria.getKey()), criteria.getValue().toString()));
        } else if (criteria.getOperation().equals(SearchOperation.GREATER_THAN_EQUAL)) {
            predicates.add(builder.greaterThanOrEqualTo(
                    root.get(criteria.getKey()), criteria.getValue().toString()));
        } else if (criteria.getOperation().equals(SearchOperation.LESS_THAN_EQUAL)) {
            predicates.add(builder.lessThanOrEqualTo(
                    root.get(criteria.getKey()), criteria.getValue().toString()));
        } else if (criteria.getOperation().equals(SearchOperation.NOT_EQUAL)) {
            predicates.add(builder.notEqual(
                    root.get(criteria.getKey()), criteria.getValue()));
        } else if (criteria.getOperation().equals(SearchOperation.EQUAL)) {
            predicates.add(builder.equal(
                    root.get(criteria.getKey()), criteria.getValue()));
        } else if (criteria.getOperation().equals(SearchOperation.MATCH)) {
            predicates.add(builder.like(
                    builder.lower(root.get(criteria.getKey())),
                    "%" + criteria.getValue().toString().toLowerCase() + "%"));
        } else if (criteria.getOperation().equals(SearchOperation.MATCH_END)) {
            predicates.add(builder.like(
                    builder.lower(root.get(criteria.getKey())),
                    criteria.getValue().toString().toLowerCase() + "%"));
        }
    }

    return builder.and(predicates.toArray(new Predicate[0]));
}

我在搜索操作中的代码

public enum SearchOperation {

GREATER_THAN,
LESS_THAN,
GREATER_THAN_EQUAL,
LESS_THAN_EQUAL,
NOT_EQUAL,
EQUAL,
MATCH,
MATCH_END,
}

共有1个答案

岑经纶
2023-03-14

Criteria API的好处在于,您可以使用CriteriaBuilder基于您拥有的字段构建复杂的SQL语句。您可以使用< code>and和< code>or语句轻松组合多个条件字段。

我过去是如何处理类似的事情的,是使用一个忠告类,该类接受一个Filter,该类具有最常见操作的构建器(等于、等于、等于、等于、等于等)。我实际上在我开始的一个开源项目中也有类似的东西:https://gitlab.com/pazvanti/logaritmical/-/blob/master/app/data/dao/GenericDao.javahttps://gitlab.com/pazvanti/logaritmical/-/blob/master/app/data/filter/JPAFilter.java

接下来,隐式DAO类扩展了这个忠告,当我想做一个操作时(例如:找到一个具有提供的用户名的用户),我在那里创建了一个Filter

现在,魔力就在过滤器中。这是创建谓词的那个。在您的请求中,您将收到如下内容:field1=something

现在,对于请求中的每个字段,使用来自< code>JPAFilter类的helper方法创建一个谓词,并返回结果< code >谓词。在下面的示例中,我假设您没有将它作为地图,而是作为单独的字段(很容易将代码改编为地图):

public class SearchFilter extends JPAFilter {
    private Optional<String> field1 = Optional.empty();
    private Optional<String> field2 = Optional.empty();

    @Override
    public Predicate getPredicate(CriteriaBuilder criteriaBuilder, Root root) {
        Predicate predicateField1 = field1.map(f -> equals(criteriaBuilder, root, "field1", f)).orElse(null);
        Predicate predicateField2 = field2.map(f -> equals(criteriaBuilder, root, "field2", f)).orElse(null);

        return andPredicateBuilder(criteriaBuilder, predicateField1, predicateField2);
    }
}

现在,我将字段设置为可选字段,因为在这种情况下,我假设您在请求映射中将它们作为可选(Spring 有这个),我知道将 Optional 作为输入参数有点争议,但在这种情况下,我认为这是可以接受的(更多关于这里:https://petrepopescu.tech/2021/10/an-argument-for-using-optional-as-input-parameters/)

< code >和PredicateBuilder()的构造方式是,即使提供的谓词之一为空,它也能正常工作。此外,我制作了一个简单的映射函数,调整为包含< code >

现在,在您的DAO类中,只需提供适当的过滤器:

public class SearchDao extends GenericDAO {

    public List<MyEntity> search(Filter filter) {
       return get(filter);
    }

}

需要进行一些调整(这只是开始代码),比如一种更简单的方法来初始化过滤器(并在DAO中执行此操作),并确保过滤器只能应用于指定的实体(可能使用泛型,<code>JPAFIlter

一个缺点是字段必须与实体类中的变量名称匹配。

 类似资料:
  • 问题内容: 我正在使用Hibernate 4和Lucene 3.6。我对构面计数有要求。根据我的要求,我有一个实体“产品”。实体“产品”具有某些属性,例如ID,颜色,品牌。 现在,我的要求是,我想以多维方式获取该实体的商品数,并获取红色(彩色)耐克(品牌)服装的数量。 所以举个例子。我的数据库中保存了以下产品实体。 id品牌颜色 1锐步红 2锐步黑 3锐步绿 4利红 5利黑 6利黑 现在,我希望我

  • null 我正在寻找一个解决方案,如Groovy GPath语法 store.book-此数组的大小。 store.book[*].category-如何计算数组中的键值。 store.bicycle-如果发现它必须返回true值

  • 是的,我对这个问题非常认真。使用pip搜索是如何工作的? 关键字

  • 在这里,我可以搜索python。 我希望放置负模式,实际上应该不会产生任何结果或不匹配。 当字符串包含python但字符串“在python上工作很容易”中不包含容易时,我喜欢使用re.search。我该怎么做?同时使用正负条件。

  • 我目前正在研究如何在我的项目中实现搜索。我有一个名为users的表,它有两列,firstName和lastName。我希望能够在这两列之间搜索,例如,用户的名字是John,姓是Smith,因此当他们搜索John Smith时,它将返回具有该名称的用户。 或者他们可以只搜索名字等。解决这个问题的方法是什么? 使用PostgreSQL的全文功能是正确的途径吗?我目前正在使用Node w/TypeORM

  • 问题内容: 我有一个对象列表,列表很大。对象是 现在,我必须在列表中搜索对象的特定值。假设 我必须返回那些对象(我的搜索并不总是基于value3) 清单是 有效的方法是什么? 谢谢。 问题答案: 您可以尝试使用Apache Commons Collections。 有一个CollectionUtils类,允许您通过自定义谓词选择或过滤项目。 您的代码将如下所示: 更新: 在 java8中 ,使用