diff --git a/src/main/java/com/example/betteriter/bo_domain/menufacturer/service/ManufacturerService.java b/src/main/java/com/example/betteriter/bo_domain/menufacturer/service/ManufacturerService.java new file mode 100644 index 0000000..49a7c65 --- /dev/null +++ b/src/main/java/com/example/betteriter/bo_domain/menufacturer/service/ManufacturerService.java @@ -0,0 +1,22 @@ +package com.example.betteriter.bo_domain.menufacturer.service; + +import com.example.betteriter.bo_domain.menufacturer.domain.Manufacturer; +import com.example.betteriter.bo_domain.menufacturer.exception.ManufacturerHandler; +import com.example.betteriter.bo_domain.menufacturer.repository.ManufacturerRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import static com.example.betteriter.global.error.exception.ErrorCode._MANUFACTURER_NOT_FOUND; + +@Slf4j +@RequiredArgsConstructor +@Service +public class ManufacturerService { + private final ManufacturerRepository manufacturerRepository; + + public Manufacturer findManufacturerById(Long id) { + return this.manufacturerRepository.findById(id) + .orElseThrow(() -> new ManufacturerHandler(_MANUFACTURER_NOT_FOUND)); + } +} diff --git a/src/main/java/com/example/betteriter/bo_domain/news/controller/NewsController.java b/src/main/java/com/example/betteriter/bo_domain/news/controller/NewsController.java index 98e6073..7bc4c88 100644 --- a/src/main/java/com/example/betteriter/bo_domain/news/controller/NewsController.java +++ b/src/main/java/com/example/betteriter/bo_domain/news/controller/NewsController.java @@ -3,10 +3,14 @@ import com.example.betteriter.bo_domain.news.dto.CreateITNewsRequestDto; import com.example.betteriter.bo_domain.news.dto.ITNewsResponseDto; import com.example.betteriter.bo_domain.news.dto.UpdateITNewsRequestDto; +import com.example.betteriter.bo_domain.news.exception.NewsHandler; import com.example.betteriter.bo_domain.news.service.NewsService; import com.example.betteriter.global.common.response.ResponseDto; +import com.example.betteriter.global.error.exception.ErrorCode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; @@ -22,8 +26,10 @@ public class NewsController { @PostMapping public ResponseDto createITNews( - @Valid @RequestBody CreateITNewsRequestDto request + @Valid @RequestBody CreateITNewsRequestDto request, + BindingResult bindingResult ) { + this.checkRequestValidation(bindingResult); return ResponseDto.onSuccess(this.newsService.createITNews(request)); } @@ -35,7 +41,9 @@ public ResponseDto> getITNews() { @PutMapping("/{id}") public ResponseDto updateITNews( @Valid @RequestBody UpdateITNewsRequestDto request, - @PathVariable Long id) { + @PathVariable Long id, + BindingResult bindingResult) { + this.checkRequestValidation(bindingResult); this.newsService.updateITNews(id, request); return ResponseDto.onSuccess(); } @@ -46,4 +54,11 @@ public ResponseDto deleteITNews(@PathVariable Long id) { return ResponseDto.onSuccess(); } + private void checkRequestValidation(BindingResult bindingResult) { + if (bindingResult.hasErrors()) { + FieldError fieldError = bindingResult.getFieldErrors().get(0); + log.debug("fieldError occurs : {}", fieldError.getDefaultMessage()); + throw new NewsHandler(ErrorCode._METHOD_ARGUMENT_ERROR); + } + } } diff --git a/src/main/java/com/example/betteriter/fo_domain/review/controller/ReviewController.java b/src/main/java/com/example/betteriter/fo_domain/review/controller/ReviewController.java index 23ed92b..b053c1d 100644 --- a/src/main/java/com/example/betteriter/fo_domain/review/controller/ReviewController.java +++ b/src/main/java/com/example/betteriter/fo_domain/review/controller/ReviewController.java @@ -1,13 +1,44 @@ package com.example.betteriter.fo_domain.review.controller; +import com.example.betteriter.fo_domain.review.dto.CreateReviewRequestDto; +import com.example.betteriter.fo_domain.review.exception.ReviewHandler; +import com.example.betteriter.fo_domain.review.service.ReviewService; +import com.example.betteriter.global.common.response.ResponseDto; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.validation.Valid; + +import static com.example.betteriter.global.error.exception.ErrorCode._METHOD_ARGUMENT_ERROR; + @Slf4j -@RequestMapping("/follow") +@RequestMapping("/review") @RequiredArgsConstructor @RestController public class ReviewController { + private final ReviewService reviewService; + + @PostMapping + public ResponseDto createReview( + @Valid @RequestBody CreateReviewRequestDto request, + BindingResult bindingResult + ) { + this.checkRequestValidation(bindingResult); + return ResponseDto.onSuccess(this.reviewService.createReview(request)); + } + + + private void checkRequestValidation(BindingResult bindingResult) { + if (bindingResult.hasErrors()) { + FieldError fieldError = bindingResult.getFieldErrors().get(0); + log.debug("fieldError occurs : {}", fieldError.getDefaultMessage()); + throw new ReviewHandler(_METHOD_ARGUMENT_ERROR); + } + } } diff --git a/src/main/java/com/example/betteriter/fo_domain/review/domain/Review.java b/src/main/java/com/example/betteriter/fo_domain/review/domain/Review.java index 7b3de55..237e9f0 100644 --- a/src/main/java/com/example/betteriter/fo_domain/review/domain/Review.java +++ b/src/main/java/com/example/betteriter/fo_domain/review/domain/Review.java @@ -10,7 +10,7 @@ import lombok.extern.slf4j.Slf4j; import javax.persistence.*; -import java.sql.Timestamp; +import java.time.LocalDate; import java.util.List; @Slf4j @@ -28,12 +28,12 @@ public class Review extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) private User writer; - @JoinColumn(name = "made_by_id") + @JoinColumn(name = "manufacturer_id") @ManyToOne(fetch = FetchType.LAZY) - private Manufacturer madeBy; + private Manufacturer manufacturer; @Enumerated(EnumType.STRING) - private Category category; // 리뷰 카테고리 + private Category category; @Column(name = "product_name", nullable = false) private String productName; @@ -42,20 +42,23 @@ public class Review extends BaseEntity { private int amount; @Column(name = "store_name", nullable = false) - private String storeName; + private int storeName; @Column(name = "bought_at", nullable = false) - private Timestamp boughtAt; + private LocalDate boughtAt; @Column(name = "star_point", nullable = false) private int starPoint; - @Column(name = "shot_review", nullable = false) - private String shotReview; + @Column(name = "short_review", nullable = false) + private String shortReview; + + @Lob // 최대 500 자 @Column(name = "good_point", nullable = false) private String goodPoint; + @Lob // 최대 500 자 @Column(name = "bad_point", nullable = false) private String badPoint; diff --git a/src/main/java/com/example/betteriter/fo_domain/review/dto/CreateReviewRequestDto.java b/src/main/java/com/example/betteriter/fo_domain/review/dto/CreateReviewRequestDto.java new file mode 100644 index 0000000..7a9cbd5 --- /dev/null +++ b/src/main/java/com/example/betteriter/fo_domain/review/dto/CreateReviewRequestDto.java @@ -0,0 +1,72 @@ +package com.example.betteriter.fo_domain.review.dto; + +import com.example.betteriter.bo_domain.menufacturer.domain.Manufacturer; +import com.example.betteriter.fo_domain.review.domain.Review; +import com.example.betteriter.fo_domain.review.domain.ReviewImage; +import com.example.betteriter.global.constant.Category; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import java.time.LocalDate; +import java.util.List; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CreateReviewRequestDto { + @NotBlank(message = "카테고리는 필수 입력 값입니다.") + private String category; // 카테고리 + private String productName; // 상품명 + private LocalDate boughtAt; // 구매 일자 + private Long manufacturerId; // 제조사 아이디 + private int amount; // 가격 + private int storeName; // 구매처 + private String shortReview; // + private int starPoint; // 별점 + private String goodPoint; // 좋은 점 + private String badPoint; // 나쁜 점 + private List images; // 리뷰 이미지 + + public Review toEntity(Manufacturer manufacturer) { + return Review.builder() + .category(this.toCategory()) + .productName(productName) + .boughtAt(boughtAt) + .manufacturer(manufacturer) + .amount(amount) + .storeName(storeName) + .shortReview(shortReview) + .starPoint(starPoint) + .goodPoint(goodPoint) + .badPoint(badPoint) + .build(); + } + + private Category toCategory() { + for (Category category : Category.values()) { + if (this.category.equals(category.getName())) { + return category; + } + } + return null; + } + + @Getter + @Setter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CreateReviewImageRequestDto { + private String imgUrl; + + public ReviewImage toEntity(int orderNum, Review review) { + return ReviewImage.builder() + .imgUrl(imgUrl) + .review(review) + .orderNum(orderNum) + .build(); + } + } +} diff --git a/src/main/java/com/example/betteriter/fo_domain/review/service/ReviewService.java b/src/main/java/com/example/betteriter/fo_domain/review/service/ReviewService.java index 0039237..dcc9f11 100644 --- a/src/main/java/com/example/betteriter/fo_domain/review/service/ReviewService.java +++ b/src/main/java/com/example/betteriter/fo_domain/review/service/ReviewService.java @@ -1,6 +1,10 @@ package com.example.betteriter.fo_domain.review.service; +import com.example.betteriter.bo_domain.menufacturer.domain.Manufacturer; +import com.example.betteriter.bo_domain.menufacturer.service.ManufacturerService; import com.example.betteriter.fo_domain.review.domain.Review; +import com.example.betteriter.fo_domain.review.dto.CreateReviewRequestDto; +import com.example.betteriter.fo_domain.review.dto.CreateReviewRequestDto.CreateReviewImageRequestDto; import com.example.betteriter.fo_domain.review.dto.ReviewResponseDto; import com.example.betteriter.fo_domain.review.repository.ReviewImageRepository; import com.example.betteriter.fo_domain.review.repository.ReviewRepository; @@ -11,6 +15,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.LinkedHashMap; import java.util.List; @@ -21,9 +26,21 @@ @RequiredArgsConstructor @Service public class ReviewService { + private final UserService userService; + private final ManufacturerService manufacturerService; + private final ReviewRepository reviewRepository; private final ReviewImageRepository reviewImageRepository; - private final UserService userService; + + + /* 리뷰 등록 */ + @Transactional + public Long createReview(CreateReviewRequestDto request) { + Manufacturer manufacturer = this.manufacturerService.findManufacturerById(request.getManufacturerId()); + Review review = this.reviewRepository.save(request.toEntity(manufacturer)); + this.saveReviewImagesFromRequest(request, review); + return review.getId(); + } /* 유저가 관심 등록한 카테고리 리뷰 리스트 조회 메소드 */ public Map> getUserCategoryReviews() { @@ -67,4 +84,11 @@ private User getCurrentUser() { private String getFirstImageWithReview(Review review) { return this.reviewImageRepository.findFirstImageWithReview(review); } + + private void saveReviewImagesFromRequest(CreateReviewRequestDto request, Review review) { + List images = request.getImages(); + for (CreateReviewImageRequestDto image : images) { + reviewImageRepository.save(image.toEntity(images.indexOf(image), review)); + } + } } diff --git a/src/main/java/com/example/betteriter/fo_domain/user/controller/AuthController.java b/src/main/java/com/example/betteriter/fo_domain/user/controller/AuthController.java index d9a4c80..9fd6eb7 100644 --- a/src/main/java/com/example/betteriter/fo_domain/user/controller/AuthController.java +++ b/src/main/java/com/example/betteriter/fo_domain/user/controller/AuthController.java @@ -143,7 +143,7 @@ public ResponseDto checkNickname( private void checkRequestValidation(BindingResult bindingResult) { if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldErrors().get(0); - log.debug("filedError occurs : {}", fieldError.getDefaultMessage()); + log.debug("fieldError occurs : {}", fieldError.getDefaultMessage()); throw new UserHandler(_METHOD_ARGUMENT_ERROR); } } diff --git a/src/main/java/com/example/betteriter/global/error/exception/ErrorCode.java b/src/main/java/com/example/betteriter/global/error/exception/ErrorCode.java index a2dbf48..a182eb0 100644 --- a/src/main/java/com/example/betteriter/global/error/exception/ErrorCode.java +++ b/src/main/java/com/example/betteriter/global/error/exception/ErrorCode.java @@ -55,7 +55,11 @@ public enum ErrorCode { // News - _NEWS_NOT_FOUND(HttpStatus.BAD_REQUEST, "NEWS_400", "일치하는 뉴스 정보를 찾을 수 없습니다."); + _NEWS_NOT_FOUND(HttpStatus.BAD_REQUEST, "NEWS_400", "일치하는 뉴스 정보를 찾을 수 없습니다."), + + + // Manufacturer + _MANUFACTURER_NOT_FOUND(HttpStatus.BAD_REQUEST, "MANUFACTURER_400", "일치하는 제조사 정보를 찾을 수 없습니다."); private final HttpStatus httpStatus; diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index ea565ea..9dfa910 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -18,6 +18,6 @@ spring: ## 개발 환경 = debug logging: level: - org.hibernate.sql: debug + org.hibernate.SQL: debug org.hibernate.type: trace diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 985d02f..2f1e6ea 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -18,5 +18,5 @@ spring: ## 운영 환경 = info logging: level: - org.hibernate.sql: info + org.hibernate.SQL: info org.hibernate.type: info \ No newline at end of file