Розробка бекенду сайту на Java (Quarkus)

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка бекенду сайту на Java (Quarkus)
Складна
від 2 тижнів до 3 місяців
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка бекенду сайту на Java (Quarkus)

Quarkus — Java-фреймворк, переосмислений для cloud-native і Kubernetes. Головна різниця від Spring Boot: Quarkus компілює додаток у нативний бінарник через GraalVM Native Image. Час холодного старту — 0.01–0.1 секунди проти 2–10 секунд у Spring Boot. Споживання пам'яті — 20–60 МБ проти 200–500 МБ.

Це не просто цифри для бенчмарків. У Kubernetes-оточенні з автомасштабуванням швидкий старт означає реальне горизонтальне масштабування: Pod піднімається за секунди, не хвилини. На Serverless — це різниця між робочим і нероблячим рішенням.

У JVM-режимі Quarkus конкурує з Spring Boot, у нативному — з Go.

Відмінності від Spring Boot

Quarkus використовує знайомі специфікації: JAX-RS, CDI, JPA, MicroProfile. Якщо знаєте Spring, перехід займає кілька днів. Ключові відмінності:

  • Dependency Injection через CDI (@ApplicationScoped, @RequestScoped), не Spring DI
  • REST через RESTEasy Reactive (JAX-RS), не Spring MVC
  • ORM — Hibernate з Panache (Active Record або Repository pattern)
  • Конфігурація через application.properties або YAML, MicroProfile Config

Структура та REST

// Product entity з Panache Active Record
@Entity
@Table(name = "products")
public class Product extends PanacheEntityBase {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;

    @Column(nullable = false, length = 255)
    public String name;

    @Column(unique = true)
    public String slug;

    @Column(precision = 10, scale = 2)
    public BigDecimal price;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id")
    public Category category;

    public boolean isActive = true;

    @Column(columnDefinition = "jsonb")
    @Type(JsonType.class)
    public Map<String, Object> attributes = new HashMap<>();

    // Статичні методи Panache
    public static List<Product> findActive() {
        return list("isActive", true);
    }

    public static Page<Product> findActiveByCategory(Long categoryId, int page, int size) {
        return find("category.id = ?1 and isActive = true", categoryId)
            .page(page, size);
    }
}

Resource (Controller)

@Path("/api/v1/products")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@ApplicationScoped
public class ProductResource {

    @Inject
    ProductService productService;

    @GET
    @Authenticated
    public Response list(
            @QueryParam("page") @DefaultValue("0") int page,
            @QueryParam("size") @DefaultValue("20") @Max(100) int size,
            @QueryParam("category_id") Long categoryId) {

        PanacheQuery<Product> query = categoryId != null
            ? Product.find("category.id = ?1 and isActive = true", categoryId)
            : Product.find("isActive", true);

        List<Product> products = query
            .page(page, size)
            .list();

        long total = query.count();

        return Response.ok(new PagedResponse<>(
            products.stream().map(ProductDto::from).toList(),
            page, size, total
        )).build();
    }

    @POST
    @RolesAllowed("admin")
    @Transactional
    public Response create(@Valid CreateProductRequest request) {
        Product product = productService.create(request);
        return Response.status(Response.Status.CREATED)
            .entity(ProductDto.from(product))
            .build();
    }

    @GET
    @Path("/{id}")
    public ProductDto get(@PathParam("id") Long id) {
        return Product.findByIdOptional(id)
            .map(ProductDto::from)
            .orElseThrow(NotFoundException::new);
    }

    @DELETE
    @Path("/{id}")
    @RolesAllowed("admin")
    @Transactional
    public Response delete(@PathParam("id") Long id) {
        boolean deleted = Product.deleteById(id);
        return deleted ? Response.noContent().build() : Response.status(404).build();
    }
}

Reactive endpoint

Quarkus з RESTEasy Reactive підтримує неблокуючі операції нативно:

@GET
@Path("/search")
public Uni<List<ProductDto>> search(@QueryParam("q") String query) {
    return Product.<Product>find("name like ?1", "%" + query + "%")
        .list()
        .map(products -> products.stream().map(ProductDto::from).toList());
}

