«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-запросы, которые они делают.