почти все

This commit is contained in:
dasha 2023-04-22 11:47:42 +04:00
parent 63dcaa4d7a
commit 2d2394bce5
33 changed files with 1131 additions and 57 deletions

View File

@ -12,22 +12,24 @@ repositories {
mavenCentral()
}
jar {
enabled = false
}
dependencies {
implementation(project(':front'))
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.h2database:h2:2.1.210'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
implementation 'org.webjars:bootstrap:5.1.3'
implementation 'org.webjars:jquery:3.6.0'
implementation 'org.webjars:font-awesome:6.1.0'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.h2database:h2:2.1.210'
implementation 'org.hibernate.validator:hibernate-validator'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.5'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.hibernate.validator:hibernate-validator'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.5'
}
tasks.named('test') {

View File

@ -1,35 +1,19 @@
package com.labwork1.app;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.*;
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
public static final String REST_API = "/api";
@Override
public void addViewControllers(ViewControllerRegistry registry) {
WebMvcConfigurer.super.addViewControllers(registry);
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("*");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
ViewControllerRegistration registration = registry.addViewController("/notFound");
registration.setViewName("forward:/index.html");
registration.setStatusCode(HttpStatus.OK);
// Alternative way (404 error hits the console):
// > registry.addViewController("/notFound").setViewName("forward:/index.html");
}
@Bean
public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> containerCustomizer() {
return container -> {
container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notFound"));
};
}
}

View File

@ -1,5 +1,6 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.WebConfiguration;
import com.labwork1.app.student.service.CinemaService;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
@ -7,7 +8,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/cinema")
@RequestMapping(WebConfiguration.REST_API + "/cinema")
public class CinemaController {
private final CinemaService cinemaService;

View File

@ -18,6 +18,18 @@ public class CinemaDto {
this.image = new String(cinema.getImage(), StandardCharsets.UTF_8);
}
public void setId(long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setImage(String image) {
this.image = image;
}
public String getImage() {
return image;
}

View File

@ -0,0 +1,81 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.service.CinemaService;
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.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Base64;
import java.util.List;
@Controller
@RequestMapping("/cinema")
public class CinemaMvcController {
private final CinemaService cinemaService;
public CinemaMvcController(CinemaService cinemaService) {
this.cinemaService = cinemaService;
}
@GetMapping
public String getCinemas(Model model) {
model.addAttribute("cinemas",
cinemaService.findAllCinemas().stream()
.map(CinemaDto::new)
.toList());
return "cinema";
}
@GetMapping(value = {"/edit", "/edit/{id}"})
public String editCinema(@PathVariable(required = false) Long id,
Model model) {
if (id == null || id <= 0) {
model.addAttribute("cinemaDto", new CinemaDto());
} else {
model.addAttribute("cinemaId", id);
model.addAttribute("cinemaDto", new CinemaDto(cinemaService.findCinema(id)));
}
return "cinema-edit";
}
@GetMapping (value = "/search/")
public String searchCinema(@RequestParam String request,
Model model) {
List<CinemaDto> cinemas = cinemaService.findAllCinemas(request)
.stream().map(CinemaDto::new).toList();
model.addAttribute("cinemas", cinemas);
return "cinema";
}
@PostMapping(value = {"/", "/{id}"})
public String saveCinema(@PathVariable(required = false) Long id,
@RequestParam("multipartFile") MultipartFile multipartFile,
@ModelAttribute @Valid CinemaDto cinemaDto,
BindingResult bindingResult,
Model model) throws IOException {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "cinema-edit";
}
if (id == null || id <= 0) {
cinemaDto.setImage("data:image/jpeg;base64," + Base64.getEncoder().encodeToString(multipartFile.getBytes()));
cinemaService.addCinema(cinemaDto);
} else {
cinemaDto.setId(id);
cinemaDto.setImage("data:image/jpeg;base64," + Base64.getEncoder().encodeToString(multipartFile.getBytes()));
cinemaService.updateCinema(cinemaDto);
}
return "redirect:/cinema";
}
@PostMapping("/delete/{id}")
public String deleteCinema(@PathVariable Long id) {
cinemaService.deleteCinema(id);
return "redirect:/cinema";
}
}

View File

@ -1,12 +1,13 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.WebConfiguration;
import com.labwork1.app.student.service.CustomerService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/customer")
@RequestMapping(WebConfiguration.REST_API + "/customer")
public class CustomerController {
private final CustomerService customerService;

View File

@ -27,6 +27,22 @@ public class CustomerDto {
}
}
public void setId(long id) {
this.id = id;
}
public void setLogin(String login) {
this.login = login;
}
public void setPassword(String password) {
this.password = password;
}
public void setOrders(List<OrderDto> orders) {
this.orders = orders;
}
public long getId() {
return id;
}

View File

@ -0,0 +1,64 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.service.CustomerService;
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.*;
@Controller
@RequestMapping("/customer")
public class CustomerMvcController {
private final CustomerService customerService;
public CustomerMvcController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping
public String getCustomers(Model model) {
model.addAttribute("customers",
customerService.findAllCustomers().stream()
.map(CustomerDto::new)
.toList());
return "customer";
}
@GetMapping(value = {"/edit", "/edit/{id}"})
public String editCustomer(@PathVariable(required = false) Long id,
Model model) {
if (id == null || id <= 0) {
model.addAttribute("customerDto", new CustomerDto());
} else {
model.addAttribute("customerId", id);
model.addAttribute("customerDto", new CustomerDto(customerService.findCustomer(id)));
}
return "customer-edit";
}
@PostMapping(value = {"/", "/{id}"})
public String saveCustomer(@PathVariable(required = false) Long id,
@ModelAttribute @Valid CustomerDto customerDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "customer-edit";
}
if (id == null || id <= 0) {
customerService.addCustomer(customerDto.getLogin(), customerDto.getPassword());
} else {
customerDto.setId(id);
customerService.updateCustomer(id, customerDto.getLogin(), customerDto.getPassword());
}
return "redirect:/customer";
}
@PostMapping("/delete/{id}")
public String deleteCustomer(@PathVariable Long id) {
customerService.deleteCustomer(id);
return "redirect:/customer";
}
}

