This commit is contained in:
2024-09-17 19:14:27 +03:00
parent 5d9a063603
commit 2e0819561f
10 changed files with 231 additions and 75 deletions

View File

@@ -3,6 +3,10 @@ package ru.lionarius.isdojplab.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import ru.lionarius.isdojplab.model.Product;
import java.util.ArrayList;
import java.util.List;
@Controller
public class HomeController {
@@ -10,6 +14,14 @@ public class HomeController {
@GetMapping("/")
public String home(Model model) {
model.addAttribute("message", "Добро пожаловать в магазин электротоваров!");
List<Product> products = new ArrayList<>();
products.add(new Product("Электрический чайник", 900.0, "Высококачественный чайник с быстрой функцией закипания", "https://example.com/electro1.jpg"));
products.add(new Product("Утюг с парогенератором", 1000.0, "Мощный утюг с автоматической подачей пара", "https://example.com/electro2.jpg"));
products.add(new Product("Мультиварка", 400.0, "Универсальная мультиварка с множеством режимов приготовления", "https://example.com/electro3.jpg"));
model.addAttribute("products", products);
return "home";
}
}

View File

@@ -1,29 +0,0 @@
package ru.lionarius.isdojplab.controller;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import ru.lionarius.isdojplab.model.Product;
@Controller
public class ProductFormController {
@GetMapping("/product_form")
public String showForm(Model model) {
model.addAttribute("product", new Product());
return "product_form";
}
@PostMapping("/product_form")
public String submitForm(@Valid @ModelAttribute("product") Product product, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
return "product_form";
}
model.addAttribute("message", "Товар успешно добавлен: " + product.getName());
return "redirect:/";
}
}

View File

@@ -0,0 +1,32 @@
package ru.lionarius.isdojplab.controller;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import ru.lionarius.isdojplab.model.User;
@Controller
public class RegisterFormController {
@GetMapping("/register")
public String showForm(Model model) {
model.addAttribute("user", new User());
return "register_form";
}
@PostMapping("/register")
public String submitForm(@Valid @ModelAttribute("user") User user, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
return "register_form";
}
model.addAttribute("message", "Пользователь успешно зарегистрирован");
return "register_form";
}
}

View File

@@ -3,18 +3,16 @@ package ru.lionarius.isdojplab.model;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
@Data
@AllArgsConstructor
public class Product {
@NotBlank(message = "Название товара обязательно")
private String name;
@NotNull(message = "Цена товара обязательна")
@Min(value = 1, message = "Цена должна быть больше 0")
private Double price;
@NotBlank(message = "Описание товара обязательно")
private String description;
private String imageUrl;
}

View File

@@ -0,0 +1,18 @@
package ru.lionarius.isdojplab.model;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Data
public class User {
@NotBlank(message = "Поле не может быть пустым")
private String name;
@NotBlank(message = "Поле не может быть пустым")
@Email(message = "Неверный формат электронной почты")
private String email;
@NotBlank(message = "Поле не может быть пустым")
@Size(min = 6, message = "Пароль должен состоять не менее 6 символов")
private String password;
}

View File