// Реактивна робота з БД через Hibernate Reactive
@GET
@Path("/{id}/with-reviews")
public Uni<ProductWithReviews> getWithReviews(@PathParam("id") Long id) {
    return Panache.withTransaction(() ->
        Product.<Product>findById(id)
            .flatMap(product -> Review.<Review>find("product.id", id).list()
                .map(reviews -> new ProductWithReviews(product, reviews)))
    );
}

Безпека через SmallRye JWT

# application.properties
mp.jwt.verify.publickey.location=META-INF/resources/publicKey.pem
mp.jwt.verify.issuer=https://myapp.com
quarkus.http.auth.permission.authenticated.paths=/api/v1/*
quarkus.http.auth.permission.authenticated.policy=authenticated
quarkus.http.auth.permission.public.paths=/api/v1/auth/*,/api/v1/products
quarkus.http.auth.permission.public.policy=permit
@Path("/api/v1/auth")
public class AuthResource {

    @Inject
    @Claim(standard = Claims.sub)
    Optional<JsonString> subject;

    @POST
    @Path("/login")
    @PermitAll
    public Response login(@Valid LoginRequest request) {
        User user = User.findByEmail(request.email())
            .orElseThrow(() -> new UnauthorizedException("Invalid credentials"));

        if (!BCrypt.verifyer().verify(request.password().toCharArray(), user.passwordHash).verified) {
            throw new UnauthorizedException("Invalid credentials");
        }

        String token = Jwt.issuer("https://myapp.com")
            .subject(user.id.toString())
            .groups(Set.of(user.role))
            .claim("email", user.email)
            .expiresIn(Duration.ofHours(1))
            .sign();

        return Response.ok(new LoginResponse(token)).build();
    }
}

Нативна збірка

# JVM-режим (звичайна збірка)
./mvnw package -DskipTests
java -jar target/quarkus-app/quarkus-run.jar

# Нативний образ — потребує GraalVM або Docker
./mvnw package -Pnative -DskipTests

# Нативний в Docker без локального GraalVM
./mvnw package -Pnative -Dquarkus.native.container-build=true
docker build -f src/main/docker/Dockerfile.native -t myapp .

# Розмір образу: ~100MB (проти ~500MB JVM Spring Boot)
# Startup: ~50ms (проти 3-8s Spring Boot)
# Пам'ять: ~30MB (проти ~200MB Spring Boot)

Інтеграція Kafka

// Producer
@ApplicationScoped
public class ProductEventProducer {

    @Inject
    @Channel("products-out")
    Emitter<ProductEvent> emitter;

    public void publishCreated(Product product) {
        emitter.send(Message.of(new ProductEvent("created", product.id, product.name)));
    }
}

// Consumer
@ApplicationScoped
public class InventoryConsumer {

    @Incoming("inventory-updates")
    public void onInventoryUpdate(InventoryUpdateEvent event) {
        Product.update("stock = ?1 where id = ?2", event.stock(), event.productId());
    }
}

Dev режим

Quarkus Dev Mode — один із найкращих hot-reload механізмів у Java-екосистемі:

./mvnw quarkus:dev
# Будь-які зміни застосовуються без перезапуску
# Dev UI доступний на localhost:8080/q/dev
# Вбудований Dev Services: PostgreSQL, Redis, Kafka — запускаються автоматично в Docker

Графік розробки

  • Налаштування проекту + Dev Services + міграції Flyway — 3–5 днів
  • Entities (Panache) + Resources — 1–1,5 тижні
  • Security + JWT — 3–5 днів
  • Reactive endpoints якщо потрібні — додаткова тиждень
  • Налаштування нативної збірки — 2–5 днів (часто потребує reflection hints)
  • Тести (QuarkusTest + RestAssured) — 1 тиждень

Корпоративний бекенд: 7–14 тижнів. Quarkus окупається у Kubernetes-середовищі, особливо коли потрібне швидке автомасштабування або Serverless-деплой.