«1. Обзор

В этом руководстве мы продолжим вторую часть веб-поддержки Spring Data Querydsl. Здесь мы сосредоточимся на связанных объектах и ​​на том, как создавать запросы через HTTP.

Следуя той же конфигурации, что и в первой части, мы создадим проект на основе Maven. Пожалуйста, обратитесь к оригинальной статье, чтобы узнать, как настроить основы.

2. Сущности

Во-первых, давайте добавим новую сущность (Адрес), создающую связь между пользователем и его адресом. Мы использовали отношение OneToOne для простоты.

Следовательно, у нас будут следующие классы:

@Entity 
public class User {

    @Id 
    @GeneratedValue
    private Long id;

    private String name;

    @OneToOne(fetch = FetchType.LAZY, mappedBy = "user") 
    private Address addresses;

    // getters & setters 
}
@Entity 
public class Address {

    @Id 
    @GeneratedValue
    private Long id;

    private String address;

    private String country;

    @OneToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "user_id") 
    private User user;

    // getters & setters
}

3. Репозитории Spring Data

На этом этапе мы должны создать репозитории Spring Data, как обычно, по одному для каждой сущности . Обратите внимание, что эти репозитории будут иметь конфигурацию Querydsl.

public interface AddressRepository extends JpaRepository<Address, Long>, 
  QuerydslPredicateExecutor<Address>, QuerydslBinderCustomizer<QAddress> {
 
    @Override 
    default void customize(QuerydslBindings bindings, QAddress root) {
        bindings.bind(String.class)
          .first((SingleValueBinding<StringPath, String>) StringExpression::eq);
    }
}

Давайте посмотрим на репозиторий AddressRepository и объясним, как работает конфигурация фреймворка:

Мы переопределяем метод custom(), чтобы настроить привязку по умолчанию. В этом случае мы настроим привязку метода по умолчанию, чтобы она была равна для всех свойств String.

После того, как репозиторий настроен, нам просто нужно добавить @RestController для управления HTTP-запросами.

4. Query Rest Controller

В первой части мы объяснили Query@RestController поверх пользовательского репозитория, здесь мы просто воспользуемся им.

@GetMapping(value = "/addresses", produces = MediaType.APPLICATION_JSON_VALUE)
public Iterable<Address> queryOverAddress(
  @QuerydslPredicate(root = Address.class) Predicate predicate) {
    BooleanBuilder builder = new BooleanBuilder();
    return addressRepository.findAll(builder.and(predicate));
}

Кроме того, мы можем запросить таблицу адресов; поэтому для этого мы просто добавим аналогичный метод:

Давайте создадим несколько тестов, чтобы увидеть, как это работает.

5. Интеграционное тестирование

Мы включили тест, чтобы проверить, как работает Querydsl. Для этого мы используем инфраструктуру MockMvc для имитации HTTP-запросов пользователя, присоединяющегося к этому объекту с новым: адресом. Поэтому теперь мы можем делать запросы, фильтрующие атрибуты адреса.

Давайте получим всех пользователей, проживающих в Испании:

@Test
public void givenRequest_whenQueryUserFilteringByCountrySpain_thenGetJohn() throws Exception {
    mockMvc.perform(get("/users?address.country=Spain")).andExpect(status().isOk()).andExpect(content()
      .contentType(contentType))
      .andExpect(jsonPath("$", hasSize(1)))
      .andExpect(jsonPath("$[0].name", is("John")))
      .andExpect(jsonPath("$[0].address.address", is("Fake Street 1")))
      .andExpect(jsonPath("$[0].address.country", is("Spain")));
}

/users?addresses.country=Spain

select user0_.id as id1_1_, 
       user0_.name as name2_1_ 
from user user0_ 
      cross join address address1_ 
where user0_.id=address1_.user_id 
      and address1_.country='Spain'

В результате Querydsl сопоставит предикат, отправленный по HTTP, и сгенерирует следующий сценарий SQL:

6. Заключение

Подводя итог, мы увидели, что Querydsl предлагает веб-клиентам очень простую альтернативу созданию динамических запросов; еще одно мощное использование этой структуры.

В части I мы видели, как извлекать данные из одной таблицы; следовательно, теперь мы можем добавлять запросы, объединяющие несколько таблиц, предлагая веб-клиентам лучший опыт фильтрации непосредственно через HTTP-запросы, которые они делают.