View File

@ -1,12 +1,13 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.WebConfiguration;
import com.labwork1.app.student.service.OrderService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/order")
@RequestMapping(WebConfiguration.REST_API + "/order")
public class OrderController {
private final OrderService orderService;

View File

@ -10,6 +10,7 @@ import java.util.List;
public class OrderDto {
private long id;
private Date dateOfPurchase;
private Long customerId;
private String customer;
private List<OrderSessionDto> sessions;
@ -19,6 +20,7 @@ public class OrderDto {
public OrderDto(Order order) {
this.id = order.getId();
this.dateOfPurchase = order.getDateOfPurchase();
this.customerId = order.getCustomer().getId();
this.customer = order.getCustomer().getLogin();
if (order.getSessions() != null && order.getSessions().size() > 0)
this.sessions = order.getSessions()
@ -27,6 +29,30 @@ public class OrderDto {
x.getId().getOrderId(), x.getCount())).toList();
}
public Long getCustomerId() {
return customerId;
}
public void setCustomerId(Long customerId) {
this.customerId = customerId;
}
public void setId(long id) {
this.id = id;
}
public void setDateOfPurchase(Date dateOfPurchase) {
this.dateOfPurchase = dateOfPurchase;
}
public void setCustomer(String customer) {
this.customer = customer;
}
public void setSessions(List<OrderSessionDto> sessions) {
this.sessions = sessions;
}
public long getId() {
return id;
}

View File

@ -0,0 +1,99 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.service.CustomerService;
import com.labwork1.app.student.service.OrderService;
import com.labwork1.app.student.service.SessionService;
import jakarta.validation.Valid;
import org.slf4j.event.KeyValuePair;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/order")
public class OrderMvcController {
private final OrderService orderService;
private final SessionService sessionService;
private final CustomerService customerService;
public OrderMvcController(OrderService orderService, SessionService sessionService, CustomerService customerService) {
this.orderService = orderService;
this.sessionService = sessionService;
this.customerService = customerService;
}
@GetMapping
public String getOrders(Model model) {
model.addAttribute("orders",
orderService.findAllOrders().stream()
.map(OrderDto::new)
.toList());
return "order";
}
@GetMapping(value = {"/edit", "/edit/{id}"})
public String editOrder(@PathVariable(required = false) Long id,
Model model) {
if (id == null || id <= 0) {
List<CustomerDto> customers = customerService.findAllCustomers().stream()
.map(CustomerDto::new)
.toList();
model.addAttribute("orderDto", new OrderDto());
model.addAttribute("customers", customers);
return "order-edit";
} else {
List<OrderSessionDto> temp = orderService.findOrder(id).getSessions()
.stream().map(x -> new OrderSessionDto(new SessionDto(x.getSession()),
x.getOrder().getId(), x.getCount())).toList();
List<SessionDto> sessions = sessionService.findAllSessions().stream()
.map(SessionDto::new)
.toList();
HashMap<SessionDto, Integer> orderSessions = new HashMap<>();
for (var os : temp) {
orderSessions.put(os.getSession(), os.getCount());
}
model.addAttribute("orderSessions", orderSessions);
model.addAttribute("sessions", sessions);
model.addAttribute("orderSessionDto", new OrderSessionDto());
return "ordersession";
}
}
@PostMapping(value = "/")
public String saveOrder(@ModelAttribute @Valid OrderDto orderDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "order-edit";
}
orderService.addOrder(orderDto.getCustomerId());
return "redirect:/order";
}
@PostMapping(value = {"/{id}"})
public String editOrder(@PathVariable Long id,
@RequestParam("session") Long session,
@RequestParam(value = "count", required = false) Integer count,
Model model) {
if (count == null)
orderService.deleteSessionInOrder(id, session, Integer.MAX_VALUE);
else if (count > 0)
orderService.addSession(id, session, count);
return "redirect:/order/edit/" + id;
}
@PostMapping("/delete/{id}")
public String deleteOrder(@PathVariable Long id) {
orderService.deleteOrder(id);
return "redirect:/order";
}
}

View File

@ -14,6 +14,18 @@ public class OrderSessionDto {
this.count = count;
}
public void setSession(SessionDto session) {
this.session = session;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public void setCount(Integer count) {
this.count = count;
}
public SessionDto getSession() {
return session;
}

View File

@ -1,16 +1,19 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.WebConfiguration;
import com.labwork1.app.student.service.SessionService;
import org.springframework.web.bind.annotation.*;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping("/session")
@RequestMapping(WebConfiguration.REST_API + "/session")
public class SessionController {
private final SessionService sessionService;
@ -36,11 +39,11 @@ public class SessionController {
@RequestParam("cinemaid") Long cinemaId,
@RequestParam("capacity") Integer capacity) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat();
format.applyPattern("yyyy-MM-dd-HH:ss");
format.applyPattern("yyyy-MM-dd-HH:mm");
Date docDate = format.parse(timestamp.replace('T', '-'));
return new SessionDto(sessionService.findSession(
sessionService.addSession(Double.parseDouble(price),
new Timestamp(docDate.getTime()), cinemaId, capacity).getId()));
LocalDateTime.now(), cinemaId, capacity).getId()));
}
@PutMapping("/{id}")

