From c8f3bf6adc18a5e1059c1e377fbb0b1a2f9853fe Mon Sep 17 00:00:00 2001 From: ChabVlad Date: Wed, 11 Sep 2024 15:34:27 +0400 Subject: [PATCH 1/4] not finished --- pom.xml | 5 ++ .../bookstore/controller/BookController.java | 6 ++- .../bookstore/dto/CreateBookRequestDto.java | 8 ++++ .../CustomGlobalExceptionHandler.java | 46 +++++++++++++++++++ .../bookstore/repository/BookRepository.java | 2 + 5 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java diff --git a/pom.xml b/pom.xml index 99b831f..ec943d2 100644 --- a/pom.xml +++ b/pom.xml @@ -87,6 +87,11 @@ liquibase-core ${liquibase.version} + + org.hibernate.validator + hibernate-validator + 7.0.5.Final + diff --git a/src/main/java/project/bookstore/controller/BookController.java b/src/main/java/project/bookstore/controller/BookController.java index 48a58a0..53bf481 100644 --- a/src/main/java/project/bookstore/controller/BookController.java +++ b/src/main/java/project/bookstore/controller/BookController.java @@ -1,6 +1,8 @@ package project.bookstore.controller; import java.util.List; + +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -34,13 +36,13 @@ public BookDto getBookById(@PathVariable Long id) { } @PostMapping - public BookDto createBook(@RequestBody CreateBookRequestDto requestDto) { + public BookDto createBook(@RequestBody @Valid CreateBookRequestDto requestDto) { return bookMapper.toDto(bookService.save(requestDto)); } @PutMapping("/{id}") public BookDto updateBook( - @RequestBody CreateBookRequestDto requestDto, + @RequestBody @Valid CreateBookRequestDto requestDto, @PathVariable Long id ) { return bookService.updateBook(requestDto, id); diff --git a/src/main/java/project/bookstore/dto/CreateBookRequestDto.java b/src/main/java/project/bookstore/dto/CreateBookRequestDto.java index 85ff4eb..823ac7a 100644 --- a/src/main/java/project/bookstore/dto/CreateBookRequestDto.java +++ b/src/main/java/project/bookstore/dto/CreateBookRequestDto.java @@ -1,15 +1,23 @@ package project.bookstore.dto; import java.math.BigDecimal; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PositiveOrZero; import lombok.Getter; import lombok.Setter; @Getter @Setter public class CreateBookRequestDto { + @NotBlank private String title; + @NotBlank private String author; + @NotNull private String isbn; + @NotNull + @PositiveOrZero private BigDecimal price; private String description; private String coverImage; diff --git a/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java b/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java new file mode 100644 index 0000000..9c933fc --- /dev/null +++ b/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java @@ -0,0 +1,46 @@ +package project.bookstore.exception; + +import java.time.LocalDateTime; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +@ControllerAdvice +public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler { + + @Override + protected ResponseEntity handleMethodArgumentNotValid( + MethodArgumentNotValidException ex, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request + ) { + Map body = new LinkedHashMap<>(); + body.put("timestamp", LocalDateTime.now()); + body.put("status", HttpStatus.BAD_REQUEST); + List errors = ex.getBindingResult().getAllErrors().stream() + .map(this::getErrorMessage) + .toList(); + body.put("error", errors); + return new ResponseEntity<>(body, headers, status); + } + + private String getErrorMessage(ObjectError e) { + if (e instanceof FieldError) { + String fieldName = ((FieldError) e).getField(); + String message = ((FieldError) e).getDefaultMessage(); + return fieldName + ": " + message; + } + return e.getDefaultMessage(); + } +} diff --git a/src/main/java/project/bookstore/repository/BookRepository.java b/src/main/java/project/bookstore/repository/BookRepository.java index 0ec1c4b..e660f91 100644 --- a/src/main/java/project/bookstore/repository/BookRepository.java +++ b/src/main/java/project/bookstore/repository/BookRepository.java @@ -6,4 +6,6 @@ public interface BookRepository extends JpaRepository, JpaSpecificationExecutor { + boolean existsByIsbn(String isbn); + } From 351373729d5a5f447993af56cefa855c48723832 Mon Sep 17 00:00:00 2001 From: ChabVlad Date: Wed, 11 Sep 2024 16:11:50 +0400 Subject: [PATCH 2/4] customGlobalExceptionHandler added validation annotations added to CreateBookRequestDto --- .../bookstore/controller/BookController.java | 3 +-- .../bookstore/dto/CreateBookRequestDto.java | 4 +++- .../project/bookstore/validation/Unique.java | 17 +++++++++++++++++ .../bookstore/validation/UniqueValidation.java | 16 ++++++++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/main/java/project/bookstore/validation/Unique.java create mode 100644 src/main/java/project/bookstore/validation/UniqueValidation.java diff --git a/src/main/java/project/bookstore/controller/BookController.java b/src/main/java/project/bookstore/controller/BookController.java index 53bf481..8958572 100644 --- a/src/main/java/project/bookstore/controller/BookController.java +++ b/src/main/java/project/bookstore/controller/BookController.java @@ -1,8 +1,7 @@ package project.bookstore.controller; -import java.util.List; - import jakarta.validation.Valid; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/project/bookstore/dto/CreateBookRequestDto.java b/src/main/java/project/bookstore/dto/CreateBookRequestDto.java index 823ac7a..08f309a 100644 --- a/src/main/java/project/bookstore/dto/CreateBookRequestDto.java +++ b/src/main/java/project/bookstore/dto/CreateBookRequestDto.java @@ -1,11 +1,12 @@ package project.bookstore.dto; -import java.math.BigDecimal; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.PositiveOrZero; +import java.math.BigDecimal; import lombok.Getter; import lombok.Setter; +import project.bookstore.validation.Unique; @Getter @Setter @@ -15,6 +16,7 @@ public class CreateBookRequestDto { @NotBlank private String author; @NotNull + @Unique private String isbn; @NotNull @PositiveOrZero diff --git a/src/main/java/project/bookstore/validation/Unique.java b/src/main/java/project/bookstore/validation/Unique.java new file mode 100644 index 0000000..92b06d4 --- /dev/null +++ b/src/main/java/project/bookstore/validation/Unique.java @@ -0,0 +1,17 @@ +package project.bookstore.validation; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Constraint(validatedBy = UniqueValidation.class) +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface Unique { + String message() default "This field is already exist!"; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/project/bookstore/validation/UniqueValidation.java b/src/main/java/project/bookstore/validation/UniqueValidation.java new file mode 100644 index 0000000..a3d9d59 --- /dev/null +++ b/src/main/java/project/bookstore/validation/UniqueValidation.java @@ -0,0 +1,16 @@ +package project.bookstore.validation; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import org.springframework.beans.factory.annotation.Autowired; +import project.bookstore.repository.BookRepository; + +public class UniqueValidation implements ConstraintValidator { + @Autowired + private BookRepository repository; + + @Override + public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + return !repository.existsByIsbn(value); + } +} From cdc7a8f6b3ffdcfd62a2bf2df38d39ccbc378fea Mon Sep 17 00:00:00 2001 From: ChabVlad Date: Wed, 11 Sep 2024 18:07:07 +0400 Subject: [PATCH 3/4] uniqueValidation removed, pattern format isbn added --- .../bookstore/dto/CreateBookRequestDto.java | 6 +++--- .../exception/CustomGlobalExceptionHandler.java | 4 ++-- .../project/bookstore/validation/Unique.java | 17 ----------------- .../bookstore/validation/UniqueValidation.java | 16 ---------------- 4 files changed, 5 insertions(+), 38 deletions(-) delete mode 100644 src/main/java/project/bookstore/validation/Unique.java delete mode 100644 src/main/java/project/bookstore/validation/UniqueValidation.java diff --git a/src/main/java/project/bookstore/dto/CreateBookRequestDto.java b/src/main/java/project/bookstore/dto/CreateBookRequestDto.java index 08f309a..b962d62 100644 --- a/src/main/java/project/bookstore/dto/CreateBookRequestDto.java +++ b/src/main/java/project/bookstore/dto/CreateBookRequestDto.java @@ -2,11 +2,11 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.PositiveOrZero; import java.math.BigDecimal; import lombok.Getter; import lombok.Setter; -import project.bookstore.validation.Unique; @Getter @Setter @@ -15,8 +15,8 @@ public class CreateBookRequestDto { private String title; @NotBlank private String author; - @NotNull - @Unique + @NotBlank + @Pattern(regexp = "//d{13}", message = "Should be a valid ISBN number: 13 numbers only!") private String isbn; @NotNull @PositiveOrZero diff --git a/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java b/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java index 9c933fc..3c1a357 100644 --- a/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java +++ b/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java @@ -32,13 +32,13 @@ protected ResponseEntity handleMethodArgumentNotValid( .map(this::getErrorMessage) .toList(); body.put("error", errors); - return new ResponseEntity<>(body, headers, status); + return new ResponseEntity<>(body, headers, HttpStatus.BAD_REQUEST); } private String getErrorMessage(ObjectError e) { if (e instanceof FieldError) { String fieldName = ((FieldError) e).getField(); - String message = ((FieldError) e).getDefaultMessage(); + String message = e.getDefaultMessage(); return fieldName + ": " + message; } return e.getDefaultMessage(); diff --git a/src/main/java/project/bookstore/validation/Unique.java b/src/main/java/project/bookstore/validation/Unique.java deleted file mode 100644 index 92b06d4..0000000 --- a/src/main/java/project/bookstore/validation/Unique.java +++ /dev/null @@ -1,17 +0,0 @@ -package project.bookstore.validation; - -import jakarta.validation.Constraint; -import jakarta.validation.Payload; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Constraint(validatedBy = UniqueValidation.class) -@Target({ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface Unique { - String message() default "This field is already exist!"; - Class[] groups() default {}; - Class[] payload() default {}; -} diff --git a/src/main/java/project/bookstore/validation/UniqueValidation.java b/src/main/java/project/bookstore/validation/UniqueValidation.java deleted file mode 100644 index a3d9d59..0000000 --- a/src/main/java/project/bookstore/validation/UniqueValidation.java +++ /dev/null @@ -1,16 +0,0 @@ -package project.bookstore.validation; - -import jakarta.validation.ConstraintValidator; -import jakarta.validation.ConstraintValidatorContext; -import org.springframework.beans.factory.annotation.Autowired; -import project.bookstore.repository.BookRepository; - -public class UniqueValidation implements ConstraintValidator { - @Autowired - private BookRepository repository; - - @Override - public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { - return !repository.existsByIsbn(value); - } -} From d2453f7d446169b95e9655554db96c110bc698f8 Mon Sep 17 00:00:00 2001 From: ChabVlad Date: Wed, 11 Sep 2024 18:31:59 +0400 Subject: [PATCH 4/4] redundant method removed from BookRepository --- .../bookstore/exception/CustomGlobalExceptionHandler.java | 1 - src/main/java/project/bookstore/repository/BookRepository.java | 3 --- 2 files changed, 4 deletions(-) diff --git a/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java b/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java index 3c1a357..1a12905 100644 --- a/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java +++ b/src/main/java/project/bookstore/exception/CustomGlobalExceptionHandler.java @@ -17,7 +17,6 @@ @ControllerAdvice public class CustomGlobalExceptionHandler extends ResponseEntityExceptionHandler { - @Override protected ResponseEntity handleMethodArgumentNotValid( MethodArgumentNotValidException ex, diff --git a/src/main/java/project/bookstore/repository/BookRepository.java b/src/main/java/project/bookstore/repository/BookRepository.java index e660f91..b4a3020 100644 --- a/src/main/java/project/bookstore/repository/BookRepository.java +++ b/src/main/java/project/bookstore/repository/BookRepository.java @@ -5,7 +5,4 @@ import project.bookstore.model.Book; public interface BookRepository extends JpaRepository, JpaSpecificationExecutor { - - boolean existsByIsbn(String isbn); - }