Создание условно запущенных критериев с аннотацией запуска hibernate - PullRequest
0 голосов
/ 28 ноября 2018

Я создаю 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 голосов
/ 29 ноября 2018

Хотя кажется, что все должно быть просто, похоже, вам нужно использовать Предикаты и 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);
      }
}

Затем клиент предикат, чтобы взять ваш список параметров

public 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
public class 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);
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...