Создание потокобезопасного REST‑сервиса для управления постами пользователей

Разделите controller и in-memory service. Все изменения списка и получение его снимка защищайте одним lock; наружу возвращайте неизменяемые записи, а не внутреннюю коллекцию.

Короткий ответ

Что ответить на собеседовании

Разделите controller и in-memory service. Все изменения списка и получение его снимка защищайте одним lock; наружу возвращайте неизменяемые записи, а не внутреннюю коллекцию.

Подробный разбор

Ответ с пояснениями

Условие

Разработать REST‑API, которое реализует следующие возможности:

  1. Эндпоинт для сохранения нового сообщения от пользователя.
  2. Эндпоинт для получения ленты новостей: возвращает либо все сообщения, либо только сообщения конкретного автора по параметру user_name.

Требования к реализации:

  • Данные должны храниться в оперативной памяти (InMemory).
  • Решение должно быть безопасным при работе из нескольких потоков.
  • Придерживаться объектно‑ориентированных принципов при проектировании.

Структура входящего запроса:

  • Request:

    • user_name — уникальный идентификатор автора.
    • message — текст сообщения.

Ответ

Разделите controller и in-memory service. Все изменения списка и получение его снимка защищайте одним lock; наружу возвращайте неизменяемые записи, а не внутреннюю коллекцию.

Минимальный пример для Java 17+/Spring MVC (imports опущены):

record Post(String user_name, String message) {}

@Service
class PostService {
    private final List<Post> posts = new ArrayList<>();
    synchronized Post add(Post post) {
        posts.add(post);
        return post;
    }
    synchronized List<Post> list(String author) {
        return posts.stream()
            .filter(p -> author == null || author.equals(p.user_name()))
            .toList();
    }
}

@RestController
@RequestMapping("/posts")
class PostController {
    private final PostService service;
    PostController(PostService service) { this.service = service; }
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    Post add(@RequestBody Post post) {
        if (post == null || post.user_name() == null || post.user_name().isBlank()
                || post.message() == null || post.message().isBlank()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Пустые поля");
        }
        return service.add(post);
    }
    @GetMapping
    List<Post> list(@RequestParam(name="user_name", required=false) String author) {
        return service.list(author);
    }
}

Гарантии действуют в одном процессе, данные теряются при рестарте. Для production дополнительно нужны лимит хранения, пагинация и получение автора из проверенной авторизации, а не доверие произвольному user_name.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее