Если frontend и backend живут на разных доменах или портах, браузер начнет резать запросы по CORS. Это не баг Spring Boot и не проблема React. Это нормальный механизм безопасности браузера.
Правильный способ - настроить CORS на стороне backend.
В Spring Boot это можно сделать глобально через
WebMvcConfigurer: указать маршруты, разрешенные origins, HTTP-методы, заголовки и работу с credentials.Главное - не ставить бездумно
* везде подряд, особенно если используете cookies, токены или allowCredentials(true). В проде лучше явно перечислять доверенные домены, например frontend-домен приложения.Такой подход дает централизованный контроль: вы один раз задаете политику CORS и не размазываете настройки по каждому контроллеру.
Для Java backend-разработчика это базовая, но важная вещь: CORS должен быть частью архитектуры API, а не случайной правкой перед деплоем.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍5🔥1
Небольшой, но полезный совет для Spring Boot.
Если у вас есть scheduled task, не стоит хардкодить интервал прямо в аннотации:
Лучше вынести значение в конфиг:
А в
Почему так лучше:
• интервал можно менять без правки кода;
• настройки проще различать для dev, staging и production;
• меньше магических чисел в бизнес-логике;
• конфигурация становится прозрачнее.
Мелочь, но именно из таких мелочей и складывается нормальная поддерживаемость Spring Boot-проекта.
Если у вас есть scheduled task, не стоит хардкодить интервал прямо в аннотации:
`@Scheduled(fixedRate = 5000)`
Лучше вынести значение в конфиг:
`@Scheduled(fixedRateString = "${task.interval}")`
А в
application.properties указать:
`task.interval=5000`
Почему так лучше:
• интервал можно менять без правки кода;
• настройки проще различать для dev, staging и production;
• меньше магических чисел в бизнес-логике;
• конфигурация становится прозрачнее.
Мелочь, но именно из таких мелочей и складывается нормальная поддерживаемость Spring Boot-проекта.
👍10❤7
13 мая(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
📂 Виктор Анохин, старший разработчик из WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Виктор будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Виктору
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4
N+1 в Spring Boot выглядит безобидно, пока прод не начинает молиться на базу данных.
Классический сценарий:
Вы грузите список заказов:
А потом в цикле обращаетесь к
Hibernate сначала делает один запрос за заказами, а потом ещё по одному запросу на каждый заказ, чтобы достать items.
100 заказов = 101 SQL-запрос.
И вот здесь спасает
Он позволяет явно сказать репозиторию, какие связи нужно подтянуть сразу:
В итоге Hibernate может сгенерировать один запрос с
Что получаем:
- меньше SQL-запросов
- меньше нагрузки на БД
- чище код репозитория
- без ручного JPQL
- fetch-стратегия управляется точечно под конкретный кейс
Классический сценарий:
Вы грузите список заказов:
orderRepository.findAll()А потом в цикле обращаетесь к
order.getItems().Hibernate сначала делает один запрос за заказами, а потом ещё по одному запросу на каждый заказ, чтобы достать items.
100 заказов = 101 SQL-запрос.
И вот здесь спасает
@EntityGraph.Он позволяет явно сказать репозиторию, какие связи нужно подтянуть сразу:
@EntityGraph(attributePaths = {"items"})В итоге Hibernate может сгенерировать один запрос с
JOIN, вместо десятков лишних походов в базу.Что получаем:
- меньше SQL-запросов
- меньше нагрузки на БД
- чище код репозитория
- без ручного JPQL
- fetch-стратегия управляется точечно под конкретный кейс
LAZY сам по себе не зло. Зло - когда вы не контролируете, где и как он срабатывает.@EntityGraph - один из самых простых способов держать N+1 под контролем в Spring Boot.❤12👍4
Spring Boot: уберите try/catch из контроллеров
В Spring Boot не нужно размазывать обработку ошибок по каждому endpoint через бесконечные
Для этого есть
Идея простая: вы выносите обработку исключений в один глобальный класс, а контроллеры оставляете чистыми.
Например:
После этого контроллер может выглядеть спокойно:
Если пользователь не найден - сервис кидает ResourceNotFoundException, а Spring сам отправит нормальный 404.
Что это даёт:
• меньше мусора в контроллерах
• единый формат ошибок
• проще поддерживать API
• легче логировать исключения
• меньше копипасты в endpoint-ах
Контроллер должен описывать сценарий запроса, а не превращаться в свалку обработки ошибок.
В Spring Boot не нужно размазывать обработку ошибок по каждому endpoint через бесконечные
try/catch.Для этого есть
@RestControllerAdvice.Идея простая: вы выносите обработку исключений в один глобальный класс, а контроллеры оставляете чистыми.
Например:
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<?> handleNotFound(ResourceNotFoundException ex) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse("NOT_FOUND", ex.getMessage()));
}
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<?> handleBadRequest(IllegalArgumentException ex) {
return ResponseEntity
.badRequest()
.body(new ErrorResponse("BAD_REQUEST", ex.getMessage()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<?> handleGeneric(Exception ex) {
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse("INTERNAL_ERROR", "Something went wrong"));
}
}
После этого контроллер может выглядеть спокойно:
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
Если пользователь не найден - сервис кидает ResourceNotFoundException, а Spring сам отправит нормальный 404.
Что это даёт:
• меньше мусора в контроллерах
• единый формат ошибок
• проще поддерживать API
• легче логировать исключения
• меньше копипасты в endpoint-ах
Контроллер должен описывать сценарий запроса, а не превращаться в свалку обработки ошибок.
❤5👍2🥰1
Твой код — в сердце мощного ИИ! 💚
Команда GigaChat зовёт на One Day Offer амбициозных Java-разработчиков, которые готовы создавать AI‑продукты уровня BigTech и стать частью крупнейшего AI-комьюнити.
Если ты дружишь с Java (версии 8–25), ладишь со Spring и Hibernate, а PostgreSQL и ClickHouse для тебя — не просто слова, переходи по ссылке и занимай слот на One Day Offer.
Встречаемся 23 мая — очень ждём именно тебя!
Команда GigaChat зовёт на One Day Offer амбициозных Java-разработчиков, которые готовы создавать AI‑продукты уровня BigTech и стать частью крупнейшего AI-комьюнити.
Если ты дружишь с Java (версии 8–25), ладишь со Spring и Hibernate, а PostgreSQL и ClickHouse для тебя — не просто слова, переходи по ссылке и занимай слот на One Day Offer.
Встречаемся 23 мая — очень ждём именно тебя!
❤3
Forwarded from Java
N+1 в Spring Boot выглядит безобидно, пока прод не начинает молиться на базу данных.
Классический сценарий:
Вы грузите список заказов:
А потом в цикле обращаетесь к
Hibernate сначала делает один запрос за заказами, а потом ещё по одному запросу на каждый заказ, чтобы достать items.
100 заказов = 101 SQL-запрос.
И вот здесь спасает
Он позволяет явно сказать репозиторию, какие связи нужно подтянуть сразу:
В итоге Hibernate может сгенерировать один запрос с
Что получаем:
- меньше SQL-запросов
- меньше нагрузки на БД
- чище код репозитория
- без ручного JPQL
- fetch-стратегия управляется точечно под конкретный кейс
Классический сценарий:
Вы грузите список заказов:
orderRepository.findAll()А потом в цикле обращаетесь к
order.getItems().Hibernate сначала делает один запрос за заказами, а потом ещё по одному запросу на каждый заказ, чтобы достать items.
100 заказов = 101 SQL-запрос.
И вот здесь спасает
@EntityGraph.Он позволяет явно сказать репозиторию, какие связи нужно подтянуть сразу:
@EntityGraph(attributePaths = {"items"})В итоге Hibernate может сгенерировать один запрос с
JOIN, вместо десятков лишних походов в базу.Что получаем:
- меньше SQL-запросов
- меньше нагрузки на БД
- чище код репозитория
- без ручного JPQL
- fetch-стратегия управляется точечно под конкретный кейс
LAZY сам по себе не зло. Зло - когда вы не контролируете, где и как он срабатывает.@EntityGraph - один из самых простых способов держать N+1 под контролем в Spring Boot.❤2