From c66d3e1e498b318d8954d6ebe8d1d79d20f63ede Mon Sep 17 00:00:00 2001 From: lemarginal Date: Thu, 26 Feb 2026 05:31:17 +0300 Subject: [PATCH] mushanov | projectPantera --- .gitignore | 3 +- pom.xml | 102 ++++--- .../com/javarush/khmelov/cmd/Command.java | 37 --- .../com/javarush/khmelov/cmd/EditUser.java | 52 ---- .../com/javarush/khmelov/cmd/ListUser.java | 26 -- .../com/javarush/khmelov/cmd/StartPage.java | 6 - .../com/javarush/khmelov/config/Winter.java | 29 -- .../khmelov/controller/FrontController.java | 43 --- .../khmelov/controller/HttpResolver.java | 41 --- .../com/javarush/khmelov/entity/Role.java | 5 - .../com/javarush/khmelov/entity/User.java | 26 -- .../khmelov/repository/Repository.java | 19 -- .../khmelov/repository/UserRepository.java | 50 ---- .../javarush/khmelov/service/UserService.java | 36 --- .../javarush/ushanov/cmd/ChoiceCommand.java | 47 ++++ .../com/javarush/ushanov/cmd/Command.java | 25 ++ .../javarush/ushanov/cmd/NewGameCommand.java | 43 +++ .../javarush/ushanov/cmd/QuestCommand.java | 50 ++++ .../ushanov/cmd/StartPageCommand.java | 17 ++ .../ushanov/controller/FrontController.java | 96 +++++++ .../javarush/ushanov/entity/GameSession.java | 43 +++ .../javarush/ushanov/entity/QuestStep.java | 35 +++ .../javarush/ushanov/entity/StepStatus.java | 14 + .../exception/QuestStepNotFoundException.java | 11 + .../ushanov/repository/QuestRepository.java | 182 ++++++++++++ .../ushanov/service/QuestService.java | 44 +++ .../ushanov/service/SessionService.java | 61 ++++ src/main/resources/logback.xml | 14 + src/main/webapp/WEB-INF/edit-user.jsp | 73 ----- src/main/webapp/WEB-INF/error-page.jsp | 37 +++ src/main/webapp/WEB-INF/head.jsp | 11 - src/main/webapp/WEB-INF/header.jsp | 32 +++ src/main/webapp/WEB-INF/list-user.jsp | 9 - src/main/webapp/WEB-INF/quest-page.jsp | 91 ++++++ src/main/webapp/WEB-INF/start-page.jsp | 78 +++++- src/main/webapp/WEB-INF/web.xml | 26 +- src/main/webapp/css/styles.css | 262 ++++++++++++++++++ src/main/webapp/images/cat.png | Bin 98607 -> 0 bytes .../repository/QuestRepositoryTest.java | 113 ++++++++ .../ushanov/service/QuestServiceTest.java | 110 ++++++++ 40 files changed, 1486 insertions(+), 513 deletions(-) delete mode 100644 src/main/java/com/javarush/khmelov/cmd/Command.java delete mode 100644 src/main/java/com/javarush/khmelov/cmd/EditUser.java delete mode 100644 src/main/java/com/javarush/khmelov/cmd/ListUser.java delete mode 100644 src/main/java/com/javarush/khmelov/cmd/StartPage.java delete mode 100644 src/main/java/com/javarush/khmelov/config/Winter.java delete mode 100644 src/main/java/com/javarush/khmelov/controller/FrontController.java delete mode 100644 src/main/java/com/javarush/khmelov/controller/HttpResolver.java delete mode 100644 src/main/java/com/javarush/khmelov/entity/Role.java delete mode 100644 src/main/java/com/javarush/khmelov/entity/User.java delete mode 100644 src/main/java/com/javarush/khmelov/repository/Repository.java delete mode 100644 src/main/java/com/javarush/khmelov/repository/UserRepository.java delete mode 100644 src/main/java/com/javarush/khmelov/service/UserService.java create mode 100644 src/main/java/com/javarush/ushanov/cmd/ChoiceCommand.java create mode 100644 src/main/java/com/javarush/ushanov/cmd/Command.java create mode 100644 src/main/java/com/javarush/ushanov/cmd/NewGameCommand.java create mode 100644 src/main/java/com/javarush/ushanov/cmd/QuestCommand.java create mode 100644 src/main/java/com/javarush/ushanov/cmd/StartPageCommand.java create mode 100644 src/main/java/com/javarush/ushanov/controller/FrontController.java create mode 100644 src/main/java/com/javarush/ushanov/entity/GameSession.java create mode 100644 src/main/java/com/javarush/ushanov/entity/QuestStep.java create mode 100644 src/main/java/com/javarush/ushanov/entity/StepStatus.java create mode 100644 src/main/java/com/javarush/ushanov/exception/QuestStepNotFoundException.java create mode 100644 src/main/java/com/javarush/ushanov/repository/QuestRepository.java create mode 100644 src/main/java/com/javarush/ushanov/service/QuestService.java create mode 100644 src/main/java/com/javarush/ushanov/service/SessionService.java create mode 100644 src/main/resources/logback.xml delete mode 100644 src/main/webapp/WEB-INF/edit-user.jsp create mode 100644 src/main/webapp/WEB-INF/error-page.jsp delete mode 100644 src/main/webapp/WEB-INF/head.jsp create mode 100644 src/main/webapp/WEB-INF/header.jsp delete mode 100644 src/main/webapp/WEB-INF/list-user.jsp create mode 100644 src/main/webapp/WEB-INF/quest-page.jsp create mode 100644 src/main/webapp/css/styles.css delete mode 100644 src/main/webapp/images/cat.png create mode 100644 src/test/java/com/javarush/ushanov/repository/QuestRepositoryTest.java create mode 100644 src/test/java/com/javarush/ushanov/service/QuestServiceTest.java diff --git a/.gitignore b/.gitignore index a2afc5d..c38ea4f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,11 @@ target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ !**/src/test/**/target/ +*.class ### IntelliJ IDEA ### .idea - +*.iml ### Eclipse ### .apt_generated diff --git a/pom.xml b/pom.xml index 78ee59d..d192786 100644 --- a/pom.xml +++ b/pom.xml @@ -1,94 +1,114 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.javarush.khmelov - project-ledzeppelin + com.javarush.ushanov + project-pantera 1.0-SNAPSHOT - ProjectLedzeppelin + war - UTF-8 - 21 21 - 5.10.2 + 21 + UTF-8 - - org.springframework.boot - spring-boot-starter-parent - 3.3.5 - - - - - - org.springframework.boot - spring-boot-dependencies - pom - import - 3.3.5 - - - - + jakarta.servlet jakarta.servlet-api + 6.0.0 provided + + jakarta.servlet.jsp.jstl jakarta.servlet.jsp.jstl-api + 3.0.0 org.glassfish.web jakarta.servlet.jsp.jstl + 3.0.1 + org.projectlombok lombok + 1.18.30 provided + + + + org.slf4j + slf4j-api + 2.0.9 + + + - org.junit.jupiter - junit-jupiter-api - test + ch.qos.logback + logback-classic + 1.5.32 + + org.junit.jupiter - junit-jupiter-engine + junit-jupiter + 5.10.1 test - + org.apache.maven.plugins maven-war-plugin 3.4.0 + org.apache.maven.plugins - maven-compiler-plugin - - - - org.projectlombok - lombok - 1.18.34 - - - + maven-surefire-plugin + 3.1.2 - \ No newline at end of file diff --git a/src/main/java/com/javarush/khmelov/cmd/Command.java b/src/main/java/com/javarush/khmelov/cmd/Command.java deleted file mode 100644 index fd4035b..0000000 --- a/src/main/java/com/javarush/khmelov/cmd/Command.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.javarush.khmelov.cmd; - -import jakarta.servlet.http.HttpServletRequest; - -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public interface Command { - - default String doGet(HttpServletRequest request) { - return getView(); - } - - default String doPost(HttpServletRequest request) { - return getView(); - } - - default String getView() { - String simpleName = this.getClass().getSimpleName(); - return convertCamelCaseToKebabStyle(simpleName); - } - - private static String convertCamelCaseToKebabStyle(String string) { - String snakeName = string.chars() - .mapToObj(s -> String.valueOf((char) s)) - .flatMap(s -> s.matches("[A-Z]") - ? Stream.of("-", s) - : Stream.of(s)) - .collect(Collectors.joining()) - .toLowerCase(); - return snakeName.startsWith("-") - ? snakeName.substring(1) - : snakeName; - } - - -} diff --git a/src/main/java/com/javarush/khmelov/cmd/EditUser.java b/src/main/java/com/javarush/khmelov/cmd/EditUser.java deleted file mode 100644 index ae191b4..0000000 --- a/src/main/java/com/javarush/khmelov/cmd/EditUser.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.javarush.khmelov.cmd; - -import com.javarush.khmelov.entity.Role; -import com.javarush.khmelov.entity.User; -import com.javarush.khmelov.service.UserService; -import jakarta.servlet.http.HttpServletRequest; - -import java.util.Optional; - - -@SuppressWarnings("unused") -public class EditUser implements Command { - - private final UserService userService; - - public EditUser(UserService userService) { - this.userService = userService; - } - - - @Override - public String doGet(HttpServletRequest req) { - String stringId = req.getParameter("id"); - if (stringId != null) { - long id = Long.parseLong(stringId); - Optional optionalUser = userService.get(id); - if (optionalUser.isPresent()) { - User user = optionalUser.get(); - req.setAttribute("user", user); - } - } - return getView(); - } - - @Override - public String doPost(HttpServletRequest req) { - User user = User.builder() - .login(req.getParameter("login")) - .password(req.getParameter("password")) - .role(Role.valueOf(req.getParameter("role"))) - .build(); - if (req.getParameter("create") != null) { - userService.create(user); - } else if (req.getParameter("update") != null) { - user.setId(Long.parseLong(req.getParameter("id"))); - userService.update(user); - } - return getView() + "?id=" + user.getId(); - } - - -} \ No newline at end of file diff --git a/src/main/java/com/javarush/khmelov/cmd/ListUser.java b/src/main/java/com/javarush/khmelov/cmd/ListUser.java deleted file mode 100644 index 9257917..0000000 --- a/src/main/java/com/javarush/khmelov/cmd/ListUser.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.javarush.khmelov.cmd; - -import com.javarush.khmelov.entity.User; -import com.javarush.khmelov.service.UserService; -import jakarta.servlet.http.HttpServletRequest; - -import java.util.Collection; - -@SuppressWarnings("unused") -public class ListUser implements Command { - - private final UserService userService; - - public ListUser(UserService userService) { - this.userService = userService; - } - - @Override - public String doGet(HttpServletRequest request) { - Collection users = userService.getAll(); - request.setAttribute("users", users); - return getView(); - } - - -} \ No newline at end of file diff --git a/src/main/java/com/javarush/khmelov/cmd/StartPage.java b/src/main/java/com/javarush/khmelov/cmd/StartPage.java deleted file mode 100644 index d268f93..0000000 --- a/src/main/java/com/javarush/khmelov/cmd/StartPage.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.javarush.khmelov.cmd; - -@SuppressWarnings("unused") -public class StartPage implements Command { - -} diff --git a/src/main/java/com/javarush/khmelov/config/Winter.java b/src/main/java/com/javarush/khmelov/config/Winter.java deleted file mode 100644 index 48bd8a7..0000000 --- a/src/main/java/com/javarush/khmelov/config/Winter.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.javarush.khmelov.config; - -import lombok.SneakyThrows; - -import java.lang.reflect.Constructor; -import java.util.concurrent.ConcurrentHashMap; - -public class Winter { - - public static ConcurrentHashMap, Object> components = new ConcurrentHashMap<>(); - - - @SuppressWarnings("unchecked") - @SneakyThrows - public static T find(Class aClass) { - Object component = components.get(aClass); - if (component == null) { - Constructor constructor = aClass.getConstructors()[0]; - Class[] parameterTypes = constructor.getParameterTypes(); - Object[] parameters = new Object[parameterTypes.length]; - for (int i = 0; i < parameters.length; i++) { - parameters[i] = Winter.find(parameterTypes[i]); - } - Object newInstance = constructor.newInstance(parameters); - components.put(aClass, newInstance); - } - return (T) components.get(aClass); - } -} diff --git a/src/main/java/com/javarush/khmelov/controller/FrontController.java b/src/main/java/com/javarush/khmelov/controller/FrontController.java deleted file mode 100644 index 33242b2..0000000 --- a/src/main/java/com/javarush/khmelov/controller/FrontController.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.javarush.khmelov.controller; - -import com.javarush.khmelov.cmd.Command; -import com.javarush.khmelov.config.Winter; -import com.javarush.khmelov.entity.Role; -import jakarta.servlet.ServletConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.annotation.WebServlet; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import java.io.IOException; - -@WebServlet({"", "/home", "/list-user", "/edit-user"}) -public class FrontController extends HttpServlet { - - private final HttpResolver httpResolver = Winter.find(HttpResolver.class); - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - Command command = httpResolver.resolve(req); - String view = command.doGet(req); - String jsp = getJsp(view); - req.getRequestDispatcher(jsp).forward(req, resp); - } - - @Override - public void init(ServletConfig config) { - config.getServletContext().setAttribute("roles", Role.values()); - } - - private static String getJsp(String view) { - return "/WEB-INF/" + view + ".jsp"; - } - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - Command command = httpResolver.resolve(req); - String redirect = command.doPost(req); - resp.sendRedirect(redirect); - } -} diff --git a/src/main/java/com/javarush/khmelov/controller/HttpResolver.java b/src/main/java/com/javarush/khmelov/controller/HttpResolver.java deleted file mode 100644 index 18bb761..0000000 --- a/src/main/java/com/javarush/khmelov/controller/HttpResolver.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.javarush.khmelov.controller; - -import com.javarush.khmelov.cmd.Command; -import com.javarush.khmelov.config.Winter; -import jakarta.servlet.http.HttpServletRequest; - -public class HttpResolver { - - public Command resolve(HttpServletRequest request) { - // /cmd-example - try { - String requestURI = request.getRequestURI(); - requestURI = requestURI.equals("/") ? "/start-page" : requestURI; - String kebabName = requestURI.split("[?#/]")[1]; - String simpleName = convertKebabStyleToCamelCase(kebabName); - String fullName = Command.class.getPackageName() + "." + simpleName; - Class aClass = Class.forName(fullName); - return (Command) Winter.find(aClass); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - } - - private String convertKebabStyleToCamelCase(String input) { - StringBuilder result = new StringBuilder(); - boolean capitalizeNext = true; - for (char c : input.toCharArray()) { - if (c == '-') { - capitalizeNext = true; - } else { - if (capitalizeNext) { - result.append(Character.toUpperCase(c)); - capitalizeNext = false; - } else { - result.append(Character.toLowerCase(c)); - } - } - } - return result.toString(); - } -} diff --git a/src/main/java/com/javarush/khmelov/entity/Role.java b/src/main/java/com/javarush/khmelov/entity/Role.java deleted file mode 100644 index 5ae365f..0000000 --- a/src/main/java/com/javarush/khmelov/entity/Role.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.javarush.khmelov.entity; - -public enum Role { - USER, ADMIN, GUEST -} diff --git a/src/main/java/com/javarush/khmelov/entity/User.java b/src/main/java/com/javarush/khmelov/entity/User.java deleted file mode 100644 index f7fa2d6..0000000 --- a/src/main/java/com/javarush/khmelov/entity/User.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.javarush.khmelov.entity; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class User { - - private Long id; - - private String login; - - private String password; - - private Role role; - - public String getImage() { //TODO move to DTO - return "image-" + id; - } - -} diff --git a/src/main/java/com/javarush/khmelov/repository/Repository.java b/src/main/java/com/javarush/khmelov/repository/Repository.java deleted file mode 100644 index f1abdac..0000000 --- a/src/main/java/com/javarush/khmelov/repository/Repository.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.javarush.khmelov.repository; - -import com.javarush.khmelov.entity.User; - -import java.util.Collection; -import java.util.Optional; - -public interface Repository { - - Collection getAll(); - - Optional get(long id); - - void create(T entity); - - void update(T entity); - - void delete(T entity); -} diff --git a/src/main/java/com/javarush/khmelov/repository/UserRepository.java b/src/main/java/com/javarush/khmelov/repository/UserRepository.java deleted file mode 100644 index 58b32ea..0000000 --- a/src/main/java/com/javarush/khmelov/repository/UserRepository.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.javarush.khmelov.repository; - -import com.javarush.khmelov.entity.Role; -import com.javarush.khmelov.entity.User; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicLong; - -public class UserRepository implements Repository { - - private final Map map = new HashMap<>(); - - public static final AtomicLong id = new AtomicLong(System.currentTimeMillis()); - - public UserRepository() { - map.put(1L, new User(1L, "Alisa", "qwerty", Role.USER)); - map.put(2L, new User(2L, "Bob", "", Role.GUEST)); - map.put(3L, new User(3L, "Carl", "admin", Role.ADMIN)); - map.put(4L, new User(4L, "Khmelov", "admin", Role.ADMIN)); - } - - @Override - public Collection getAll() { - return map.values(); - } - - @Override - public Optional get(long id) { - return Optional.ofNullable(map.get(id)); - } - - @Override - public void create(User entity) { - entity.setId(id.incrementAndGet()); - update(entity); - } - - @Override - public void update(User entity) { - map.put(entity.getId(), entity); - } - - @Override - public void delete(User entity) { - map.remove(entity.getId()); - } -} diff --git a/src/main/java/com/javarush/khmelov/service/UserService.java b/src/main/java/com/javarush/khmelov/service/UserService.java deleted file mode 100644 index b17527c..0000000 --- a/src/main/java/com/javarush/khmelov/service/UserService.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.javarush.khmelov.service; - -import com.javarush.khmelov.entity.User; -import com.javarush.khmelov.repository.UserRepository; - -import java.util.Collection; -import java.util.Optional; - -public class UserService { - - private final UserRepository userRepository; - - public UserService(UserRepository userRepository) { - this.userRepository = userRepository; - } - - public void create(User user) { - userRepository.create(user); - } - - public void update(User user) { - userRepository.update(user); - } - - public void delete(User user) { - userRepository.delete(user); - } - - public Collection getAll() { - return userRepository.getAll(); - } - - public Optional get(long id) { - return userRepository.get(id); - } -} diff --git a/src/main/java/com/javarush/ushanov/cmd/ChoiceCommand.java b/src/main/java/com/javarush/ushanov/cmd/ChoiceCommand.java new file mode 100644 index 0000000..ef351e6 --- /dev/null +++ b/src/main/java/com/javarush/ushanov/cmd/ChoiceCommand.java @@ -0,0 +1,47 @@ +package com.javarush.ushanov.cmd; + +import com.javarush.ushanov.entity.GameSession; +import com.javarush.ushanov.service.SessionService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Команда для обработки выбора игрока. + * + * POST /choice — игрок нажал на кнопку с вариантом ответа. + * + * Логика: + * 1. Читаем параметр "option" из POST-запроса (текст кнопки) + * 2. Через SessionService обновляем текущий шаг в сессии + * 3. Делаем redirect на GET /quest — паттерн PRG (Post-Redirect-Get) + * + * Паттерн PRG важен: если после POST-запроса не делать redirect, + * и пользователь обновит страницу (F5) — браузер отправит POST повторно, + * и выбор будет сделан ещё раз. Redirect это предотвращает. + */ +public class ChoiceCommand implements Command { + + private final SessionService sessionService; + + public ChoiceCommand(SessionService sessionService) { + this.sessionService = sessionService; + } + + @Override + public String execute(HttpServletRequest request, HttpServletResponse response) { + GameSession gameSession = sessionService.getSession(request.getSession()); + + if (gameSession == null) { + return "redirect:/"; + } + + String chosenOption = request.getParameter("option"); + + if (chosenOption != null && !chosenOption.isEmpty()) { + sessionService.processChoice(request.getSession(), chosenOption); + } + + // PRG паттерн: после обработки POST — redirect на GET + return "redirect:/quest"; + } +} diff --git a/src/main/java/com/javarush/ushanov/cmd/Command.java b/src/main/java/com/javarush/ushanov/cmd/Command.java new file mode 100644 index 0000000..751a179 --- /dev/null +++ b/src/main/java/com/javarush/ushanov/cmd/Command.java @@ -0,0 +1,25 @@ +package com.javarush.ushanov.cmd; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Интерфейс команды — основа паттерна Command. + * + * Паттерн Command — каждое действие (показать страницу, обработать выбор) + * оформляется как отдельный класс, реализующий этот интерфейс. + * + * Метод execute() выполняет действие и возвращает путь к JSP-странице, + * которую нужно показать пользователю (или путь для redirect). + */ +public interface Command { + + /** + * Выполнить команду. + * + * @param request HTTP-запрос (содержит параметры, сессию и т.д.) + * @param response HTTP-ответ + * @return путь к JSP-странице для отображения, или "redirect:/path" для перенаправления + */ + String execute(HttpServletRequest request, HttpServletResponse response); +} diff --git a/src/main/java/com/javarush/ushanov/cmd/NewGameCommand.java b/src/main/java/com/javarush/ushanov/cmd/NewGameCommand.java new file mode 100644 index 0000000..aa77d20 --- /dev/null +++ b/src/main/java/com/javarush/ushanov/cmd/NewGameCommand.java @@ -0,0 +1,43 @@ +package com.javarush.ushanov.cmd; + +import com.javarush.ushanov.entity.GameSession; +import com.javarush.ushanov.service.SessionService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Команда для начала новой игры. + * + * Обрабатывает два случая: + * 1. Первый запуск: игрок ввёл имя на стартовой странице — создаём новую сессию. + * 2. Перезапуск: игрок нажал "Играть снова" — сбрасываем прогресс, сохраняем статистику. + */ +public class NewGameCommand implements Command { + + private final SessionService sessionService; + + public NewGameCommand(SessionService sessionService) { + this.sessionService = sessionService; + } + + @Override + public String execute(HttpServletRequest request, HttpServletResponse response) { + String playerName = request.getParameter("playerName"); + GameSession existingSession = sessionService.getSession(request.getSession()); + + if (playerName != null && !playerName.trim().isEmpty()) { + // Пришло имя — это первый запуск или смена имени + // Создаём новую сессию (или пересоздаём с новым именем) + sessionService.createSession(request.getSession(), playerName.trim()); + } else if (existingSession != null) { + // Имя не пришло, но сессия есть — это "Играть снова" + sessionService.restartGame(request.getSession()); + } else { + // Нет ни имени, ни сессии — возвращаем на старт с ошибкой + request.setAttribute("error", "Please, enter your name!"); + return "/WEB-INF/start-page.jsp"; + } + + return "redirect:/quest"; + } +} diff --git a/src/main/java/com/javarush/ushanov/cmd/QuestCommand.java b/src/main/java/com/javarush/ushanov/cmd/QuestCommand.java new file mode 100644 index 0000000..f41b291 --- /dev/null +++ b/src/main/java/com/javarush/ushanov/cmd/QuestCommand.java @@ -0,0 +1,50 @@ +package com.javarush.ushanov.cmd; + +import com.javarush.ushanov.entity.GameSession; +import com.javarush.ushanov.entity.QuestStep; +import com.javarush.ushanov.service.QuestService; +import com.javarush.ushanov.service.SessionService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Команда для отображения текущего шага квеста. + * + * GET /quest — показывает текущий шаг игроку. + * + * Логика: + * 1. Получаем игровую сессию из HttpSession + * 2. Если сессии нет — перенаправляем на стартовую страницу + * 3. Загружаем текущий шаг квеста + * 4. Кладём данные в request.setAttribute() — JSP их прочитает + * 5. Возвращаем путь к JSP + */ +public class QuestCommand implements Command { + + private final QuestService questService; + private final SessionService sessionService; + + public QuestCommand(QuestService questService, SessionService sessionService) { + this.questService = questService; + this.sessionService = sessionService; + } + + @Override + public String execute(HttpServletRequest request, HttpServletResponse response) { + GameSession gameSession = sessionService.getSession(request.getSession()); + + // Если сессии нет — игрок не начинал игру, отправляем на старт + if (gameSession == null) { + return "redirect:/"; + } + + // Загружаем текущий шаг + QuestStep currentStep = questService.getStep(gameSession.getCurrentStepId()); + + // Кладём данные в request — JSP получит их через ${step} и ${gameSession} + request.setAttribute("step", currentStep); + request.setAttribute("gameSession", gameSession); + + return "/WEB-INF/quest-page.jsp"; + } +} \ No newline at end of file diff --git a/src/main/java/com/javarush/ushanov/cmd/StartPageCommand.java b/src/main/java/com/javarush/ushanov/cmd/StartPageCommand.java new file mode 100644 index 0000000..3f169b6 --- /dev/null +++ b/src/main/java/com/javarush/ushanov/cmd/StartPageCommand.java @@ -0,0 +1,17 @@ +package com.javarush.ushanov.cmd; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Команда для отображения стартовой страницы-приветствия. + * Просто показывает JSP с предысторией квеста и формой ввода имени. + */ +public class StartPageCommand implements Command { + + @Override + public String execute(HttpServletRequest request, HttpServletResponse response) { + // Просто возвращаем путь к JSP — контроллер сам сделает forward + return "/WEB-INF/start-page.jsp"; + } +} diff --git a/src/main/java/com/javarush/ushanov/controller/FrontController.java b/src/main/java/com/javarush/ushanov/controller/FrontController.java new file mode 100644 index 0000000..57718f6 --- /dev/null +++ b/src/main/java/com/javarush/ushanov/controller/FrontController.java @@ -0,0 +1,96 @@ +package com.javarush.ushanov.controller; + +import com.javarush.ushanov.cmd.*; +import com.javarush.ushanov.repository.QuestRepository; +import com.javarush.ushanov.service.QuestService; +import com.javarush.ushanov.service.SessionService; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * FrontController — единственный сервлет в приложении. + * + * Паттерн Front Controller: все HTTP-запросы приходят сюда, + * а этот класс решает, какую команду (Command) вызвать. + * + * Важно: мы используем urlPatterns с конкретными путями вместо "/*", + * чтобы Tomcat сам обслуживал статику (CSS, картинки) напрямую, + * не пропуская их через наш сервлет. + */ +@WebServlet(urlPatterns = {"/", "/quest", "/new-game", "/choice"}) +public class FrontController extends HttpServlet { + + private static final Logger log = LoggerFactory.getLogger(FrontController.class); + + private final Map getCommands = new HashMap<>(); + private final Map postCommands = new HashMap<>(); + + @Override + public void init() { + log.info("Initializing FrontController - creating dependencies and registering commands"); + + QuestRepository questRepository = new QuestRepository(); + QuestService questService = new QuestService(questRepository); + SessionService sessionService = new SessionService(questService); + + // GET-команды: показывают страницы + getCommands.put("/", new StartPageCommand()); + getCommands.put("/quest", new QuestCommand(questService, sessionService)); + + // POST-команды: обрабатывают действия пользователя + postCommands.put("/new-game", new NewGameCommand(sessionService)); + postCommands.put("/choice", new ChoiceCommand(sessionService)); + + log.info("FrontController ready. GET commands: {}, POST commands: {}", + getCommands.size(), postCommands.size()); + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + processRequest(request, response, getCommands, "GET"); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + processRequest(request, response, postCommands, "POST"); + } + + private void processRequest(HttpServletRequest request, HttpServletResponse response, + Map commands, String method) + throws ServletException, IOException { + + String uri = request.getRequestURI().substring(request.getContextPath().length()); + log.debug("{} {}", method, uri); + + Command command = commands.get(uri); + + if (command == null) { + log.warn("Command not found for {} {}, returning 404", method, uri); + response.sendError(HttpServletResponse.SC_NOT_FOUND); + return; + } + + String view = command.execute(request, response); + log.debug("Command {} returned view: {}", command.getClass().getSimpleName(), view); + + if (view.startsWith("redirect:")) { + String redirectPath = request.getContextPath() + view.substring("redirect:".length()); + log.debug("Redirect -> {}", redirectPath); + response.sendRedirect(redirectPath); + } else { + log.debug("Forward -> {}", view); + request.getRequestDispatcher(view).forward(request, response); + } + } +} diff --git a/src/main/java/com/javarush/ushanov/entity/GameSession.java b/src/main/java/com/javarush/ushanov/entity/GameSession.java new file mode 100644 index 0000000..323c45c --- /dev/null +++ b/src/main/java/com/javarush/ushanov/entity/GameSession.java @@ -0,0 +1,43 @@ +package com.javarush.ushanov.entity; + +import lombok.Getter; +import lombok.Setter; + +/** + * Данные игровой сессии игрока. + * Этот объект хранится в HttpSession — то есть живёт на сервере + * и привязан к конкретному браузеру/пользователю. + * + * Мы храним здесь: + * - имя игрока (вводится на стартовой странице) + * - id текущего шага квеста + * - количество сыгранных игр + * - количество побед + */ +@Getter +@Setter +public class GameSession { + + private String playerName; + private int currentStepId; + private int gamesPlayed; + private int gamesWon; + + public GameSession(String playerName, int startStepId) { + this.playerName = playerName; + this.currentStepId = startStepId; + this.gamesPlayed = 0; + this.gamesWon = 0; + } + + /** Вызывается при начале новой игры — сбрасывает шаг на стартовый */ + public void startNewGame(int startStepId) { + this.currentStepId = startStepId; + this.gamesPlayed++; + } + + /** Вызывается при победе */ + public void registerWin() { + this.gamesWon++; + } +} diff --git a/src/main/java/com/javarush/ushanov/entity/QuestStep.java b/src/main/java/com/javarush/ushanov/entity/QuestStep.java new file mode 100644 index 0000000..1cf7200 --- /dev/null +++ b/src/main/java/com/javarush/ushanov/entity/QuestStep.java @@ -0,0 +1,35 @@ +package com.javarush.ushanov.entity; + +import lombok.Builder; +import lombok.Getter; + +import java.util.Map; + +/** + * Один шаг (узел) квеста. + * + * Каждый шаг имеет: + * - уникальный id + * - текст вопроса/описания ситуации, который видит игрок + * - статус: PLAYING (обычный шаг), WIN (победа), LOSE (поражение) + * - карту вариантов ответов: текст кнопки -> id следующего шага + * (если шаг финальный — options будет пустой Map) + */ +@Getter +@Builder +public class QuestStep { + + private final int id; + private final String description; + private final StepStatus status; + + /** + * Ключ — текст варианта ответа (то, что видит игрок на кнопке) + * Значение — id шага, на который переходим при выборе этого варианта + */ + private final Map options; + + public boolean isCompleted() { + return status == StepStatus.WIN || status == StepStatus.LOSE; + } +} diff --git a/src/main/java/com/javarush/ushanov/entity/StepStatus.java b/src/main/java/com/javarush/ushanov/entity/StepStatus.java new file mode 100644 index 0000000..efc5909 --- /dev/null +++ b/src/main/java/com/javarush/ushanov/entity/StepStatus.java @@ -0,0 +1,14 @@ +package com.javarush.ushanov.entity; + +/** + * Статус шага квеста. + * + * PLAYING — обычный шаг, игра продолжается + * WIN — финальный шаг с победой + * LOSE — финальный шаг с поражением + */ +public enum StepStatus { + PLAYING, + WIN, + LOSE +} diff --git a/src/main/java/com/javarush/ushanov/exception/QuestStepNotFoundException.java b/src/main/java/com/javarush/ushanov/exception/QuestStepNotFoundException.java new file mode 100644 index 0000000..7fbf310 --- /dev/null +++ b/src/main/java/com/javarush/ushanov/exception/QuestStepNotFoundException.java @@ -0,0 +1,11 @@ +package com.javarush.ushanov.exception; + +/** + * Кастомное исключение — бросается когда шаг квеста не найден. + */ +public class QuestStepNotFoundException extends RuntimeException { + + public QuestStepNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/javarush/ushanov/repository/QuestRepository.java b/src/main/java/com/javarush/ushanov/repository/QuestRepository.java new file mode 100644 index 0000000..8be3a3c --- /dev/null +++ b/src/main/java/com/javarush/ushanov/repository/QuestRepository.java @@ -0,0 +1,182 @@ +package com.javarush.ushanov.repository; + +import com.javarush.ushanov.entity.QuestStep; +import com.javarush.ushanov.entity.StepStatus; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * Репозиторий квеста — хранит все шаги квеста в памяти (в Map). + */ +public class QuestRepository { + + /** Все шаги квеста: ключ — id шага, значение — объект QuestStep */ + private final Map steps = new HashMap<>(); + + /** id первого шага, с которого начинается игра */ + public static final int START_STEP_ID = 1; + + public QuestRepository() { + initQuest(); + } + + /** + * Логика квеста в виде дерева шагов. + * + * Сюжет: игрок — пилот разведывательного корабля. + * Корабль получил сигнал бедствия от неизвестной станции. + * + * Дерево решений: + * + * [1] Принять сигнал? + * -> "Принять сигнал" => [2] + * -> "Игнорировать сигнал" => [3] LOSE + * + * [2] Пристыковаться к станции? + * -> "Пристыковаться" => [4] + * -> "Остаться на орбите" => [5] LOSE + * + * [4] Что делать на станции? + * -> "Исследовать реактор" => [6] LOSE + * -> "Найти команду" => [7] + * + * [7] Команда предлагает улететь вместе. Взять всех? + * -> "Взять всех" => [8] WIN + * -> "Взять только капитана" => [9] LOSE + */ + private void initQuest() { + + // Шаг 1 — начало + steps.put(1, QuestStep.builder() + .id(1) + .description("Ты — пилот разведывательного корабля «Аврора». " + + "В пустоте космоса твой бортовой компьютер фиксирует слабый сигнал бедствия. " + + "Источник — заброшенная исследовательская станция «Кеплер-7». " + + "Что ты будешь делать?") + .status(StepStatus.PLAYING) + .options(Map.of( + "Принять сигнал и изменить курс", 2, + "Игнорировать — миссия важнее", 3 + )) + .build()); + + // Шаг 2 — приближаемся к станции + steps.put(2, QuestStep.builder() + .id(2) + .description("Ты изменил курс и приближаешься к станции «Кеплер-7». " + + "Внешне она выглядит повреждённой — несколько секций разгерметизированы. " + + "Однако стыковочный модуль, кажется, работает. " + + "Твои действия?") + .status(StepStatus.PLAYING) + .options(Map.of( + "Пристыковаться и войти на станцию", 4, + "Остаться на орбите и попытаться выйти на связь", 5 + )) + .build()); + + // Шаг 3 — ПОРАЖЕНИЕ: проигнорировал сигнал + steps.put(3, QuestStep.builder() + .id(3) + .description("Ты проигнорировал сигнал и продолжил миссию. " + + "Спустя несколько часов ты узнал из новостей: выжившие со станции «Кеплер-7» " + + "были обнаружены мёртвыми. Ты мог их спасти... " + + "Командование отстранило тебя от полётов.") + .status(StepStatus.LOSE) + .options(Map.of()) + .build()); + + // Шаг 4 — на станции + steps.put(4, QuestStep.builder() + .id(4) + .description("Ты на борту станции. Воздух разреженный, аварийное освещение мигает. " + + "Датчики показывают двух выживших в жилом модуле. " + + "Но также фиксируется нестабильность реактора. " + + "Что исследовать первым?") + .status(StepStatus.PLAYING) + .options(Map.of( + "Срочно проверить реактор", 6, + "Найти выживших в жилом модуле", 7 + )) + .build()); + + // Шаг 5 — ПОРАЖЕНИЕ: остался на орбите + steps.put(5, QuestStep.builder() + .id(5) + .description("Ты пытался выйти на связь несколько часов, но ответа не было. " + + "Пока ты медлил, реактор станции вышел из строя. " + + "Мощный взрыв уничтожил станцию вместе со всеми выжившими. " + + "Нужно было действовать быстрее.") + .status(StepStatus.LOSE) + .options(Map.of()) + .build()); + + // Шаг 6 — ПОРАЖЕНИЕ: пошёл к реактору + steps.put(6, QuestStep.builder() + .id(6) + .description("Ты направился к реактору, но не успел дойти — " + + "перегрузка системы вызвала разрыв трубопровода. " + + "Радиоактивный пар заполнил коридор. " + + "Ты получил критическую дозу облучения. " + + "Выживших найти не удалось.") + .status(StepStatus.LOSE) + .options(Map.of()) + .build()); + + // Шаг 7 — нашли выживших + steps.put(7, QuestStep.builder() + .id(7) + .description("Ты нашёл двух выживших: капитана Марину Волкову и бортинженера Алекса Рида. " + + "Они истощены, но в сознании. Капитан говорит: " + + "«Нас трое — мой напарник застрял в заблокированном отсеке, " + + "но корабль может принять только двух пассажиров». " + + "Что решаешь?") + .status(StepStatus.PLAYING) + .options(Map.of( + "Забрать обоих — найдём способ", 8, + "Взять только капитана — она важнее для расследования", 9 + )) + .build()); + + // Шаг 8 — ПОБЕДА + steps.put(8, QuestStep.builder() + .id(8) + .description("Ты нашёл решение: один из выживших может разместиться в грузовом отсеке. " + + "Немного тесновато, зато все живы! " + + "«Аврора» отстыковалась от станции за минуту до того, как реактор взорвался. " + + "Оба выживших доставлены на базу. " + + "Командование объявило тебя героем. Миссия выполнена!") + .status(StepStatus.WIN) + .options(Map.of()) + .build()); + + // Шаг 9 — ПОРАЖЕНИЕ: бросил инженера + steps.put(9, QuestStep.builder() + .id(9) + .description("Ты взял только капитана и улетел. " + + "Бортинженер Алекс Рид погиб при взрыве реактора. " + + "Капитан Волкова так и не простила тебя. " + + "На базе тебя ждал трибунал за нарушение устава: " + + "«Не оставляй своих». Конец карьеры.") + .status(StepStatus.LOSE) + .options(Map.of()) + .build()); + } + + /** + * Получить шаг по id. + */ + public Optional findById(int id) { + return Optional.ofNullable(steps.get(id)); + } + + public int getStartStepId() { + return START_STEP_ID; + } + + /** Общее количество шагов в квесте (для тестов) */ + public int size() { + return steps.size(); + } +} diff --git a/src/main/java/com/javarush/ushanov/service/QuestService.java b/src/main/java/com/javarush/ushanov/service/QuestService.java new file mode 100644 index 0000000..0417e32 --- /dev/null +++ b/src/main/java/com/javarush/ushanov/service/QuestService.java @@ -0,0 +1,44 @@ +package com.javarush.ushanov.service; + +import com.javarush.ushanov.entity.QuestStep; +import com.javarush.ushanov.exception.QuestStepNotFoundException; +import com.javarush.ushanov.repository.QuestRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class QuestService { + + private static final Logger log = LoggerFactory.getLogger(QuestService.class); + + private final QuestRepository questRepository; + + public QuestService(QuestRepository questRepository) { + this.questRepository = questRepository; + } + + public QuestStep getStep(int stepId) { + return questRepository.findById(stepId) + .orElseThrow(() -> { + // ERROR — что-то пошло не так, нужно разобраться + log.error("Quest step with id={} not found", stepId); + return new QuestStepNotFoundException("Quest step with id=" + stepId + " not found"); + }); + } + + public int getStartStepId() { + return questRepository.getStartStepId(); + } + + public int getNextStepId(int currentStepId, String chosenOption) { + QuestStep currentStep = getStep(currentStepId); + Integer nextStepId = currentStep.getOptions().get(chosenOption); + if (nextStepId == null) { + log.error("Choice option '{}' not found for step id={}", chosenOption, currentStepId); + throw new QuestStepNotFoundException( + "Choice option '" + chosenOption + "' not found for step id=" + currentStepId + ); + } + log.debug("Transition: step {} -> step {} (choice: '{}')", currentStepId, nextStepId, chosenOption); + return nextStepId; + } +} diff --git a/src/main/java/com/javarush/ushanov/service/SessionService.java b/src/main/java/com/javarush/ushanov/service/SessionService.java new file mode 100644 index 0000000..c07a0bb --- /dev/null +++ b/src/main/java/com/javarush/ushanov/service/SessionService.java @@ -0,0 +1,61 @@ +package com.javarush.ushanov.service; + +import com.javarush.ushanov.entity.GameSession; +import com.javarush.ushanov.entity.StepStatus; +import jakarta.servlet.http.HttpSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SessionService { + + private static final Logger log = LoggerFactory.getLogger(SessionService.class); + + public static final String SESSION_KEY = "gameSession"; + + private final QuestService questService; + + public SessionService(QuestService questService) { + this.questService = questService; + } + + public GameSession createSession(HttpSession httpSession, String playerName) { + GameSession gameSession = new GameSession(playerName, questService.getStartStepId()); + gameSession.startNewGame(questService.getStartStepId()); + httpSession.setAttribute(SESSION_KEY, gameSession); + log.info("New session created for player '{}'", playerName); + return gameSession; + } + + public GameSession getSession(HttpSession httpSession) { + return (GameSession) httpSession.getAttribute(SESSION_KEY); + } + + public void processChoice(HttpSession httpSession, String chosenOption) { + GameSession gameSession = getSession(httpSession); + if (gameSession == null) { + log.warn("processChoice called without active session"); + return; + } + + int nextStepId = questService.getNextStepId(gameSession.getCurrentStepId(), chosenOption); + gameSession.setCurrentStepId(nextStepId); + + var nextStep = questService.getStep(nextStepId); + if (nextStep.getStatus() == StepStatus.WIN) { + gameSession.registerWin(); + log.info("Player '{}' won! Total wins: {}", + gameSession.getPlayerName(), gameSession.getGamesWon()); + } else if (nextStep.getStatus() == StepStatus.LOSE) { + log.info("Player '{}' lost at step {}", gameSession.getPlayerName(), nextStepId); + } + } + + public void restartGame(HttpSession httpSession) { + GameSession gameSession = getSession(httpSession); + if (gameSession != null) { + gameSession.startNewGame(questService.getStartStepId()); + log.info("Player '{}' restarted the game. Games played: {}", + gameSession.getPlayerName(), gameSession.getGamesPlayed()); + } + } +} diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..a4800b6 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + UTF-8 + %d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + diff --git a/src/main/webapp/WEB-INF/edit-user.jsp b/src/main/webapp/WEB-INF/edit-user.jsp deleted file mode 100644 index f274104..0000000 --- a/src/main/webapp/WEB-INF/edit-user.jsp +++ /dev/null @@ -1,73 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@include file="head.jsp" %> - -
-
-
- - - Edit user: - - -
- -
- - min 3 symbols -
-
- - -
- -
- - min 8 symb -
-
- - - -
- -
- -
-
- - -
- -
- - - - - - - -
-
- -
-
-
- - diff --git a/src/main/webapp/WEB-INF/error-page.jsp b/src/main/webapp/WEB-INF/error-page.jsp new file mode 100644 index 0000000..60a7363 --- /dev/null +++ b/src/main/webapp/WEB-INF/error-page.jsp @@ -0,0 +1,37 @@ +<%-- + Created by IntelliJ IDEA. + User: ushan + Date: 26.02.2026 + Time: 1:50 + To change this template use File | Settings | File Templates. +--%> +<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %> +<%@ taglib prefix="c" uri="jakarta.tags.core" %> + +<%@ include file="header.jsp" %> + +
+
+
+ + + ${pageContext.errorData.statusCode} + + Ошибка + +
+
Системный сбой
+
+ Бортовой компьютер зафиксировал критическую ошибку системы навигации. + Запрошенный маршрут не существует или временно недоступен. +
+ + ← Вернуться на главную + +
+
+ + + + diff --git a/src/main/webapp/WEB-INF/head.jsp b/src/main/webapp/WEB-INF/head.jsp deleted file mode 100644 index 2f7b9f2..0000000 --- a/src/main/webapp/WEB-INF/head.jsp +++ /dev/null @@ -1,11 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> - - - Title - - - \ No newline at end of file diff --git a/src/main/webapp/WEB-INF/header.jsp b/src/main/webapp/WEB-INF/header.jsp new file mode 100644 index 0000000..ac8cf90 --- /dev/null +++ b/src/main/webapp/WEB-INF/header.jsp @@ -0,0 +1,32 @@ +<%-- + Created by IntelliJ IDEA. + User: ushan + Date: 26.02.2026 + Time: 1:49 + To change this template use File | Settings | File Templates. +--%> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="jakarta.tags.core" %> + + + + + + 🚀 Операция «Кеплер-7» + + + + +
+