View File

@ -1,16 +1,17 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.model.Session;
import org.springframework.format.annotation.DateTimeFormat;
import java.sql.Timestamp;
import java.time.LocalDateTime;
public class SessionDto {
private long id;
private Double price;
private Timestamp timestamp;
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm")
private LocalDateTime timestamp;
private CinemaDto cinema;
private Long capacity;
private int maxCount;
public SessionDto() {
@ -22,31 +23,56 @@ public class SessionDto {
this.timestamp = session.getTimestamp();
this.capacity = session.getCapacity();
this.maxCount = session.getMaxCount();
if (session.getCinema() != null) this.cinema = new CinemaDto(session.getCinema());
else this.cinema = null;
if (session.getCinema() != null) {
this.cinema = new CinemaDto(session.getCinema());
} else this.cinema = null;
}
public int getMaxCount() {
return maxCount;
public CinemaDto getCinema() {
return cinema;
}
public void setCinema(CinemaDto cinema) {
this.cinema = cinema;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Double getPrice() {
return price;
}
public Timestamp getTimestamp() {
public void setPrice(Double price) {
this.price = price;
}
public LocalDateTime getTimestamp() {
return timestamp;
}
public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}
public Long getCapacity() {
return capacity;
}
public CinemaDto getCinema() {
return cinema;
public void setCapacity(Long capacity) {
this.capacity = capacity;
}
public int getMaxCount() {
return maxCount;
}
public void setMaxCount(int maxCount) {
this.maxCount = maxCount;
}
}

View File

@ -0,0 +1,81 @@
package com.labwork1.app.student.controller;
import com.labwork1.app.student.service.CinemaService;
import com.labwork1.app.student.service.SessionService;
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.*;
import java.time.LocalDateTime;
import java.util.List;
@Controller
@RequestMapping("/session")
public class SessionMvcController {
private final SessionService sessionService;
private final CinemaService cinemaService;
public SessionMvcController(SessionService sessionService, CinemaService cinemaService) {
this.sessionService = sessionService;
this.cinemaService = cinemaService;
}
@GetMapping
public String getSessions(Model model) {
model.addAttribute("sessions",
sessionService.findAllSessions().stream()
.map(SessionDto::new)
.toList());
return "session";
}
@GetMapping(value = {"/edit", "/edit/{id}"})
public String editSession(@PathVariable(required = false) Long id,
Model model) {
if (id == null || id <= 0) {
List<CinemaDto> cinemas = cinemaService.findAllCinemas().stream()
.map(CinemaDto::new)
.toList();
model.addAttribute("sessionDto", new SessionDto());
model.addAttribute("cinemas", cinemas);
} else {
model.addAttribute("sessionId", id);
model.addAttribute("sessionDto", new SessionDto(sessionService.findSession(id)));
}
return "session-edit";
}
@PostMapping(value = "/{id}")
public String editSession(@PathVariable Long id,
@ModelAttribute @Valid SessionDto sessionDto,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
model.addAttribute("errors", bindingResult.getAllErrors());
return "session-edit";
}
sessionService.updateSession(id, sessionDto.getPrice());
return "redirect:/session";
}
@PostMapping(value = "/")
public String saveSession(@RequestParam("price") String price,
@RequestParam("timestamp") LocalDateTime timestamp,
@RequestParam("cinemaid") Long cinemaId,
@RequestParam("maxCount") Integer capacity,
Model model) {
sessionService.addSession(Double.parseDouble(price), timestamp,
cinemaId, capacity);
return "redirect:/session";
}
@PostMapping("/delete/{id}")
public String deleteSession(@PathVariable Long id) {
sessionService.deleteSession(id);
return "redirect:/session";
}
}

View File

@ -2,8 +2,10 @@ package com.labwork1.app.student.model;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import org.springframework.format.annotation.DateTimeFormat;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -18,7 +20,8 @@ public class Session {
@NotNull(message = "timestamp can't be null or empty")
@Column
@Temporal(TemporalType.TIMESTAMP)
private Timestamp timestamp;
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm")
private LocalDateTime timestamp;
@OneToMany(mappedBy = "session", fetch = FetchType.EAGER)
private List<OrderSession> orders;
@ManyToOne(fetch = FetchType.EAGER)
@ -37,7 +40,7 @@ public class Session {
return maxCount;
}
public Session(Double price, Timestamp timestamp, Integer maxCount) {
public Session(Double price, LocalDateTime timestamp, Integer maxCount) {
this.price = price;
this.timestamp = timestamp;
this.maxCount = maxCount;
@ -125,11 +128,11 @@ public class Session {
this.price = price;
}
public Timestamp getTimestamp() {
public LocalDateTime getTimestamp() {
return timestamp;
}
public void setTimestamp(Timestamp timestamp) {
public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}

View File

@ -8,6 +8,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.List;
@Service
@ -23,7 +24,7 @@ public class SessionService {
}
@Transactional
public Session addSession(Double price, Timestamp date, Long cinemaId, Integer capacity) {
public Session addSession(Double price, LocalDateTime date, Long cinemaId, Integer capacity) {
final Session session = new Session(price, date, capacity);
final Cinema cinema = cinemaService.findCinema(cinemaId);
session.setCinema(cinema);

View File

@ -0,0 +1,112 @@
html,
body {
background: #2b2d33;
}
.green-mark {
background-color: #38a65d;
}
.willSee {
background-color: #38a65d;
}
.delete {
background-color: #e94049;
}
.icon {
width: 50px;
height: 50px;
}
hr {
height: 2px !important;
}
.description {
color: #8f9398;
}
.editIcon {
height: 2.5vh;
}
.posterChoiceToTaste {
width: 290px;
height: 437px;
}
.posterFilmPage{
width: 290px;
height: 437px;
}
a {
text-decoration: none;
}
a:hover {
color: white;
}
.current a {
color: white;
}
/* for film-page */
.table {
color: #8f9398;
}
/* main */
@media screen and (max-width: 290px) {
.posterItem {
display: none !important;
}
.fs-1 {
margin-left: 1em !important;
}
}
body {
background: #2b2d33;
}
.content {
min-height: calc(100vh - 25.1vh);
background: #40444d;
}
.content_header {
margin: -1.5em -1.5em 0em -1.5em;
background-color: #8f9297;
}
.posterItem {
width: 90px;
height: 90px;
margin-top: -10px;
}
form input {
max-width: 300px;
}
table tbody tr td {
border: 0px !important;
}
footer {
flex: 0 0 auto !important;
background: #1a1c20;
color: #c2c2c2;
}
footer nav {
color: #c2c2c2;
}
header {
background: #1a1c20;
}
header a {
color: #c2c2c2;
}
header a:hover {
color: #ffffff;
}
.mainInput {
max-width: 200px;
}

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"><!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
<path d="M448 48V384c-63.09 22.54-82.34 32-119.5 32c-62.82 0-86.6-32-149.3-32C158.6 384 142.6 387.6 128 392.2v-64C142.6 323.6 158.6 320 179.2 320c62.73 0 86.51 32 149.3 32C348.9 352 364.1 349 384 342.7v-208C364.1 141 348.9 144 328.5 144c-62.82 0-86.6-32-149.3-32C128.4 112 104.3 132.6 64 140.7v307.3C64 465.7 49.67 480 32 480S0 465.7 0 448V63.1C0 46.33 14.33 32 31.1 32S64 46.33 64 63.1V76.66C104.3 68.63 128.4 48 179.2 48c62.73 0 86.51 32 149.3 32C365.7 80 384.9 70.54 448 48z"/>
</svg>

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<h1>Фильм</h1>
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/cinema/{id}(id=${id})}" th:object="${cinemaDto}" enctype="multipart/form-data" method="post">
<div class="mb-3">
<label for="name" class="form-label">Название</label>
<input type="text" class="form-control" id="name" th:field="${cinemaDto.name}" required="true">
</div>
<div class="mb-3">
<label for="multipartFile" class="form-label">Изображение</label>
<input type="file" class="form-control" id="multipartFile" th:name="multipartFile" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/cinema}">
Назад
</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<h1>Фильмы</h1>
<div class="d-flex justify-content-end">
<a class="btn btn-success button-fixed"
th:href="@{/cinema/edit}">
<i class="fa-solid fa-plus"></i>
</a>
</div>
<form action="#" th:action="@{/cinema/search/}">
<input class="form-control mainInput" type="text" name="request" search="true" rounded="true" required="true" />
<button class="border border-0 p-0 ms-2" type="submit"><img class="icon" src="/search.jpg" alt="Поиск" /></button>
</form>
<hr class="border border-0 bg-black" />
<table class="table" id="tbl-items">
<tbody>
<tr th:each="cinema, iterator: ${cinemas}">
<td>
<img class="posterItem me-3" th:src="${cinema.image}" alt="${cinema.name}" align="left"/>
<div class="d-flex flex-row flex-wrap flex-grow-1 align-items-center">
<div class="pt-3 description d-flex flex-column justify-content-start align-items-center mb-3 fs-6 fw-bold">
<p class="text-start description">
<a class="text-white fs-5 fw-bold pt-3" th:text="${cinema.name}"></a>
</p>
</div>
<div id="rightPanel" class="d-flex flex-wrap justify-content-end text-white fw-bold fs-4 flex-grow-1">
<div class="rounded p-1 mx-2 green-mark">9.2</div>
<div>
<a type="button" class="m-1 btn btn-primary" th:href="@{/cinema/edit/{id}(id=${cinema.id})}">
<i class="fa fa-pencil"></i>
</a>
<a type="button" class="m-1 btn btn-danger"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${cinema.id}').click()|">
<i class="fa fa-trash"></i>
</a>
</div>
</div>
<form th:action="@{/cinema/delete/{id}(id=${cinema.id})}" method="post">
<button th:id="'remove-' + ${cinema.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</div>
<hr class="border border-0 bg-black" />
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<h1>Пользователь</h1>
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/customer/{id}(id=${id})}" th:object="${customerDto}" method="post">
<div class="mb-3">
<label for="login" class="form-label">Логин</label>
<input type="text" class="form-control" id="login" th:field="${customerDto.login}" required="true">
</div>
<div class="mb-3">
<label for="password" class="form-label">Пароль</label>
<input type="text" class="form-control" id="password" th:field="${customerDto.password}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/customer}">
Назад
</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<h1>Пользователи</h1>
<div class="d-flex justify-content-end">
<a class="btn btn-success button-fixed"
th:href="@{/customer/edit}">
<i class="fa-solid fa-plus"></i>
</a>
</div>
<table class="table text-white" id="tbl-items">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Логин</th>
<th scope="col">Пароль</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="customer, iterator: ${customers}">
<td th:text="${customer.id}"/>
<td th:text="${customer.login}"/>
<td th:text="${customer.password}"/>
<td>
<div>
<a type="button" class="m-1 btn btn-primary" th:href="@{/customer/edit/{id}(id=${customer.id})}">
<i class="fa fa-pencil"></i>
</a>
<a type="button" class="m-1 btn btn-danger"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${customer.id}').click()|">
<i class="fa fa-trash"></i>
</a>
</div>
<form th:action="@{/customer/delete/{id}(id=${customer.id})}" method="post">
<button th:id="'remove-' + ${customer.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

View File

@ -0,0 +1,68 @@
<!DOCTYPE html>
<html lang="ru"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="UTF-8"/>
<title>Киносайт</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="icon" href="/favicon.svg">
<script type="text/javascript" src="/webjars/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script>
<script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script>
<link rel="stylesheet" href="/webjars/bootstrap/5.1.3/css/bootstrap.min.css"/>
<link rel="stylesheet" href="/webjars/font-awesome/6.1.0/css/all.min.css"/>
<link rel="stylesheet" href="/css/style.css"/>
</head>
<body class="d-flex flex-column h-100 text-white">
<header class="fs-4 fw-bold p-1">
<nav class="navbar navbar-expand-lg navbar-dark text-white">
<div class="container-fluid">
<a class="navbar-brand" href="/">
<i class="fa-solid fa-font-awesome"></i>
</a>
<button class="navbar-toggler" type="button"
data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse menu" id="navbarNav">
<ul class="navbar-nav">
<a class="nav-link" href="/">Главная</a>
<a class="nav-link" href="/cinema">Фильмы</a>
<a class="nav-link" href="/customer">Регистрация</a>
<a class="nav-link" href="/order">Заказы</a>
<a class="nav-link" href="/session">Сеансы</a>
<a class="nav-link" href="/h2-console/" target="_blank">Консоль H2</a>
</ul>
</div>
</div>
</nav>
</header>
<div class="container rounded my-5 p-4 content">
<div class="content_header rounded-top p-2 mb-2">
<h1 class="fs-1 fw-bold text-white ms-5">Киносайт</h1>
</div>
<div layout:fragment="content">
</div>
</div>
</body>
<th:block layout:fragment="scripts">
<script>
$(function () {
var location = window.location.href;
var cur_url = '/' + location.split('/').pop();
$('.menu li').each(function () {
var link = $(this).find('a').attr('href');
if (cur_url == link) {
$(this).addClass('current');
}
});
});
</script>
</th:block>
<footer class="d-flex align-items-center fw-bold fs-4 p-2 ps-5">2022 г.
<nav class="d-flex justify-content-center flex-grow-1"><a href="https://vk.com/id0" target="_blank"><img class="icon" src="/vk.jpg" alt="VK" /></a></nav>
</footer>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div><span th:text="${error}"></span></div>
<a href="/">На главную</a>
</div>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<div>It's works!</div>
<a href="123">ERROR</a>
</div>
</body>
</html>

View File

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<h1 th:if="${id == null}">Создание заказа</h1>
<h1 th:if="${id != null}">Добавление сеансов в заказ</h1>
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/order/{id}(id=${id})}" th:object="${orderDto}" method="post" th:if="${id == null}">
<div class="mb-3" >
<label for="customer" class="form-label">Пользователь</label>
<select id="customer" class="form-select" th:field="${orderDto.customerId}" required="true">
<option th:each="value: ${customers}"
th:value="${value.id}"
th:text="${value.login}">
</option>
</select>
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/order}">
Назад
</a>
</div>
</form>
<form action="#" th:action="@{/order/{id}(id=${id})}" th:object="${orderSessionDto}" method="post" th:if="${id != null}">
<div class="mb-3">
<label for="session" class="form-label">Сеанс</label>
<select id="session" class="form-select" required="true" th:name="session">
<option th:each="value: ${sessions}"
th:value="${value.id}"
th:text="${value.cinema.name} + ' ' + ${value.timestamp}">
</option>
</select>
</div>
<div class="mb-3" >
<label for="count" class="form-label">Количество</label>
<input type="number" class="form-control" min="1" id="count" th:name="count" th:field="${orderSessionDto.count}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span>Добавить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/order}">
Назад
</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<h1>Заказы</h1>
<div class="d-flex justify-content-end">
<a class="btn btn-success button-fixed"
th:href="@{/order/edit}">
<i class="fa-solid fa-plus"></i>
</a>
</div>
<table class="table text-white" id="tbl-items">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Customer</th>
<th scope="col">DateOfPurchase</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="item, iterator: ${orders}">
<td th:text="${item.id}"/>
<td th:text="${item.customer}"/>
<td th:text="${item.dateOfPurchase}"/>
<td>
<div>
<a type="button" class="m-1 btn btn-primary" th:href="@{/order/edit/{id}(id=${item.id})}">
<i class="fa fa-pencil"></i>
</a>
<a type="button" class="m-1 btn btn-danger"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${item.id}').click()|">
<i class="fa fa-trash"></i>
</a>
</div>
<form th:action="@{/order/delete/{id}(id=${item.id})}" method="post">
<button th:id="'remove-' + ${item.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<h1 th:text="'Сеансы заказа ' + ${id}"></h1>
<form action="#" th:action="@{/order/{id}(id=${id})}" method="post">
<div class="mb-3">
<label for="session" class="form-label">Сеанс</label>
<select id="session" class="form-select" th:name="session" required="true">
<option th:each="value: ${sessions}"
th:value="${value.id}"
th:text="${value.cinema.name} + ' ' + ${value.timestamp}">
</option>
</select>
</div>
<div class="mb-3">
<label for="count" class="form-label">Количество</label>
<input type="number" class="form-control" min="1" id="count" th:name="count" th:field="${orderSessionDto.count}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span>Добавить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/order}">
Назад
</a>
</div>
</form>
<table class="table text-white" id="tbl-items">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Price</th>
<th scope="col">Cinema</th>
<th scope="col">Timestamp</th>
<th scope="col">Count</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="item, iterator: ${orderSessions}">
<td th:text="${item.key.id}"/>
<td th:text="${item.key.price}"/>
<td th:text="${item.key.cinema.name}"/>
<td th:text="${item.key.timestamp}"/>
<td th:text="${item.value}"/>
<td>
<div>
<a type="button" class="m-1 btn btn-danger"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${item.key.id}').click()|">
<i class="fa fa-trash"></i>
</a>
</div>
<form th:action="@{'/order/' + ${id} + '?session=' + ${item.key.id}}" method="post">
<button th:id="'remove-' + ${item.key.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

View File

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<h1>Сеанс</h1>
<div th:text="${errors}" class="margin-bottom alert-danger"></div>
<form action="#" th:action="@{/session/{id}(id=${id})}" th:object="${sessionDto}" method="post">
<div class="mb-3">
<label for="price" class="form-label">Цена</label>
<input type="number" class="form-control" min="1" step="0.01" id="price" th:field="${sessionDto.price}" required="true">
</div>
<div class="mb-3" th:if="${id == null}">
<label for="cinemaid" class="form-label">Фильм</label>
<select id="cinemaid" class="form-select" th:name="cinemaid" required="true">
<option th:each="value: ${cinemas}"
th:value="${value.id}"
th:text="${value.name}">
</option>
</select>
</div>
<div class="mb-3" th:if="${id == null}">
<label for="count" class="form-label">Кол-во сеансов</label>
<input type="number" class="form-control" min="1" id="count" th:field="${sessionDto.maxCount}" required="true">
</div>
<div class="mb-3" th:if="${id == null}">
<label for="date" class="form-label">Дата</label>
<input type="datetime-local" class="form-control" id="date" th:field="${sessionDto.timestamp}" required="true">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary button-fixed">
<span th:if="${id == null}">Добавить</span>
<span th:if="${id != null}">Обновить</span>
</button>
<a class="btn btn-secondary button-fixed" th:href="@{/session}">
Назад
</a>
</div>
</form>
</div>
</body>
</html>

View File

@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{default}">
<head>
</head>
<body>
<div layout:fragment="content">
<h1>Сеансы</h1>
<div class="d-flex justify-content-end">
<a class="btn btn-success button-fixed"
th:href="@{/session/edit}">
<i class="fa-solid fa-plus"></i>
</a>
</div>
<table class="table text-white" id="tbl-items">
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Price</th>
<th scope="col">Cinema</th>
<th scope="col">Timestamp</th>
<th scope="col">Capacity</th>
<th scope="col">MaxCount</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr th:each="item, iterator: ${sessions}">
<td th:text="${item.id}"/>
<td th:text="${item.price}"/>
<td th:text="${item.cinema.name}"/>
<td th:text="${item.timestamp}"/>
<td th:text="${item.capacity} == null ? ${item.maxCount} : ${item.maxCount}-${item.capacity}"/>
<td th:text="${item.maxCount}"/>
<td>
<div>
<a type="button" class="m-1 btn btn-primary" th:href="@{/session/edit/{id}(id=${item.id})}">
<i class="fa fa-pencil"></i>
</a>
<a type="button" class="m-1 btn btn-danger"
th:attr="onclick=|confirm('Удалить запись?') && document.getElementById('remove-${item.id}').click()|">
<i class="fa fa-trash"></i>
</a>
</div>
<form th:action="@{/session/delete/{id}(id=${item.id})}" method="post">
<button th:id="'remove-' + ${item.id}" type="submit" style="display: none">
Удалить
</button>
</form>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>