오늘의 학습 키워드
📖 프로젝트 문제점
📖 코드 리팩토링
📖 최적화
📖 스프링 부트 이벤트 적용
@PatchMapping("/{eventId}/coupons/{couponId}/issued-coupons")
@PreAuthorize("hasAnyRole('ROLE_USER')")
public ResponseEntity<Void> issueCoupon(
@PathVariable Long eventId, @PathVariable Long couponId,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
eventService.issueCoupon(eventId, couponId, customUserDetails.getUser(),
LocalDateTime.now());
log.info(String.format("쿠폰이 발행되었습니다."));
return ResponseEntity.ok().build();
}
public void issueCoupon(Long eventId, Long couponId, User user, LocalDateTime now) {
RLock lock = redissonClient.getFairLock(LOCK_KEY);
try {
boolean isLocked = lock.tryLock(10, 60, TimeUnit.SECONDS);
if (isLocked) {
try {
boolean isDuplicatedIssuance = issuedCouponRepository.existsByCouponIdAndUserId(
couponId, user.getId());
if (isDuplicatedIssuance) {
throw new InvalidCouponException(INVALID_COUPON);
}
Event event = findEvent(eventId);
if (now.isBefore(event.getOpenAt())) {
throw new InvalidCouponException(INVALID_COUPON);
}
Coupon coupon = findCoupon(couponId);
if (coupon.getQuantity() <= 0) {
throw new InvalidCouponException(INVALID_COUPON);
}
coupon.decrease();
IssuedCoupon issuedCoupon = new IssuedCoupon(user, coupon);
issuedCouponRepository.save(issuedCoupon);
log.info(
String.format("쿠폰 발행 처리 [쿠폰 ID : %s]", issuedCoupon.getCoupon().getId()));
publisher.publishEvent(
new CouponEvent(issuedCoupon.getCoupon().getId(),
issuedCoupon.getUser().getId()));
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private Event findEvent(Long eventId) {
return eventRepository.findById(eventId)
.orElseThrow(() -> new NotFoundException(NOT_FOUND));
}
private Coupon findCoupon(Long couponId) {
return couponRepository.findById(couponId)
.orElseThrow(() -> new NotFoundException(NOT_FOUND));
}
@PatchMapping("/{couponId}/issued-coupons")
@PreAuthorize("hasAnyRole('ROLE_USER')")
public ResponseEntity<Void> issueCoupon(
@PathVariable Long couponId,
@AuthenticationPrincipal CustomUserDetails customUserDetails) {
couponService.issueCoupon(couponId, customUserDetails.getUser(),
LocalDateTime.now());
log.info("쿠폰이 발행되었습니다.");
return ResponseEntity.ok().build();
}
public void issueCoupon(Long couponId, User user, LocalDateTime now) {
RLock lock = redissonClient.getFairLock(LOCK_KEY);
try {
boolean isLocked = lock.tryLock(10, 60, TimeUnit.SECONDS);
if (isLocked) {
try {
boolean isDuplicatedIssuance = issuedCouponRepository.existsByCouponIdAndUserId(
couponId, user.getId());
if (isDuplicatedIssuance) {
throw new InvalidCouponException(INVALID_COUPON);
}
LocalDateTime openAt = eventQuery.getOpenDate(couponId);
if (now.isBefore(openAt)) {
throw new InvalidCouponException(INVALID_COUPON);
}
Coupon coupon = findCoupon(couponId);
if (coupon.getQuantity() <= 0) {
throw new InvalidCouponException(INVALID_COUPON);
}
coupon.decrease();
IssuedCoupon issuedCoupon = new IssuedCoupon(user, coupon);
issuedCouponRepository.save(issuedCoupon);
log.info(
String.format("쿠폰 발행 처리 [쿠폰 ID : %s]", issuedCoupon.getCoupon().getId()));
publisher.publishEvent(
new CouponEvent(issuedCoupon.getCoupon().getId(),
issuedCoupon.getUser().getId()));
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
public LocalDateTime getOpenDate(Long couponId) {
QEvent qevent = QEvent.event;
return jpaQueryFactory.select(qevent.openAt)
.from(qevent)
.where(qevent.coupon.id.eq(couponId))
.fetchOne();
}
Event event = findEvent(eventId);
if (now.isBefore(event.getOpenAt())) {
throw new InvalidCouponException(INVALID_COUPON);
}
LocalDateTime openAt = eventQuery.getOpenDate(couponId);
if (now.isBefore(openAt)) {
throw new InvalidCouponException(INVALID_COUPON);
}
[Spring Boot] ApplicationEventPublisher를 통해 스프링 부트 이벤트 적용하기