🚀 Операция «Кеплер-7»

+ <%-- Показываем имя игрока и статистику, если сессия есть --%> + +
+ Пилот: ${sessionScope.gameSession.playerName} +  |  + Игр сыграно: ${sessionScope.gameSession.gamesPlayed} +  |  + Побед: ${sessionScope.gameSession.gamesWon} +
+
+
diff --git a/src/main/webapp/WEB-INF/list-user.jsp b/src/main/webapp/WEB-INF/list-user.jsp deleted file mode 100644 index dd52c55..0000000 --- a/src/main/webapp/WEB-INF/list-user.jsp +++ /dev/null @@ -1,9 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@include file="head.jsp"%> - - - ${user.login} - - - - diff --git a/src/main/webapp/WEB-INF/quest-page.jsp b/src/main/webapp/WEB-INF/quest-page.jsp new file mode 100644 index 0000000..9671383 --- /dev/null +++ b/src/main/webapp/WEB-INF/quest-page.jsp @@ -0,0 +1,91 @@ +<%-- + Created by IntelliJ IDEA. + User: ushan + Date: 26.02.2026 + Time: 1:50 + To change this template use File | Settings | File Templates. +--%> +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="jakarta.tags.core" %> + +<%@ include file="header.jsp" %> + +
+ + <%-- + Определяем CSS-класс карточки в зависимости от статуса шага. + step.status — это наш enum StepStatus (PLAYING, WIN, LOSE) + В JSP мы обращаемся к нему через строку для сравнения. + --%> + + +
+
🏆
+
МИССИЯ ВЫПОЛНЕНА!
+ + +
+
💀
+
МИССИЯ ПРОВАЛЕНА
+ + +
+
📍 Ситуация
+ + + + <%-- Текст текущего шага квеста --%> +
+ ${step.description} +
+ + <%-- + Если шаг финальный — показываем статистику и кнопку "Играть снова". + Если обычный — показываем кнопки с вариантами ответов. + --%> + + + <%-- Финальный экран: статистика --%> +
+

