From 114fdb328bb75e11a4d9b4047ff9d759bcb5d111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Thu, 27 Mar 2025 20:26:28 +0900 Subject: [PATCH 01/24] =?UTF-8?q?fix:=20Redis=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EB=A5=BC=20=EB=B0=A9=EC=A7=80=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=9C=84=ED=95=B4=20=EC=A3=BC=EC=84=9D=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coupon/controller/CouponController.java | 76 +++---- .../domain/coupon/service/CouponService.java | 152 ++++++------- .../event/controller/EventController.java | 74 +++--- .../domain/event/service/EventService.java | 210 +++++++++--------- .../eightyage/global/config/RedisConfig.java | 52 ++--- 5 files changed, 282 insertions(+), 282 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/coupon/controller/CouponController.java b/src/main/java/com/example/eightyage/domain/coupon/controller/CouponController.java index a57223a..c1e1939 100644 --- a/src/main/java/com/example/eightyage/domain/coupon/controller/CouponController.java +++ b/src/main/java/com/example/eightyage/domain/coupon/controller/CouponController.java @@ -1,38 +1,38 @@ -package com.example.eightyage.domain.coupon.controller; - -import com.example.eightyage.domain.coupon.dto.response.CouponResponseDto; -import com.example.eightyage.domain.coupon.service.CouponService; -import com.example.eightyage.global.dto.AuthUser; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@RestController -@RequestMapping("/api") -@RequiredArgsConstructor -public class CouponController { - - private final CouponService couponService; - - @PostMapping("/v1/events/{eventId}/coupons") - public ResponseEntity issueCoupon(@AuthenticationPrincipal AuthUser authUser, @PathVariable Long eventId) { - return ResponseEntity.ok(couponService.issueCoupon(authUser, eventId)); - } - - @GetMapping("/v1/coupons/my") - public ResponseEntity> getMyCoupons( - @AuthenticationPrincipal AuthUser authUser, - @RequestParam(defaultValue = "1") int page, - @RequestParam(defaultValue = "10") int size) { - return ResponseEntity.ok(couponService.getMyCoupons(authUser, page, size)); - } - - @GetMapping("/v1/coupons/{couponId}") - public ResponseEntity getCoupon(@AuthenticationPrincipal AuthUser authUser,@PathVariable Long couponId) { - return ResponseEntity.ok(couponService.getCoupon(authUser, couponId)); - } -} +//package com.example.eightyage.domain.coupon.controller; +// +//import com.example.eightyage.domain.coupon.dto.response.CouponResponseDto; +//import com.example.eightyage.domain.coupon.service.CouponService; +//import com.example.eightyage.global.dto.AuthUser; +//import lombok.RequiredArgsConstructor; +//import org.springframework.data.domain.Page; +//import org.springframework.http.ResponseEntity; +//import org.springframework.security.core.annotation.AuthenticationPrincipal; +//import org.springframework.web.bind.annotation.*; +// +//import java.util.List; +// +//@RestController +//@RequestMapping("/api") +//@RequiredArgsConstructor +//public class CouponController { +// +// private final CouponService couponService; +// +// @PostMapping("/v1/events/{eventId}/coupons") +// public ResponseEntity issueCoupon(@AuthenticationPrincipal AuthUser authUser, @PathVariable Long eventId) { +// return ResponseEntity.ok(couponService.issueCoupon(authUser, eventId)); +// } +// +// @GetMapping("/v1/coupons/my") +// public ResponseEntity> getMyCoupons( +// @AuthenticationPrincipal AuthUser authUser, +// @RequestParam(defaultValue = "1") int page, +// @RequestParam(defaultValue = "10") int size) { +// return ResponseEntity.ok(couponService.getMyCoupons(authUser, page, size)); +// } +// +// @GetMapping("/v1/coupons/{couponId}") +// public ResponseEntity getCoupon(@AuthenticationPrincipal AuthUser authUser,@PathVariable Long couponId) { +// return ResponseEntity.ok(couponService.getCoupon(authUser, couponId)); +// } +//} diff --git a/src/main/java/com/example/eightyage/domain/coupon/service/CouponService.java b/src/main/java/com/example/eightyage/domain/coupon/service/CouponService.java index 81a2d66..2852a82 100644 --- a/src/main/java/com/example/eightyage/domain/coupon/service/CouponService.java +++ b/src/main/java/com/example/eightyage/domain/coupon/service/CouponService.java @@ -1,76 +1,76 @@ -package com.example.eightyage.domain.coupon.service; - -import com.example.eightyage.domain.coupon.dto.response.CouponResponseDto; -import com.example.eightyage.domain.coupon.entity.Coupon; -import com.example.eightyage.domain.coupon.entity.CouponState; -import com.example.eightyage.domain.coupon.repository.CouponRepository; -import com.example.eightyage.domain.event.entity.Event; -import com.example.eightyage.domain.event.service.EventService; -import com.example.eightyage.domain.user.entity.User; -import com.example.eightyage.global.dto.AuthUser; -import com.example.eightyage.global.exception.BadRequestException; -import com.example.eightyage.global.exception.ErrorMessage; -import com.example.eightyage.global.exception.ForbiddenException; -import com.example.eightyage.global.exception.NotFoundException; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.stereotype.Service; - -@Service -@RequiredArgsConstructor -public class CouponService { - - private final CouponRepository couponRepository; - private final EventService eventService; - private final StringRedisTemplate stringRedisTemplate; - - public CouponResponseDto issueCoupon(AuthUser authUser, Long eventId) { - // 수량 우선 차감 - Long remain = stringRedisTemplate.opsForValue().decrement("event:quantity:" + eventId); - if (remain == null || remain < 0) { // atomic? `DESC`? - throw new BadRequestException(ErrorMessage.COUPON_OUT_OF_STOCK.getMessage()); - } - - Event event = eventService.getValidEventOrThrow(eventId); - - if(couponRepository.existsByUserIdAndEventId(authUser.getUserId(), eventId)) { - throw new BadRequestException(ErrorMessage.COUPON_ALREADY_ISSUED.getMessage()); - } - - // 쿠폰 발급 및 저장 - Coupon coupon = Coupon.create(User.fromAuthUser(authUser),event); - - couponRepository.save(coupon); - - return coupon.toDto(); - } - - public Page getMyCoupons(AuthUser authUser, int page, int size) { - Pageable pageable = PageRequest.of(page-1, size); - Page coupons = couponRepository.findAllByUserIdAndState(authUser.getUserId(), CouponState.VALID, pageable); - - return coupons.map(Coupon::toDto); - } - - public CouponResponseDto getCoupon(AuthUser authUser, Long couponId) { - Coupon coupon = findByIdOrElseThrow(couponId); - - if(!coupon.getUser().equals(User.fromAuthUser(authUser))) { - throw new ForbiddenException(ErrorMessage.COUPON_FORBIDDEN.getMessage()); - } - - if(!coupon.getState().equals(CouponState.VALID)) { - throw new BadRequestException(ErrorMessage.COUPON_ALREADY_USED.getMessage()); - } - - return coupon.toDto(); - } - - public Coupon findByIdOrElseThrow(Long couponId) { - return couponRepository.findById(couponId) - .orElseThrow(() -> new NotFoundException(ErrorMessage.COUPON_NOT_FOUND.getMessage())); - } -} +//package com.example.eightyage.domain.coupon.service; +// +//import com.example.eightyage.domain.coupon.dto.response.CouponResponseDto; +//import com.example.eightyage.domain.coupon.entity.Coupon; +//import com.example.eightyage.domain.coupon.entity.CouponState; +//import com.example.eightyage.domain.coupon.repository.CouponRepository; +//import com.example.eightyage.domain.event.entity.Event; +//import com.example.eightyage.domain.event.service.EventService; +//import com.example.eightyage.domain.user.entity.User; +//import com.example.eightyage.global.dto.AuthUser; +//import com.example.eightyage.global.exception.BadRequestException; +//import com.example.eightyage.global.exception.ErrorMessage; +//import com.example.eightyage.global.exception.ForbiddenException; +//import com.example.eightyage.global.exception.NotFoundException; +//import lombok.RequiredArgsConstructor; +//import org.springframework.data.domain.Page; +//import org.springframework.data.domain.PageRequest; +//import org.springframework.data.domain.Pageable; +//import org.springframework.data.redis.core.StringRedisTemplate; +//import org.springframework.stereotype.Service; +// +//@Service +//@RequiredArgsConstructor +//public class CouponService { +// +// private final CouponRepository couponRepository; +// private final EventService eventService; +// private final StringRedisTemplate stringRedisTemplate; +// +// public CouponResponseDto issueCoupon(AuthUser authUser, Long eventId) { +// // 수량 우선 차감 +// Long remain = stringRedisTemplate.opsForValue().decrement("event:quantity:" + eventId); +// if (remain == null || remain < 0) { // atomic? `DESC`? +// throw new BadRequestException(ErrorMessage.COUPON_OUT_OF_STOCK.getMessage()); +// } +// +// Event event = eventService.getValidEventOrThrow(eventId); +// +// if(couponRepository.existsByUserIdAndEventId(authUser.getUserId(), eventId)) { +// throw new BadRequestException(ErrorMessage.COUPON_ALREADY_ISSUED.getMessage()); +// } +// +// // 쿠폰 발급 및 저장 +// Coupon coupon = Coupon.create(User.fromAuthUser(authUser),event); +// +// couponRepository.save(coupon); +// +// return coupon.toDto(); +// } +// +// public Page getMyCoupons(AuthUser authUser, int page, int size) { +// Pageable pageable = PageRequest.of(page-1, size); +// Page coupons = couponRepository.findAllByUserIdAndState(authUser.getUserId(), CouponState.VALID, pageable); +// +// return coupons.map(Coupon::toDto); +// } +// +// public CouponResponseDto getCoupon(AuthUser authUser, Long couponId) { +// Coupon coupon = findByIdOrElseThrow(couponId); +// +// if(!coupon.getUser().equals(User.fromAuthUser(authUser))) { +// throw new ForbiddenException(ErrorMessage.COUPON_FORBIDDEN.getMessage()); +// } +// +// if(!coupon.getState().equals(CouponState.VALID)) { +// throw new BadRequestException(ErrorMessage.COUPON_ALREADY_USED.getMessage()); +// } +// +// return coupon.toDto(); +// } +// +// public Coupon findByIdOrElseThrow(Long couponId) { +// return couponRepository.findById(couponId) +// .orElseThrow(() -> new NotFoundException(ErrorMessage.COUPON_NOT_FOUND.getMessage())); +// } +//} diff --git a/src/main/java/com/example/eightyage/domain/event/controller/EventController.java b/src/main/java/com/example/eightyage/domain/event/controller/EventController.java index 7c12b97..3d3104c 100644 --- a/src/main/java/com/example/eightyage/domain/event/controller/EventController.java +++ b/src/main/java/com/example/eightyage/domain/event/controller/EventController.java @@ -1,37 +1,37 @@ -package com.example.eightyage.domain.event.controller; - -import com.example.eightyage.domain.event.dto.request.EventRequestDto; -import com.example.eightyage.domain.event.dto.response.EventResponseDto; -import com.example.eightyage.domain.event.service.EventService; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/api") -@RequiredArgsConstructor -public class EventController { - - private final EventService eventService; - - @PostMapping("/v1/events") - public ResponseEntity createEvent(@RequestBody EventRequestDto eventRequestDto) { - return ResponseEntity.ok(eventService.saveEvent(eventRequestDto)); - } - - @GetMapping("/v1/events") - public ResponseEntity> getEvents(@RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size) { - return ResponseEntity.ok(eventService.getEvents(page, size)); - } - - @GetMapping("/v1/events/{eventId}") - public ResponseEntity getEvent(@PathVariable long eventId) { - return ResponseEntity.ok(eventService.getEvent(eventId)); - } - - @PatchMapping("/v1/events/{eventId}") - public ResponseEntity updateEvent(@PathVariable long eventId, @RequestBody EventRequestDto eventRequestDto) { - return ResponseEntity.ok(eventService.updateEvent(eventId, eventRequestDto)); - } -} +//package com.example.eightyage.domain.event.controller; +// +//import com.example.eightyage.domain.event.dto.request.EventRequestDto; +//import com.example.eightyage.domain.event.dto.response.EventResponseDto; +//import com.example.eightyage.domain.event.service.EventService; +//import lombok.RequiredArgsConstructor; +//import org.springframework.data.domain.Page; +//import org.springframework.http.ResponseEntity; +//import org.springframework.web.bind.annotation.*; +// +//@RestController +//@RequestMapping("/api") +//@RequiredArgsConstructor +//public class EventController { +// +// private final EventService eventService; +// +// @PostMapping("/v1/events") +// public ResponseEntity createEvent(@RequestBody EventRequestDto eventRequestDto) { +// return ResponseEntity.ok(eventService.saveEvent(eventRequestDto)); +// } +// +// @GetMapping("/v1/events") +// public ResponseEntity> getEvents(@RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size) { +// return ResponseEntity.ok(eventService.getEvents(page, size)); +// } +// +// @GetMapping("/v1/events/{eventId}") +// public ResponseEntity getEvent(@PathVariable long eventId) { +// return ResponseEntity.ok(eventService.getEvent(eventId)); +// } +// +// @PatchMapping("/v1/events/{eventId}") +// public ResponseEntity updateEvent(@PathVariable long eventId, @RequestBody EventRequestDto eventRequestDto) { +// return ResponseEntity.ok(eventService.updateEvent(eventId, eventRequestDto)); +// } +//} diff --git a/src/main/java/com/example/eightyage/domain/event/service/EventService.java b/src/main/java/com/example/eightyage/domain/event/service/EventService.java index a96f6e1..539a7d8 100644 --- a/src/main/java/com/example/eightyage/domain/event/service/EventService.java +++ b/src/main/java/com/example/eightyage/domain/event/service/EventService.java @@ -1,105 +1,105 @@ -package com.example.eightyage.domain.event.service; - -import com.example.eightyage.domain.event.dto.request.EventRequestDto; -import com.example.eightyage.domain.event.dto.response.EventResponseDto; -import com.example.eightyage.domain.event.entity.Event; -import com.example.eightyage.domain.event.entity.EventState; -import com.example.eightyage.domain.event.repository.EventRepository; -import com.example.eightyage.global.exception.BadRequestException; -import com.example.eightyage.global.exception.ErrorMessage; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.security.access.annotation.Secured; -import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; - -@Service -@RequiredArgsConstructor -public class EventService { - - private final EventRepository eventRepository; - private final StringRedisTemplate stringRedisTemplate; - - @Secured("ADMIN") - public EventResponseDto saveEvent(EventRequestDto eventRequestDto) { - Event event = new Event( - eventRequestDto.getName(), - eventRequestDto.getDescription(), - eventRequestDto.getQuantity(), - eventRequestDto.getStartDate(), - eventRequestDto.getEndDate() - ); - - checkEventState(event); - - Event savedEvent = eventRepository.save(event); - - stringRedisTemplate.opsForValue().set("event:quantity:" + savedEvent.getId(), String.valueOf(savedEvent.getQuantity())); - - return savedEvent.toDto(); - } - - public Page getEvents(int page, int size) { - Pageable pageable = PageRequest.of(page-1, size); - Page events = eventRepository.findAll(pageable); - - // 모든 events들 checkState로 state 상태 갱신하기 - events.forEach(this::checkEventState); - - return events.map(Event::toDto); - } - - public EventResponseDto getEvent(long eventId) { - Event event = findByIdOrElseThrow(eventId); - - checkEventState(event); - - return event.toDto(); - } - - @Secured("ADMIN") - public EventResponseDto updateEvent(long eventId, EventRequestDto eventRequestDto) { - Event event = findByIdOrElseThrow(eventId); - - event.update(eventRequestDto); - - checkEventState(event); - - return event.toDto(); - } - - private void checkEventState(Event event) { - LocalDateTime now = LocalDateTime.now(); - EventState newState = - ( (event.getStartDate().isBefore(now) || event.getStartDate().isEqual(now)) && - (event.getEndDate().isAfter(now) || event.getEndDate().isEqual(now)) ) - ? EventState.VALID - : EventState.INVALID; - - if (event.getState() != newState) { - event.setState(newState); - eventRepository.save(event); - } - } - - public Event getValidEventOrThrow(Long eventId) { - Event event = findByIdOrElseThrow(eventId); - - checkEventState(event); - - if(event.getState() != EventState.VALID) { - throw new BadRequestException(ErrorMessage.INVALID_EVENT_PERIOD.getMessage()); - } - - return event; - } - - public Event findByIdOrElseThrow(Long eventId) { - return eventRepository.findById(eventId) - .orElseThrow(() -> new BadRequestException(ErrorMessage.EVENT_NOT_FOUND.getMessage())); - } -} +//package com.example.eightyage.domain.event.service; +// +//import com.example.eightyage.domain.event.dto.request.EventRequestDto; +//import com.example.eightyage.domain.event.dto.response.EventResponseDto; +//import com.example.eightyage.domain.event.entity.Event; +//import com.example.eightyage.domain.event.entity.EventState; +//import com.example.eightyage.domain.event.repository.EventRepository; +//import com.example.eightyage.global.exception.BadRequestException; +//import com.example.eightyage.global.exception.ErrorMessage; +//import lombok.RequiredArgsConstructor; +//import org.springframework.data.domain.Page; +//import org.springframework.data.domain.PageRequest; +//import org.springframework.data.domain.Pageable; +//import org.springframework.data.redis.core.StringRedisTemplate; +//import org.springframework.security.access.annotation.Secured; +//import org.springframework.stereotype.Service; +// +//import java.time.LocalDateTime; +// +//@Service +//@RequiredArgsConstructor +//public class EventService { +// +// private final EventRepository eventRepository; +// private final StringRedisTemplate stringRedisTemplate; +// +// @Secured("ADMIN") +// public EventResponseDto saveEvent(EventRequestDto eventRequestDto) { +// Event event = new Event( +// eventRequestDto.getName(), +// eventRequestDto.getDescription(), +// eventRequestDto.getQuantity(), +// eventRequestDto.getStartDate(), +// eventRequestDto.getEndDate() +// ); +// +// checkEventState(event); +// +// Event savedEvent = eventRepository.save(event); +// +// stringRedisTemplate.opsForValue().set("event:quantity:" + savedEvent.getId(), String.valueOf(savedEvent.getQuantity())); +// +// return savedEvent.toDto(); +// } +// +// public Page getEvents(int page, int size) { +// Pageable pageable = PageRequest.of(page-1, size); +// Page events = eventRepository.findAll(pageable); +// +// // 모든 events들 checkState로 state 상태 갱신하기 +// events.forEach(this::checkEventState); +// +// return events.map(Event::toDto); +// } +// +// public EventResponseDto getEvent(long eventId) { +// Event event = findByIdOrElseThrow(eventId); +// +// checkEventState(event); +// +// return event.toDto(); +// } +// +// @Secured("ADMIN") +// public EventResponseDto updateEvent(long eventId, EventRequestDto eventRequestDto) { +// Event event = findByIdOrElseThrow(eventId); +// +// event.update(eventRequestDto); +// +// checkEventState(event); +// +// return event.toDto(); +// } +// +// private void checkEventState(Event event) { +// LocalDateTime now = LocalDateTime.now(); +// EventState newState = +// ( (event.getStartDate().isBefore(now) || event.getStartDate().isEqual(now)) && +// (event.getEndDate().isAfter(now) || event.getEndDate().isEqual(now)) ) +// ? EventState.VALID +// : EventState.INVALID; +// +// if (event.getState() != newState) { +// event.setState(newState); +// eventRepository.save(event); +// } +// } +// +// public Event getValidEventOrThrow(Long eventId) { +// Event event = findByIdOrElseThrow(eventId); +// +// checkEventState(event); +// +// if(event.getState() != EventState.VALID) { +// throw new BadRequestException(ErrorMessage.INVALID_EVENT_PERIOD.getMessage()); +// } +// +// return event; +// } +// +// public Event findByIdOrElseThrow(Long eventId) { +// return eventRepository.findById(eventId) +// .orElseThrow(() -> new BadRequestException(ErrorMessage.EVENT_NOT_FOUND.getMessage())); +// } +//} diff --git a/src/main/java/com/example/eightyage/global/config/RedisConfig.java b/src/main/java/com/example/eightyage/global/config/RedisConfig.java index 8373a4a..8eed9c0 100644 --- a/src/main/java/com/example/eightyage/global/config/RedisConfig.java +++ b/src/main/java/com/example/eightyage/global/config/RedisConfig.java @@ -1,26 +1,26 @@ -package com.example.eightyage.global.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -@Configuration -public class RedisConfig { - @Bean - public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { - return new StringRedisTemplate(redisConnectionFactory); - } - - @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { - RedisTemplate redisTemplate = new RedisTemplate<>(); - redisTemplate.setConnectionFactory(redisConnectionFactory); - redisTemplate.setKeySerializer(new StringRedisSerializer()); - redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); - return redisTemplate; - } -} +//package com.example.eightyage.global.config; +// +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.data.redis.connection.RedisConnectionFactory; +//import org.springframework.data.redis.core.RedisTemplate; +//import org.springframework.data.redis.core.StringRedisTemplate; +//import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +//import org.springframework.data.redis.serializer.StringRedisSerializer; +// +//@Configuration +//public class RedisConfig { +// @Bean +// public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { +// return new StringRedisTemplate(redisConnectionFactory); +// } +// +// @Bean +// public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { +// RedisTemplate redisTemplate = new RedisTemplate<>(); +// redisTemplate.setConnectionFactory(redisConnectionFactory); +// redisTemplate.setKeySerializer(new StringRedisSerializer()); +// redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); +// return redisTemplate; +// } +//} From dfcf3356eb227e7742b29a53e389fe07c76c9685 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Thu, 27 Mar 2025 20:27:04 +0900 Subject: [PATCH 02/24] =?UTF-8?q?test(product):=20=EC=A0=9C=ED=92=88=20?= =?UTF-8?q?=EB=8B=A8=EA=B1=B4=20=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20=EC=A0=9C?= =?UTF-8?q?=ED=92=88=20=EC=82=AD=EC=A0=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/entity/Product.java | 2 + .../domain/review/entity/Review.java | 2 + .../eightyage/domain/user/entity/User.java | 5 +- .../product/service/ProductServiceTest.java | 88 +++++++++++++++++++ 4 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java diff --git a/src/main/java/com/example/eightyage/domain/product/entity/Product.java b/src/main/java/com/example/eightyage/domain/product/entity/Product.java index f4c64a1..e3ffaeb 100644 --- a/src/main/java/com/example/eightyage/domain/product/entity/Product.java +++ b/src/main/java/com/example/eightyage/domain/product/entity/Product.java @@ -2,6 +2,7 @@ import com.example.eightyage.global.entity.TimeStamped; import jakarta.persistence.*; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -14,6 +15,7 @@ @Entity @Getter @NoArgsConstructor +@AllArgsConstructor @Table(name = "product") public class Product extends TimeStamped { diff --git a/src/main/java/com/example/eightyage/domain/review/entity/Review.java b/src/main/java/com/example/eightyage/domain/review/entity/Review.java index f198fd1..dd690cd 100644 --- a/src/main/java/com/example/eightyage/domain/review/entity/Review.java +++ b/src/main/java/com/example/eightyage/domain/review/entity/Review.java @@ -4,6 +4,7 @@ import com.example.eightyage.domain.user.entity.User; import com.example.eightyage.global.entity.TimeStamped; import jakarta.persistence.*; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -11,6 +12,7 @@ @Entity @Getter @NoArgsConstructor +@AllArgsConstructor @Table(name = "review") public class Review extends TimeStamped { diff --git a/src/main/java/com/example/eightyage/domain/user/entity/User.java b/src/main/java/com/example/eightyage/domain/user/entity/User.java index f208901..fb8ff87 100644 --- a/src/main/java/com/example/eightyage/domain/user/entity/User.java +++ b/src/main/java/com/example/eightyage/domain/user/entity/User.java @@ -3,10 +3,7 @@ import com.example.eightyage.global.dto.AuthUser; import com.example.eightyage.global.entity.TimeStamped; import jakarta.persistence.*; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; import java.time.LocalDateTime; diff --git a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java new file mode 100644 index 0000000..5cd2b3f --- /dev/null +++ b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java @@ -0,0 +1,88 @@ +package com.example.eightyage.domain.product.service; + +import com.example.eightyage.domain.product.dto.response.ProductGetResponseDto; +import com.example.eightyage.domain.product.entity.Category; +import com.example.eightyage.domain.product.entity.Product; +import com.example.eightyage.domain.product.entity.SaleState; +import com.example.eightyage.domain.product.repository.ProductRepository; +import com.example.eightyage.domain.review.entity.Review; +import com.example.eightyage.domain.review.repository.ReviewRepository; +import com.example.eightyage.domain.user.entity.User; +import com.example.eightyage.domain.user.entity.UserRole; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +@ExtendWith(MockitoExtension.class) +class ProductServiceTest { + + @Mock + ProductRepository productRepository; + + @Mock + ReviewRepository reviewRepository; + + @InjectMocks + ProductService productService; + + @Mock + private Product product; + + @Mock + private Review review1; + + @Mock + private Review review2; + + @Test + void 제품_단건_조회_성공(){ + // given + Long productId = 1L; + +// Product product = new Product(1L, "8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴주는 퍼펙트 스킨", 20000, SaleState.FOR_SALE); + + given(productRepository.findById(any(Long.class))).willReturn(Optional.of(product)); + + // when + ProductGetResponseDto responseDto = productService.findProductById(productId); + + // then + assertThat(responseDto.getProductName()).isEqualTo(product.getName()); + } + + @Test + void 제품_삭제_성공(){ + // given + Long productId = 1L; + + List reviewList = new ArrayList<>(); + reviewList.add(review1); + reviewList.add(review2); + + given(productRepository.findById(any(Long.class))).willReturn(Optional.of(product)); + given(reviewRepository.findReviewsByProductId(any(Long.class))).willReturn(reviewList); + + // when + productService.deleteProduct(productId); + + // then + verify(review1, times(1)).delete(); + verify(review2, times(1)).delete(); + + verify(product, times(1)).delete(); + } +} \ No newline at end of file From f86fa21c02acdf3f1c78867f62844cb6b3f708f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Thu, 27 Mar 2025 21:06:57 +0900 Subject: [PATCH 03/24] =?UTF-8?q?chore:=20=ED=99=98=EA=B2=BD=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20AWS=5FACCESS=5FKEY,=20AWS=5FSECRET=5FKEY=20?= =?UTF-8?q?=EB=A5=BC=20S3=5FACCESS=5FKEY,=20S3=5FSECRET=5FKEY=20=EB=A1=9C?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7717011..44a0d39 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -35,8 +35,8 @@ spring: cloud: aws: credentials: - access-key: ${AWS_ACCESS_KEY} - secret-key: ${AWS_SECRET_KEY} + access-key: ${S3_ACCESS_KEY} + secret-key: ${S3_SECRET_KEY} region: static: ap-northeast-2 s3: @@ -44,8 +44,8 @@ spring: aws: credentials: - access-key: ${AWS_ACCESS_KEY} - secret-key: ${AWS_SECRET_KEY} + access-key: ${S3_ACCESS_KEY} + secret-key: ${S3_SECRET_KEY} region: ap-northeast-2 s3: bucket: my-gom-bucket From c6830204b7f6ede28e31d0ad2f2709138e085c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 09:34:41 +0900 Subject: [PATCH 04/24] =?UTF-8?q?test(product):=20=EC=A0=9C=ED=92=88=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=88=98=EC=A0=95=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1=20?= =?UTF-8?q?#28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/ProductSaveRequestDto.java | 2 + .../dto/request/ProductUpdateRequestDto.java | 2 + .../product/service/ProductServiceTest.java | 40 ++++++++++++++++++- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/product/dto/request/ProductSaveRequestDto.java b/src/main/java/com/example/eightyage/domain/product/dto/request/ProductSaveRequestDto.java index c8d2a04..9cb5616 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/request/ProductSaveRequestDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/request/ProductSaveRequestDto.java @@ -4,9 +4,11 @@ import com.example.eightyage.global.dto.ValidationMessage; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Getter; @Getter +@AllArgsConstructor public class ProductSaveRequestDto { @NotBlank(message= ValidationMessage.NOT_BLANK_PRODUCT_NAME) diff --git a/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java b/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java index 5b0e3ab..c7bccbd 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java @@ -2,9 +2,11 @@ import com.example.eightyage.domain.product.entity.Category; import com.example.eightyage.domain.product.entity.SaleState; +import lombok.AllArgsConstructor; import lombok.Getter; @Getter +@AllArgsConstructor public class ProductUpdateRequestDto { private String productName; diff --git a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java index 5cd2b3f..2fe9c0c 100644 --- a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java +++ b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java @@ -1,6 +1,10 @@ package com.example.eightyage.domain.product.service; +import com.example.eightyage.domain.product.dto.request.ProductSaveRequestDto; +import com.example.eightyage.domain.product.dto.request.ProductUpdateRequestDto; import com.example.eightyage.domain.product.dto.response.ProductGetResponseDto; +import com.example.eightyage.domain.product.dto.response.ProductSaveResponseDto; +import com.example.eightyage.domain.product.dto.response.ProductUpdateResponseDto; import com.example.eightyage.domain.product.entity.Category; import com.example.eightyage.domain.product.entity.Product; import com.example.eightyage.domain.product.entity.SaleState; @@ -49,11 +53,43 @@ class ProductServiceTest { private Review review2; @Test - void 제품_단건_조회_성공(){ + void 제품_생성_성공(){ + // given + Product product = new Product(1L, "8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴주는 퍼펙트 스킨", 20000, SaleState.FOR_SALE); + + given(productRepository.save(any())).willReturn(product); + + ProductSaveRequestDto requestDto = new ProductSaveRequestDto("8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴줍니다.", 20000); + + // when + ProductSaveResponseDto savedProduct = productService.saveProduct(requestDto); + + // then + assertThat(savedProduct.getProductName()).isEqualTo(product.getName()); + } + + @Test + void 제품_수정_성공(){ // given Long productId = 1L; -// Product product = new Product(1L, "8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴주는 퍼펙트 스킨", 20000, SaleState.FOR_SALE); + Product product = new Product(1L, "8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴주는 퍼펙트 스킨", 20000, SaleState.FOR_SALE); + + given(productRepository.findById(any(Long.class))).willReturn(Optional.of(product)); + + ProductUpdateRequestDto requestDto = new ProductUpdateRequestDto("8자 주름 향수", Category.FRAGRANCE, "8자 주름의 은은한 향기", SaleState.FOR_SALE, 50000); + + // when + ProductUpdateResponseDto responseDto = productService.updateProduct(productId, requestDto); + + // then + assertThat(responseDto.getProductName()).isEqualTo(requestDto.getProductName()); + } + + @Test + void 제품_단건_조회_성공(){ + // given + Long productId = 1L; given(productRepository.findById(any(Long.class))).willReturn(Optional.of(product)); From 0e010b5789be7e5d09c534352d2692f93123c084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 11:48:49 +0900 Subject: [PATCH 05/24] =?UTF-8?q?test(review):=20=EB=A6=AC=EB=B7=B0=20CRUD?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20#28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/request/ReviewSaveRequestDto.java | 2 + .../dto/request/ReviewUpdateRequestDto.java | 2 + .../review/service/ReviewServiceTest.java | 188 ++++++++++++++++++ 3 files changed, 192 insertions(+) create mode 100644 src/test/java/com/example/eightyage/domain/review/service/ReviewServiceTest.java diff --git a/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewSaveRequestDto.java b/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewSaveRequestDto.java index 9c1d183..5293830 100644 --- a/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewSaveRequestDto.java +++ b/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewSaveRequestDto.java @@ -3,9 +3,11 @@ import com.example.eightyage.global.dto.ValidationMessage; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Getter; @Getter +@AllArgsConstructor public class ReviewSaveRequestDto { @NotNull(message = ValidationMessage.NOT_NULL_SCORE) diff --git a/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewUpdateRequestDto.java b/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewUpdateRequestDto.java index c6b3e36..6fa8ef6 100644 --- a/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewUpdateRequestDto.java +++ b/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewUpdateRequestDto.java @@ -2,8 +2,10 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Getter; @Getter +@AllArgsConstructor public class ReviewUpdateRequestDto { private Double score; diff --git a/src/test/java/com/example/eightyage/domain/review/service/ReviewServiceTest.java b/src/test/java/com/example/eightyage/domain/review/service/ReviewServiceTest.java new file mode 100644 index 0000000..0b4a973 --- /dev/null +++ b/src/test/java/com/example/eightyage/domain/review/service/ReviewServiceTest.java @@ -0,0 +1,188 @@ +package com.example.eightyage.domain.review.service; + +import com.example.eightyage.domain.product.entity.Product; +import com.example.eightyage.domain.product.repository.ProductRepository; +import com.example.eightyage.domain.product.service.ProductService; +import com.example.eightyage.domain.review.dto.request.ReviewSaveRequestDto; +import com.example.eightyage.domain.review.dto.request.ReviewUpdateRequestDto; +import com.example.eightyage.domain.review.dto.response.ReviewSaveResponseDto; +import com.example.eightyage.domain.review.dto.response.ReviewUpdateResponseDto; +import com.example.eightyage.domain.review.dto.response.ReviewsGetResponseDto; +import com.example.eightyage.domain.review.entity.Review; +import com.example.eightyage.domain.review.repository.ReviewRepository; +import com.example.eightyage.domain.user.entity.User; +import com.example.eightyage.domain.user.entity.UserRole; +import com.example.eightyage.domain.user.repository.UserRepository; +import com.example.eightyage.domain.user.service.UserService; +import com.example.eightyage.global.exception.UnauthorizedException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; +import org.springframework.data.domain.*; +import org.springframework.data.querydsl.QPageRequest; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class ReviewServiceTest { + + @Mock + ReviewRepository reviewRepository; + + @Mock + UserService userService; + + @Mock + ProductService productService; + + @InjectMocks + ReviewService reviewService; + + @Mock + User user; + + @Mock + Product product; + + @Mock + Review review; + + @Test + void 리뷰_생성_성공(){ + // given + Long userId = 1L; + Long productId = 1L; + Long reviewId = 1L; + + Review review = new Review(reviewId, user, product, 5.0, "8자 주름을 다리미처럼 펴줘요 짱짱"); + given(reviewRepository.save(any())).willReturn(review); + + ReviewSaveRequestDto requestDto = new ReviewSaveRequestDto(5.0, "8자 주름을 다리미처럼 펴줘요 짱짱"); + + // when + ReviewSaveResponseDto responseDto = reviewService.saveReview(userId, productId, requestDto); + + // then + assertEquals(requestDto.getContent(), responseDto.getContent()); + } + + @Test + void 리뷰_수정_작성한_본인이_아닐_경우_실패(){ + // given + Long userId = 2L; + Long reviewId = 1L; + ReviewUpdateRequestDto requestDto = new ReviewUpdateRequestDto(1.0, "쓰다보니 8자 주름이 깊어졌어요. 대실망"); + + User user1 = new User(1L, "ijieun@gmail.com", "이지은B", "password123", UserRole.ROLE_USER); + User user2 = new User(userId, "ijieun@gmail.com", "이지은B", "password123", UserRole.ROLE_USER); + Review review = new Review(reviewId, user1, product, 5.0, "8자 주름을 펴줘요"); + + given(userService.findUserByIdOrElseThrow(any())).willReturn(user2); + given(reviewRepository.findById(any())).willReturn(Optional.of(review)); + + // when + UnauthorizedException exception = assertThrows(UnauthorizedException.class, () -> { + reviewService.updateReview(userId, reviewId, requestDto); + }); + + // then + assertEquals("리뷰를 수정할 권한이 없습니다.", exception.getMessage()); + } + + @Test + void 리뷰_수정_성공(){ + // given + Long userId = 1L; + Long reviewId = 1L; + ReviewUpdateRequestDto requestDto = new ReviewUpdateRequestDto(1.0, "쓰다보니 8자 주름이 깊어졌어요. 대실망"); + + User user = new User(userId, "ijieun@gmail.com", "이지은B", "password123", UserRole.ROLE_USER); + Review review = new Review(reviewId, user, product, 5.0, "8자 주름을 펴줘요"); + + given(userService.findUserByIdOrElseThrow(any())).willReturn(user); + given(reviewRepository.findById(any())).willReturn(Optional.of(review)); + + // when + ReviewUpdateResponseDto responseDto = reviewService.updateReview(userId, reviewId, requestDto); + + // then + assertEquals(requestDto.getContent(), responseDto.getContent()); + } + + @Test + void 리뷰_다건_조회_성공(){ + // given + Long productId = 1L; + PageRequest pageRequest = PageRequest.of(0, 10, Sort.by(Sort.Direction.DESC, "score")); + + Review review1 = new Review(1L, user, product, 5.0, "8자 주름을 펴줘요"); + Review review2 = new Review(1L, user, product, 5.0, "8자 주름을 펴줘요"); + + List reviewList = new ArrayList<>(); + reviewList.add(review1); + reviewList.add(review2); + + Page reviewPage = new PageImpl<>(reviewList, pageRequest, reviewList.size()); + + when(reviewRepository.findByProductIdAndProductDeletedAtIsNull(any(Long.class), eq(pageRequest))).thenReturn(reviewPage); + + // when + Page result = reviewService.findReviews(productId, pageRequest); + + // then + assertNotNull(result); + assertEquals(2, result.getContent().size()); + verify(reviewRepository, times(1)).findByProductIdAndProductDeletedAtIsNull(any(Long.class), eq(pageRequest)); + } + + @Test + void 리뷰_삭제_작성한_본인이_아닐_경우_실패(){ + // given + Long userId = 2L; + Long reviewId = 1L; + + User user1 = new User(1L, "ijieun@gmail.com", "이지은B", "password123", UserRole.ROLE_USER); + User user2 = new User(userId, "ijieun@gmail.com", "이지은B", "password123", UserRole.ROLE_USER); + Review review = new Review(reviewId, user1, product, 5.0, "8자 주름을 펴줘요"); + + given(userService.findUserByIdOrElseThrow(any())).willReturn(user2); + given(reviewRepository.findById(any())).willReturn(Optional.of(review)); + + // when + UnauthorizedException exception = assertThrows(UnauthorizedException.class, () -> { + reviewService.deleteReview(userId, reviewId); + }); + + // then + assertEquals("리뷰를 삭제할 권한이 없습니다.", exception.getMessage()); + } + + @Test + void 리뷰_삭제_성공(){ + // given + Long userId = 1L; + Long reviewId = 1L; + + User user = new User(userId, "ijieun@gmail.com", "이지은B", "password123", UserRole.ROLE_USER); + + given(userService.findUserByIdOrElseThrow(any())).willReturn(user); + given(reviewRepository.findById(any())).willReturn(Optional.of(review)); + given(review.getUser()).willReturn(user); + + // when + reviewService.deleteReview(userId, reviewId); + + // then + verify(review, times(1)).delete(); + } +} \ No newline at end of file From 37e3d92191757564a747cb82e491fbc9fb40cd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 13:45:43 +0900 Subject: [PATCH 06/24] =?UTF-8?q?test(productImage):=20mock=20=EC=A3=BC?= =?UTF-8?q?=EC=9E=85=20#28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ProductImageServiceTest.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java diff --git a/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java b/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java new file mode 100644 index 0000000..e05f6f0 --- /dev/null +++ b/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java @@ -0,0 +1,46 @@ +package com.example.eightyage.domain.product.service; + +import com.example.eightyage.domain.product.repository.ProductImageRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockMultipartFile; +import software.amazon.awssdk.services.s3.S3Client; + +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(MockitoExtension.class) +class ProductImageServiceTest { + + @Mock + S3Client s3Client; + + @Mock + ProductImageRepository productImageRepository; + + @Mock + ProductService productService; + + @InjectMocks + ProductImageService productImageService; + + private MockMultipartFile mockFile; + + @BeforeEach + void setUp(){ + mockFile = new MockMultipartFile( + "file", + "tesst.jpg", + "image/jpeg", + "test image content".getBytes() + ); + } + + @Test + void 이미지_업로드_성공(){ + + } +} \ No newline at end of file From 8ca619dc595b34c7dcf616bfaf801b193db7e6ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 13:54:02 +0900 Subject: [PATCH 07/24] =?UTF-8?q?config:=20Redis=20=ED=98=B8=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=99=80=20S3=20=EB=B2=84=ED=82=B7=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20env=20=ED=8C=8C=EC=9D=BC=EC=97=90=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 44a0d39..164064b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -40,7 +40,7 @@ spring: region: static: ap-northeast-2 s3: - bucket: my-gom-bucket + bucket: ${S3_BUCKET} aws: credentials: @@ -48,11 +48,11 @@ aws: secret-key: ${S3_SECRET_KEY} region: ap-northeast-2 s3: - bucket: my-gom-bucket + bucket: ${S3_BUCKET} data: redis: - host: localhost + host: ${REDIS_HOST} port: 6379 jwt: From cc78153f65fee1147dd0dda87934df399d2d3cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 17:01:05 +0900 Subject: [PATCH 08/24] =?UTF-8?q?test(productImage):=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EB=B0=8F=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=82=AD=EC=A0=9C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1=20#28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ProductImageRepository.java | 1 - .../service/ProductImageServiceTest.java | 52 +++++++++++++++++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/product/repository/ProductImageRepository.java b/src/main/java/com/example/eightyage/domain/product/repository/ProductImageRepository.java index a29cc6c..ed16385 100644 --- a/src/main/java/com/example/eightyage/domain/product/repository/ProductImageRepository.java +++ b/src/main/java/com/example/eightyage/domain/product/repository/ProductImageRepository.java @@ -1,7 +1,6 @@ package com.example.eightyage.domain.product.repository; import com.example.eightyage.domain.product.entity.ProductImage; -import com.example.eightyage.global.exception.NotFoundException; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; diff --git a/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java b/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java index e05f6f0..77db7ee 100644 --- a/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java +++ b/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java @@ -1,16 +1,29 @@ package com.example.eightyage.domain.product.service; +import com.example.eightyage.domain.product.entity.Product; +import com.example.eightyage.domain.product.entity.ProductImage; import com.example.eightyage.domain.product.repository.ProductImageRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; +import org.mockito.*; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.util.ReflectionTestUtils; +import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; -import static org.junit.jupiter.api.Assertions.*; +import java.util.Optional; +import java.util.function.Consumer; + + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; @ExtendWith(MockitoExtension.class) class ProductImageServiceTest { @@ -27,6 +40,9 @@ class ProductImageServiceTest { @InjectMocks ProductImageService productImageService; + @Mock + ProductImage productImage; + private MockMultipartFile mockFile; @BeforeEach @@ -37,10 +53,40 @@ void setUp(){ "image/jpeg", "test image content".getBytes() ); + + ReflectionTestUtils.setField(productImageService, "bucket", "test-bucket"); + ReflectionTestUtils.setField(productImageService, "region", "us-west-2"); } @Test void 이미지_업로드_성공(){ + // given + Long productId = 1L; + String bucket = "test-bucket"; + String region = "us-west-2"; + String expectedImageUrl = String.format("https://%s.s3.%s.amazonaws.com/", bucket, region); + + given(productImageRepository.save(any())).willReturn(productImage); + + // when + String imageUrl = productImageService.uploadImage(productId, mockFile); + + // then + assertTrue(imageUrl.startsWith(expectedImageUrl)); + } + + @Test + void 이미지_삭제_성공(){ + // given + Long imageId = 1L; + String imageUrl = "imageUrl-example"; + + given(productImageRepository.findById(any())).willReturn(Optional.of(productImage)); + + // when + productImageService.deleteImage(imageId); + // then + verify(productImage, times(1)).delete(); } } \ No newline at end of file From e4caf73b11bb5c8dd5462e4ba7b1c4534939710e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 17:13:18 +0900 Subject: [PATCH 09/24] =?UTF-8?q?test(product):=20=EC=A0=9C=ED=92=88=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=A0=9C=ED=92=88=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20#28?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/service/ProductServiceTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java index 2fe9c0c..811dc93 100644 --- a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java +++ b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java @@ -55,8 +55,6 @@ class ProductServiceTest { @Test void 제품_생성_성공(){ // given - Product product = new Product(1L, "8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴주는 퍼펙트 스킨", 20000, SaleState.FOR_SALE); - given(productRepository.save(any())).willReturn(product); ProductSaveRequestDto requestDto = new ProductSaveRequestDto("8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴줍니다.", 20000); @@ -72,8 +70,11 @@ class ProductServiceTest { void 제품_수정_성공(){ // given Long productId = 1L; + List reviewList = new ArrayList<>(); + reviewList.add(review1); + reviewList.add(review2); - Product product = new Product(1L, "8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴주는 퍼펙트 스킨", 20000, SaleState.FOR_SALE); + Product product = new Product(1L, "8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴주는 퍼펙트 스킨", 20000, SaleState.FOR_SALE, reviewList); given(productRepository.findById(any(Long.class))).willReturn(Optional.of(product)); From 000e65b1c20e1369b306541315ea71c38595c3cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 17:15:01 +0900 Subject: [PATCH 10/24] =?UTF-8?q?refactor:=20Redis=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=ED=95=B4=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../coupon/controller/CouponController.java | 76 +++---- .../domain/coupon/service/CouponService.java | 152 ++++++------- .../event/controller/EventController.java | 74 +++--- .../domain/event/service/EventService.java | 210 +++++++++--------- 4 files changed, 256 insertions(+), 256 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/coupon/controller/CouponController.java b/src/main/java/com/example/eightyage/domain/coupon/controller/CouponController.java index c1e1939..a57223a 100644 --- a/src/main/java/com/example/eightyage/domain/coupon/controller/CouponController.java +++ b/src/main/java/com/example/eightyage/domain/coupon/controller/CouponController.java @@ -1,38 +1,38 @@ -//package com.example.eightyage.domain.coupon.controller; -// -//import com.example.eightyage.domain.coupon.dto.response.CouponResponseDto; -//import com.example.eightyage.domain.coupon.service.CouponService; -//import com.example.eightyage.global.dto.AuthUser; -//import lombok.RequiredArgsConstructor; -//import org.springframework.data.domain.Page; -//import org.springframework.http.ResponseEntity; -//import org.springframework.security.core.annotation.AuthenticationPrincipal; -//import org.springframework.web.bind.annotation.*; -// -//import java.util.List; -// -//@RestController -//@RequestMapping("/api") -//@RequiredArgsConstructor -//public class CouponController { -// -// private final CouponService couponService; -// -// @PostMapping("/v1/events/{eventId}/coupons") -// public ResponseEntity issueCoupon(@AuthenticationPrincipal AuthUser authUser, @PathVariable Long eventId) { -// return ResponseEntity.ok(couponService.issueCoupon(authUser, eventId)); -// } -// -// @GetMapping("/v1/coupons/my") -// public ResponseEntity> getMyCoupons( -// @AuthenticationPrincipal AuthUser authUser, -// @RequestParam(defaultValue = "1") int page, -// @RequestParam(defaultValue = "10") int size) { -// return ResponseEntity.ok(couponService.getMyCoupons(authUser, page, size)); -// } -// -// @GetMapping("/v1/coupons/{couponId}") -// public ResponseEntity getCoupon(@AuthenticationPrincipal AuthUser authUser,@PathVariable Long couponId) { -// return ResponseEntity.ok(couponService.getCoupon(authUser, couponId)); -// } -//} +package com.example.eightyage.domain.coupon.controller; + +import com.example.eightyage.domain.coupon.dto.response.CouponResponseDto; +import com.example.eightyage.domain.coupon.service.CouponService; +import com.example.eightyage.global.dto.AuthUser; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor +public class CouponController { + + private final CouponService couponService; + + @PostMapping("/v1/events/{eventId}/coupons") + public ResponseEntity issueCoupon(@AuthenticationPrincipal AuthUser authUser, @PathVariable Long eventId) { + return ResponseEntity.ok(couponService.issueCoupon(authUser, eventId)); + } + + @GetMapping("/v1/coupons/my") + public ResponseEntity> getMyCoupons( + @AuthenticationPrincipal AuthUser authUser, + @RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "10") int size) { + return ResponseEntity.ok(couponService.getMyCoupons(authUser, page, size)); + } + + @GetMapping("/v1/coupons/{couponId}") + public ResponseEntity getCoupon(@AuthenticationPrincipal AuthUser authUser,@PathVariable Long couponId) { + return ResponseEntity.ok(couponService.getCoupon(authUser, couponId)); + } +} diff --git a/src/main/java/com/example/eightyage/domain/coupon/service/CouponService.java b/src/main/java/com/example/eightyage/domain/coupon/service/CouponService.java index 2852a82..81a2d66 100644 --- a/src/main/java/com/example/eightyage/domain/coupon/service/CouponService.java +++ b/src/main/java/com/example/eightyage/domain/coupon/service/CouponService.java @@ -1,76 +1,76 @@ -//package com.example.eightyage.domain.coupon.service; -// -//import com.example.eightyage.domain.coupon.dto.response.CouponResponseDto; -//import com.example.eightyage.domain.coupon.entity.Coupon; -//import com.example.eightyage.domain.coupon.entity.CouponState; -//import com.example.eightyage.domain.coupon.repository.CouponRepository; -//import com.example.eightyage.domain.event.entity.Event; -//import com.example.eightyage.domain.event.service.EventService; -//import com.example.eightyage.domain.user.entity.User; -//import com.example.eightyage.global.dto.AuthUser; -//import com.example.eightyage.global.exception.BadRequestException; -//import com.example.eightyage.global.exception.ErrorMessage; -//import com.example.eightyage.global.exception.ForbiddenException; -//import com.example.eightyage.global.exception.NotFoundException; -//import lombok.RequiredArgsConstructor; -//import org.springframework.data.domain.Page; -//import org.springframework.data.domain.PageRequest; -//import org.springframework.data.domain.Pageable; -//import org.springframework.data.redis.core.StringRedisTemplate; -//import org.springframework.stereotype.Service; -// -//@Service -//@RequiredArgsConstructor -//public class CouponService { -// -// private final CouponRepository couponRepository; -// private final EventService eventService; -// private final StringRedisTemplate stringRedisTemplate; -// -// public CouponResponseDto issueCoupon(AuthUser authUser, Long eventId) { -// // 수량 우선 차감 -// Long remain = stringRedisTemplate.opsForValue().decrement("event:quantity:" + eventId); -// if (remain == null || remain < 0) { // atomic? `DESC`? -// throw new BadRequestException(ErrorMessage.COUPON_OUT_OF_STOCK.getMessage()); -// } -// -// Event event = eventService.getValidEventOrThrow(eventId); -// -// if(couponRepository.existsByUserIdAndEventId(authUser.getUserId(), eventId)) { -// throw new BadRequestException(ErrorMessage.COUPON_ALREADY_ISSUED.getMessage()); -// } -// -// // 쿠폰 발급 및 저장 -// Coupon coupon = Coupon.create(User.fromAuthUser(authUser),event); -// -// couponRepository.save(coupon); -// -// return coupon.toDto(); -// } -// -// public Page getMyCoupons(AuthUser authUser, int page, int size) { -// Pageable pageable = PageRequest.of(page-1, size); -// Page coupons = couponRepository.findAllByUserIdAndState(authUser.getUserId(), CouponState.VALID, pageable); -// -// return coupons.map(Coupon::toDto); -// } -// -// public CouponResponseDto getCoupon(AuthUser authUser, Long couponId) { -// Coupon coupon = findByIdOrElseThrow(couponId); -// -// if(!coupon.getUser().equals(User.fromAuthUser(authUser))) { -// throw new ForbiddenException(ErrorMessage.COUPON_FORBIDDEN.getMessage()); -// } -// -// if(!coupon.getState().equals(CouponState.VALID)) { -// throw new BadRequestException(ErrorMessage.COUPON_ALREADY_USED.getMessage()); -// } -// -// return coupon.toDto(); -// } -// -// public Coupon findByIdOrElseThrow(Long couponId) { -// return couponRepository.findById(couponId) -// .orElseThrow(() -> new NotFoundException(ErrorMessage.COUPON_NOT_FOUND.getMessage())); -// } -//} +package com.example.eightyage.domain.coupon.service; + +import com.example.eightyage.domain.coupon.dto.response.CouponResponseDto; +import com.example.eightyage.domain.coupon.entity.Coupon; +import com.example.eightyage.domain.coupon.entity.CouponState; +import com.example.eightyage.domain.coupon.repository.CouponRepository; +import com.example.eightyage.domain.event.entity.Event; +import com.example.eightyage.domain.event.service.EventService; +import com.example.eightyage.domain.user.entity.User; +import com.example.eightyage.global.dto.AuthUser; +import com.example.eightyage.global.exception.BadRequestException; +import com.example.eightyage.global.exception.ErrorMessage; +import com.example.eightyage.global.exception.ForbiddenException; +import com.example.eightyage.global.exception.NotFoundException; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CouponService { + + private final CouponRepository couponRepository; + private final EventService eventService; + private final StringRedisTemplate stringRedisTemplate; + + public CouponResponseDto issueCoupon(AuthUser authUser, Long eventId) { + // 수량 우선 차감 + Long remain = stringRedisTemplate.opsForValue().decrement("event:quantity:" + eventId); + if (remain == null || remain < 0) { // atomic? `DESC`? + throw new BadRequestException(ErrorMessage.COUPON_OUT_OF_STOCK.getMessage()); + } + + Event event = eventService.getValidEventOrThrow(eventId); + + if(couponRepository.existsByUserIdAndEventId(authUser.getUserId(), eventId)) { + throw new BadRequestException(ErrorMessage.COUPON_ALREADY_ISSUED.getMessage()); + } + + // 쿠폰 발급 및 저장 + Coupon coupon = Coupon.create(User.fromAuthUser(authUser),event); + + couponRepository.save(coupon); + + return coupon.toDto(); + } + + public Page getMyCoupons(AuthUser authUser, int page, int size) { + Pageable pageable = PageRequest.of(page-1, size); + Page coupons = couponRepository.findAllByUserIdAndState(authUser.getUserId(), CouponState.VALID, pageable); + + return coupons.map(Coupon::toDto); + } + + public CouponResponseDto getCoupon(AuthUser authUser, Long couponId) { + Coupon coupon = findByIdOrElseThrow(couponId); + + if(!coupon.getUser().equals(User.fromAuthUser(authUser))) { + throw new ForbiddenException(ErrorMessage.COUPON_FORBIDDEN.getMessage()); + } + + if(!coupon.getState().equals(CouponState.VALID)) { + throw new BadRequestException(ErrorMessage.COUPON_ALREADY_USED.getMessage()); + } + + return coupon.toDto(); + } + + public Coupon findByIdOrElseThrow(Long couponId) { + return couponRepository.findById(couponId) + .orElseThrow(() -> new NotFoundException(ErrorMessage.COUPON_NOT_FOUND.getMessage())); + } +} diff --git a/src/main/java/com/example/eightyage/domain/event/controller/EventController.java b/src/main/java/com/example/eightyage/domain/event/controller/EventController.java index 3d3104c..7c12b97 100644 --- a/src/main/java/com/example/eightyage/domain/event/controller/EventController.java +++ b/src/main/java/com/example/eightyage/domain/event/controller/EventController.java @@ -1,37 +1,37 @@ -//package com.example.eightyage.domain.event.controller; -// -//import com.example.eightyage.domain.event.dto.request.EventRequestDto; -//import com.example.eightyage.domain.event.dto.response.EventResponseDto; -//import com.example.eightyage.domain.event.service.EventService; -//import lombok.RequiredArgsConstructor; -//import org.springframework.data.domain.Page; -//import org.springframework.http.ResponseEntity; -//import org.springframework.web.bind.annotation.*; -// -//@RestController -//@RequestMapping("/api") -//@RequiredArgsConstructor -//public class EventController { -// -// private final EventService eventService; -// -// @PostMapping("/v1/events") -// public ResponseEntity createEvent(@RequestBody EventRequestDto eventRequestDto) { -// return ResponseEntity.ok(eventService.saveEvent(eventRequestDto)); -// } -// -// @GetMapping("/v1/events") -// public ResponseEntity> getEvents(@RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size) { -// return ResponseEntity.ok(eventService.getEvents(page, size)); -// } -// -// @GetMapping("/v1/events/{eventId}") -// public ResponseEntity getEvent(@PathVariable long eventId) { -// return ResponseEntity.ok(eventService.getEvent(eventId)); -// } -// -// @PatchMapping("/v1/events/{eventId}") -// public ResponseEntity updateEvent(@PathVariable long eventId, @RequestBody EventRequestDto eventRequestDto) { -// return ResponseEntity.ok(eventService.updateEvent(eventId, eventRequestDto)); -// } -//} +package com.example.eightyage.domain.event.controller; + +import com.example.eightyage.domain.event.dto.request.EventRequestDto; +import com.example.eightyage.domain.event.dto.response.EventResponseDto; +import com.example.eightyage.domain.event.service.EventService; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor +public class EventController { + + private final EventService eventService; + + @PostMapping("/v1/events") + public ResponseEntity createEvent(@RequestBody EventRequestDto eventRequestDto) { + return ResponseEntity.ok(eventService.saveEvent(eventRequestDto)); + } + + @GetMapping("/v1/events") + public ResponseEntity> getEvents(@RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size) { + return ResponseEntity.ok(eventService.getEvents(page, size)); + } + + @GetMapping("/v1/events/{eventId}") + public ResponseEntity getEvent(@PathVariable long eventId) { + return ResponseEntity.ok(eventService.getEvent(eventId)); + } + + @PatchMapping("/v1/events/{eventId}") + public ResponseEntity updateEvent(@PathVariable long eventId, @RequestBody EventRequestDto eventRequestDto) { + return ResponseEntity.ok(eventService.updateEvent(eventId, eventRequestDto)); + } +} diff --git a/src/main/java/com/example/eightyage/domain/event/service/EventService.java b/src/main/java/com/example/eightyage/domain/event/service/EventService.java index 539a7d8..a96f6e1 100644 --- a/src/main/java/com/example/eightyage/domain/event/service/EventService.java +++ b/src/main/java/com/example/eightyage/domain/event/service/EventService.java @@ -1,105 +1,105 @@ -//package com.example.eightyage.domain.event.service; -// -//import com.example.eightyage.domain.event.dto.request.EventRequestDto; -//import com.example.eightyage.domain.event.dto.response.EventResponseDto; -//import com.example.eightyage.domain.event.entity.Event; -//import com.example.eightyage.domain.event.entity.EventState; -//import com.example.eightyage.domain.event.repository.EventRepository; -//import com.example.eightyage.global.exception.BadRequestException; -//import com.example.eightyage.global.exception.ErrorMessage; -//import lombok.RequiredArgsConstructor; -//import org.springframework.data.domain.Page; -//import org.springframework.data.domain.PageRequest; -//import org.springframework.data.domain.Pageable; -//import org.springframework.data.redis.core.StringRedisTemplate; -//import org.springframework.security.access.annotation.Secured; -//import org.springframework.stereotype.Service; -// -//import java.time.LocalDateTime; -// -//@Service -//@RequiredArgsConstructor -//public class EventService { -// -// private final EventRepository eventRepository; -// private final StringRedisTemplate stringRedisTemplate; -// -// @Secured("ADMIN") -// public EventResponseDto saveEvent(EventRequestDto eventRequestDto) { -// Event event = new Event( -// eventRequestDto.getName(), -// eventRequestDto.getDescription(), -// eventRequestDto.getQuantity(), -// eventRequestDto.getStartDate(), -// eventRequestDto.getEndDate() -// ); -// -// checkEventState(event); -// -// Event savedEvent = eventRepository.save(event); -// -// stringRedisTemplate.opsForValue().set("event:quantity:" + savedEvent.getId(), String.valueOf(savedEvent.getQuantity())); -// -// return savedEvent.toDto(); -// } -// -// public Page getEvents(int page, int size) { -// Pageable pageable = PageRequest.of(page-1, size); -// Page events = eventRepository.findAll(pageable); -// -// // 모든 events들 checkState로 state 상태 갱신하기 -// events.forEach(this::checkEventState); -// -// return events.map(Event::toDto); -// } -// -// public EventResponseDto getEvent(long eventId) { -// Event event = findByIdOrElseThrow(eventId); -// -// checkEventState(event); -// -// return event.toDto(); -// } -// -// @Secured("ADMIN") -// public EventResponseDto updateEvent(long eventId, EventRequestDto eventRequestDto) { -// Event event = findByIdOrElseThrow(eventId); -// -// event.update(eventRequestDto); -// -// checkEventState(event); -// -// return event.toDto(); -// } -// -// private void checkEventState(Event event) { -// LocalDateTime now = LocalDateTime.now(); -// EventState newState = -// ( (event.getStartDate().isBefore(now) || event.getStartDate().isEqual(now)) && -// (event.getEndDate().isAfter(now) || event.getEndDate().isEqual(now)) ) -// ? EventState.VALID -// : EventState.INVALID; -// -// if (event.getState() != newState) { -// event.setState(newState); -// eventRepository.save(event); -// } -// } -// -// public Event getValidEventOrThrow(Long eventId) { -// Event event = findByIdOrElseThrow(eventId); -// -// checkEventState(event); -// -// if(event.getState() != EventState.VALID) { -// throw new BadRequestException(ErrorMessage.INVALID_EVENT_PERIOD.getMessage()); -// } -// -// return event; -// } -// -// public Event findByIdOrElseThrow(Long eventId) { -// return eventRepository.findById(eventId) -// .orElseThrow(() -> new BadRequestException(ErrorMessage.EVENT_NOT_FOUND.getMessage())); -// } -//} +package com.example.eightyage.domain.event.service; + +import com.example.eightyage.domain.event.dto.request.EventRequestDto; +import com.example.eightyage.domain.event.dto.response.EventResponseDto; +import com.example.eightyage.domain.event.entity.Event; +import com.example.eightyage.domain.event.entity.EventState; +import com.example.eightyage.domain.event.repository.EventRepository; +import com.example.eightyage.global.exception.BadRequestException; +import com.example.eightyage.global.exception.ErrorMessage; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.security.access.annotation.Secured; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +@Service +@RequiredArgsConstructor +public class EventService { + + private final EventRepository eventRepository; + private final StringRedisTemplate stringRedisTemplate; + + @Secured("ADMIN") + public EventResponseDto saveEvent(EventRequestDto eventRequestDto) { + Event event = new Event( + eventRequestDto.getName(), + eventRequestDto.getDescription(), + eventRequestDto.getQuantity(), + eventRequestDto.getStartDate(), + eventRequestDto.getEndDate() + ); + + checkEventState(event); + + Event savedEvent = eventRepository.save(event); + + stringRedisTemplate.opsForValue().set("event:quantity:" + savedEvent.getId(), String.valueOf(savedEvent.getQuantity())); + + return savedEvent.toDto(); + } + + public Page getEvents(int page, int size) { + Pageable pageable = PageRequest.of(page-1, size); + Page events = eventRepository.findAll(pageable); + + // 모든 events들 checkState로 state 상태 갱신하기 + events.forEach(this::checkEventState); + + return events.map(Event::toDto); + } + + public EventResponseDto getEvent(long eventId) { + Event event = findByIdOrElseThrow(eventId); + + checkEventState(event); + + return event.toDto(); + } + + @Secured("ADMIN") + public EventResponseDto updateEvent(long eventId, EventRequestDto eventRequestDto) { + Event event = findByIdOrElseThrow(eventId); + + event.update(eventRequestDto); + + checkEventState(event); + + return event.toDto(); + } + + private void checkEventState(Event event) { + LocalDateTime now = LocalDateTime.now(); + EventState newState = + ( (event.getStartDate().isBefore(now) || event.getStartDate().isEqual(now)) && + (event.getEndDate().isAfter(now) || event.getEndDate().isEqual(now)) ) + ? EventState.VALID + : EventState.INVALID; + + if (event.getState() != newState) { + event.setState(newState); + eventRepository.save(event); + } + } + + public Event getValidEventOrThrow(Long eventId) { + Event event = findByIdOrElseThrow(eventId); + + checkEventState(event); + + if(event.getState() != EventState.VALID) { + throw new BadRequestException(ErrorMessage.INVALID_EVENT_PERIOD.getMessage()); + } + + return event; + } + + public Event findByIdOrElseThrow(Long eventId) { + return eventRepository.findById(eventId) + .orElseThrow(() -> new BadRequestException(ErrorMessage.EVENT_NOT_FOUND.getMessage())); + } +} From f97f111f7a4ce43100f10cbbfa2b2dd5bc683bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 20:51:08 +0900 Subject: [PATCH 11/24] =?UTF-8?q?refactor:=20KEY=20=EB=AA=85=EC=B9=AD=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 164064b..b7d1ee6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -32,23 +32,23 @@ spring: use_sql_comments: true dialect: org.hibernate.dialect.MySQLDialect - cloud: - aws: - credentials: - access-key: ${S3_ACCESS_KEY} - secret-key: ${S3_SECRET_KEY} - region: - static: ap-northeast-2 - s3: - bucket: ${S3_BUCKET} - -aws: - credentials: - access-key: ${S3_ACCESS_KEY} - secret-key: ${S3_SECRET_KEY} - region: ap-northeast-2 - s3: - bucket: ${S3_BUCKET} +# cloud: +# aws: +# credentials: +# access-key: ${S3_ACCESS_KEY} +# secret-key: ${S3_SECRET_KEY} +# region: +# static: ap-northeast-2 +# s3: +# bucket: ${S3_BUCKET} +# +#aws: +# credentials: +# access-key: ${S3_ACCESS_KEY} +# secret-key: ${S3_SECRET_KEY} +# region: ap-northeast-2 +# s3: +# bucket: ${S3_BUCKET} data: redis: From 1d1f14fefb72d4a7e8f75323859ad7fd92ae1eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 21:46:18 +0900 Subject: [PATCH 12/24] =?UTF-8?q?refactor(product):=20update=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20ifNotNull=20=EB=B6=99=EC=97=AC=EC=84=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eightyage/domain/product/entity/Product.java | 10 +++++----- .../domain/product/service/ProductService.java | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/product/entity/Product.java b/src/main/java/com/example/eightyage/domain/product/entity/Product.java index bf19b02..14890b4 100644 --- a/src/main/java/com/example/eightyage/domain/product/entity/Product.java +++ b/src/main/java/com/example/eightyage/domain/product/entity/Product.java @@ -52,31 +52,31 @@ public Product(String name, Category category, String content, Integer price, Sa this.saleState = saleState; } - public void updateName(String newName){ + public void updateNameIfNotNull(String newName){ if(newName != null){ this.name = newName; } } - public void updateCategory(Category newCategory) { + public void updateCategoryIfNotNull(Category newCategory) { if (newCategory != null) { this.category = newCategory; } } - public void updateContent(String newContent) { + public void updateContentIfNotNull(String newContent) { if (newContent != null) { this.content = newContent; } } - public void updatePrice(Integer newPrice) { + public void updatePriceIfNotNull(Integer newPrice) { if (newPrice != null) { this.price = newPrice; } } - public void updateSaleState(SaleState newSaleState) { + public void updateSaleStateIfNotNull(SaleState newSaleState) { if (newSaleState != null) { this.saleState = newSaleState; } diff --git a/src/main/java/com/example/eightyage/domain/product/service/ProductService.java b/src/main/java/com/example/eightyage/domain/product/service/ProductService.java index 052a4a0..cd5465c 100644 --- a/src/main/java/com/example/eightyage/domain/product/service/ProductService.java +++ b/src/main/java/com/example/eightyage/domain/product/service/ProductService.java @@ -57,11 +57,11 @@ public ProductSaveResponseDto saveProduct(ProductSaveRequestDto requestDto) { public ProductUpdateResponseDto updateProduct(Long productId, ProductUpdateRequestDto requestDto) { Product findProduct = findProductByIdOrElseThrow(productId); - findProduct.updateName(requestDto.getProductName()); - findProduct.updateCategory(requestDto.getCategory()); - findProduct.updateContent(requestDto.getContent()); - findProduct.updateSaleState(requestDto.getSaleState()); - findProduct.updatePrice(requestDto.getPrice()); + findProduct.updateNameIfNotNull(requestDto.getProductName()); + findProduct.updateCategoryIfNotNull(requestDto.getCategory()); + findProduct.updateContentIfNotNull(requestDto.getContent()); + findProduct.updateSaleStateIfNotNull(requestDto.getSaleState()); + findProduct.updatePriceIfNotNull(requestDto.getPrice()); return ProductUpdateResponseDto.builder() .productName(findProduct.getName()) From 609fb78099595b8f9fc1d498b4d97c1e7665b5d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 21:46:30 +0900 Subject: [PATCH 13/24] =?UTF-8?q?refactor(review):=20update=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20ifNotNull=20=EB=B6=99=EC=97=AC=EC=84=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/eightyage/domain/review/entity/Review.java | 4 ++-- .../eightyage/domain/review/service/ReviewService.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/review/entity/Review.java b/src/main/java/com/example/eightyage/domain/review/entity/Review.java index dd690cd..3af3698 100644 --- a/src/main/java/com/example/eightyage/domain/review/entity/Review.java +++ b/src/main/java/com/example/eightyage/domain/review/entity/Review.java @@ -39,13 +39,13 @@ public Review(User user, Product product, Double score, String content) { this.content = content; } - public void updateScore(Double newScore){ + public void updateScoreIfNotNull(Double newScore){ if(newScore != null){ this.score = newScore; } } - public void updateContent(String newContent){ + public void updateContentIfNotNull(String newContent){ if(newContent != null){ this.content = newContent; } diff --git a/src/main/java/com/example/eightyage/domain/review/service/ReviewService.java b/src/main/java/com/example/eightyage/domain/review/service/ReviewService.java index 3d025ef..6039934 100644 --- a/src/main/java/com/example/eightyage/domain/review/service/ReviewService.java +++ b/src/main/java/com/example/eightyage/domain/review/service/ReviewService.java @@ -61,8 +61,8 @@ public ReviewUpdateResponseDto updateReview(Long userId, Long reviewId, ReviewUp Review findReview = findReviewByIdOrElseThrow(reviewId); if(findUser.getId().equals(findReview.getUser().getId())){ - findReview.updateScore(requestDto.getScore()); - findReview.updateContent(requestDto.getContent()); + findReview.updateScoreIfNotNull(requestDto.getScore()); + findReview.updateContentIfNotNull(requestDto.getContent()); } else { throw new UnauthorizedException("리뷰를 수정할 권한이 없습니다."); } From e580188545d86e4390dcaa04fffba1cb41ad2d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 21:50:24 +0900 Subject: [PATCH 14/24] =?UTF-8?q?refactor(product):=20find,=20get=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/controller/ProductController.java | 4 ++-- .../eightyage/domain/product/service/ProductService.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/product/controller/ProductController.java b/src/main/java/com/example/eightyage/domain/product/controller/ProductController.java index 54c28ed..fe87fc7 100644 --- a/src/main/java/com/example/eightyage/domain/product/controller/ProductController.java +++ b/src/main/java/com/example/eightyage/domain/product/controller/ProductController.java @@ -46,8 +46,8 @@ public ResponseEntity updateProduct( // 제품 단건 조회 @GetMapping("/v1/products/{productId}") - public ResponseEntity getProduct(@PathVariable Long productId){ - ProductGetResponseDto responseDto = productService.findProductById(productId); + public ResponseEntity findProduct(@PathVariable Long productId){ + ProductGetResponseDto responseDto = productService.getProductById(productId); return ResponseEntity.ok(responseDto); } diff --git a/src/main/java/com/example/eightyage/domain/product/service/ProductService.java b/src/main/java/com/example/eightyage/domain/product/service/ProductService.java index cd5465c..5b8732e 100644 --- a/src/main/java/com/example/eightyage/domain/product/service/ProductService.java +++ b/src/main/java/com/example/eightyage/domain/product/service/ProductService.java @@ -76,7 +76,7 @@ public ProductUpdateResponseDto updateProduct(Long productId, ProductUpdateReque // 제품 단건 조회 @Transactional(readOnly = true) - public ProductGetResponseDto findProductById(Long productId) { + public ProductGetResponseDto getProductById(Long productId) { Product findProduct = findProductByIdOrElseThrow(productId); return ProductGetResponseDto.builder() From c9e2a674354cce7ad70aca0631196fc6d05df14d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 21:50:31 +0900 Subject: [PATCH 15/24] =?UTF-8?q?refactor(review):=20find,=20get=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eightyage/domain/review/controller/ReviewController.java | 4 ++-- .../eightyage/domain/review/service/ReviewService.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/review/controller/ReviewController.java b/src/main/java/com/example/eightyage/domain/review/controller/ReviewController.java index bdab2e7..e5cbea2 100644 --- a/src/main/java/com/example/eightyage/domain/review/controller/ReviewController.java +++ b/src/main/java/com/example/eightyage/domain/review/controller/ReviewController.java @@ -55,7 +55,7 @@ public ResponseEntity updateReview( // 리뷰 다건 조회 @GetMapping("/v1/products/{productId}/reviews") - public ResponseEntity> getReviews( + public ResponseEntity> findReviews( @PathVariable Long productId, @RequestParam(required = false, defaultValue = "score") String orderBy, @RequestParam(defaultValue = "0") int page, @@ -63,7 +63,7 @@ public ResponseEntity> getReviews( ){ PageRequest pageRequest = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, orderBy)); - Page reviews = reviewService.findReviews(productId, pageRequest); + Page reviews = reviewService.getReviews(productId, pageRequest); return ResponseEntity.ok(reviews); } diff --git a/src/main/java/com/example/eightyage/domain/review/service/ReviewService.java b/src/main/java/com/example/eightyage/domain/review/service/ReviewService.java index 6039934..f7616b2 100644 --- a/src/main/java/com/example/eightyage/domain/review/service/ReviewService.java +++ b/src/main/java/com/example/eightyage/domain/review/service/ReviewService.java @@ -80,7 +80,7 @@ public ReviewUpdateResponseDto updateReview(Long userId, Long reviewId, ReviewUp // 리뷰 다건 조회 @Transactional(readOnly = true) - public Page findReviews(Long productId, PageRequest pageRequest) { + public Page getReviews(Long productId, PageRequest pageRequest) { Page reviewPage = reviewRepository.findByProductIdAndProductDeletedAtIsNull(productId, pageRequest); return reviewPage.map(review -> ReviewsGetResponseDto.builder() From 96b5528d0e54baca7b0cf40dec3689d04897a396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 21:53:54 +0900 Subject: [PATCH 16/24] =?UTF-8?q?refactor(product):=20category,=20salestat?= =?UTF-8?q?e=20enums=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EB=94=B0=EB=A1=9C=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/{entity => category}/Category.java | 2 +- .../domain/product/controller/ProductController.java | 2 +- .../domain/product/dto/request/ProductSaveRequestDto.java | 2 +- .../product/dto/request/ProductUpdateRequestDto.java | 4 ++-- .../domain/product/dto/response/ProductGetResponseDto.java | 4 ++-- .../product/dto/response/ProductSaveResponseDto.java | 4 ++-- .../product/dto/response/ProductSearchResponseDto.java | 2 +- .../product/dto/response/ProductUpdateResponseDto.java | 4 ++-- .../example/eightyage/domain/product/entity/Product.java | 2 ++ .../example/eightyage/domain/product/entity/SaleState.java | 6 ------ .../domain/product/repository/ProductBulkRepository.java | 4 ++-- .../domain/product/repository/ProductRepository.java | 2 +- .../eightyage/domain/product/salestate/SaleState.java | 6 ++++++ .../eightyage/domain/product/service/ProductService.java | 4 ++-- .../domain/product/service/ProductServiceTest.java | 7 ++----- 15 files changed, 27 insertions(+), 28 deletions(-) rename src/main/java/com/example/eightyage/domain/product/{entity => category}/Category.java (90%) delete mode 100644 src/main/java/com/example/eightyage/domain/product/entity/SaleState.java create mode 100644 src/main/java/com/example/eightyage/domain/product/salestate/SaleState.java diff --git a/src/main/java/com/example/eightyage/domain/product/entity/Category.java b/src/main/java/com/example/eightyage/domain/product/category/Category.java similarity index 90% rename from src/main/java/com/example/eightyage/domain/product/entity/Category.java rename to src/main/java/com/example/eightyage/domain/product/category/Category.java index 044799d..12c9345 100644 --- a/src/main/java/com/example/eightyage/domain/product/entity/Category.java +++ b/src/main/java/com/example/eightyage/domain/product/category/Category.java @@ -1,4 +1,4 @@ -package com.example.eightyage.domain.product.entity; +package com.example.eightyage.domain.product.category; public enum Category { SKINCARE("스킨케어"), diff --git a/src/main/java/com/example/eightyage/domain/product/controller/ProductController.java b/src/main/java/com/example/eightyage/domain/product/controller/ProductController.java index fe87fc7..f44cbd4 100644 --- a/src/main/java/com/example/eightyage/domain/product/controller/ProductController.java +++ b/src/main/java/com/example/eightyage/domain/product/controller/ProductController.java @@ -6,7 +6,7 @@ import com.example.eightyage.domain.product.dto.response.ProductSaveResponseDto; import com.example.eightyage.domain.product.dto.response.ProductSearchResponseDto; import com.example.eightyage.domain.product.dto.response.ProductUpdateResponseDto; -import com.example.eightyage.domain.product.entity.Category; +import com.example.eightyage.domain.product.category.Category; import com.example.eightyage.domain.product.service.ProductService; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/example/eightyage/domain/product/dto/request/ProductSaveRequestDto.java b/src/main/java/com/example/eightyage/domain/product/dto/request/ProductSaveRequestDto.java index 9cb5616..a7cd103 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/request/ProductSaveRequestDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/request/ProductSaveRequestDto.java @@ -1,6 +1,6 @@ package com.example.eightyage.domain.product.dto.request; -import com.example.eightyage.domain.product.entity.Category; +import com.example.eightyage.domain.product.category.Category; import com.example.eightyage.global.dto.ValidationMessage; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java b/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java index c7bccbd..ec72ff0 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java @@ -1,7 +1,7 @@ package com.example.eightyage.domain.product.dto.request; -import com.example.eightyage.domain.product.entity.Category; -import com.example.eightyage.domain.product.entity.SaleState; +import com.example.eightyage.domain.product.category.Category; +import com.example.eightyage.domain.product.salestate.SaleState; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java index 4b76fd7..b2fb059 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java @@ -1,7 +1,7 @@ package com.example.eightyage.domain.product.dto.response; -import com.example.eightyage.domain.product.entity.Category; -import com.example.eightyage.domain.product.entity.SaleState; +import com.example.eightyage.domain.product.category.Category; +import com.example.eightyage.domain.product.salestate.SaleState; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSaveResponseDto.java b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSaveResponseDto.java index 552387e..23fb6d6 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSaveResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSaveResponseDto.java @@ -1,7 +1,7 @@ package com.example.eightyage.domain.product.dto.response; -import com.example.eightyage.domain.product.entity.Category; -import com.example.eightyage.domain.product.entity.SaleState; +import com.example.eightyage.domain.product.category.Category; +import com.example.eightyage.domain.product.salestate.SaleState; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSearchResponseDto.java b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSearchResponseDto.java index d52d526..3205518 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSearchResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSearchResponseDto.java @@ -1,6 +1,6 @@ package com.example.eightyage.domain.product.dto.response; -import com.example.eightyage.domain.product.entity.Category; +import com.example.eightyage.domain.product.category.Category; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductUpdateResponseDto.java b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductUpdateResponseDto.java index a2bf8f4..62ab718 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductUpdateResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductUpdateResponseDto.java @@ -1,7 +1,7 @@ package com.example.eightyage.domain.product.dto.response; -import com.example.eightyage.domain.product.entity.Category; -import com.example.eightyage.domain.product.entity.SaleState; +import com.example.eightyage.domain.product.category.Category; +import com.example.eightyage.domain.product.salestate.SaleState; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/com/example/eightyage/domain/product/entity/Product.java b/src/main/java/com/example/eightyage/domain/product/entity/Product.java index 14890b4..4c09ac5 100644 --- a/src/main/java/com/example/eightyage/domain/product/entity/Product.java +++ b/src/main/java/com/example/eightyage/domain/product/entity/Product.java @@ -1,5 +1,7 @@ package com.example.eightyage.domain.product.entity; +import com.example.eightyage.domain.product.category.Category; +import com.example.eightyage.domain.product.salestate.SaleState; import com.example.eightyage.domain.review.entity.Review; import com.example.eightyage.global.entity.TimeStamped; import jakarta.persistence.*; diff --git a/src/main/java/com/example/eightyage/domain/product/entity/SaleState.java b/src/main/java/com/example/eightyage/domain/product/entity/SaleState.java deleted file mode 100644 index e69c789..0000000 --- a/src/main/java/com/example/eightyage/domain/product/entity/SaleState.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.example.eightyage.domain.product.entity; - -public enum SaleState { - FOR_SALE, - SOLD_OUT -} diff --git a/src/main/java/com/example/eightyage/domain/product/repository/ProductBulkRepository.java b/src/main/java/com/example/eightyage/domain/product/repository/ProductBulkRepository.java index 272b3e8..e9818db 100644 --- a/src/main/java/com/example/eightyage/domain/product/repository/ProductBulkRepository.java +++ b/src/main/java/com/example/eightyage/domain/product/repository/ProductBulkRepository.java @@ -1,8 +1,8 @@ package com.example.eightyage.domain.product.repository; -import com.example.eightyage.domain.product.entity.Category; +import com.example.eightyage.domain.product.category.Category; import com.example.eightyage.domain.product.entity.Product; -import com.example.eightyage.domain.product.entity.SaleState; +import com.example.eightyage.domain.product.salestate.SaleState; import lombok.RequiredArgsConstructor; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; diff --git a/src/main/java/com/example/eightyage/domain/product/repository/ProductRepository.java b/src/main/java/com/example/eightyage/domain/product/repository/ProductRepository.java index 6158523..90baefc 100644 --- a/src/main/java/com/example/eightyage/domain/product/repository/ProductRepository.java +++ b/src/main/java/com/example/eightyage/domain/product/repository/ProductRepository.java @@ -1,7 +1,7 @@ package com.example.eightyage.domain.product.repository; import com.example.eightyage.domain.product.dto.response.ProductSearchResponseDto; -import com.example.eightyage.domain.product.entity.Category; +import com.example.eightyage.domain.product.category.Category; import com.example.eightyage.domain.product.entity.Product; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; diff --git a/src/main/java/com/example/eightyage/domain/product/salestate/SaleState.java b/src/main/java/com/example/eightyage/domain/product/salestate/SaleState.java new file mode 100644 index 0000000..7445bbb --- /dev/null +++ b/src/main/java/com/example/eightyage/domain/product/salestate/SaleState.java @@ -0,0 +1,6 @@ +package com.example.eightyage.domain.product.salestate; + +public enum SaleState { + FOR_SALE, + SOLD_OUT +} diff --git a/src/main/java/com/example/eightyage/domain/product/service/ProductService.java b/src/main/java/com/example/eightyage/domain/product/service/ProductService.java index 5b8732e..01a81a4 100644 --- a/src/main/java/com/example/eightyage/domain/product/service/ProductService.java +++ b/src/main/java/com/example/eightyage/domain/product/service/ProductService.java @@ -3,9 +3,9 @@ import com.example.eightyage.domain.product.dto.request.ProductSaveRequestDto; import com.example.eightyage.domain.product.dto.request.ProductUpdateRequestDto; import com.example.eightyage.domain.product.dto.response.*; -import com.example.eightyage.domain.product.entity.Category; +import com.example.eightyage.domain.product.category.Category; import com.example.eightyage.domain.product.entity.Product; -import com.example.eightyage.domain.product.entity.SaleState; +import com.example.eightyage.domain.product.salestate.SaleState; import com.example.eightyage.domain.product.repository.ProductRepository; import com.example.eightyage.domain.review.entity.Review; import com.example.eightyage.domain.review.repository.ReviewRepository; diff --git a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java index 811dc93..da23f05 100644 --- a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java +++ b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java @@ -5,14 +5,12 @@ import com.example.eightyage.domain.product.dto.response.ProductGetResponseDto; import com.example.eightyage.domain.product.dto.response.ProductSaveResponseDto; import com.example.eightyage.domain.product.dto.response.ProductUpdateResponseDto; -import com.example.eightyage.domain.product.entity.Category; +import com.example.eightyage.domain.product.category.Category; import com.example.eightyage.domain.product.entity.Product; -import com.example.eightyage.domain.product.entity.SaleState; +import com.example.eightyage.domain.product.salestate.SaleState; import com.example.eightyage.domain.product.repository.ProductRepository; import com.example.eightyage.domain.review.entity.Review; import com.example.eightyage.domain.review.repository.ReviewRepository; -import com.example.eightyage.domain.user.entity.User; -import com.example.eightyage.domain.user.entity.UserRole; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -24,7 +22,6 @@ import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; From f7800fb482a2da8f72ceab487070685ab35a23a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 22:00:59 +0900 Subject: [PATCH 17/24] =?UTF-8?q?feat(review):=20findReviews=20=EC=97=94?= =?UTF-8?q?=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=ED=99=95=EC=9E=A5?= =?UTF-8?q?=EC=84=B1=20=EC=9E=88=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eightyage/domain/review/controller/ReviewController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/review/controller/ReviewController.java b/src/main/java/com/example/eightyage/domain/review/controller/ReviewController.java index e5cbea2..ef1d780 100644 --- a/src/main/java/com/example/eightyage/domain/review/controller/ReviewController.java +++ b/src/main/java/com/example/eightyage/domain/review/controller/ReviewController.java @@ -54,9 +54,9 @@ public ResponseEntity updateReview( } // 리뷰 다건 조회 - @GetMapping("/v1/products/{productId}/reviews") + @GetMapping("/v1/reviews") public ResponseEntity> findReviews( - @PathVariable Long productId, + @RequestParam(required = true) Long productId, @RequestParam(required = false, defaultValue = "score") String orderBy, @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "10") int size From 843c9aaa8e17daec27cca9187518314e7b3d5b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 22:05:14 +0900 Subject: [PATCH 18/24] =?UTF-8?q?refactor(product):=20=EA=B3=B5=EB=B0=B1?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/dto/request/ProductUpdateRequestDto.java | 5 ----- .../domain/product/dto/response/ProductGetResponseDto.java | 7 ------- .../product/dto/response/ProductSaveResponseDto.java | 7 ------- .../product/dto/response/ProductUpdateResponseDto.java | 7 ------- 4 files changed, 26 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java b/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java index ec72ff0..272fccc 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/request/ProductUpdateRequestDto.java @@ -8,14 +8,9 @@ @Getter @AllArgsConstructor public class ProductUpdateRequestDto { - private String productName; - private Category category; - private String content; - private SaleState saleState; - private Integer price; } diff --git a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java index b2fb059..534ae84 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java @@ -12,18 +12,11 @@ @Builder @AllArgsConstructor public class ProductGetResponseDto { - private final String productName; - private final String content; - private final Category category; - private final Integer price; - private final SaleState saleState; - private final LocalDateTime createdAt; - private final LocalDateTime modifiedAt; } diff --git a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSaveResponseDto.java b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSaveResponseDto.java index 23fb6d6..86abc5d 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSaveResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductSaveResponseDto.java @@ -12,18 +12,11 @@ @Builder @AllArgsConstructor public class ProductSaveResponseDto { - private final String productName; - private final Category category; - private final Integer price; - private final String content; - private final SaleState saleState; - private final LocalDateTime createdAt; - private final LocalDateTime modifiedAt; } diff --git a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductUpdateResponseDto.java b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductUpdateResponseDto.java index 62ab718..d44aea6 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductUpdateResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductUpdateResponseDto.java @@ -12,18 +12,11 @@ @Builder @AllArgsConstructor public class ProductUpdateResponseDto { - private final String productName; - private final Integer price; - private final String content; - private final Category category; - private final SaleState saleState; - private final LocalDateTime createdAt; - private final LocalDateTime modifiedAt; } From b787710b743d741234bbce5094d40f2869adf9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Fri, 28 Mar 2025 22:05:27 +0900 Subject: [PATCH 19/24] =?UTF-8?q?refactor(review):=20=EA=B3=B5=EB=B0=B1=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/review/dto/request/ReviewUpdateRequestDto.java | 2 -- .../domain/review/dto/response/ReviewSaveResponseDto.java | 8 -------- .../review/dto/response/ReviewUpdateResponseDto.java | 7 ------- .../domain/review/dto/response/ReviewsGetResponseDto.java | 7 ------- 4 files changed, 24 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewUpdateRequestDto.java b/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewUpdateRequestDto.java index 6fa8ef6..5f573ac 100644 --- a/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewUpdateRequestDto.java +++ b/src/main/java/com/example/eightyage/domain/review/dto/request/ReviewUpdateRequestDto.java @@ -7,8 +7,6 @@ @Getter @AllArgsConstructor public class ReviewUpdateRequestDto { - private Double score; - private String content; } \ No newline at end of file diff --git a/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewSaveResponseDto.java b/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewSaveResponseDto.java index 03febd7..043cca4 100644 --- a/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewSaveResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewSaveResponseDto.java @@ -10,20 +10,12 @@ @Builder @AllArgsConstructor public class ReviewSaveResponseDto { - private final Long id; - private final Long userId; - private final Long productId; - private final String nickname; - private final Double score; - private final String content; - private final LocalDateTime createdAt; - private final LocalDateTime modifiedAt; } diff --git a/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewUpdateResponseDto.java b/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewUpdateResponseDto.java index 9c387e5..6350d3e 100644 --- a/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewUpdateResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewUpdateResponseDto.java @@ -10,18 +10,11 @@ @Builder @AllArgsConstructor public class ReviewUpdateResponseDto { - private final Long id; - private final Long userId; - private final String nickname; - private final Double score; - private final String content; - private final LocalDateTime createdAt; - private final LocalDateTime modifiedAt; } \ No newline at end of file diff --git a/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewsGetResponseDto.java b/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewsGetResponseDto.java index c8742ce..9ee2dff 100644 --- a/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewsGetResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/review/dto/response/ReviewsGetResponseDto.java @@ -10,18 +10,11 @@ @Builder @AllArgsConstructor public class ReviewsGetResponseDto { - private final Long id; - private final Long userId; - private final String nickname; - private final Double score; - private final String content; - private final LocalDateTime createdAt; - private final LocalDateTime modifiedAt; } From 2038dbbb890ab09360a6a8113db47bf1cb7922bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Sat, 29 Mar 2025 11:56:00 +0900 Subject: [PATCH 20/24] =?UTF-8?q?fix(product):=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20=EC=A4=91=20=EB=B0=9C=EA=B2=AC=EB=90=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eightyage/domain/product/entity/Product.java | 1 + .../domain/product/service/ProductServiceTest.java | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/eightyage/domain/product/entity/Product.java b/src/main/java/com/example/eightyage/domain/product/entity/Product.java index 4c09ac5..020abe8 100644 --- a/src/main/java/com/example/eightyage/domain/product/entity/Product.java +++ b/src/main/java/com/example/eightyage/domain/product/entity/Product.java @@ -43,6 +43,7 @@ public class Product extends TimeStamped { private List reviews = new ArrayList<>(); @Temporal(TemporalType.TIMESTAMP) + @Column(nullable = true) private LocalDateTime deletedAt; @Builder diff --git a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java index da23f05..b7bff21 100644 --- a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java +++ b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java @@ -17,6 +17,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -71,7 +72,7 @@ class ProductServiceTest { reviewList.add(review1); reviewList.add(review2); - Product product = new Product(1L, "8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴주는 퍼펙트 스킨", 20000, SaleState.FOR_SALE, reviewList); + Product product = new Product(1L, "8자 주름 스킨", Category.SKINCARE, "8자 주름을 1자로 펴주는 퍼펙트 스킨", 20000, SaleState.FOR_SALE, reviewList, null); given(productRepository.findById(any(Long.class))).willReturn(Optional.of(product)); @@ -92,7 +93,7 @@ class ProductServiceTest { given(productRepository.findById(any(Long.class))).willReturn(Optional.of(product)); // when - ProductGetResponseDto responseDto = productService.findProductById(productId); + ProductGetResponseDto responseDto = productService.getProductById(productId); // then assertThat(responseDto.getProductName()).isEqualTo(product.getName()); @@ -114,9 +115,7 @@ class ProductServiceTest { productService.deleteProduct(productId); // then - verify(review1, times(1)).delete(); - verify(review2, times(1)).delete(); - - verify(product, times(1)).delete(); + verify(reviewRepository, times(1)).deleteAll(reviewList); + verify(product, times(1)).deleteProduct(); } } \ No newline at end of file From b30f7e9377ee19f4d10d8401cfe5efc4b8997167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Sat, 29 Mar 2025 11:56:12 +0900 Subject: [PATCH 21/24] =?UTF-8?q?fix(productImage):=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20=EC=A4=91=20=EB=B0=9C=EA=B2=AC=EB=90=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/service/ProductImageServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java b/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java index 77db7ee..bdbc2b1 100644 --- a/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java +++ b/src/test/java/com/example/eightyage/domain/product/service/ProductImageServiceTest.java @@ -87,6 +87,6 @@ void setUp(){ productImageService.deleteImage(imageId); // then - verify(productImage, times(1)).delete(); + verify(productImageRepository, times(1)).delete(productImage); } } \ No newline at end of file From a3e6c5b9e7b0ab22689efdfd10911d22446bbc21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Sat, 29 Mar 2025 11:56:18 +0900 Subject: [PATCH 22/24] =?UTF-8?q?fix(review):=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81=20=EC=A4=91=20=EB=B0=9C=EA=B2=AC=EB=90=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eightyage/domain/review/service/ReviewServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/example/eightyage/domain/review/service/ReviewServiceTest.java b/src/test/java/com/example/eightyage/domain/review/service/ReviewServiceTest.java index 0b4a973..18bb5df 100644 --- a/src/test/java/com/example/eightyage/domain/review/service/ReviewServiceTest.java +++ b/src/test/java/com/example/eightyage/domain/review/service/ReviewServiceTest.java @@ -137,7 +137,7 @@ class ReviewServiceTest { when(reviewRepository.findByProductIdAndProductDeletedAtIsNull(any(Long.class), eq(pageRequest))).thenReturn(reviewPage); // when - Page result = reviewService.findReviews(productId, pageRequest); + Page result = reviewService.getReviews(productId, pageRequest); // then assertNotNull(result); @@ -183,6 +183,6 @@ class ReviewServiceTest { reviewService.deleteReview(userId, reviewId); // then - verify(review, times(1)).delete(); + verify(reviewRepository, times(1)).delete(review); } } \ No newline at end of file From dbcd5145c581b5235c1191f6f09a91d75ead1bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Sat, 29 Mar 2025 12:13:33 +0900 Subject: [PATCH 23/24] =?UTF-8?q?feat(product):=20=EC=A0=9C=ED=92=88=20?= =?UTF-8?q?=EB=8B=A8=EA=B1=B4=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20productIm?= =?UTF-8?q?ageList=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/dto/response/ProductGetResponseDto.java | 3 +++ .../domain/product/repository/ProductImageRepository.java | 5 ++++- .../eightyage/domain/product/service/ProductService.java | 5 +++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java index 534ae84..60d93ab 100644 --- a/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java +++ b/src/main/java/com/example/eightyage/domain/product/dto/response/ProductGetResponseDto.java @@ -1,12 +1,14 @@ package com.example.eightyage.domain.product.dto.response; import com.example.eightyage.domain.product.category.Category; +import com.example.eightyage.domain.product.entity.ProductImage; import com.example.eightyage.domain.product.salestate.SaleState; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import java.time.LocalDateTime; +import java.util.List; @Getter @Builder @@ -17,6 +19,7 @@ public class ProductGetResponseDto { private final Category category; private final Integer price; private final SaleState saleState; + private final List productImageList; private final LocalDateTime createdAt; private final LocalDateTime modifiedAt; } diff --git a/src/main/java/com/example/eightyage/domain/product/repository/ProductImageRepository.java b/src/main/java/com/example/eightyage/domain/product/repository/ProductImageRepository.java index aa2c50e..9589344 100644 --- a/src/main/java/com/example/eightyage/domain/product/repository/ProductImageRepository.java +++ b/src/main/java/com/example/eightyage/domain/product/repository/ProductImageRepository.java @@ -4,11 +4,14 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import java.awt.*; +import java.util.List; import java.util.Optional; public interface ProductImageRepository extends JpaRepository { @Query("SELECT pi FROM ProductImage pi WHERE pi.id = :imageId") Optional findById(Long imageId); + + @Query("SELECT pi.imageUrl FROM ProductImage pi WHERE pi.product.id = :productId") + List findProductImageByProductId(Long productId); } diff --git a/src/main/java/com/example/eightyage/domain/product/service/ProductService.java b/src/main/java/com/example/eightyage/domain/product/service/ProductService.java index 01a81a4..bc36a31 100644 --- a/src/main/java/com/example/eightyage/domain/product/service/ProductService.java +++ b/src/main/java/com/example/eightyage/domain/product/service/ProductService.java @@ -5,6 +5,8 @@ import com.example.eightyage.domain.product.dto.response.*; import com.example.eightyage.domain.product.category.Category; import com.example.eightyage.domain.product.entity.Product; +import com.example.eightyage.domain.product.entity.ProductImage; +import com.example.eightyage.domain.product.repository.ProductImageRepository; import com.example.eightyage.domain.product.salestate.SaleState; import com.example.eightyage.domain.product.repository.ProductRepository; import com.example.eightyage.domain.review.entity.Review; @@ -30,6 +32,7 @@ public class ProductService { private final ProductRepository productRepository; private final ReviewRepository reviewRepository; + private final ProductImageRepository productImageRepository; private final SearchServiceV1 searchServiceV1; private final SearchServiceV2 searchServiceV2; private final SearchServiceV3 searchServiceV3; @@ -78,6 +81,7 @@ public ProductUpdateResponseDto updateProduct(Long productId, ProductUpdateReque @Transactional(readOnly = true) public ProductGetResponseDto getProductById(Long productId) { Product findProduct = findProductByIdOrElseThrow(productId); + List productImageList = productImageRepository.findProductImageByProductId(productId); return ProductGetResponseDto.builder() .productName(findProduct.getName()) @@ -85,6 +89,7 @@ public ProductGetResponseDto getProductById(Long productId) { .category(findProduct.getCategory()) .price(findProduct.getPrice()) .saleState(findProduct.getSaleState()) + .productImageList(productImageList) .createdAt(findProduct.getCreatedAt()) .modifiedAt(findProduct.getModifiedAt()) .build(); From 7ad2d7bb8ed7a09403af7dcb49299121e9caa794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B5=E1=84=8C=E1=85=B5=E1=84=8B=E1=85=B3?= =?UTF-8?q?=E1=86=AB?= Date: Sat, 29 Mar 2025 12:21:46 +0900 Subject: [PATCH 24/24] =?UTF-8?q?fix(product):=20productImageList=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=ED=9B=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/service/ProductServiceTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java index b7bff21..aa91cb0 100644 --- a/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java +++ b/src/test/java/com/example/eightyage/domain/product/service/ProductServiceTest.java @@ -7,6 +7,7 @@ import com.example.eightyage.domain.product.dto.response.ProductUpdateResponseDto; import com.example.eightyage.domain.product.category.Category; import com.example.eightyage.domain.product.entity.Product; +import com.example.eightyage.domain.product.repository.ProductImageRepository; import com.example.eightyage.domain.product.salestate.SaleState; import com.example.eightyage.domain.product.repository.ProductRepository; import com.example.eightyage.domain.review.entity.Review; @@ -35,6 +36,9 @@ class ProductServiceTest { @Mock ProductRepository productRepository; + @Mock + ProductImageRepository productImageRepository; + @Mock ReviewRepository reviewRepository; @@ -89,8 +93,13 @@ class ProductServiceTest { void 제품_단건_조회_성공(){ // given Long productId = 1L; + List productImageList = new ArrayList<>(); + + productImageList.add("image1.png"); + productImageList.add("image2.png"); given(productRepository.findById(any(Long.class))).willReturn(Optional.of(product)); + given(productImageRepository.findProductImageByProductId(any(Long.class))).willReturn(productImageList); // when ProductGetResponseDto responseDto = productService.getProductById(productId);