Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Запросы: поиск, сортировка, страницы

listAll() возвращает всю таблицу, а блогу нужно больше: искать посты по заголовку, показывать свежие первыми, отдавать список по страницам. Panache принимает запросы на языке HQL — это SQL, в котором вместо таблиц и столбцов пишут классы и поля. Для простых случаев хватает короткой записи — упрощённого запроса.

Упрощённые запросы

ЗаписьЧто выполнится
Post.list("title", "Привет")where title = 'Привет'
Post.list("title like ?1", "%Quarkus%")Условие с позиционным параметром
Post.list("title = :t", Parameters.with("t", "Привет"))Условие с именованным параметром
Post.count("title", "Привет")Число подходящих строк
Post.find("order by createdAt desc")Только сортировка

Методы list сразу возвращают List, а find — объект запроса, к которому можно добавить страницы. Значения всегда передают параметрами (?1, :t), а не склеивают в строку: так нет риска SQL-инъекции.

Запросы в классе сущности

В стиле активной записи свои запросы оформляют статическими методами сущности:

// src/main/java/com/example/blog/Post.java
@Entity
public class Post extends PanacheEntity {
 
    // ... поля title, body, createdAt
 
    public static List<Post> latest(int page, int size) {
        return findAll(Sort.by("createdAt").descending())
                .page(Page.of(page, size))
                .list();
    }
 
    public static List<Post> search(String text) {
        return list("lower(title) like ?1", Sort.by("title"), "%" + text.toLowerCase() + "%");
    }
 
    public static boolean titleExists(String title) {
        return count("title", title) > 0;
    }
}

Импорты — io.quarkus.panache.common.Sort, io.quarkus.panache.common.Page и java.util.List. Sort.by("createdAt").descending() сортирует от новых к старым. Page.of(page, size) берёт страницу номер page (счёт с нуля) по size записей. lower(title) делает поиск нечувствительным к регистру.

Ресурс со страницами и поиском

Размер страницы берём из BlogConfig — настройки blog.page-size:

// src/main/java/com/example/blog/PostResource.java
@Inject
BlogConfig config;
 
@GET
public List<Post> list(@QueryParam("search") String search,
                       @QueryParam("page") @DefaultValue("0") int page) {
    if (search != null) {
        return Post.search(search);
    }
    return Post.latest(page, config.pageSize());
}
 
@GET
@Path("/count")
public long count() {
    return Post.count();
}

Путь /count — отдельный эндпоинт с общим числом постов. Quarkus не спутает его с /{id}: точное совпадение пути важнее шаблона.

Проверка

Поставьте в application.properties значение blog.page-size=2, создайте ещё два поста через POST /posts и запросите страницы:

curl "http://localhost:8080/posts?page=0"
curl "http://localhost:8080/posts?page=1"
curl "http://localhost:8080/posts?search=QUARKUS"
curl http://localhost:8080/posts/count

Вывод сокращён до заголовков:

"title":"Часть 2" "title":"Часть 1"
"title":"Режим разработки" "title":"Привет, Quarkus"
[{"id":1,"title":"Привет, Quarkus", ...}]
4

На нулевой странице — два новых поста, на первой — два старых. Поиск нашёл пост, хотя запрос был в верхнем регистре. Верните blog.page-size=10.

Когда упрощённого запроса мало

Если начало строки — не select, from или order by, Panache сам дописывает from Post where. Полный запрос тоже можно передать: Post.find("from Post p where p.createdAt > ?1", date). Для сложных отчётов есть обычный EntityManager из Jakarta Persistence — его можно внедрить через @Inject.

Частая ошибка

В запросах пишут имена полей класса, а не столбцов таблицы. Если ошибиться в имени, например Post.list("titel", "x"), клиент получит 500, а в логе будет:

ERROR [io.quarkus.vertx.http.runtime.QuarkusErrorHandler] HTTP Request to /posts failed, error id: ...: org.hibernate.query.SemanticException: Could not interpret path expression 'titel'

Ошибка возникает только при выполнении запроса, а не при старте, потому что запрос — обычная строка. Сверяйте имена в запросе с полями сущности.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.