Пилот: ${gameSession.playerName}

+

Игр сыграно: ${gameSession.gamesPlayed}

+

Побед: ${gameSession.gamesWon}

+
+ + <%-- + Кнопка "Играть снова" отправляет POST /new-game без параметра playerName. + NewGameCommand увидит, что сессия уже есть, и просто сбросит прогресс. + --%> +
+ +
+
+ + <%-- Обычный шаг: варианты ответов --%> +
+ <%-- + Итерируемся по Map options. + entry.key — текст варианта (то, что видит игрок) + entry.value — id следующего шага (нам он здесь не нужен) + + Каждая кнопка отправляет POST /choice с параметром option=текст_кнопки + --%> + +
+ + +
+
+
+
+
+ +
<%-- конец .card --%> +
+ + + diff --git a/src/main/webapp/WEB-INF/start-page.jsp b/src/main/webapp/WEB-INF/start-page.jsp index 0531c1c..3c5ca66 100644 --- a/src/main/webapp/WEB-INF/start-page.jsp +++ b/src/main/webapp/WEB-INF/start-page.jsp @@ -1,8 +1,74 @@ +<%-- + Created by IntelliJ IDEA. + User: ushan + Date: 26.02.2026 + Time: 1:51 + To change this template use File | Settings | File Templates. +--%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@include file="head.jsp"%> - -