@@ -0,0 +1,71 @@
body {
font-family: Arial, sans-serif;
background-color: #f4f4f9;
color: #333;
margin: 0;
padding: 0;
}
header {
background-color: #007BFF;
color: white;
padding: 1rem;
text-align: center;
}
h1 {
font-size: 2.5rem;
}
.container {
margin: 2rem auto;
max-width: 1200px;
padding: 1rem;
text-align: center;
}
.catalog {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1rem;
margin-top: 2rem;
}
.product {
background: white;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
padding: 1rem;
transition: transform 0.3s;
}
.product img {
width: 100%;
border-bottom: 1px solid #ddd;
padding-bottom: 1rem;
margin-bottom: 1rem;
}
.product:hover {
transform: scale(1.05);
}
.product h3 {
font-size: 1.5rem;
margin-bottom: 1rem;
}
.product p {
font-size: 1rem;
margin-bottom: 1rem;
}
.product button {
background-color: #007BFF;
color: white;
padding: 0.5rem 1rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
.product button:hover {
background-color: #0056b3;
}
footer {
background-color: #333;
color: white;
text-align: center;
padding: 1rem;
bottom: 0;
width: 100%;
}

View File

@@ -1,10 +1,43 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="ru">
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Магазин электротоваров</title>
<link rel="stylesheet" th:href="@{/css/styles.css}">
</head>
<body>
<h1 th:text="${message}"></h1>
<header>
<h1>Магазин электротоваров</h1>
<p>Все для вашего дома и офиса</p>
</header>
<div class="container">
<div class="register-container">
<a href="/register" class="register-button">Регистрация</a>
</div>
<h2>Каталог товаров</h2>
<div class="catalog">
<div th:each="product : ${products}" class="product">
<img th:src="${product.imageUrl}" alt="Product Image" style="width: 300px;">
<h3 th:text="${product.name}"></h3>
<p th:text="${product.description}"></p>
<p>Цена: <span th:text="${product.price} + ' $'"></span></p>
<button>Добавить в корзину</button>
</div>
</div>
<a href="#" style="margin-top: 2rem; display: inline-block;">
<button style="padding: 1rem 2rem; font-size: 1.2rem;">Перейти в корзину</button>
</a>
</div>
<footer>
<p>© 2024 Магазин электротоваров. Все права защищены.</p>
</footer>
</body>
</html>
</html>

View File

@@ -1,28 +0,0 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="ru">
<head>
<meta charset="UTF-8">
<title>Форма добавления товара</title>
</head>
<body>
<h1>Добавить новый товар</h1>
<form action="#" th:action="@{/product_form}" th:object="${product}" method="post">
<p>
<label for="name">Название товара: </label>
<input type="text" id="name" th:field="*{name}"/>
<span style="color: red" th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Ошибка</span>
</p>
<p>
<label for="price">Цена: </label>
<input type="text" id="price" th:field="*{price}"/>
<span style="color: red" th:if="${#fields.hasErrors('price')}" th:errors="*{price}">Ошибка</span>
</p>
<p>
<label for="description">Описание товара: </label>
<input type="text" id="description" th:field="*{description}"/>
<span style="color: red" th:if="${#fields.hasErrors('description')}" th:errors="*{description}">Ошибка</span>
</p>
<button type="submit">Добавить товар</button>
</form>
</body>
</html>

View File

@@ -0,0 +1,49 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Регистрация</title>
<link rel="stylesheet" th:href="@{/css/styles.css}">
</head>
<body>
<header>
<h1>Регистрация нового пользователя</h1>
</header>
<div class="container">
<form th:action="@{/register}" th:object="${user}" method="post">
<div>
<label for="name">Имя:</label>
<input type="text" id="name" th:field="*{name}" />
<br />
<span style="color: red" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
</div>
<div>
<label for="email">Email:</label>
<input type="email" id="email" th:field="*{email}" />
<br />
<span style="color: red" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span>
</div>
<div>
<label for="password">Пароль:</label>
<input type="password" id="password" th:field="*{password}" />
<br />
<span style="color: red" th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></span>
</div>
<button type="submit">Зарегистрироваться</button>
</form>
<p th:if="${message}" th:text="${message}"></p>
</div>
<footer>
<p>© 2024 Магазин электротоваров. Все права защищены.</p>
</footer>
</body>
</html>

View File

@@ -15,6 +15,12 @@ public class HomeControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testHomePageReturnsOkStatus() throws Exception {
mockMvc.perform(get("/"))
.andExpect(status().isOk());
}
@Test
public void testHomePageReturnsCorrectView() throws Exception {
mockMvc.perform(get("/"))
@@ -22,17 +28,11 @@ public class HomeControllerTest {
.andExpect(view().name("home"));
}
@Test
public void testHomePageContainsMessage() throws Exception {
mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(model().attribute("message", "Добро пожаловать в магазин электротоваров!"));
}
@Test
public void testHomePageRendersCorrectHtml() throws Exception {
mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(content().string(org.hamcrest.Matchers.containsString("Добро пожаловать в магазин электротоваров!")));
.andExpect(content().contentType("text/html;charset=UTF-8"))
.andExpect(model().attribute("message", "Добро пожаловать в магазин электротоваров!"));
}
}