From b6d7f40c431a1585d0fe84019439d8f3c65d868d Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:52:36 +0100 Subject: [PATCH 01/16] Modified application properties --- src/main/resources/application.properties | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e02ff3e..a262c59 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -9,7 +9,5 @@ server.servlet.context-path=/api spring.jpa.show-sql=true spring.jpa.open-in-view=false -jwt.expiration=60000 +jwt.expiration=900000 jwt.secret=s3cr3t_str!ng*s0me_Rand0mVa!u?s3cr3t_str!ng*s0me_Rand0mVa!u - - From a37df3131b4c77827c596e32c0399c407533c255 Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:53:25 +0100 Subject: [PATCH 02/16] was added categories field with required annotation --- .../spring/boot/bookstore/model/Book.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/spring/boot/bookstore/model/Book.java b/src/main/java/spring/boot/bookstore/model/Book.java index 3e9db6b..8fca67c 100644 --- a/src/main/java/spring/boot/bookstore/model/Book.java +++ b/src/main/java/spring/boot/bookstore/model/Book.java @@ -5,10 +5,19 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; import jakarta.persistence.Table; import java.math.BigDecimal; +import java.util.HashSet; +import java.util.Set; +import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; +import org.apache.commons.lang3.builder.ToStringExclude; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; @@ -34,6 +43,15 @@ public class Book { private String description; @Column(name = "coverImage") private String coverImage; - @Column(name = "is_deleted",nullable = false) + + @ToStringExclude + @EqualsAndHashCode.Exclude + @ManyToMany + @JoinTable(name = "books_categories", + joinColumns = @JoinColumn(name = "books_id"), + inverseJoinColumns = @JoinColumn(name = "category_id")) + private Set categories = new HashSet<>(); + + @Column(name = "is_deleted", nullable = false) private boolean isDeleted = false; } From cfd2e741d2979c5b74613d4d1ea0c9fbdf25a48e Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:53:52 +0100 Subject: [PATCH 03/16] modified BookController --- .../bookstore/controller/BookController.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/spring/boot/bookstore/controller/BookController.java b/src/main/java/spring/boot/bookstore/controller/BookController.java index a7d65bc..bef2367 100644 --- a/src/main/java/spring/boot/bookstore/controller/BookController.java +++ b/src/main/java/spring/boot/bookstore/controller/BookController.java @@ -36,14 +36,16 @@ public class BookController { @GetMapping @Operation(summary = "Get all books from the library", description = "Retrieves a paginated list of all available books in the library." + + "Requires authentication for authorized access." ) public List getAll(Pageable pageable) { return bookService.findAll(pageable); } @GetMapping("/{id}") - @Operation(summary = "Get a book by its ID", - description = "Retrieves a book from the library by its unique identifier (ID)." + @Operation(summary = "Retrieve a book by ID", + description = "Get book details using its unique identifier (ID). " + + "Requires authentication for authorized access." ) public BookResponseDto getBookById(@PathVariable Long id) { return bookService.getBookById(id); @@ -52,16 +54,18 @@ public BookResponseDto getBookById(@PathVariable Long id) { @PostMapping @Operation(summary = "Create a new book", description = "Adds a new book to the library's collection." - + " Requires a valid book data payload in the request body.") + + " Requires a valid book data payload in the request body." + + "Requires authentication for authorized access.") @PreAuthorize("hasRole('ADMIN')") public BookResponseDto createBook(@RequestBody @Valid CreateBookRequestDto requestDto) { logger.info("Received a request to create a book: {}", requestDto.getTitle()); - return bookService.createBook(requestDto); + return bookService.save(requestDto); } @GetMapping("/title") @Operation(summary = "Get books by title", description = "Retrieves a list of books in the library that match the specified title." + + "Requires authentication for authorized access." ) public List getAllByTitle(@RequestParam String title) { return bookService.getBookByTitle(title); @@ -70,6 +74,7 @@ public List getAllByTitle(@RequestParam String title) { @ResponseStatus(HttpStatus.NO_CONTENT) @Operation(summary = "Delete a book by its ID", description = "Soft deletes a book from the library by its unique identifier (ID)." + + "Requires authentication for authorized access." ) @DeleteMapping("/{id}") @PreAuthorize("hasRole('ADMIN')") @@ -93,8 +98,8 @@ public BookResponseDto updateById(@PathVariable Long id, + "various search parameters such as title, author, or genre." ) @GetMapping("/search") - @PreAuthorize("hasRole('USER')") - public List searchBooks(BookSearchParameter searchParameters) { - return bookService.searchBooks(searchParameters); + public List searchBooks(BookSearchParameter searchParameters, + Pageable pageable) { + return bookService.searchBooks(searchParameters, pageable); } } From 3ada323a897cb88e82297b709537f0e7dda66b04 Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:54:13 +0100 Subject: [PATCH 04/16] was added new method setCategoryIds --- .../boot/bookstore/mapper/BookMapper.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/spring/boot/bookstore/mapper/BookMapper.java b/src/main/java/spring/boot/bookstore/mapper/BookMapper.java index f67b4a7..698d2ec 100644 --- a/src/main/java/spring/boot/bookstore/mapper/BookMapper.java +++ b/src/main/java/spring/boot/bookstore/mapper/BookMapper.java @@ -1,14 +1,30 @@ package spring.boot.bookstore.mapper; +import java.util.stream.Collectors; +import org.mapstruct.AfterMapping; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.MappingTarget; import spring.boot.bookstore.config.MapperConfig; import spring.boot.bookstore.dto.book.BookResponseDto; +import spring.boot.bookstore.dto.book.BookWithoutCategoryIdsDto; import spring.boot.bookstore.dto.book.CreateBookRequestDto; import spring.boot.bookstore.model.Book; +import spring.boot.bookstore.model.Category; @Mapper(config = MapperConfig.class) public interface BookMapper { + @Mapping(target = "categoryIds", ignore = true) BookResponseDto toDto(Book book); - Book toModel(CreateBookRequestDto requestDto); + Book toModel(CreateBookRequestDto bookDto); + + BookWithoutCategoryIdsDto toDtoWithoutCategories(Book book); + + @AfterMapping + default void setCategoryIds(@MappingTarget BookResponseDto bookResponseDto, Book book) { + bookResponseDto.setCategoryIds(book.getCategories().stream() + .map(Category::getId) + .collect(Collectors.toSet())); + } } From cd3c973be0085cfc300a185d16a606142870be01 Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:54:47 +0100 Subject: [PATCH 05/16] was deleted comments --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index d3f4f7c..efe6b9e 100644 --- a/pom.xml +++ b/pom.xml @@ -30,26 +30,20 @@ - - org.springframework.boot spring-boot-starter - org.springframework.boot spring-boot-starter-logging - - org.springframework.boot spring-boot-starter-log4j2 - From 3846d245c86d10e22070ba824eaf0abe551edb4d Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:55:07 +0100 Subject: [PATCH 06/16] added path to new changelog --- src/main/resources/db/changelog/db.changelog-master.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml index 8a7ad6e..af8d98a 100644 --- a/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/src/main/resources/db/changelog/db.changelog-master.yaml @@ -15,6 +15,14 @@ databaseChangeLog: file: db/changelog/changes/07-create-users-roles-table.yaml - include: file: db/changelog/changes/08-fill-users-roles-table-with-data.yaml + - include: + file: db/changelog/changes/09-create-category-table.yaml + - include: + file: db/changelog/changes/10-fill-category-table-with-data.yaml + - include: + file: db/changelog/changes/11-create-books-categories-table.yaml + - include: + file: db/changelog/changes/12-fill-books-categories-table-with-data.yaml From f3fcf4145180a9012134d0b37a7b0110dbec7a81 Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:55:44 +0100 Subject: [PATCH 07/16] created Category service interface and his implementation --- .../service/category/CategoryService.java | 19 +++++++ .../category/impl/CategoryServiceImpl.java | 57 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/main/java/spring/boot/bookstore/service/category/CategoryService.java create mode 100644 src/main/java/spring/boot/bookstore/service/category/impl/CategoryServiceImpl.java diff --git a/src/main/java/spring/boot/bookstore/service/category/CategoryService.java b/src/main/java/spring/boot/bookstore/service/category/CategoryService.java new file mode 100644 index 0000000..9a8260b --- /dev/null +++ b/src/main/java/spring/boot/bookstore/service/category/CategoryService.java @@ -0,0 +1,19 @@ +package spring.boot.bookstore.service.category; + +import java.util.List; +import org.springframework.data.domain.Pageable; +import spring.boot.bookstore.dto.category.CategoryRequestDto; +import spring.boot.bookstore.dto.category.CategoryResponseDto; + +public interface CategoryService { + + List findAll(Pageable pageable); + + CategoryResponseDto getById(Long id); + + CategoryResponseDto save(CategoryRequestDto categoryRequestDto); + + CategoryResponseDto update(Long id, CategoryRequestDto categoryRequestDto); + + void deleteById(Long id); +} diff --git a/src/main/java/spring/boot/bookstore/service/category/impl/CategoryServiceImpl.java b/src/main/java/spring/boot/bookstore/service/category/impl/CategoryServiceImpl.java new file mode 100644 index 0000000..d2dc93f --- /dev/null +++ b/src/main/java/spring/boot/bookstore/service/category/impl/CategoryServiceImpl.java @@ -0,0 +1,57 @@ +package spring.boot.bookstore.service.category.impl; + +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import spring.boot.bookstore.dto.category.CategoryRequestDto; +import spring.boot.bookstore.dto.category.CategoryResponseDto; +import spring.boot.bookstore.exception.EntityNotFoundException; +import spring.boot.bookstore.mapper.CategoryMapper; +import spring.boot.bookstore.model.Category; +import spring.boot.bookstore.repository.CategoryRepository; +import spring.boot.bookstore.service.category.CategoryService; + +@RequiredArgsConstructor +@Service +public class CategoryServiceImpl implements CategoryService { + private final CategoryRepository categoryRepository; + private final CategoryMapper categoryMapper; + + @Override + public List findAll(Pageable peagable) { + return categoryRepository.findAll(peagable) + .stream() + .map(categoryMapper::toDto) + .collect(Collectors.toList()); + } + + @Override + public CategoryResponseDto getById(Long id) { + Category category = categoryRepository.findById(id) + .orElseThrow( + () -> new EntityNotFoundException("Category not found with id: " + id)); + return categoryMapper.toDto(category); + } + + @Override + public CategoryResponseDto save(CategoryRequestDto categoryDto) { + Category savedCategory = categoryRepository.save(categoryMapper.toEntity(categoryDto)); + return categoryMapper.toDto(savedCategory); + } + + @Override + public CategoryResponseDto update(Long id, CategoryRequestDto categoryRequestDto) { + Category categoryById = categoryRepository.findById(id).orElseThrow( + () -> new EntityNotFoundException("Can`t find category by id: " + id)); + Category update = categoryMapper.toEntity(categoryRequestDto); + update.setId(id); + return categoryMapper.toDto(categoryRepository.save(update)); + } + + @Override + public void deleteById(Long id) { + categoryRepository.deleteById(id); + } +} From 59d4f13a867b80ac4bbeadac91762540355aec63 Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:56:03 +0100 Subject: [PATCH 08/16] Created Category classes --- .../controller/CategoryController.java | 93 +++++++++++++++++++ .../dto/category/CategoryRequestDto.java | 14 +++ .../dto/category/CategoryResponseDto.java | 10 ++ .../boot/bookstore/mapper/CategoryMapper.java | 14 +++ .../spring/boot/bookstore/model/Category.java | 37 ++++++++ .../repository/CategoryRepository.java | 11 +++ 6 files changed, 179 insertions(+) create mode 100644 src/main/java/spring/boot/bookstore/controller/CategoryController.java create mode 100644 src/main/java/spring/boot/bookstore/dto/category/CategoryRequestDto.java create mode 100644 src/main/java/spring/boot/bookstore/dto/category/CategoryResponseDto.java create mode 100644 src/main/java/spring/boot/bookstore/mapper/CategoryMapper.java create mode 100644 src/main/java/spring/boot/bookstore/model/Category.java create mode 100644 src/main/java/spring/boot/bookstore/repository/CategoryRepository.java diff --git a/src/main/java/spring/boot/bookstore/controller/CategoryController.java b/src/main/java/spring/boot/bookstore/controller/CategoryController.java new file mode 100644 index 0000000..c221ed0 --- /dev/null +++ b/src/main/java/spring/boot/bookstore/controller/CategoryController.java @@ -0,0 +1,93 @@ +package spring.boot.bookstore.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; +import spring.boot.bookstore.dto.book.BookWithoutCategoryIdsDto; +import spring.boot.bookstore.dto.category.CategoryRequestDto; +import spring.boot.bookstore.dto.category.CategoryResponseDto; +import spring.boot.bookstore.service.book.BookService; +import spring.boot.bookstore.service.category.CategoryService; + +@Tag(name = "Category Controller", + description = "Endpoints for managing categories for existed Books in library") +@RequiredArgsConstructor +@RestController +@RequestMapping(value = "/categories") +public class CategoryController { + + private static final Logger logger = LogManager.getLogger(BookController.class); + private final CategoryService categoryService; + private final BookService bookService; + + @Operation(summary = "Create a Category", + description = "Creates a new category for books in the library.") + @PreAuthorize("hasRole('ADMIN')") + @PostMapping + public CategoryResponseDto createCategory(@RequestBody + @Valid CategoryRequestDto categoryRequestDto) { + logger.info("Creating a new category."); + return categoryService.save(categoryRequestDto); + } + + @Operation(summary = "Get All categories ", + description = "Retrieves a list of all categories available for books.") + @GetMapping + public List getAll(Pageable pageable) { + return categoryService.findAll(pageable); + } + + @Operation(summary = "Get Category by ID", + description = "Retrieves a category by its unique identifier (ID).") + @GetMapping("/{id}") + public CategoryResponseDto getCategoryById(@PathVariable Long id) { + logger.info("Retrieving category with ID: " + id); + return categoryService.getById(id); + } + + @Operation(summary = "Update a Category by its ID", + description = "Updates an existing category in the library" + + " based on its unique identifier (ID).") + @PutMapping("/{id}") + @PreAuthorize("hasRole('ADMIN')") + public CategoryResponseDto updateCategory(@PathVariable Long id, + @RequestBody CategoryRequestDto categoryRequestDto) { + logger.info("Updating category with ID: " + id); + return categoryService.update(id, categoryRequestDto); + } + + @Operation(summary = "Delete category by their ID", + description = "Soft deletes a category from the library by its unique identifier (ID).") + @DeleteMapping("/{id}") + @ResponseStatus(HttpStatus.NO_CONTENT) + @PreAuthorize("hasRole('ADMIN')") + public void deleteCategory(@PathVariable Long id) { + logger.info("Deleting category with ID: " + id); + categoryService.deleteById(id); + } + + @Operation(summary = "Get Books by Category ID", + description = "Retrieves a list of books belonging to a specific category.") + @GetMapping("/{id}/books") + public List getBooksByCategoryId(@PathVariable Long id, + Pageable pageable) { + logger.info("Retrieving books for category with ID: " + id); + return bookService.findAllByCategoryId(id,pageable); + } +} diff --git a/src/main/java/spring/boot/bookstore/dto/category/CategoryRequestDto.java b/src/main/java/spring/boot/bookstore/dto/category/CategoryRequestDto.java new file mode 100644 index 0000000..cbce934 --- /dev/null +++ b/src/main/java/spring/boot/bookstore/dto/category/CategoryRequestDto.java @@ -0,0 +1,14 @@ +package spring.boot.bookstore.dto.category; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +@Data +public class CategoryRequestDto { + @NotNull + @Length(min = 4, max = 255) + private String name; + @Length(max = 255) + private String description; +} diff --git a/src/main/java/spring/boot/bookstore/dto/category/CategoryResponseDto.java b/src/main/java/spring/boot/bookstore/dto/category/CategoryResponseDto.java new file mode 100644 index 0000000..f07a526 --- /dev/null +++ b/src/main/java/spring/boot/bookstore/dto/category/CategoryResponseDto.java @@ -0,0 +1,10 @@ +package spring.boot.bookstore.dto.category; + +import lombok.Data; + +@Data +public class CategoryResponseDto { + private Long id; + private String name; + private String description; +} diff --git a/src/main/java/spring/boot/bookstore/mapper/CategoryMapper.java b/src/main/java/spring/boot/bookstore/mapper/CategoryMapper.java new file mode 100644 index 0000000..3e76c1e --- /dev/null +++ b/src/main/java/spring/boot/bookstore/mapper/CategoryMapper.java @@ -0,0 +1,14 @@ +package spring.boot.bookstore.mapper; + +import org.mapstruct.Mapper; +import spring.boot.bookstore.config.MapperConfig; +import spring.boot.bookstore.dto.category.CategoryRequestDto; +import spring.boot.bookstore.dto.category.CategoryResponseDto; +import spring.boot.bookstore.model.Category; + +@Mapper(config = MapperConfig.class) +public interface CategoryMapper { + CategoryResponseDto toDto(Category category); + + Category toEntity(CategoryRequestDto categoryDto); +} diff --git a/src/main/java/spring/boot/bookstore/model/Category.java b/src/main/java/spring/boot/bookstore/model/Category.java new file mode 100644 index 0000000..b165820 --- /dev/null +++ b/src/main/java/spring/boot/bookstore/model/Category.java @@ -0,0 +1,37 @@ +package spring.boot.bookstore.model; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; + +@Data +@NoArgsConstructor +@Entity +@Getter +@Setter +@SQLDelete(sql = "Update category SET is_deleted = true WHERE id=?") +@Where(clause = "is_deleted=false") +@Table(name = "category") +public class Category { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "name", nullable = false, unique = true) + private String name; + private String description; + @Column(name = "is_deleted", nullable = false) + private boolean isDeleted = false; + + public Category(Long id) { + + } +} diff --git a/src/main/java/spring/boot/bookstore/repository/CategoryRepository.java b/src/main/java/spring/boot/bookstore/repository/CategoryRepository.java new file mode 100644 index 0000000..e8ce6e9 --- /dev/null +++ b/src/main/java/spring/boot/bookstore/repository/CategoryRepository.java @@ -0,0 +1,11 @@ +package spring.boot.bookstore.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import spring.boot.bookstore.model.Category; + +@Repository +public interface CategoryRepository extends JpaRepository { + +} + From a41d5588ce274f9acb50e1ddf5d05e8e2d6cb7cf Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:56:22 +0100 Subject: [PATCH 09/16] Was added category id field --- .../boot/bookstore/dto/book/CreateBookRequestDto.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/spring/boot/bookstore/dto/book/CreateBookRequestDto.java b/src/main/java/spring/boot/bookstore/dto/book/CreateBookRequestDto.java index c6958e5..e3bd388 100644 --- a/src/main/java/spring/boot/bookstore/dto/book/CreateBookRequestDto.java +++ b/src/main/java/spring/boot/bookstore/dto/book/CreateBookRequestDto.java @@ -3,6 +3,7 @@ import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; +import java.util.Set; import lombok.Data; import org.hibernate.validator.constraints.Length; import spring.boot.bookstore.validation.book.isbn.Isbn; @@ -18,9 +19,8 @@ public class CreateBookRequestDto { private String isbn; @Min(0) private BigDecimal price; - private String description; - private String coverImage; - + @NotNull + private Set categoryIds; } From 84c7ab12b28a29754bc410d61dddd0ee56fbb715 Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:56:32 +0100 Subject: [PATCH 10/16] Created record --- .../boot/bookstore/dto/book/BookWithoutCategoryIdsDto.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/spring/boot/bookstore/dto/book/BookWithoutCategoryIdsDto.java diff --git a/src/main/java/spring/boot/bookstore/dto/book/BookWithoutCategoryIdsDto.java b/src/main/java/spring/boot/bookstore/dto/book/BookWithoutCategoryIdsDto.java new file mode 100644 index 0000000..2757819 --- /dev/null +++ b/src/main/java/spring/boot/bookstore/dto/book/BookWithoutCategoryIdsDto.java @@ -0,0 +1,7 @@ +package spring.boot.bookstore.dto.book; + +import java.math.BigDecimal; + +public record BookWithoutCategoryIdsDto(Long id, String title, String author, + String isbn, BigDecimal price, + String description, String coverImage){} From ad9b49d4a268b62b34dc18062972f96b86fc8fae Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:56:54 +0100 Subject: [PATCH 11/16] modified BookService --- .../bookstore/service/book/BookService.java | 7 ++++-- .../service/book/impl/BookServiceImpl.java | 24 ++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/main/java/spring/boot/bookstore/service/book/BookService.java b/src/main/java/spring/boot/bookstore/service/book/BookService.java index d5e68ed..1be172b 100644 --- a/src/main/java/spring/boot/bookstore/service/book/BookService.java +++ b/src/main/java/spring/boot/bookstore/service/book/BookService.java @@ -4,10 +4,11 @@ import org.springframework.data.domain.Pageable; import spring.boot.bookstore.dto.book.BookResponseDto; import spring.boot.bookstore.dto.book.BookSearchParameter; +import spring.boot.bookstore.dto.book.BookWithoutCategoryIdsDto; import spring.boot.bookstore.dto.book.CreateBookRequestDto; public interface BookService { - BookResponseDto createBook(CreateBookRequestDto requestDto); + BookResponseDto save(CreateBookRequestDto requestDto); List findAll(Pageable pageable); @@ -19,5 +20,7 @@ public interface BookService { void deleteById(Long id); - List searchBooks(BookSearchParameter searchParameters); + List searchBooks(BookSearchParameter searchParameters, Pageable pageable); + + List findAllByCategoryId(Long categoryId, Pageable pageable); } diff --git a/src/main/java/spring/boot/bookstore/service/book/impl/BookServiceImpl.java b/src/main/java/spring/boot/bookstore/service/book/impl/BookServiceImpl.java index 4f84466..6a3ab87 100644 --- a/src/main/java/spring/boot/bookstore/service/book/impl/BookServiceImpl.java +++ b/src/main/java/spring/boot/bookstore/service/book/impl/BookServiceImpl.java @@ -2,13 +2,12 @@ import java.util.List; import lombok.RequiredArgsConstructor; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import spring.boot.bookstore.dto.book.BookResponseDto; import spring.boot.bookstore.dto.book.BookSearchParameter; +import spring.boot.bookstore.dto.book.BookWithoutCategoryIdsDto; import spring.boot.bookstore.dto.book.CreateBookRequestDto; import spring.boot.bookstore.exception.EntityNotFoundException; import spring.boot.bookstore.mapper.BookMapper; @@ -20,26 +19,24 @@ @RequiredArgsConstructor @Service public class BookServiceImpl implements BookService { - private static final Logger logger = LogManager.getLogger(BookServiceImpl.class); private final BookRepository bookRepository; private final BookMapper bookMapper; private final BookSpecificationBuilder bookSpecificationBuilder; @Override - public BookResponseDto createBook(CreateBookRequestDto requestDto) { - logger.info("Creating a new book: {}", requestDto.getTitle()); + public BookResponseDto save(CreateBookRequestDto requestDto) { Book book = bookMapper.toModel(requestDto); return bookMapper.toDto(bookRepository.save(book)); } @Override public List findAll(Pageable pageable) { - return bookRepository.findAll(pageable) + return bookRepository.findAllWithCategories(pageable) .stream() .map(bookMapper::toDto) .toList(); } - + @Override public BookResponseDto getBookById(Long id) { Book book = bookRepository.findById(id).orElseThrow( @@ -79,11 +76,20 @@ public BookResponseDto updateBook(Long id, CreateBookRequestDto bookRequestDto) } @Override - public List searchBooks(BookSearchParameter searchParameters) { + public List searchBooks(BookSearchParameter searchParameters, + Pageable pageable) { Specification bookSpecification = bookSpecificationBuilder.build(searchParameters); - return bookRepository.findAll(bookSpecification) + return bookRepository.findAll(bookSpecification, pageable) .stream() .map(bookMapper::toDto) .toList(); } + + @Override + public List findAllByCategoryId(Long categoryId, Pageable pageable) { + return bookRepository.findByCategoryId(categoryId, pageable) + .stream() + .map(bookMapper::toDtoWithoutCategories) + .toList(); + } } From 36b6ec13df0d70e7317b163a60625b00de773317 Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:57:20 +0100 Subject: [PATCH 12/16] modified search parameters --- .../spring/boot/bookstore/dto/book/BookSearchParameter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/spring/boot/bookstore/dto/book/BookSearchParameter.java b/src/main/java/spring/boot/bookstore/dto/book/BookSearchParameter.java index f088f27..0aafa74 100644 --- a/src/main/java/spring/boot/bookstore/dto/book/BookSearchParameter.java +++ b/src/main/java/spring/boot/bookstore/dto/book/BookSearchParameter.java @@ -1,5 +1,5 @@ package spring.boot.bookstore.dto.book; public record BookSearchParameter(String[] title, String[] author, String[] isbn, - String [] price, String description) { + String [] price, String description,String[] categories) { } From 77be54fda0534dacfa6aade1902d418990f348fa Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:57:32 +0100 Subject: [PATCH 13/16] added category filed --- .../java/spring/boot/bookstore/dto/book/BookResponseDto.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/spring/boot/bookstore/dto/book/BookResponseDto.java b/src/main/java/spring/boot/bookstore/dto/book/BookResponseDto.java index fa44c86..767005f 100644 --- a/src/main/java/spring/boot/bookstore/dto/book/BookResponseDto.java +++ b/src/main/java/spring/boot/bookstore/dto/book/BookResponseDto.java @@ -1,6 +1,7 @@ package spring.boot.bookstore.dto.book; import java.math.BigDecimal; +import java.util.Set; import lombok.Data; @Data @@ -12,4 +13,5 @@ public class BookResponseDto { private BigDecimal price; private String description; private String coverImage; + private Set categoryIds; } From 2a8e8654757522a49aa09741e62551d5a5c44f9c Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:57:42 +0100 Subject: [PATCH 14/16] modified repository --- .../spring/boot/bookstore/repository/BookRepository.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/spring/boot/bookstore/repository/BookRepository.java b/src/main/java/spring/boot/bookstore/repository/BookRepository.java index 0defb98..307cdc4 100644 --- a/src/main/java/spring/boot/bookstore/repository/BookRepository.java +++ b/src/main/java/spring/boot/bookstore/repository/BookRepository.java @@ -1,12 +1,21 @@ package spring.boot.bookstore.repository; import java.util.List; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import spring.boot.bookstore.model.Book; @Repository public interface BookRepository extends JpaRepository, JpaSpecificationExecutor { List findAllByTitleContainsIgnoreCase(String title); + + @Query("FROM Book b JOIN b.categories c WHERE c.id =:categoryId") + List findByCategoryId(Long categoryId, Pageable pageable); + + @Query("FROM Book b INNER JOIN FETCH b.categories") + List findAllWithCategories(Pageable peageable); + } From 7ee1b6d423e7b6750e2498d5d32ed9e96dc0dbb7 Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 14:58:04 +0100 Subject: [PATCH 15/16] Was created Changelogs --- .../changes/09-create-category-table.yaml | 30 +++++++++++++++++++ .../10-fill-category-table-with-data.yaml | 16 ++++++++++ .../11-create-books-categories-table.yaml | 26 ++++++++++++++++ ...fill-books-categories-table-with-data.yaml | 25 ++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 src/main/resources/db/changelog/changes/09-create-category-table.yaml create mode 100644 src/main/resources/db/changelog/changes/10-fill-category-table-with-data.yaml create mode 100644 src/main/resources/db/changelog/changes/11-create-books-categories-table.yaml create mode 100644 src/main/resources/db/changelog/changes/12-fill-books-categories-table-with-data.yaml diff --git a/src/main/resources/db/changelog/changes/09-create-category-table.yaml b/src/main/resources/db/changelog/changes/09-create-category-table.yaml new file mode 100644 index 0000000..37251db --- /dev/null +++ b/src/main/resources/db/changelog/changes/09-create-category-table.yaml @@ -0,0 +1,30 @@ +databaseChangeLog: + - changeSet: + id: create-categories-table + author: Ros + changes: + - createTable: + tableName: category + columns: + - column: + name: id + type: bigint + autoIncrement: true + constraints: + primaryKey: true + nullable: false + - column: + name: name + type: varchar(255) + constraints: + nullable: false + unique: true + - column: + name: description + type: varchar(255) + - column: + name: is_deleted + type: boolean + constraints: + nullable: false + defaultValue: "false" diff --git a/src/main/resources/db/changelog/changes/10-fill-category-table-with-data.yaml b/src/main/resources/db/changelog/changes/10-fill-category-table-with-data.yaml new file mode 100644 index 0000000..f3c9ffa --- /dev/null +++ b/src/main/resources/db/changelog/changes/10-fill-category-table-with-data.yaml @@ -0,0 +1,16 @@ +databaseChangeLog: + - changeSet: + id: fill-categories-table-with-data + author: Ros + changes: + - insert: + tableName: category + columns: + - column: {name: "name", value: "Action and Adventure Fiction"} + - column: {name: "description", value: "Books in the action adventure genre not only have the action sequenc..."} + - insert: + tableName: category + columns: + - column: { name: "name", value: "Graphic Novel" } + - column: { name: "description", value: " long-form, fictional work of sequential art....." } + diff --git a/src/main/resources/db/changelog/changes/11-create-books-categories-table.yaml b/src/main/resources/db/changelog/changes/11-create-books-categories-table.yaml new file mode 100644 index 0000000..3a2ea72 --- /dev/null +++ b/src/main/resources/db/changelog/changes/11-create-books-categories-table.yaml @@ -0,0 +1,26 @@ +databaseChangeLog: + - changeSet: + id: create-books-categories-table + author: Ros + changes: + - createTable: + tableName: books_categories + columns: + - column: + name: category_id + type: bigint + constraints: + foreignKeyName: books_categories_FK + referencedTableName: category + referencedColumnNames: id + nullable: false + primaryKey: true + - column: + name: books_id + type: bigint + constraints: + foreignKeyName: books-categories_book_FK + referencedTableName: books + referencedColumnNames: id + nullable: false + primaryKey: true \ No newline at end of file diff --git a/src/main/resources/db/changelog/changes/12-fill-books-categories-table-with-data.yaml b/src/main/resources/db/changelog/changes/12-fill-books-categories-table-with-data.yaml new file mode 100644 index 0000000..1abdf9b --- /dev/null +++ b/src/main/resources/db/changelog/changes/12-fill-books-categories-table-with-data.yaml @@ -0,0 +1,25 @@ +databaseChangeLog: + - changeSet: + id: fill-books-categories-table-with-data + author: Ros + changes: + - insert: + tableName: books_categories + columns: + - column: {name: "category_id",value: "1"} + - column: {name: "books_id",value: "1"} + - insert: + tableName: books_categories + columns: + - column: { name: "category_id",value: "2" } + - column: { name: "books_id",value: "1" } + - insert: + tableName: books_categories + columns: + - column: { name: "category_id",value: "1" } + - column: { name: "books_id",value: "2" } + - insert: + tableName: books_categories + columns: + - column: { name: "category_id",value: "2" } + - column: { name: "books_id",value: "3" } \ No newline at end of file From 9637b05ea044273f085cd2c99417d0fe0d343508 Mon Sep 17 00:00:00 2001 From: Ros Date: Mon, 18 Sep 2023 15:07:19 +0100 Subject: [PATCH 16/16] added (fetch = FetchType.EAGER) --- src/main/java/spring/boot/bookstore/model/Book.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/spring/boot/bookstore/model/Book.java b/src/main/java/spring/boot/bookstore/model/Book.java index 8fca67c..0d77181 100644 --- a/src/main/java/spring/boot/bookstore/model/Book.java +++ b/src/main/java/spring/boot/bookstore/model/Book.java @@ -2,6 +2,7 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -12,10 +13,8 @@ import java.math.BigDecimal; import java.util.HashSet; import java.util.Set; -import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import org.apache.commons.lang3.builder.ToStringExclude; import org.hibernate.annotations.SQLDelete; @@ -46,7 +45,7 @@ public class Book { @ToStringExclude @EqualsAndHashCode.Exclude - @ManyToMany + @ManyToMany (fetch = FetchType.EAGER) // added (fetch = FetchType.EAGER) @JoinTable(name = "books_categories", joinColumns = @JoinColumn(name = "books_id"), inverseJoinColumns = @JoinColumn(name = "category_id"))