From a10275c124edc7ed63af13206765790e13f6ceaa Mon Sep 17 00:00:00 2001 From: wellbeing-dough Date: Mon, 1 Jul 2024 04:02:34 +0900 Subject: [PATCH 1/7] =?UTF-8?q?[Feat]=20:=20pessimistic=20lock=20->=20redi?= =?UTF-8?q?sson=20=EC=9C=BC=EB=A1=9C=20=EB=B2=A0=ED=83=80=20=EB=9D=BD=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 + .../apply/service/ApplyService.java | 2 - .../StudyPostApplyEventPublisher.java | 47 ++++++++--- .../implementations/StudyPostReader.java | 24 ++++++ .../implementations/StudyPostWriter.java | 28 +++++++ .../plugins/WebMvcRequestHandlerProvider.java | 81 +++++++++++++++++++ .../fixture/StudyPostEntityFixture.java | 2 +- 7 files changed, 174 insertions(+), 12 deletions(-) create mode 100644 src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostReader.java create mode 100644 src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostWriter.java create mode 100644 src/main/java/springfox/documentation/spring/web/plugins/WebMvcRequestHandlerProvider.java diff --git a/build.gradle b/build.gradle index d7131212..99f92299 100644 --- a/build.gradle +++ b/build.gradle @@ -56,6 +56,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-mail' // redis implementation 'org.springframework.boot:spring-boot-starter-data-redis' + implementation 'org.redisson:redisson-spring-boot-starter:3.17.4' + //s3 implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/apply/service/ApplyService.java b/src/main/java/kr/co/studyhubinu/studyhubserver/apply/service/ApplyService.java index 3cded01a..f7cda42b 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/apply/service/ApplyService.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/apply/service/ApplyService.java @@ -43,7 +43,6 @@ @RequiredArgsConstructor @Service -@Transactional(readOnly = true) public class ApplyService { private final UserRepository userRepository; @@ -110,7 +109,6 @@ public void rejectApply(final RejectApplyRequest rejectApplyRequest, final UserI rejectRepository.save(rejectApplyRequest.toRejectEntity()); } - @Transactional public void acceptApply(AcceptApplyRequest acceptApplyRequest, UserId userId) { userRepository.findById(userId.getId()).orElseThrow(UserNotFoundException::new); StudyEntity study = studyRepository.findById(acceptApplyRequest.getStudyId()).orElseThrow(StudyNotFoundException::new); diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java index 722c1c43..a635a2dd 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java @@ -1,23 +1,52 @@ package kr.co.studyhubinu.studyhubserver.studypost.domain.implementations; -import kr.co.studyhubinu.studyhubserver.exception.study.PostNotFoundException; +import kr.co.studyhubinu.studyhubserver.common.timer.Timer; import kr.co.studyhubinu.studyhubserver.studypost.domain.StudyPostEntity; -import kr.co.studyhubinu.studyhubserver.studypost.repository.StudyPostRepository; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; + +import java.util.concurrent.TimeUnit; @Component @RequiredArgsConstructor +@Slf4j public class StudyPostApplyEventPublisher { - private final StudyPostRepository studyPostRepository; + private final RedissonClient redissonClient; + private final StudyPostWriter studyPostWriter; + private final StudyPostReader studyPostReader; - @Transactional + @Timer public void acceptApplyEventPublish(Long studyId) { - StudyPostEntity studyPost = studyPostRepository.findByIdWithPessimisticLock(studyId).orElseThrow(PostNotFoundException::new); - studyPost.decreaseRemainingSeat(); - studyPost.closeStudyPostIfRemainingSeatIsZero(); - studyPostRepository.save(studyPost); + StudyPostEntity studyPost = studyPostReader.readByStudyId(studyId); + RLock lock = redissonClient.getLock(studyPost.getId().toString()); + boolean available = false; + try { + available = lock.tryLock(10, 1, TimeUnit.SECONDS); + if (!available) { + log.info("락 획득 실패 for studyPostId: " + studyPost.getId()); + return; + } + studyPostWriter.updateStudyPostApply(studyPost.getId()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + if (available) { + lock.unlock(); + } + } + } + // @Transactional +// public void acceptApplyEventPublish(Long studyId) { +// StudyPostEntity studyPost = studyPostRepository.findByIdWithPessimisticLock(studyId).orElseThrow(PostNotFoundException::new); +// studyPost.decreaseRemainingSeat(); +// studyPost.closeStudyPostIfRemainingSeatIsZero(); +// studyPostRepository.save(studyPost); +// } + + } diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostReader.java b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostReader.java new file mode 100644 index 00000000..972084ce --- /dev/null +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostReader.java @@ -0,0 +1,24 @@ +package kr.co.studyhubinu.studyhubserver.studypost.domain.implementations; + +import kr.co.studyhubinu.studyhubserver.exception.study.PostNotFoundException; +import kr.co.studyhubinu.studyhubserver.studypost.domain.StudyPostEntity; +import kr.co.studyhubinu.studyhubserver.studypost.repository.StudyPostRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Slf4j +public class StudyPostReader { + + private final StudyPostRepository studyPostRepository; + + public StudyPostEntity readByStudyId(Long studyId) { + log.info("dddddddddd 게시글 읽음"); + return studyPostRepository.findByStudyId(studyId).orElseThrow(PostNotFoundException::new); + } + +} diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostWriter.java b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostWriter.java new file mode 100644 index 00000000..a222ce4d --- /dev/null +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostWriter.java @@ -0,0 +1,28 @@ +package kr.co.studyhubinu.studyhubserver.studypost.domain.implementations; + +import kr.co.studyhubinu.studyhubserver.exception.study.PostNotFoundException; +import kr.co.studyhubinu.studyhubserver.studypost.domain.StudyPostEntity; +import kr.co.studyhubinu.studyhubserver.studypost.repository.StudyPostRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + + +@Component +@RequiredArgsConstructor +@Slf4j +public class StudyPostWriter { + + private final StudyPostRepository studyPostRepository; + private final StudyPostReader studyPostReader; + + @Transactional + public void updateStudyPostApply(Long studyPostId) { + StudyPostEntity studyPost = studyPostRepository.findById(studyPostId).orElseThrow(PostNotFoundException::new); + studyPost.decreaseRemainingSeat(); + studyPost.closeStudyPostIfRemainingSeatIsZero(); + studyPostRepository.saveAndFlush(studyPost); + } + +} diff --git a/src/main/java/springfox/documentation/spring/web/plugins/WebMvcRequestHandlerProvider.java b/src/main/java/springfox/documentation/spring/web/plugins/WebMvcRequestHandlerProvider.java new file mode 100644 index 00000000..ad1e5491 --- /dev/null +++ b/src/main/java/springfox/documentation/spring/web/plugins/WebMvcRequestHandlerProvider.java @@ -0,0 +1,81 @@ +package springfox.documentation.spring.web.plugins; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Conditional; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping; +import springfox.documentation.RequestHandler; +import springfox.documentation.spi.service.RequestHandlerProvider; +import springfox.documentation.spring.web.OnServletBasedWebApplication; +import springfox.documentation.spring.web.WebMvcRequestHandler; +import springfox.documentation.spring.web.readers.operation.HandlerMethodResolver; + +import javax.servlet.ServletContext; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static java.util.stream.Collectors.toList; +import static springfox.documentation.builders.BuilderDefaults.nullToEmptyList; +import static springfox.documentation.spi.service.contexts.Orderings.byPatternsCondition; +import static springfox.documentation.spring.web.paths.Paths.ROOT; + +@Component +@Order(Ordered.HIGHEST_PRECEDENCE) +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) +@Conditional(OnServletBasedWebApplication.class) +public class WebMvcRequestHandlerProvider implements RequestHandlerProvider { + private final List handlerMappings; + private final HandlerMethodResolver methodResolver; + private final String contextPath; + + @Autowired + public WebMvcRequestHandlerProvider( + Optional servletContext, + HandlerMethodResolver methodResolver, + List handlerMappings) { + this.handlerMappings = handlerMappings.stream() + .filter(mapping -> mapping.getPatternParser() == null) + .collect(Collectors.toList()); + this.methodResolver = methodResolver; + this.contextPath = servletContext + .map(ServletContext::getContextPath) + .orElse(ROOT); + } + + @Override + public List requestHandlers() { + return nullToEmptyList(handlerMappings).stream() + .filter(requestMappingInfoHandlerMapping -> + !("org.springframework.integration.http.inbound.IntegrationRequestMappingHandlerMapping" + .equals(requestMappingInfoHandlerMapping.getClass() + .getName()))) + .map(toMappingEntries()) + .flatMap((entries -> StreamSupport.stream(entries.spliterator(), false))) + .map(toRequestHandler()) + .sorted(byPatternsCondition()) + .collect(toList()); + } + + private Function>> toMappingEntries() { + return input -> input.getHandlerMethods() + .entrySet(); + } + + private Function, RequestHandler> toRequestHandler() { + return input -> new WebMvcRequestHandler( + contextPath, + methodResolver, + input.getKey(), + input.getValue()); + } +} \ No newline at end of file diff --git a/src/test/java/kr/co/studyhubinu/studyhubserver/support/fixture/StudyPostEntityFixture.java b/src/test/java/kr/co/studyhubinu/studyhubserver/support/fixture/StudyPostEntityFixture.java index 2c552307..9b70629c 100644 --- a/src/test/java/kr/co/studyhubinu/studyhubserver/support/fixture/StudyPostEntityFixture.java +++ b/src/test/java/kr/co/studyhubinu/studyhubserver/support/fixture/StudyPostEntityFixture.java @@ -9,7 +9,7 @@ public enum StudyPostEntityFixture { - SQLD("SQLD딸사람 구해요", "열심히 할 사람만요", MajorType.COMPUTER_SCIENCE_ENGINEERING, 5, GenderType.MALE, StudyWayType.MIX, 10000, "지각비", LocalDate.of(2023, 10, 25), LocalDate.of(2023, 12, 25), 100, 5L), + SQLD("SQLD딸사람 구해요", "열심히 할 사람만요", MajorType.COMPUTER_SCIENCE_ENGINEERING, 100, GenderType.MALE, StudyWayType.MIX, 10000, "지각비", LocalDate.of(2023, 10, 25), LocalDate.of(2023, 12, 25), 100, 5L), ENGINEER_INFORMATION_PROCESSING("정처기 딸사람 구해요", "심장을 바칠 사람만요", MajorType.COMPUTER_SCIENCE_ENGINEERING, 8, GenderType.FEMALE, StudyWayType.MIX, 5000, "지각비", LocalDate.of(2023, 10, 25), LocalDate.of(2024, 2, 13), 8, 7L), TOEIC("토익 딸사람 구해요", "800점 이상 목표인 사람들만", MajorType.NONE, 3, GenderType.NULL, StudyWayType.MIX, 50000, "800 달성 실패시", LocalDate.of(2023, 4, 30), LocalDate.of(2023, 8, 25), 3, 8L), ENGINEER_INFORMATION_PROCESSING_WITH_MALE("정처기 딸사람!!", "남자만요", MajorType.COMPUTER_SCIENCE_ENGINEERING, 8, GenderType.MALE, StudyWayType.MIX, 5000, "지각비", LocalDate.of(2023, 10, 25), LocalDate.of(2024, 2, 13), 8, 10L); From 7faa864d5e1688fcdfe58c0eb34f5906bad0712c Mon Sep 17 00:00:00 2001 From: wellbeing-dough Date: Mon, 1 Jul 2024 17:53:21 +0900 Subject: [PATCH 2/7] =?UTF-8?q?[Feat]=20:=20=EB=9D=BD=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=20=EB=B6=80=EB=B6=84=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../studyhubserver/exception/StatusType.java | 1 + .../StudyApplyLockAcquisitionException.java | 25 +++++++++++++++++++ .../StudyPostApplyEventPublisher.java | 6 ++--- 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/StudyApplyLockAcquisitionException.java diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/exception/StatusType.java b/src/main/java/kr/co/studyhubinu/studyhubserver/exception/StatusType.java index f86cf151..6a4f605a 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/exception/StatusType.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/exception/StatusType.java @@ -21,6 +21,7 @@ public enum StatusType { SORT_TYPE_NOT_FOUND(404, "SORT_TYPE_NOT_FOUND"), MAJOR_TYPE_NOT_FOUND(404, "MAJOR_TYPE_NOT_FOUND"), NO_REMAINING_SEAT(409, "NO_REMAINING_SEAT"), + STUDY_APPLY_LOCK_ACQUISITION(423, "STUDY_APPLY_LOCK_ACQUISITION"), STUDY_POST_CLOSED(409, "STUDY_POST_CLOSED"); private final int statusCode; diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/StudyApplyLockAcquisitionException.java b/src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/StudyApplyLockAcquisitionException.java new file mode 100644 index 00000000..d53020e5 --- /dev/null +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/StudyApplyLockAcquisitionException.java @@ -0,0 +1,25 @@ +package kr.co.studyhubinu.studyhubserver.exception.apply; + +import kr.co.studyhubinu.studyhubserver.exception.StatusType; +import kr.co.studyhubinu.studyhubserver.exception.common.CustomException; + +public class StudyApplyLockAcquisitionException extends CustomException { + + private final StatusType status; + private static final String message = "스터디 지원에 대한 락 획득에 실패했습니다."; + + public StudyApplyLockAcquisitionException() { + super(message); + this.status = StatusType.STUDY_APPLY_LOCK_ACQUISITION; + } + + @Override + public StatusType getStatus() { + return status; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java index a635a2dd..a649ca69 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java @@ -1,6 +1,7 @@ package kr.co.studyhubinu.studyhubserver.studypost.domain.implementations; import kr.co.studyhubinu.studyhubserver.common.timer.Timer; +import kr.co.studyhubinu.studyhubserver.exception.apply.StudyApplyLockAcquisitionException; import kr.co.studyhubinu.studyhubserver.studypost.domain.StudyPostEntity; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -27,12 +28,11 @@ public void acceptApplyEventPublish(Long studyId) { try { available = lock.tryLock(10, 1, TimeUnit.SECONDS); if (!available) { - log.info("락 획득 실패 for studyPostId: " + studyPost.getId()); - return; + throw new StudyApplyLockAcquisitionException(); } studyPostWriter.updateStudyPostApply(studyPost.getId()); } catch (InterruptedException e) { - throw new RuntimeException(e); + throw new StudyApplyLockAcquisitionException(); } finally { if (available) { lock.unlock(); From ad425936bdb56e428615e014a9510e495d554956 Mon Sep 17 00:00:00 2001 From: wellbeing-dough Date: Mon, 1 Jul 2024 18:12:47 +0900 Subject: [PATCH 3/7] =?UTF-8?q?[Feat]=20:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20import=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/implementations/StudyPostApplyEventPublisher.java | 1 - .../studypost/domain/implementations/StudyPostReader.java | 1 - 2 files changed, 2 deletions(-) diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java index a649ca69..3c8aaea6 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java @@ -20,7 +20,6 @@ public class StudyPostApplyEventPublisher { private final StudyPostWriter studyPostWriter; private final StudyPostReader studyPostReader; - @Timer public void acceptApplyEventPublish(Long studyId) { StudyPostEntity studyPost = studyPostReader.readByStudyId(studyId); RLock lock = redissonClient.getLock(studyPost.getId().toString()); diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostReader.java b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostReader.java index 972084ce..f1d26fba 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostReader.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostReader.java @@ -17,7 +17,6 @@ public class StudyPostReader { private final StudyPostRepository studyPostRepository; public StudyPostEntity readByStudyId(Long studyId) { - log.info("dddddddddd 게시글 읽음"); return studyPostRepository.findByStudyId(studyId).orElseThrow(PostNotFoundException::new); } From 610c520cc74f1eca9c3cc152fe74d546e5f25da2 Mon Sep 17 00:00:00 2001 From: wellbeing-dough Date: Mon, 15 Jul 2024 01:18:00 +0900 Subject: [PATCH 4/7] =?UTF-8?q?[Feat]=20:=20post=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=8B=9C=20=EC=9E=94=EC=97=AC=EC=84=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../studyhubserver/exception/StatusType.java | 3 ++- .../PostRemainingSeatOverStudyPerson.java | 25 +++++++++++++++++++ .../studypost/domain/StudyPostEntity.java | 3 ++- .../studypost/service/StudyPostService.java | 14 ++++++++++- 4 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 src/main/java/kr/co/studyhubinu/studyhubserver/exception/study/PostRemainingSeatOverStudyPerson.java diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/exception/StatusType.java b/src/main/java/kr/co/studyhubinu/studyhubserver/exception/StatusType.java index 6a4f605a..baf2b067 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/exception/StatusType.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/exception/StatusType.java @@ -22,7 +22,8 @@ public enum StatusType { MAJOR_TYPE_NOT_FOUND(404, "MAJOR_TYPE_NOT_FOUND"), NO_REMAINING_SEAT(409, "NO_REMAINING_SEAT"), STUDY_APPLY_LOCK_ACQUISITION(423, "STUDY_APPLY_LOCK_ACQUISITION"), - STUDY_POST_CLOSED(409, "STUDY_POST_CLOSED"); + STUDY_POST_CLOSED(409, "STUDY_POST_CLOSED"), + REMAINING_SEATS_OVER_STUDY_PERSON(409, "REMAINING_SEATS_OVER_STUDY_PERSON"); private final int statusCode; private final String code; diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/exception/study/PostRemainingSeatOverStudyPerson.java b/src/main/java/kr/co/studyhubinu/studyhubserver/exception/study/PostRemainingSeatOverStudyPerson.java new file mode 100644 index 00000000..674dbabf --- /dev/null +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/exception/study/PostRemainingSeatOverStudyPerson.java @@ -0,0 +1,25 @@ +package kr.co.studyhubinu.studyhubserver.exception.study; + +import kr.co.studyhubinu.studyhubserver.exception.StatusType; +import kr.co.studyhubinu.studyhubserver.exception.common.CustomException; + +public class PostRemainingSeatOverStudyPerson extends CustomException { + + private final StatusType status; + private static final String message = "잔여석은 0개가 될 수 없습니다"; + + public PostRemainingSeatOverStudyPerson() { + super(message); + this.status = StatusType.REMAINING_SEATS_OVER_STUDY_PERSON; + } + + @Override + public StatusType getStatus() { + return status; + } + + @Override + public String getMessage() { + return message; + } +} diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/StudyPostEntity.java b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/StudyPostEntity.java index 6979d788..acfe90c3 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/StudyPostEntity.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/StudyPostEntity.java @@ -90,7 +90,7 @@ public StudyPostEntity(Long id, String title, String content, String chatUrl, Ma this.studyId = studyId; } - public void update(UpdateStudyPostInfo info) { + public void update(UpdateStudyPostInfo info, int currentJoinCount) { this.title = info.getTitle(); this.content = info.getContent(); this.chatUrl = info.getChatUrl(); @@ -103,6 +103,7 @@ public void update(UpdateStudyPostInfo info) { this.close = info.isClose(); this.studyStartDate = info.getStudyStartDate(); this.studyEndDate = info.getStudyEndDate(); + this.remainingSeat = info.getStudyPerson() - currentJoinCount; } public boolean isPostOfUser(Long userId) { diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/service/StudyPostService.java b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/service/StudyPostService.java index 3c181fae..03401df2 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/service/StudyPostService.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/service/StudyPostService.java @@ -2,6 +2,7 @@ import kr.co.studyhubinu.studyhubserver.exception.study.PostEndDateConflictException; import kr.co.studyhubinu.studyhubserver.exception.study.PostNotFoundException; +import kr.co.studyhubinu.studyhubserver.exception.study.PostRemainingSeatOverStudyPerson; import kr.co.studyhubinu.studyhubserver.exception.study.PostStartDateConflictException; import kr.co.studyhubinu.studyhubserver.exception.user.UserNotAccessRightException; import kr.co.studyhubinu.studyhubserver.exception.user.UserNotFoundException; @@ -51,10 +52,21 @@ public Long updatePost(UpdateStudyPostInfo info) { StudyPostEntity post = findPost(info.getPostId()); validStudyPostDate(info.getStudyStartDate(), info.getStudyEndDate()); validatePostByUser(user.getId(), post); - post.update(info); + int currentJoinCount = getCurrentJoinCount(info.getStudyPerson(), post.getRemainingSeat(), post.getRemainingSeat()); + post.update(info, currentJoinCount); return post.getId(); } + private int getCurrentJoinCount(int studyPerson, Integer updateRemainingSeat, Integer remainingSeat) { + int currentJoinCount = studyPerson - remainingSeat; + if(studyPerson - currentJoinCount <= 0) { + throw new PostRemainingSeatOverStudyPerson(); + } + return currentJoinCount; + } + + // 총10명 3명 들어와서 잔여석 7명됬어, 근데 총 인원 5명으로 하면 5-3 해서 2가 되어야돼 근데 + @Transactional public void deletePost(Long postId, Long userId) { UserEntity user = findUser(userId); From 40c4077e110603f87dbf82a7a16933c7471dcbcd Mon Sep 17 00:00:00 2001 From: wellbeing-dough Date: Sat, 20 Jul 2024 04:28:15 +0900 Subject: [PATCH 5/7] =?UTF-8?q?[Feat]=20:=20redisson=20aop=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + .../apply/service/ApplyService.java | 5 +- .../common/redisson/CustomSpringELParser.java | 24 +++++++ .../redisson/RedissonDistributedLock.java | 14 +++++ .../redisson/RedissonDistributedLockAop.java | 62 +++++++++++++++++++ .../studyhubserver/config/RedissonConfig.java | 28 +++++++++ .../StudyPostApplyEventPublisher.java | 44 ++++++------- .../StudyPostApplyEventPublisherTest.java | 3 +- 8 files changed, 154 insertions(+), 27 deletions(-) create mode 100644 src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/CustomSpringELParser.java create mode 100644 src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLock.java create mode 100644 src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java create mode 100644 src/main/java/kr/co/studyhubinu/studyhubserver/config/RedissonConfig.java diff --git a/build.gradle b/build.gradle index 99f92299..369dbcf1 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ dependencies { developmentOnly 'org.springframework.boot:spring-boot-devtools' testImplementation 'org.springframework.boot:spring-boot-starter-test' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-aop' // swagger diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/apply/service/ApplyService.java b/src/main/java/kr/co/studyhubinu/studyhubserver/apply/service/ApplyService.java index f7cda42b..8bb5edd0 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/apply/service/ApplyService.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/apply/service/ApplyService.java @@ -28,6 +28,7 @@ import kr.co.studyhubinu.studyhubserver.study.repository.StudyRepository; import kr.co.studyhubinu.studyhubserver.studypost.domain.StudyPostEntity; import kr.co.studyhubinu.studyhubserver.studypost.domain.implementations.StudyPostApplyEventPublisher; +import kr.co.studyhubinu.studyhubserver.studypost.domain.implementations.StudyPostReader; import kr.co.studyhubinu.studyhubserver.studypost.repository.StudyPostRepository; import kr.co.studyhubinu.studyhubserver.user.domain.UserEntity; import kr.co.studyhubinu.studyhubserver.user.dto.data.UserId; @@ -52,6 +53,7 @@ public class ApplyService { private final StudyPostRepository studyPostRepository; private final StudyPostApplyEventPublisher studyPostApplyEventPublisher; private final ApplyWriter applyWriter; + private final StudyPostReader studyPostReader; @Transactional public void enroll(UserId userId, EnrollApplyRequest request) { @@ -113,8 +115,9 @@ public void acceptApply(AcceptApplyRequest acceptApplyRequest, UserId userId) { userRepository.findById(userId.getId()).orElseThrow(UserNotFoundException::new); StudyEntity study = studyRepository.findById(acceptApplyRequest.getStudyId()).orElseThrow(StudyNotFoundException::new); ApplyEntity applyEntity = applyRepository.findByUserIdAndStudyId(acceptApplyRequest.getRejectedUserId(), study.getId()).orElseThrow(ApplyNotFoundException::new); + StudyPostEntity studyPost = studyPostReader.readByStudyId(study.getId()); applyWriter.applyAccept(applyEntity); - studyPostApplyEventPublisher.acceptApplyEventPublish(study.getId()); + studyPostApplyEventPublisher.acceptApplyEventPublish(studyPost.getId()); } @Transactional diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/CustomSpringELParser.java b/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/CustomSpringELParser.java new file mode 100644 index 00000000..d8660e88 --- /dev/null +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/CustomSpringELParser.java @@ -0,0 +1,24 @@ +package kr.co.studyhubinu.studyhubserver.common.redisson; + +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +@Slf4j +@NoArgsConstructor +public class CustomSpringELParser { + public static String getDynamicValue(String[] parameterNames, Object[] args, String key) { + SpelExpressionParser parser = new SpelExpressionParser(); + StandardEvaluationContext context = new StandardEvaluationContext(); + for (int i = 0; i < parameterNames.length; i++) { + context.setVariable(parameterNames[i], args[i]); + } + Object value = parser.parseExpression(key).getValue(context, Object.class); + if (value == null) { + log.warn("CustomSpringELParser evaluated value is null for key={}", key); + return null; + } + return value.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLock.java b/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLock.java new file mode 100644 index 00000000..e592f352 --- /dev/null +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLock.java @@ -0,0 +1,14 @@ +package kr.co.studyhubinu.studyhubserver.common.redisson; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface RedissonDistributedLock { + + String hashKey(); + String field(); +} \ No newline at end of file diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java b/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java new file mode 100644 index 00000000..82dd00c9 --- /dev/null +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java @@ -0,0 +1,62 @@ +package kr.co.studyhubinu.studyhubserver.common.redisson; + +import kr.co.studyhubinu.studyhubserver.exception.apply.StudyApplyLockAcquisitionException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; + +@Aspect +@Slf4j +@RequiredArgsConstructor +@Component +public class RedissonDistributedLockAop { + + private final RedissonClient redissonClient; + + @Around("@annotation(kr.co.studyhubinu.studyhubserver.common.redisson.RedissonDistributedLock)") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + RedissonDistributedLock redissonDistributedLock = method.getAnnotation(RedissonDistributedLock.class); + String hashKey = getDynamicValue(signature, joinPoint, redissonDistributedLock.hashKey()); + String field = getDynamicValue(signature, joinPoint, redissonDistributedLock.field()); + + RLock lock = redissonClient.getLock(hashKey + ":" + field); + + Object result; + boolean available = false; + try { + available = lock.tryLock(10, 3, TimeUnit.SECONDS); + if (!available) { + log.warn("Redisson GetLock Timeout {}", field); + throw new StudyApplyLockAcquisitionException(); + } + + result = joinPoint.proceed(); + } catch (InterruptedException e) { + throw new StudyApplyLockAcquisitionException(); + } finally { + if (available) { + lock.unlock(); + } + } + return result; + } + + // 메서드 파라미터(field와 hashkey)를 기반으로 동적으로 값을 지정 + public String getDynamicValue(MethodSignature signature, ProceedingJoinPoint joinPoint, String distributedLock) { + return CustomSpringELParser.getDynamicValue( + signature.getParameterNames(), + joinPoint.getArgs(), + distributedLock); + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/config/RedissonConfig.java b/src/main/java/kr/co/studyhubinu/studyhubserver/config/RedissonConfig.java new file mode 100644 index 00000000..cddf33a8 --- /dev/null +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/config/RedissonConfig.java @@ -0,0 +1,28 @@ +package kr.co.studyhubinu.studyhubserver.config; + +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class RedissonConfig { + @Value("${spring.redis.host}") + private String redisHost; + + @Value("${spring.redis.port}") + private int redisPort; + + private static final String REDISSON_HOST_PREFIX = "redis://"; + + @Bean + public RedissonClient redissonClient() { + RedissonClient redisson = null; + Config config = new Config(); + config.useSingleServer().setAddress(REDISSON_HOST_PREFIX + redisHost + ":" + redisPort); + redisson = Redisson.create(config); + return redisson; + } +} \ No newline at end of file diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java index 3c8aaea6..c7072a69 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java @@ -1,16 +1,11 @@ package kr.co.studyhubinu.studyhubserver.studypost.domain.implementations; -import kr.co.studyhubinu.studyhubserver.common.timer.Timer; -import kr.co.studyhubinu.studyhubserver.exception.apply.StudyApplyLockAcquisitionException; -import kr.co.studyhubinu.studyhubserver.studypost.domain.StudyPostEntity; +import kr.co.studyhubinu.studyhubserver.common.redisson.RedissonDistributedLock; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.stereotype.Component; -import java.util.concurrent.TimeUnit; - @Component @RequiredArgsConstructor @Slf4j @@ -20,25 +15,26 @@ public class StudyPostApplyEventPublisher { private final StudyPostWriter studyPostWriter; private final StudyPostReader studyPostReader; - public void acceptApplyEventPublish(Long studyId) { - StudyPostEntity studyPost = studyPostReader.readByStudyId(studyId); - RLock lock = redissonClient.getLock(studyPost.getId().toString()); - boolean available = false; - try { - available = lock.tryLock(10, 1, TimeUnit.SECONDS); - if (!available) { - throw new StudyApplyLockAcquisitionException(); - } - studyPostWriter.updateStudyPostApply(studyPost.getId()); - } catch (InterruptedException e) { - throw new StudyApplyLockAcquisitionException(); - } finally { - if (available) { - lock.unlock(); - } - } - + @RedissonDistributedLock(hashKey = "'apply'", field = "#studyPostId") + public void acceptApplyEventPublish(Long studyPostId) { + studyPostWriter.updateStudyPostApply(studyPostId); } + + // RLock lock = redissonClient.getLock(studyPostId.toString()); +// boolean available = false; +// try { +// available = lock.tryLock(10, 1, TimeUnit.SECONDS); +// if (!available) { +// throw new StudyApplyLockAcquisitionException(); +// } +// studyPostWriter.updateStudyPostApply(studyPostId); +// } catch (InterruptedException e) { +// throw new StudyApplyLockAcquisitionException(); +// } finally { +// if (available) { +// lock.unlock(); +// } +// } // @Transactional // public void acceptApplyEventPublish(Long studyId) { // StudyPostEntity studyPost = studyPostRepository.findByIdWithPessimisticLock(studyId).orElseThrow(PostNotFoundException::new); diff --git a/src/test/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisherTest.java b/src/test/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisherTest.java index 31f7d0b0..79dabe87 100644 --- a/src/test/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisherTest.java +++ b/src/test/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisherTest.java @@ -16,7 +16,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest -@Disabled class StudyPostApplyEventPublisherTest { @Autowired @@ -42,7 +41,7 @@ public void after() { for (int i = 0; i < threadCount; i++) { executorService.submit(() -> { try { - studyPostApplyEventPublisher.acceptApplyEventPublish(post.getStudyId()); + studyPostApplyEventPublisher.acceptApplyEventPublish(savedPost.getId()); } finally { latch.countDown(); } From 08ba1a48cf8afb0c98c4389b9ded0b44c70a35e5 Mon Sep 17 00:00:00 2001 From: wellbeing-dough Date: Sat, 20 Jul 2024 14:00:18 +0900 Subject: [PATCH 6/7] =?UTF-8?q?[Feat]=20:=20redisson=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=83=81=EC=88=98=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/redisson/RedissonDistributedLockAop.java | 4 +++- .../domain/implementations/StudyPostApplyEventPublisher.java | 3 --- .../implementations/StudyPostApplyEventPublisherTest.java | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java b/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java index 82dd00c9..afffc250 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java @@ -21,6 +21,8 @@ public class RedissonDistributedLockAop { private final RedissonClient redissonClient; + private static final int LOCK_WAIT_TIME = 10; + private static final int LOCK_LEASE_TIME = 3; @Around("@annotation(kr.co.studyhubinu.studyhubserver.common.redisson.RedissonDistributedLock)") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { @@ -35,7 +37,7 @@ public Object around(ProceedingJoinPoint joinPoint) throws Throwable { Object result; boolean available = false; try { - available = lock.tryLock(10, 3, TimeUnit.SECONDS); + available = lock.tryLock(LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS); if (!available) { log.warn("Redisson GetLock Timeout {}", field); throw new StudyApplyLockAcquisitionException(); diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java index c7072a69..f19bf781 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisher.java @@ -3,7 +3,6 @@ import kr.co.studyhubinu.studyhubserver.common.redisson.RedissonDistributedLock; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.redisson.api.RedissonClient; import org.springframework.stereotype.Component; @Component @@ -11,9 +10,7 @@ @Slf4j public class StudyPostApplyEventPublisher { - private final RedissonClient redissonClient; private final StudyPostWriter studyPostWriter; - private final StudyPostReader studyPostReader; @RedissonDistributedLock(hashKey = "'apply'", field = "#studyPostId") public void acceptApplyEventPublish(Long studyPostId) { diff --git a/src/test/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisherTest.java b/src/test/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisherTest.java index 79dabe87..d5c69371 100644 --- a/src/test/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisherTest.java +++ b/src/test/java/kr/co/studyhubinu/studyhubserver/studypost/domain/implementations/StudyPostApplyEventPublisherTest.java @@ -16,6 +16,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; @SpringBootTest +@Disabled class StudyPostApplyEventPublisherTest { @Autowired From 303f1448a2c8627781ee9c150afdfbed4099e957 Mon Sep 17 00:00:00 2001 From: wellbeing-dough Date: Mon, 22 Jul 2024 21:52:48 +0900 Subject: [PATCH 7/7] =?UTF-8?q?[Feat]=20:=20lock=20AOP=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/redisson/RedissonDistributedLockAop.java | 6 +++--- ...uisitionException.java => LockAcquisitionException.java} | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/{StudyApplyLockAcquisitionException.java => LockAcquisitionException.java} (82%) diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java b/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java index afffc250..d7dd5a0c 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/common/redisson/RedissonDistributedLockAop.java @@ -1,6 +1,6 @@ package kr.co.studyhubinu.studyhubserver.common.redisson; -import kr.co.studyhubinu.studyhubserver.exception.apply.StudyApplyLockAcquisitionException; +import kr.co.studyhubinu.studyhubserver.exception.apply.LockAcquisitionException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; @@ -40,12 +40,12 @@ public Object around(ProceedingJoinPoint joinPoint) throws Throwable { available = lock.tryLock(LOCK_WAIT_TIME, LOCK_LEASE_TIME, TimeUnit.SECONDS); if (!available) { log.warn("Redisson GetLock Timeout {}", field); - throw new StudyApplyLockAcquisitionException(); + throw new LockAcquisitionException(); } result = joinPoint.proceed(); } catch (InterruptedException e) { - throw new StudyApplyLockAcquisitionException(); + throw new LockAcquisitionException(); } finally { if (available) { lock.unlock(); diff --git a/src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/StudyApplyLockAcquisitionException.java b/src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/LockAcquisitionException.java similarity index 82% rename from src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/StudyApplyLockAcquisitionException.java rename to src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/LockAcquisitionException.java index d53020e5..010cd6c1 100644 --- a/src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/StudyApplyLockAcquisitionException.java +++ b/src/main/java/kr/co/studyhubinu/studyhubserver/exception/apply/LockAcquisitionException.java @@ -3,12 +3,12 @@ import kr.co.studyhubinu.studyhubserver.exception.StatusType; import kr.co.studyhubinu.studyhubserver.exception.common.CustomException; -public class StudyApplyLockAcquisitionException extends CustomException { +public class LockAcquisitionException extends CustomException { private final StatusType status; private static final String message = "스터디 지원에 대한 락 획득에 실패했습니다."; - public StudyApplyLockAcquisitionException() { + public LockAcquisitionException() { super(message); this.status = StatusType.STUDY_APPLY_LOCK_ACQUISITION; }