使用注释运行休眠创建条件运行条件

时间:2018-11-28 16:03:30

标签: java spring hibernate spring-boot spring-data-jpa

我正在创建一个REST服务,它将允许我提供所有对象或筛选后的子集。我的界面基于我无法更改的设计。
到目前为止:使用Spring我已经创建了控制器:

@RequestMapping(path = "/designs", method = GET)
public ResponseEntity<CommonResponse> getDesigns(
        @RequestHeader(name = "authenticationToken", required = AUTHENTICATION_TOKEN_REQUIRED) String authenticationToken
        , @RequestParam(name = "title", required = false) String title
        , @RequestParam(name = "designCategory", required = false) String designCategory
        , @RequestParam(name = "epic", required = false) String epic
        ) {
    return designService.get(title, designCategory, epic);
}

服务:

@Transactional
@Override
public ResponseEntity<CommonResponse> get(String title, String designCategory, String epic) {
    try {
        if(title == null && designCategory == null && epic == null) {
            commonResponse.setDesigns(designRepository.findAll());
        } else {
            commonResponse.setDesigns(designRepository.findByTitleAndDesignCategoryAndJiraEpicNumber(title, designCategory, epic));
        }
        checkForNoResults(commonResponse.getDesigns());
    } catch (NoResultsFoundException e) {
        return ResponseEntity.status(e.getStatus()).body(e.getResponse());
    }
    return ResponseEntity.ok(commonResponse);
}

模型:

@Entity(name = "design")
public class DesignModel extends BaseModel {

    @Column
    private String title;

    @Column
    private LocalDate createdDate;

    @Column
    private LocalDate updatedDate;

    @OneToOne
    @JoinColumn(name = "design_category_id")
    private DesignCategoryModel designCategory;

    @Column
    private String documentUrl;

    @Column
    private String featureHomeUrl;

    @Column
    private String jiraEpicNumber;

    @Column
    private String description;

    //Getters and setters... etc.
}

还有一个存储库:

@Repository
public interface DesignRepository extends CrudRepository<DesignModel, Integer> {
    ArrayList<DesignModel> findAll();
    ArrayList<DesignModel> findByTitleAndDesignCategoryAndJiraEpicNumber(String title, String designCategory, String epic);
}

这很好,但是:
如果我只想按标题过滤,不提供其他值,则我的查询什么也不提供。我在这里简要查看了CriteriaBuilder:https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/ 但是,我需要访问我的会话对象才能创建CriteraBuilder(并且鉴于我从未创建过HibernateUtils类,因此我无法获取会话)。

如何创建这些“条件条件”?

1 个答案:

答案 0 :(得分:0)

这看起来应该很简单,就像您需要使用谓词和Querydsl

https://www.baeldung.com/rest-api-search-language-spring-data-querydsl

但是这是基础知识

设置您的后继地位以接受PredicateExecutor

public interface MyUserRepository extends JpaRepository<MyUser, Long>, QuerydslPredicateExecutor<MyUser>, QuerydslBinderCustomizer<QMyUser> { @Override default public void customize( QuerydslBindings bindings, QMyUser root) { bindings.bind(String.class) .first((SingleValueBinding<StringPath, String>) StringExpression::containsIgnoreCase); bindings.excluding(root.email); } }

然后一个客户谓词获取您的参数列表

ublic class MyUserPredicate {

private SearchCriteria criteria;

public BooleanExpression getPredicate() {
    PathBuilder<MyUser> entityPath = new PathBuilder<>(MyUser.class, "user");

    if (isNumeric(criteria.getValue().toString())) {
        NumberPath<Integer> path = entityPath.getNumber(criteria.getKey(), Integer.class);
        int value = Integer.parseInt(criteria.getValue().toString());
        switch (criteria.getOperation()) {
            case ":":
                return path.eq(value);
            case ">":
                return path.goe(value);
            case "<":
                return path.loe(value);
        }
    } 
    else {
        StringPath path = entityPath.getString(criteria.getKey());
        if (criteria.getOperation().equalsIgnoreCase(":")) {
            return path.containsIgnoreCase(criteria.getValue().toString());
        }
    }
    return null;
}

}

将它们封装在SearchCriteria中

public class SearchCriteria {
private String key;
private String operation;
private Object value;

}

最后,您需要一个构建器来实际动态创建您的条件

public class MyUserPredicatesBuilder {
private List<SearchCriteria> params;

public MyUserPredicatesBuilder() {
    params = new ArrayList<>();
}

public MyUserPredicatesBuilder with(
  String key, String operation, Object value) {

    params.add(new SearchCriteria(key, operation, value));
    return this;
}

public BooleanExpression build() {
    if (params.size() == 0) {
        return null;
    }

    List predicates = params.stream().map(param -> {
        MyUserPredicate predicate = new MyUserPredicate(param);
        return predicate.getPredicate();
    }).filter(Objects::nonNull).collect(Collectors.toList());

    BooleanExpression result = Expressions.asBoolean(true).isTrue();
    for (BooleanExpression predicate : predicates) {
        result = result.and(predicate);
    }        
    return result;
}

}

这里有控制器示例-您需要对其进行调整,因为这不是REST的,但是有点时髦

@Controller

公共类UserController {

@Autowired
private MyUserRepository myUserRepository;

@RequestMapping(method = RequestMethod.GET, value = "/myusers")
@ResponseBody
public Iterable<MyUser> search(@RequestParam(value = "search") String search) {
    MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder();

    if (search != null) {
        Pattern pattern = Pattern.compile("(\w+?)(:|<|>)(\w+?),");
        Matcher matcher = pattern.matcher(search + ",");
        while (matcher.find()) {
            builder.with(matcher.group(1), matcher.group(2), matcher.group(3));
        }
    }
    BooleanExpression exp = builder.build();
    return myUserRepository.findAll(exp);
}

}