.
This commit is contained in:
@@ -3,6 +3,10 @@ package ru.lionarius.isdojplab.controller;
|
|||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import ru.lionarius.isdojplab.model.Product;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
public class HomeController {
|
public class HomeController {
|
||||||
@@ -10,6 +14,14 @@ public class HomeController {
|
|||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
public String home(Model model) {
|
public String home(Model model) {
|
||||||
model.addAttribute("message", "Добро пожаловать в магазин электротоваров!");
|
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";
|
return "home";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:/";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,18 +3,16 @@ package ru.lionarius.isdojplab.model;
|
|||||||
import jakarta.validation.constraints.Min;
|
import jakarta.validation.constraints.Min;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
public class Product {
|
public class Product {
|
||||||
|
|
||||||
@NotBlank(message = "Название товара обязательно")
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@NotNull(message = "Цена товара обязательна")
|
|
||||||
@Min(value = 1, message = "Цена должна быть больше 0")
|
|
||||||
private Double price;
|
private Double price;
|
||||||
|
|
||||||
@NotBlank(message = "Описание товара обязательно")
|
|
||||||
private String description;
|
private String description;
|
||||||
|
private String imageUrl;
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/main/java/ru/lionarius/isdojplab/model/User.java
Normal file
18
src/main/java/ru/lionarius/isdojplab/model/User.java
Normal 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;
|
||||||
|
}
|
||||||
71
src/main/resources/static/css/styles.css
Normal file
71
src/main/resources/static/css/styles.css
Normal 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%;
|
||||||
|
}
|
||||||
@@ -1,10 +1,43 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html xmlns:th="http://www.thymeleaf.org" lang="ru">
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Магазин электротоваров</title>
|
<title>Магазин электротоваров</title>
|
||||||
|
<link rel="stylesheet" th:href="@{/css/styles.css}">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -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>
|
|
||||||
49
src/main/resources/templates/register_form.html
Normal file
49
src/main/resources/templates/register_form.html
Normal 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>
|
||||||
@@ -15,6 +15,12 @@ public class HomeControllerTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHomePageReturnsOkStatus() throws Exception {
|
||||||
|
mockMvc.perform(get("/"))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHomePageReturnsCorrectView() throws Exception {
|
public void testHomePageReturnsCorrectView() throws Exception {
|
||||||
mockMvc.perform(get("/"))
|
mockMvc.perform(get("/"))
|
||||||
@@ -22,17 +28,11 @@ public class HomeControllerTest {
|
|||||||
.andExpect(view().name("home"));
|
.andExpect(view().name("home"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testHomePageContainsMessage() throws Exception {
|
|
||||||
mockMvc.perform(get("/"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(model().attribute("message", "Добро пожаловать в магазин электротоваров!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHomePageRendersCorrectHtml() throws Exception {
|
public void testHomePageRendersCorrectHtml() throws Exception {
|
||||||
mockMvc.perform(get("/"))
|
mockMvc.perform(get("/"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(org.hamcrest.Matchers.containsString("Добро пожаловать в магазин электротоваров!")));
|
.andExpect(content().contentType("text/html;charset=UTF-8"))
|
||||||
|
.andExpect(model().attribute("message", "Добро пожаловать в магазин электротоваров!"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user