Главная  /  Статьи  /  Java

Vibe Codex для Spring Boot: контроллеры, JPA, тесты

Java — это язык, где правильное «скучное» решение всегда длиннее, чем хочется. Хорошо, когда писать его не приходится.

Spring Boot — это конструктор, где 70% кода — это слой, в котором ничего не происходит: DTO, мапперы, репозитории, конфигурации. Vibe Codex закрывает этот слой за минуты, а человек остаётся в зоне ответственности за бизнес-логику и архитектурные решения.

REST-контроллер с валидацией

$ vibe-codex "REST-контроллер /api/v1/orders, \
              POST: create — принимает CreateOrderRequest, \
              GET: list с пагинацией, \
              GET: by id, \
              использует Jakarta Validation"
[plan] 5 files:
  + controller/OrderController.java
  + dto/CreateOrderRequest.java
  + dto/OrderResponse.java
  + service/OrderService.java
  + service/OrderServiceImpl.java
// controller/OrderController.java
@RestController
@RequestMapping("/api/v1/orders")
@RequiredArgsConstructor
@Validated
public class OrderController {

    private final OrderService orderService;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public OrderResponse create(@Valid @RequestBody CreateOrderRequest request,
                                @AuthenticationPrincipal User user) {
        return orderService.create(request, user);
    }

    @GetMapping
    public Page<OrderResponse> list(@PageableDefault(size = 20) Pageable pageable,
                                    @AuthenticationPrincipal User user) {
        return orderService.list(user, pageable);
    }

    @GetMapping("/{id}")
    public OrderResponse byId(@PathVariable @Positive Long id,
                              @AuthenticationPrincipal User user) {
        return orderService.byId(id, user);
    }
}

Заметьте: @AuthenticationPrincipal — потому что в проекте Spring Security, а не «передавайте userId в query». Vibe Codex прочитал конфиг и подсмотрел.

JPA-репозиторий с проекциями

$ vibe-codex "проекция OrderSummary (id, total, status, createdAt) \
              для OrderRepository, метод findSummaryByUserId"
public interface OrderRepository extends JpaRepository<Order, Long> {

    interface OrderSummary {
        Long getId();
        BigDecimal getTotal();
        OrderStatus getStatus();
        Instant getCreatedAt();
    }

    Page<OrderSummary> findSummaryByUserId(Long userId, Pageable pageable);
}

Никаких SELECT *, никаких @Query там, где справляется derived query.

MapStruct без копипасты

В Spring-проектах маппер — самое скучное, что можно представить. Vibe Codex генерирует интерфейс с правильными @Mapping, проверяет, что все поля DTO покрыты, и предупреждает, если нет.

$ vibe-codex "MapStruct маппер Order → OrderResponse, \
              total из BigDecimal в строку с двумя знаками, \
              createdAt в ISO-8601"
[mapping] 7/7 fields covered
[warn] поле customerEmail в DTO отсутствует — пропустить или добавить?

Тесты: JUnit 5 + Testcontainers

$ vibe-codex "интеграционный тест OrderControllerIT, \
              Testcontainers с Postgres, проверяет POST /orders и \
              GET /orders/{id}"
@SpringBootTest
@AutoConfigureMockMvc
@Testcontainers
class OrderControllerIT {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16")
            .withDatabaseName("test")
            .withUsername("test")
            .withPassword("test");

    @DynamicPropertySource
    static void props(DynamicPropertyRegistry r) {
        r.add("spring.datasource.url",      postgres::getJdbcUrl);
        r.add("spring.datasource.username", postgres::getUsername);
        r.add("spring.datasource.password", postgres::getPassword);
    }

    @Autowired MockMvc mvc;

    @Test
    void createAndFetchOrder() throws Exception {
        var location = mvc.perform(post("/api/v1/orders")
                .contentType(APPLICATION_JSON)
                .content("""
                    { "items": [{ "sku": "SKU-1", "qty": 2 }] }
                    """))
            .andExpect(status().isCreated())
            .andReturn().getResponse().getHeader("Location");

        mvc.perform(get(location))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.status").value("CREATED"));
    }
}

Flyway-миграции

Vibe Codex знает Flyway-конвенцию V{version}__description.sql и не позволяет себе писать миграции «в файле V1, дольше менять».

$ vibe-codex "миграция: добавить колонку customer_email \
              в orders, индекс по email, заполнить из join с users"
[plan] 1 file: db/migration/V20260512_01__order_customer_email.sql
[plan] downgrade: V20260512_01__order_customer_email_down.sql
«В Spring Boot стиль и порядок ценнее изящества. Хороший AI-ассистент даёт ровно то, что ревьюер хотел бы увидеть, без обсуждений».

Острые края

Когда переключаться на reasoning

Один контроллер — быстрая модель. Архитектурное «как разнести модуль на три bounded context» — Claude Opus 4.7 или GPT 5.2 Codex с --explain. План сначала, код потом.

Spring Boot хорош тем, что в нём всё на своих местах. Vibe Codex это уважает: не изобретает «как удобнее», а делает «как принято в вашем проекте». Ревьюеру не за что зацепиться, кроме самой логики — на ней и сосредоточиться.

Готов попробовать?

brew tap xrouter-chat/tap && brew install vibe-codex — и за 30 секунд ты в деле.

Поставить Vibe Codex →