<%= "Hello World!" %> -

-
-List Users +<%@ taglib prefix="c" uri="jakarta.tags.core" %> + +<%-- Подключаем общую шапку (HTML head + header тег) --%> +<%@ include file="header.jsp" %> + +
+
+
📡 Входящий сигнал
+ + <%-- Предыстория квеста --%> +
+

+ Год 2157. Дальний космос. +

+

+ Ты — пилот разведывательного корабля «Аврора», один из лучших + в Федерации дальних исследований. Твоя текущая миссия — картографирование + пояса астероидов в секторе Кеплера. +

+

+ Маршрут стандартный, ничего необычного. Ещё шесть часов до точки возврата, + запасы топлива в норме, связь с базой устойчивая. +

+

+ И вдруг бортовой компьютер фиксирует слабый сигнал бедствия. + Источник — заброшенная исследовательская станция «Кеплер-7». + По базе данных — станция была эвакуирована два года назад после аварии реактора. +

+

+ Но кто-то всё ещё там. И они зовут на помощь. +

+

+ ⚠ Твои решения определят, выживут ли они. +

+
+ + <%-- Форма ввода имени --%> + <%-- Отображаем ошибку, если она есть --%> + +
⚠ ${error}
+
+ + <%-- + POST /new-game — создаёт новую игру. + Поле playerName будет доступно в сервлете через request.getParameter("playerName") + --%> +
+
+ + +
+ +
+
+
+ + diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 0bf2fcb..fa9aa26 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -1,6 +1,28 @@ - \ No newline at end of file + + UTF-8 + UTF-8 + + + + 404 + /WEB-INF/error-page.jsp + + + + + 500 + /WEB-INF/error-page.jsp + + + + default + /css/* + + + diff --git a/src/main/webapp/css/styles.css b/src/main/webapp/css/styles.css new file mode 100644 index 0000000..b15ef6d --- /dev/null +++ b/src/main/webapp/css/styles.css @@ -0,0 +1,262 @@ +/* ============================== + Общие стили + ============================== */ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Courier New', Courier, monospace; + background-color: #0a0a1a; + color: #e0e0f0; + min-height: 100vh; + + /* Звёздный фон через градиент и точки */ + background-image: + radial-gradient(white 1px, transparent 1px), + radial-gradient(white 1px, transparent 1px); + background-size: 100px 100px, 70px 70px; + background-position: 0 0, 35px 35px; +} + +/* ============================== + Шапка + ============================== */ + +header { + background: rgba(10, 10, 40, 0.9); + border-bottom: 1px solid #3a3a6a; + padding: 15px 30px; + text-align: center; +} + +header h1 { + color: #7eb8f7; + font-size: 1.4rem; + letter-spacing: 3px; + text-transform: uppercase; +} + +header .player-info { + color: #a0a0c0; + font-size: 0.85rem; + margin-top: 5px; +} + +header .player-info span { + color: #7eb8f7; +} + +/* ============================== + Основной контейнер + ============================== */ + +.container { + max-width: 780px; + margin: 50px auto; + padding: 0 20px; +} + +/* ============================== + Карточка (основной блок) + ============================== */ + +.card { + background: rgba(15, 15, 40, 0.92); + border: 1px solid #2a2a5a; + border-radius: 12px; + padding: 40px; + box-shadow: 0 0 30px rgba(100, 150, 255, 0.1); +} + +.card-title { + color: #7eb8f7; + font-size: 1.1rem; + letter-spacing: 2px; + text-transform: uppercase; + margin-bottom: 20px; + padding-bottom: 15px; + border-bottom: 1px solid #2a2a5a; +} + +/* ============================== + Текст квеста + ============================== */ + +.quest-text { + font-size: 1.05rem; + line-height: 1.8; + color: #c8c8e8; + margin-bottom: 35px; +} + +/* ============================== + Кнопки вариантов ответа + ============================== */ + +.options { + display: flex; + flex-direction: column; + gap: 12px; +} + +.option-btn { + background: rgba(40, 40, 80, 0.8); + border: 1px solid #3a3a7a; + border-radius: 8px; + color: #b0c8f0; + cursor: pointer; + font-family: 'Courier New', Courier, monospace; + font-size: 0.95rem; + padding: 14px 20px; + text-align: left; + transition: all 0.2s ease; + width: 100%; +} + +.option-btn:hover { + background: rgba(60, 60, 120, 0.9); + border-color: #7eb8f7; + color: #ffffff; + transform: translateX(5px); +} + +/* ============================== + Финальные экраны (победа / поражение) + ============================== */ + +.result-win { + border-color: #2a6a3a; + box-shadow: 0 0 30px rgba(50, 200, 100, 0.1); +} + +.result-win .card-title { + color: #5dcf7f; +} + +.result-lose { + border-color: #6a2a2a; + box-shadow: 0 0 30px rgba(200, 50, 50, 0.1); +} + +.result-lose .card-title { + color: #cf5d5d; +} + +.result-icon { + font-size: 3rem; + text-align: center; + margin-bottom: 20px; +} + +/* ============================== + Статистика + ============================== */ + +.stats { + margin: 25px 0; + padding: 15px 20px; + background: rgba(30, 30, 60, 0.6); + border-radius: 8px; + border: 1px solid #2a2a5a; +} + +.stats p { + color: #a0a0c0; + font-size: 0.9rem; + margin: 5px 0; +} + +.stats span { + color: #7eb8f7; +} + +/* ============================== + Кнопка "Играть снова" + ============================== */ + +.btn-primary { + background: rgba(40, 80, 160, 0.8); + border: 1px solid #4a6aa0; + border-radius: 8px; + color: #d0e4ff; + cursor: pointer; + font-family: 'Courier New', Courier, monospace; + font-size: 1rem; + letter-spacing: 1px; + margin-top: 15px; + padding: 14px 30px; + transition: all 0.2s ease; + width: 100%; +} + +.btn-primary:hover { + background: rgba(60, 100, 200, 0.9); + border-color: #7eb8f7; + color: #ffffff; +} + +/* ============================== + Стартовая страница + ============================== */ + +.intro-text { + color: #a0a0c0; + font-size: 0.95rem; + line-height: 1.8; + margin-bottom: 25px; +} + +.intro-text p { + margin-bottom: 12px; +} + +.form-group { + margin-bottom: 20px; +} + +.form-group label { + display: block; + color: #7eb8f7; + font-size: 0.9rem; + letter-spacing: 1px; + margin-bottom: 8px; + text-transform: uppercase; +} + +.form-group input { + background: rgba(30, 30, 60, 0.8); + border: 1px solid #3a3a7a; + border-radius: 6px; + color: #e0e0f0; + font-family: 'Courier New', Courier, monospace; + font-size: 1rem; + padding: 12px 15px; + width: 100%; + outline: none; + transition: border-color 0.2s; +} + +.form-group input:focus { + border-color: #7eb8f7; +} + +.error-message { + color: #cf5d5d; + font-size: 0.9rem; + margin-bottom: 15px; +} + +/* ============================== + Страница ошибки + ============================== */ + +.error-code { + color: #cf5d5d; + font-size: 4rem; + text-align: center; + margin-bottom: 10px; +} diff --git a/src/main/webapp/images/cat.png b/src/main/webapp/images/cat.png deleted file mode 100644 index 41771a150e8b04624df7697882a13e789b48af7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98607 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%0Aj+deS- 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 startStep = questRepository.findById(QuestRepository.START_STEP_ID); + + // assertTrue: проверяем что условие истинно + assertTrue(startStep.isPresent(), "Начальный шаг должен быть в репозитории"); + } + + @Test + @DisplayName("Начальный шаг должен иметь статус PLAYING") + void startStepShouldHavePlayingStatus() { + QuestStep startStep = questRepository.findById(QuestRepository.START_STEP_ID).orElseThrow(); + + // assertEquals: проверяем что ожидаемое значение == фактическому + assertEquals(StepStatus.PLAYING, startStep.getStatus()); + } + + @Test + @DisplayName("Начальный шаг должен иметь варианты ответов") + void startStepShouldHaveOptions() { + QuestStep startStep = questRepository.findById(QuestRepository.START_STEP_ID).orElseThrow(); + + // assertFalse: проверяем что условие ложно + assertFalse(startStep.getOptions().isEmpty(), + "Начальный шаг должен содержать варианты ответов"); + } + + @Test + @DisplayName("Несуществующий шаг должен возвращать пустой Optional") + void nonExistentStepShouldReturnEmpty() { + Optional step = questRepository.findById(9999); + + assertFalse(step.isPresent(), "Несуществующий шаг должен быть пустым Optional"); + } + + @Test + @DisplayName("В квесте должны быть финальные шаги с победой") + void questShouldHaveWinSteps() { + // Проверяем, что хотя бы один шаг имеет статус WIN + boolean hasWinStep = false; + for (int i = 1; i <= questRepository.size() + 5; i++) { + Optional step = questRepository.findById(i); + if (step.isPresent() && step.get().getStatus() == StepStatus.WIN) { + hasWinStep = true; + break; + } + } + assertTrue(hasWinStep, "В квесте должен быть хотя бы один шаг с победой"); + } + + @Test + @DisplayName("В квесте должны быть финальные шаги с поражением") + void questShouldHaveLoseSteps() { + boolean hasLoseStep = false; + for (int i = 1; i <= questRepository.size() + 5; i++) { + Optional step = questRepository.findById(i); + if (step.isPresent() && step.get().getStatus() == StepStatus.LOSE) { + hasLoseStep = true; + break; + } + } + assertTrue(hasLoseStep, "В квесте должен быть хотя бы один шаг с поражением"); + } + + @Test + @DisplayName("Финальные шаги не должны иметь вариантов ответов") + void finalStepsShouldHaveNoOptions() { + for (int i = 1; i <= questRepository.size() + 5; i++) { + Optional optional = questRepository.findById(i); + if (optional.isPresent()) { + QuestStep step = optional.get(); + if (step.isCompleted()) { + // assertAll: проверяем несколько условий вместе + assertTrue(step.getOptions().isEmpty(), + "Финальный шаг id=" + step.getId() + " не должен иметь вариантов ответа"); + } + } + } + } +} diff --git a/src/test/java/com/javarush/ushanov/service/QuestServiceTest.java b/src/test/java/com/javarush/ushanov/service/QuestServiceTest.java new file mode 100644 index 0000000..822bd77 --- /dev/null +++ b/src/test/java/com/javarush/ushanov/service/QuestServiceTest.java @@ -0,0 +1,110 @@ +package com.javarush.ushanov.service; + +import com.javarush.ushanov.entity.QuestStep; +import com.javarush.ushanov.entity.StepStatus; +import com.javarush.ushanov.exception.QuestStepNotFoundException; +import com.javarush.ushanov.repository.QuestRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Тесты для QuestService. + * + * Здесь мы тестируем бизнес-логику: + * - корректно ли сервис возвращает шаги + * - правильно ли обрабатывает переходы между шагами + * - корректно ли бросает исключения + */ +class QuestServiceTest { + + private QuestService questService; + + @BeforeEach + void setUp() { + // Создаём настоящий репозиторий — в нём уже есть все шаги квеста + questService = new QuestService(new QuestRepository()); + } + + @Test + @DisplayName("getStep() должен вернуть шаг по существующему id") + void getStepShouldReturnStepById() { + QuestStep step = questService.getStep(1); + + assertNotNull(step, "Шаг не должен быть null"); + assertEquals(1, step.getId(), "Id шага должен совпадать"); + } + + @Test + @DisplayName("getStep() должен бросить исключение для несуществующего id") + void getStepShouldThrowExceptionForInvalidId() { + // assertThrows: проверяем, что метод бросает конкретное исключение + assertThrows(QuestStepNotFoundException.class, () -> questService.getStep(9999), + "Должно быть брошено QuestStepNotFoundException"); + } + + @Test + @DisplayName("getStartStepId() должен возвращать корректный id") + void getStartStepIdShouldReturnValidId() { + int startId = questService.getStartStepId(); + + // Проверяем, что стартовый шаг реально существует + assertDoesNotThrow(() -> questService.getStep(startId), + "Стартовый шаг должен существовать в репозитории"); + } + + @Test + @DisplayName("getNextStepId() должен вернуть id следующего шага") + void getNextStepIdShouldReturnCorrectNextStep() { + // Берём первый шаг и смотрим какие у него варианты + QuestStep startStep = questService.getStep(1); + assertFalse(startStep.getOptions().isEmpty(), "Первый шаг должен иметь варианты"); + + // Берём первый доступный вариант + String firstOption = startStep.getOptions().keySet().iterator().next(); + int expectedNextId = startStep.getOptions().get(firstOption); + + // Проверяем, что сервис возвращает правильный следующий шаг + int actualNextId = questService.getNextStepId(1, firstOption); + assertEquals(expectedNextId, actualNextId); + } + + @Test + @DisplayName("getNextStepId() должен бросить исключение для несуществующего варианта ответа") + void getNextStepIdShouldThrowExceptionForInvalidOption() { + assertThrows(QuestStepNotFoundException.class, + () -> questService.getNextStepId(1, "несуществующий вариант"), + "Должно быть брошено исключение для несуществующего варианта"); + } + + @Test + @DisplayName("Путь к победе должен существовать и завершаться WIN") + void winPathShouldExistAndEndWithWin() { + // Шаг 1 -> выбираем первый вариант (принять сигнал) -> шаг 2 + // Шаг 2 -> выбираем первый вариант (пристыковаться) -> шаг 4 + // Шаг 4 -> вариант "Найти выживших" -> шаг 7 + // Шаг 7 -> вариант "Забрать обоих" -> шаг 8 (WIN) + + int nextId = questService.getNextStepId(1, "Принять сигнал и изменить курс"); + nextId = questService.getNextStepId(nextId, "Пристыковаться и войти на станцию"); + nextId = questService.getNextStepId(nextId, "Найти выживших в жилом модуле"); + nextId = questService.getNextStepId(nextId, "Забрать обоих — найдём способ"); + + QuestStep finalStep = questService.getStep(nextId); + assertEquals(StepStatus.WIN, finalStep.getStatus(), + "Финальный шаг победного пути должен иметь статус WIN"); + } + + @Test + @DisplayName("Путь к поражению должен существовать и завершаться LOSE") + void losePathShouldExistAndEndWithLose() { + // Шаг 1 -> игнорировать сигнал -> шаг 3 (LOSE) + int nextId = questService.getNextStepId(1, "Игнорировать — миссия важнее"); + + QuestStep finalStep = questService.getStep(nextId); + assertEquals(StepStatus.LOSE, finalStep.getStatus(), + "Финальный шаг этого пути должен иметь статус LOSE"); + } +}