Думаю я на полпути, но это как всегда может быть обманчивым ощущением

This commit is contained in:
Kirill 2024-06-04 11:29:14 +04:00
parent 3a923d72f3
commit 3e219a70bf
20 changed files with 518 additions and 33 deletions

View File

@ -6,7 +6,7 @@
"request": "launch",
"cwd": "${workspaceFolder}",
"mainClass": "com.example.demo.DemoApplication",
"projectName": "lec5",
"projectName": "Laba5",
"args": "--populate",
"envFile": "${workspaceFolder}/.env"
}

View File

@ -12,6 +12,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.example.demo.films.model.FilmEntity;
import com.example.demo.films.service.FilmService;
import com.example.demo.genres.model.GenreEntity;
import com.example.demo.genres.service.GenreService;
import com.example.demo.orders.model.OrderEntity;
import com.example.demo.orders.service.OrderService;
import com.example.demo.subscriptions.model.SubscriptionEntity;
@ -31,6 +33,7 @@ public class DemoApplication implements CommandLineRunner {
private final SubscriptionService subscriptionService;
private final UserService userService;
private final OrderService orderService;
private final GenreService genreService;
private final FilmService filmService;
private final UserfilmService userfilmService;
@ -39,12 +42,14 @@ public class DemoApplication implements CommandLineRunner {
SubscriptionService subscriptionService,
UserService userService,
OrderService orderService,
GenreService genreService,
FilmService filmService,
UserfilmService userfilmService) {
this.typeService = typeService;
this.subscriptionService = subscriptionService;
this.userService = userService;
this.orderService = orderService;
this.genreService = genreService;
this.filmService = filmService;
this.userfilmService = userfilmService;
}
@ -84,10 +89,15 @@ public class DemoApplication implements CommandLineRunner {
new OrderEntity(type3, 67800.00, 3));
orders.forEach(order -> orderService.create(user1.getId(), order));
log.info("Create default genre values");
final var genre1 = genreService.create(new GenreEntity("Comedy"));
final var genre2 = genreService.create(new GenreEntity("Triller"));
final var genre3 = genreService.create(new GenreEntity("Drama"));
log.info("Create default film values");
final var film1 = filmService.create(new FilmEntity("Ivan Vasilevich menyaet proffessiu"));
final var film2 = filmService.create(new FilmEntity("Ironia sudby"));
final var film3 = filmService.create(new FilmEntity("S legkim parom"));
final var film1 = filmService.create(new FilmEntity(genre1, "Ivan Vasilevich menyaet proffessiu"));
final var film2 = filmService.create(new FilmEntity(genre2, "Ironia sudby"));
final var film3 = filmService.create(new FilmEntity(genre3, "S legkim parom"));
log.info("Create default userfilm values");
userfilmService.create(user1.getId(), new UserfilmEntity(film1));

View File

@ -1,10 +1,15 @@
package com.example.demo.films.api;
import groovyjarjarantlr4.v4.runtime.misc.NotNull;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public class FilmDto {
private Long id;
@NotNull
@Min(1)
private String genreName;
@NotBlank
@Size(min = 5, max = 50)
private String name;
@ -17,6 +22,14 @@ public class FilmDto {
this.id = id;
}
public String getGenreName() {
return genreName;
}
public void setGenreName(String genreName) {
this.genreName = genreName;
}
public String getName() {
return name;
}

View File

@ -3,22 +3,37 @@ package com.example.demo.films.model;
import java.util.Objects;
import com.example.demo.core.model.BaseEntity;
import com.example.demo.genres.model.GenreEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
@Entity
@Table(name = "films")
public class FilmEntity extends BaseEntity {
@ManyToOne
@JoinColumn(name = "genreId", nullable = false)
private GenreEntity genre;
@Column(nullable = false, unique = true, length = 50)
private String name;
public FilmEntity() {
}
public FilmEntity(String name) {
public FilmEntity(GenreEntity genre, String name) {
this.name = name;
this.genre = genre;
}
public GenreEntity getGenre() {
return genre;
}
public void setGenre(GenreEntity genre) {
this.genre = genre;
}
public String getName() {
@ -31,7 +46,7 @@ public class FilmEntity extends BaseEntity {
@Override
public int hashCode() {
return Objects.hash(id, name);
return Objects.hash(id, genre, name);
}
@Override
@ -42,6 +57,7 @@ public class FilmEntity extends BaseEntity {
return false;
final FilmEntity other = (FilmEntity) obj;
return Objects.equals(other.getId(), id)
&& Objects.equals(other.getGenre(), genre)
&& Objects.equals(other.getName(), name);
}

View File

@ -63,6 +63,7 @@ public class FilmService {
final FilmEntity existsEntity = get(id);
checkName(id, entity.getName());
existsEntity.setName(entity.getName());
existsEntity.setGenre(entity.getGenre());
return repository.save(existsEntity);
}

View File

@ -0,0 +1,104 @@
package com.example.demo.genres.api;
import org.modelmapper.ModelMapper;
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.demo.core.configuration.Constants;
import com.example.demo.genres.model.GenreEntity;
import com.example.demo.genres.service.GenreService;
import jakarta.validation.Valid;
@Controller
@RequestMapping(GenreController.URL)
public class GenreController {
public static final String URL = Constants.ADMIN_PREFIX + "/genre";
private static final String GENRE_VIEW = "genre";
private static final String GENRE_EDIT_VIEW = "genre-edit";
private static final String GENRE_ATTRIBUTE = "genre";
private final GenreService genreService;
private final ModelMapper modelMapper;
public GenreController(GenreService genreService, ModelMapper modelMapper) {
this.genreService = genreService;
this.modelMapper = modelMapper;
}
private GenreDto toDto(GenreEntity entity) {
return modelMapper.map(entity, GenreDto.class);
}
private GenreEntity toEntity(GenreDto dto) {
return modelMapper.map(dto, GenreEntity.class);
}
@GetMapping
public String getAll(Model model) {
model.addAttribute(
"items",
genreService.getAll().stream()
.map(this::toDto)
.toList());
return GENRE_VIEW;
}
@GetMapping("/edit/")
public String create(Model model) {
model.addAttribute(GENRE_ATTRIBUTE, new GenreDto());
return GENRE_EDIT_VIEW;
}
@PostMapping("/edit/")
public String create(
@ModelAttribute(name = GENRE_ATTRIBUTE) @Valid GenreDto genre,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
return GENRE_EDIT_VIEW;
}
genreService.create(toEntity(genre));
return Constants.REDIRECT_VIEW + URL;
}
@GetMapping("/edit/{id}")
public String update(
@PathVariable(name = "id") Long id,
Model model) {
if (id <= 0) {
throw new IllegalArgumentException();
}
model.addAttribute(GENRE_ATTRIBUTE, toDto(genreService.get(id)));
return GENRE_EDIT_VIEW;
}
@PostMapping("/edit/{id}")
public String update(
@PathVariable(name = "id") Long id,
@ModelAttribute(name = GENRE_ATTRIBUTE) @Valid GenreDto genre,
BindingResult bindingResult,
Model model) {
if (bindingResult.hasErrors()) {
return GENRE_EDIT_VIEW;
}
if (id <= 0) {
throw new IllegalArgumentException();
}
genreService.update(id, toEntity(genre));
return Constants.REDIRECT_VIEW + URL;
}
@PostMapping("/delete/{id}")
public String delete(
@PathVariable(name = "id") Long id) {
genreService.delete(id);
return Constants.REDIRECT_VIEW + URL;
}
}

View File

@ -0,0 +1,27 @@
package com.example.demo.genres.api;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
public class GenreDto {
private Long id;
@NotBlank
@Size(min = 5, max = 50)
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,48 @@
package com.example.demo.genres.model;
import java.util.Objects;
import com.example.demo.core.model.BaseEntity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
@Entity
@Table(name = "genres")
public class GenreEntity extends BaseEntity {
@Column(nullable = false, unique = true, length = 50)
private String name;
public GenreEntity() {
}
public GenreEntity(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
final GenreEntity other = (GenreEntity) obj;
return Objects.equals(other.getId(), id)
&& Objects.equals(other.getName(), name);
}
}

View File

@ -0,0 +1,13 @@
package com.example.demo.genres.repository;
import java.util.Optional;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import com.example.demo.genres.model.GenreEntity;
public interface GenreRepository
extends CrudRepository<GenreEntity, Long>, PagingAndSortingRepository<GenreEntity, Long> {
Optional<GenreEntity> findByNameIgnoreCase(String name);
}

View File

@ -0,0 +1,76 @@
package com.example.demo.genres.service;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.StreamSupport;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.demo.core.error.NotFoundException;
import com.example.demo.genres.model.GenreEntity;
import com.example.demo.genres.repository.GenreRepository;
@Service
public class GenreService {
private final GenreRepository repository;
public GenreService(GenreRepository repository) {
this.repository = repository;
}
private void checkName(Long id, String name) {
final Optional<GenreEntity> existsGenre = repository.findByNameIgnoreCase(name);
if (existsGenre.isPresent() && !existsGenre.get().getId().equals(id)) {
throw new IllegalArgumentException(
String.format("Genre with name %s is already exists", name));
}
}
@Transactional(readOnly = true)
public List<GenreEntity> getAll() {
return StreamSupport.stream(repository.findAll(Sort.by("id")).spliterator(), false).toList();
}
@Transactional(readOnly = true)
public List<GenreEntity> getByIds(Collection<Long> ids) {
final List<GenreEntity> genres = StreamSupport.stream(repository.findAllById(ids).spliterator(), false)
.toList();
if (genres.size() < ids.size()) {
throw new IllegalArgumentException("Invalid genre");
}
return genres;
}
@Transactional(readOnly = true)
public GenreEntity get(long id) {
return repository.findById(id)
.orElseThrow(() -> new NotFoundException(GenreEntity.class, id));
}
@Transactional
public GenreEntity create(GenreEntity entity) {
if (entity == null) {
throw new IllegalArgumentException("Entity is null");
}
checkName(null, entity.getName());
return repository.save(entity);
}
@Transactional
public GenreEntity update(Long id, GenreEntity entity) {
final GenreEntity existsEntity = get(id);
checkName(id, entity.getName());
existsEntity.setName(entity.getName());
return repository.save(existsEntity);
}
@Transactional
public GenreEntity delete(Long id) {
final GenreEntity existsEntity = get(id);
repository.delete(existsEntity);
return existsEntity;
}
}

View File

@ -8,6 +8,9 @@ public class UserfilmDto {
@NotNull
@Min(1)
private String filmName;
@NotNull
@Min(1)
private String genreName;
public Long getId() {
return id;
@ -24,4 +27,12 @@ public class UserfilmDto {
public void setFilmName(String filmName) {
this.filmName = filmName;
}
public String getGenreName() {
return genreName;
}
public void setGenreName(String genreName) {
this.genreName = genreName;
}
}

View File

@ -1,13 +1,22 @@
package com.example.demo.userfilms.api;
public class UserfilmGroupedDto {
private String filmName;
private Long filmCount;
private String genreName;
public String getFilmName() {
return filmName;
public Long getfilmCount() {
return filmCount;
}
public void setFilmName(String filmName) {
this.filmName = filmName;
public void setfilmCount(Long filmCount) {
this.filmCount = filmCount;
}
public String getGenreName() {
return genreName;
}
public void setGenreName(String genreName) {
this.genreName = genreName;
}
}

View File

@ -4,6 +4,7 @@ import java.util.Objects;
import com.example.demo.core.model.BaseEntity;
import com.example.demo.films.model.FilmEntity;
import com.example.demo.genres.model.GenreEntity;
import com.example.demo.users.model.UserEntity;
import jakarta.persistence.Entity;
@ -28,6 +29,10 @@ public class UserfilmEntity extends BaseEntity {
this.film = film;
}
public GenreEntity getGenre() {
return film.getGenre();
}
public FilmEntity getFilm() {
return film;
}

View File

@ -1,7 +1,9 @@
package com.example.demo.userfilms.model;
import com.example.demo.films.model.FilmEntity;
import com.example.demo.genres.model.GenreEntity;
public interface UserfilmGrouped {
FilmEntity getFilm();
Long getCount();
GenreEntity getGenre();
}

View File

@ -25,16 +25,14 @@ public interface UserfilmRepository
Page<UserfilmEntity> findByUserIdAndFilmId(long userId, long filmId, Pageable pageable);
// select
// tpe.name
// from films as tpe
// left join userfilms as userfilm on tpe.id = userfilm.film_id and
// userfilm.user_id = ?
// group by tpe.name userfilm by tpe.id
// @Query("select "
// + "t as film "
// + "from FilmEntity t left join UserfilmEntity o on o.film = t and o.user.id =
// ?1 "
// + "group by t userfilm by t.id")
// List<UserfilmGrouped> getUserfilmsTotalByFilm(long userId);
@Query("select "
+ "count(*) as count, "
+ "g as genre "
+ "from FilmEntity f "
+ "left join GenreEntity g "
+ "on f.genre = g "
+ "right join UserFilmEntity uf "
+ "on uf.film = f and uf.user.id = ?1 "
+ "group by g order by g.name")
List<UserfilmGrouped> getFilmsTotalByGenre(long userId);
}

View File

@ -97,9 +97,9 @@ public class UserfilmService {
return existsEntity;
}
// @Transactional(readOnly = true)
// public List<UserfilmGrouped> getTotal(long userId) {
// userService.get(userId);
// return repository.getUserfilmsTotalByFilm(userId);
// }
@Transactional(readOnly = true)
public List<UserfilmGrouped> getTotal(long userId) {
userService.get(userId);
return repository.getFilmsTotalByGenre(userId);
}
}

View File

@ -0,0 +1,113 @@
package com.example.demo.users.api;
import java.util.stream.Collectors;
import org.modelmapper.ModelMapper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.example.demo.core.api.PageAttributesMapper;
import com.example.demo.core.configuration.Constants;
import com.example.demo.orders.api.OrderDto;
import com.example.demo.orders.api.OrderGroupedDto;
import com.example.demo.orders.model.OrderEntity;
import com.example.demo.orders.model.OrderGrouped;
import com.example.demo.orders.service.OrderService;
import com.example.demo.types.api.TypeDto;
import com.example.demo.types.model.TypeEntity;
import com.example.demo.types.service.TypeService;
import com.example.demo.userfilms.api.UserfilmDto;
import com.example.demo.userfilms.api.UserfilmGroupedDto;
import com.example.demo.userfilms.model.UserfilmEntity;
import com.example.demo.userfilms.model.UserfilmGrouped;
import com.example.demo.userfilms.service.UserfilmService;
import com.example.demo.users.model.UserSubscriptionWithStatus;
import com.example.demo.users.service.UserService;
import jakarta.validation.Valid;
@Controller
@RequestMapping("/cabinet")
public class UserCabinetController {
private static final String PROFILE_VIEW = "cabinet";
private static final String PAGE_ATTRIBUTE = "page";
private static final String TYPEID_ATTRIBUTE = "typeId";
private static final String PROFILE_ATTRIBUTE = "profile";
private final OrderService orderService;
private final UserfilmService userfilmService;
private final TypeService typeService;
private final UserService userService;
private final ModelMapper modelMapper;
public UserCabinetController(
OrderService orderService,
UserfilmService userfilmService,
TypeService typeService,
UserService userService,
ModelMapper modelMapper) {
this.orderService = orderService;
this.userfilmService = userfilmService;
this.typeService = typeService;
this.userService = userService;
this.modelMapper = modelMapper;
}
private OrderDto toDto(OrderEntity entity) {
return modelMapper.map(entity, OrderDto.class);
}
private OrderGroupedDto toGroupedDto(OrderGrouped entity) {
return modelMapper.map(entity, OrderGroupedDto.class);
}
private UserfilmDto toUserfilmDto(UserfilmEntity entity) {
return modelMapper.map(entity, UserfilmDto.class);
}
private UserfilmGroupedDto toUserfilmGroupedDto(UserfilmGrouped entity) {
return modelMapper.map(entity, UserfilmGroupedDto.class);
}
@GetMapping()
public String getProfile(
@CookieValue(value = Constants.USER_COOKIE, defaultValue = "0") long userId,
@RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
@RequestParam(name = TYPEID_ATTRIBUTE, defaultValue = "0") int typeId,
Model model) {
if (userId <= 0) {
return Constants.REDIRECT_VIEW + UserLoginController.LOGIN_URL;
}
model.addAttribute(PAGE_ATTRIBUTE, page);
model.addAttribute(TYPEID_ATTRIBUTE, typeId);
model.addAttribute("userfilms",
userfilmService.getAll(userId).stream()
.map(this::toUserfilmDto)
.toList());
return PROFILE_VIEW;
}
@PostMapping("/delete/{id}")
public String deleteOrder(
@CookieValue(value = Constants.USER_COOKIE, defaultValue = "0") long userId,
@PathVariable(name = "id") Long id,
@RequestParam(name = PAGE_ATTRIBUTE, defaultValue = "0") int page,
@RequestParam(name = TYPEID_ATTRIBUTE, defaultValue = "0") int typeId,
RedirectAttributes redirectAttributes) {
redirectAttributes.addAttribute(PAGE_ATTRIBUTE, page);
redirectAttributes.addAttribute(TYPEID_ATTRIBUTE, typeId);
orderService.delete(userId, id);
return Constants.REDIRECT_VIEW + "/";
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,7 @@
<th:block th:switch="${items.size()}">
<h2 th:case="0">Данные отсутствуют</h2>
<th:block th:case="*">
<form th:action="@{/}" method="get" class="row mt-2">
<form th:action="@{/cabinet}" method="get" class="row mt-2">
<div class="col-sm-10">
<input type="hidden" th:name="page" th:value="${page}">
<select th:name="typeId" id="typeId" class="form-select">