有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java Spring数据规范RSQL和join

我正在尝试开发一个带有规范和RSQL的搜索API。遵循本教程-https://www.baeldung.com/rest-api-search-language-rsql-fiql

我有一个用户实体,它与UserProfile有一个OneToOne关系

@Entity
public class User{

    @Column(nullable = false)
    private String firstName;

    @OneToOne(targetEntity = UserProfile.class, fetch = FetchType.EAGER)
    @JoinColumn(nullable = false, name = "user_profile_id")
    private UserProfile userProfile;
...

@Entity
public class UserProfile{

    @Column(nullable = false)
    private String education;

    ...

和谓词函数

@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
    List<Object> args = castArguments(root);
    Object argument = args.get(0);

    switch (RsqlSearchOperation.getSimpleOperator(operator)) {

    case EQUAL: {
            if (argument instanceof String) {               
                return builder.like(root.get(property), argument.toString().replace('*', '%'));
            } else if (argument == null) {
                return builder.isNull(root.get(property));
            } else {
                return builder.equal(root.get(property), argument);
            }
        }
        case NOT_EQUAL: {

当我用参数调用API时?search=firstName==John,它将按预期返回结果。我需要的是按教育进行搜索,并返回受过教育的用户。我用Join做了如下尝试,但不起作用

if (argument instanceof String) {
                Join<User, UserProfile> profileJoin = root.join("user_profile_id");

                return builder.like(root.get(property), profileJoin.get(property));
            } else if (argument == null) {

任何通用的解决方案都会非常有用


共 (2) 个答案

  1. # 1 楼答案

    似乎没有通用的具体解决方案。所以我就这么做了,这几乎是通用的

    switch (RsqlSearchOperation.getSimpleOperator(operator)) {
    
            case EQUAL: {
                if (doesClassContainProperty(UserProfile.class, property)) {
                    Join<User, UserProfile> profileJoin = root.join("user_profile_id");
                    return builder.equal(profileJoin.get(property), argument);
                } else {
                    return builder.equal(root.get(property), argument);
                }
            }
    

    下面是检查传递的参数是在根类中还是在联接类中的方法

    public boolean doesClassContainProperty(Class<?> genericClass, String fieldName) {
            return Arrays.stream(genericClass.getDeclaredFields()).anyMatch(f -> f.getName().equals(fieldName));
        }
    
  2. # 2 楼答案

    我想向您推荐另一个库,它可以让您构建动态过滤器,而不必麻烦编码,它支持逻辑运算符、比较器、枚举、日期、布尔、在关系/连接上搜索(没有n+1查询问题)、函数等等:https://github.com/turkraft/spring-filter

    查询示例:

    /search?filter= average(ratings) > 4.5 and brand.name in ('audi', 'land rover') and (year > 2018 or km < 50000) and color : 'white' and accidents is empty

    用法:

    @GetMapping(value = "/search")
    public List<Entity> search(@EntityFilter Specification<Entity> spec, Pageable page) {
      return repo.findAll(spec, page);
    }
    

    不要忘记依赖性:

    <dependency>
        <groupId>com.turkraft</groupId>
        <artifactId>spring-filter</artifactId>
        <version>0.9.5</version>
    </dependency>