Skip to content

Project3# Quest final#3

Open
MBabkin2026 wants to merge 25 commits intoSchreiber888:mainfrom
MBabkin2026:main
Open

Project3# Quest final#3
MBabkin2026 wants to merge 25 commits intoSchreiber888:mainfrom
MBabkin2026:main

Conversation

@MBabkin2026
Copy link
Copy Markdown

No description provided.

@demologin
Copy link
Copy Markdown

Общий вывод по проекту

Проект представляет собой классическое веб-приложение на базе сервлетов. Видна хорошая попытка структурировать код по слоям (Repository, Service, Servlet). Однако основные проблемы кроются в нарушении принципов работы с многопоточностью (использование HashMap в сервлетах) и ошибках в использовании обобщений (Generics) в интерфейсе репозитория. Также стоит уделить внимание обработке исключений и инкапсуляции полей.

Итоговая оценка: C (deadline)

import java.time.LocalDateTime;

public class GameRecord {
private LocalDateTime timestamp;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Поля класса рекомендуется делать финальными, если объект не предполагает изменения после создания. Это обеспечивает потокобезопасность и упрощает логику.

this.score = score;
}

public void setWin(boolean win) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Имя сеттера 'setWin' не совсем соответствует имени поля 'isWin'. Рекомендуется использовать 'setWon' или переименовать поле в 'win' для единообразия с 'isWin()'.


import java.io.IOException;
import java.util.Collection;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Прямая зависимость от синглтона 'UserService.USER_SERVICE' затрудняет тестирование. Рекомендуется использовать внедрение зависимостей (Dependency Injection).

public class UserListServlet extends HttpServlet {

private final UserService userService= Winter.find(UserService.class);
private final UserService userService = UserService.USER_SERVICE;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Путь к JSP-файлу жестко закодирован в методе. Подобные константы следует выносить в отдельные статические переменные или конфигурацию.

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Использование пустой строки '""' в URL-паттерне может привести к конфликтам при обработке корневых запросов. Лучше использовать конкретный путь.


public class UserRepository implements Repository<User> {

private final Map<Long, User> map = new HashMap<>();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Использование 'HashMap' в многопоточной среде сервлетов небезопасно. Рекомендуется заменить на 'ConcurrentHashMap' для предотвращения проблем с консистентностью данных.


private final Map<Long, User> map = new HashMap<>();

public static final AtomicLong id = new AtomicLong(System.currentTimeMillis());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Статическое поле для генерации ID в репозитории — плохая практика. Состояние счетчика должно принадлежать экземпляру или внешнему хранилищу, чтобы избежать проблем при тестировании.


private final Map<Long, User> map = new HashMap<>();

public static final AtomicLong id = new AtomicLong(System.currentTimeMillis());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Использование 'System.currentTimeMillis()' в качестве начального значения 'AtomicLong' может привести к коллизиям ID при быстром перезапуске приложения.

import com.javarush.babkin.entity.Role;
import com.javarush.babkin.entity.User;

import java.util.*;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Использование импорта через звездочку 'java.util.*' считается плохим тоном. Следует импортировать только те классы, которые действительно используются.



public UserRepository() {
map.put(1L, User.builder()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Инициализация данных в конструкторе репозитория смешивает логику хранения и начального наполнения. Рекомендуется вынести наполнение тестовыми данными в отдельный сервис инициализации.


@Override
public Collection<User> getAll() {
return map.values();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Метод возвращает внутреннюю коллекцию напрямую. Рекомендуется возвращать неизменяемую копию (например, через 'List.copyOf()'), чтобы защитить данные от внешнего изменения.

@@ -26,30 +26,42 @@ public void init(ServletConfig config) throws ServletException {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Метод 'Long.parseLong(id)' может выбросить 'NumberFormatException', если параметр отсутствует или не является числом. Необходимо добавить проверку или блок try-catch.

@@ -26,30 +26,42 @@ public void init(ServletConfig config) throws ServletException {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если пользователь с указанным ID не найден, сервлет продолжит выполнение без уведомления об ошибке. Следует предусмотреть обработку отсутствующего значения (например, редирект на 404).


@WebServlet(value = "/edit-user", loadOnStartup = 1)
public class EditUserServlet extends HttpServlet {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Установка атрибута 'roles' в 'ServletContext' при каждом создании сервлета избыточна. Это лучше сделать один раз в 'ServletContextListener'.


@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String stringId = req.getParameter("id");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Закомментированный код ('// if (user.isPresent()) ...') следует удалять перед публикацией в репозиторий для поддержания чистоты проекта.

import java.util.Collection;
import java.util.Optional;

public enum UserService {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Реализация сервиса в виде 'enum' (Singleton) ограничивает гибкость и затрудняет расширение приложения. Рекомендуется использовать обычный класс.

public enum UserService {
USER_SERVICE;

public final Repository<User> userRepository = new UserRepository();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Поле 'userRepository' объявлено как 'public'. Это нарушает принцип инкапсуляции. Поле должно быть 'private' и доступно только внутри сервиса.

return userRepository.get(id);
}

public User getUserById(long userId) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Методы 'getById' и 'getUserById' дублируют друг друга. Следует оставить один метод с четким возвращаемым типом.

}

public User getUserById(long userId) {
return userRepository.get(userId).orElse(null);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Возврат 'null' через 'orElse(null)' в современном Java считается плохой практикой. Рекомендуется возвращать 'Optional' и обрабатывать его на уровне выше.

return userRepository.get(userId).orElse(null);
}

public void updateQuestProgress(Long userId, QuestProgress progress) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Метод 'updateQuestProgress' не содержит реализации в предоставленном коде или выглядит как проброс метода. Стоит добавить логирование или проверку входных данных.

@Override
public void create(User entity) {
entity.setId(id.incrementAndGet());
update(entity);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Метод 'create' вызывает 'update'. Хотя логика верна, для ясности кода лучше явно выполнять сохранение в карту внутри метода 'create'.

@@ -1,27 +1,28 @@
package com.javarush.khmelov.lesson14.controller;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В проекте полностью отсутствует логирование (например, через SLF4J). Использование 'System.out.println' или отсутствие логов затрудняет отладку в продакшене.

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отсутствует валидация данных, поступающих из 'HttpServletRequest'. Это может привести к уязвимостям или ошибкам при обработке некорректного ввода.

import java.util.*;
import java.util.concurrent.atomic.AtomicLong;

public class UserRepository implements Repository<User> {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Класс не помечен как 'final', хотя используется как единственный экземпляр. Рекомендуется явно ограничивать наследование, если оно не предполагается архитектурой.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants