From bb5fe1b3ef5da134f921a390f56fbebb5e8f1c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9E=A5=EB=8F=99=EA=B2=B8?= Date: Wed, 27 Nov 2024 19:55:38 +0900 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9E=20BugFix=20-=20RabbitMQ=EC=99=80?= =?UTF-8?q?=20Optimistic=20Lock=EC=9D=84=20=EC=9D=B4=EC=9A=A9=ED=95=9C=20?= =?UTF-8?q?=EB=8F=99=EC=8B=9C=EC=84=B1=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20(#176)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🐞 BugFix/#175 - add: RabbitMQ μ˜μ‘΄μ„± μΆ”κ°€ * 🐞 BugFix/#175 - feat: RabbitMQConfig κ΅¬ν˜„ * 🐞 BugFix/#175 - refactor: Optimistic Lock 적용 * 🐞 BugFix/#175 - feat: comment 생성 μ‹œ λ™μ‹œμ„± 문제 ν•΄κ²° * 🐞 BugFix/#175 - feat: like 생성 μ‹œ λ™μ‹œμ„± 문제 ν•΄κ²° --- build.gradle | 4 + .../onjung/core/config/RabbitMQConfig.java | 58 ++++++++++++ .../core/exception/error/ErrorCode.java | 3 + .../SuggestionCommandV1Controller.java | 7 +- .../consumer/CommentV1Consumer.java | 90 +++++++++++++++++++ .../controller/consumer/LikeV1Consumer.java | 69 ++++++++++++++ .../producer/CommentV1Producer.java | 18 ++++ .../controller/producer/LikeV1Producer.java | 18 ++++ .../dto/request/CommentMessage.java | 13 +++ .../application/dto/request/LikeMessage.java | 12 +++ .../service/CreateCommentService.java | 26 ++---- .../service/CreateOrDeleteLikeService.java | 59 ++---------- .../service/SendCommentRequestService.java | 24 +++++ .../service/SendLikeRequestService.java | 19 ++++ .../usecase/CreateOrDeleteLikeUseCase.java | 2 +- .../usecase/SendCommentRequestUseCase.java | 9 ++ .../usecase/SendLikeRequestUseCase.java | 9 ++ .../daon/onjung/suggestion/domain/Board.java | 3 + 18 files changed, 369 insertions(+), 74 deletions(-) create mode 100644 src/main/java/com/daon/onjung/core/config/RabbitMQConfig.java create mode 100644 src/main/java/com/daon/onjung/suggestion/application/controller/consumer/CommentV1Consumer.java create mode 100644 src/main/java/com/daon/onjung/suggestion/application/controller/consumer/LikeV1Consumer.java create mode 100644 src/main/java/com/daon/onjung/suggestion/application/controller/producer/CommentV1Producer.java create mode 100644 src/main/java/com/daon/onjung/suggestion/application/controller/producer/LikeV1Producer.java create mode 100644 src/main/java/com/daon/onjung/suggestion/application/dto/request/CommentMessage.java create mode 100644 src/main/java/com/daon/onjung/suggestion/application/dto/request/LikeMessage.java create mode 100644 src/main/java/com/daon/onjung/suggestion/application/service/SendCommentRequestService.java create mode 100644 src/main/java/com/daon/onjung/suggestion/application/service/SendLikeRequestService.java create mode 100644 src/main/java/com/daon/onjung/suggestion/application/usecase/SendCommentRequestUseCase.java create mode 100644 src/main/java/com/daon/onjung/suggestion/application/usecase/SendLikeRequestUseCase.java diff --git a/build.gradle b/build.gradle index b64c238..b86cf2b 100644 --- a/build.gradle +++ b/build.gradle @@ -75,6 +75,10 @@ dependencies { // Secheduler implementation 'org.springframework.boot:spring-boot-starter-quartz' + // RabbitMQ + implementation group: 'org.springframework.amqp', name: 'spring-amqp', version: '3.1.7' + implementation group: 'org.springframework.amqp', name: 'spring-rabbit', version: '3.1.7' + // Testing Dependencies testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' diff --git a/src/main/java/com/daon/onjung/core/config/RabbitMQConfig.java b/src/main/java/com/daon/onjung/core/config/RabbitMQConfig.java new file mode 100644 index 0000000..2347746 --- /dev/null +++ b/src/main/java/com/daon/onjung/core/config/RabbitMQConfig.java @@ -0,0 +1,58 @@ +package com.daon.onjung.core.config; + +import org.springframework.amqp.core.Binding; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.DirectExchange; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.rabbit.annotation.EnableRabbit; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableRabbit +public class RabbitMQConfig { + + @Bean + public DirectExchange boardExchange() { + return new DirectExchange("board-exchange"); + } + + @Bean + public Queue likeQueue() { + return new Queue("like-queue", true); + } + + @Bean + public Queue commentQueue1() { + return new Queue("comment-queue-1", true); + } + + @Bean Queue commentQueue2() { + return new Queue("comment-queue-2", true); + } + + @Bean + public Binding boardQueue1Binding(DirectExchange boardExchange, Queue commentQueue1) { + return BindingBuilder.bind(commentQueue1).to(boardExchange).with("board.1"); + } + + @Bean + public Binding boardQueue2Binding(DirectExchange boardExchange, Queue commentQueue2) { + return BindingBuilder.bind(commentQueue2).to(boardExchange).with("board.0"); + } + + @Bean + public Jackson2JsonMessageConverter jsonMessageConverter() { + return new Jackson2JsonMessageConverter(); + } + + @Bean + public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { + RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + rabbitTemplate.setMessageConverter(jsonMessageConverter()); // JSON 컨버터 μ„€μ • + return rabbitTemplate; + } +} diff --git a/src/main/java/com/daon/onjung/core/exception/error/ErrorCode.java b/src/main/java/com/daon/onjung/core/exception/error/ErrorCode.java index f8f91eb..ad915c8 100644 --- a/src/main/java/com/daon/onjung/core/exception/error/ErrorCode.java +++ b/src/main/java/com/daon/onjung/core/exception/error/ErrorCode.java @@ -43,6 +43,9 @@ public enum ErrorCode { TOKEN_GENERATION_ERROR(40106, HttpStatus.UNAUTHORIZED, "토큰 생성에 μ‹€νŒ¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€."), TOKEN_UNKNOWN_ERROR(40107, HttpStatus.UNAUTHORIZED, "μ•Œ 수 μ—†λŠ” ν† ν°μž…λ‹ˆλ‹€."), + // Conflict Error + OPTIMISTIC_EXCEPTION(40900, HttpStatus.CONFLICT, "Optimistic Locking μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ˜€μŠ΅λ‹ˆλ‹€."), + // Internal Server Error INTERNAL_SERVER_ERROR(50000, HttpStatus.INTERNAL_SERVER_ERROR, "μ„œλ²„ λ‚΄λΆ€ μ—λŸ¬μž…λ‹ˆλ‹€."), INTERNAL_DATA_ERROR(50001, HttpStatus.INTERNAL_SERVER_ERROR, "μ„œλ²„ λ‚΄λΆ€ 데이터 μ—λŸ¬μž…λ‹ˆλ‹€."), diff --git a/src/main/java/com/daon/onjung/suggestion/application/controller/command/SuggestionCommandV1Controller.java b/src/main/java/com/daon/onjung/suggestion/application/controller/command/SuggestionCommandV1Controller.java index 1d67e51..933b997 100644 --- a/src/main/java/com/daon/onjung/suggestion/application/controller/command/SuggestionCommandV1Controller.java +++ b/src/main/java/com/daon/onjung/suggestion/application/controller/command/SuggestionCommandV1Controller.java @@ -48,10 +48,7 @@ public ResponseDto likeBoard( @AccountID UUID accountId, @PathVariable Long id ) { - if (createOrDeleteLikeUseCase.execute(accountId, id)) { - return ResponseDto.created(null); - } else { - return ResponseDto.ok(null); - } + createOrDeleteLikeUseCase.execute(accountId, id); + return ResponseDto.ok(null); } } diff --git a/src/main/java/com/daon/onjung/suggestion/application/controller/consumer/CommentV1Consumer.java b/src/main/java/com/daon/onjung/suggestion/application/controller/consumer/CommentV1Consumer.java new file mode 100644 index 0000000..1a66719 --- /dev/null +++ b/src/main/java/com/daon/onjung/suggestion/application/controller/consumer/CommentV1Consumer.java @@ -0,0 +1,90 @@ +package com.daon.onjung.suggestion.application.controller.consumer; + +import com.daon.onjung.account.domain.User; +import com.daon.onjung.account.repository.mysql.UserRepository; +import com.daon.onjung.core.exception.error.ErrorCode; +import com.daon.onjung.core.exception.type.CommonException; +import com.daon.onjung.suggestion.application.dto.request.CommentMessage; +import com.daon.onjung.suggestion.domain.Board; +import com.daon.onjung.suggestion.domain.Comment; +import com.daon.onjung.suggestion.domain.service.BoardService; +import com.daon.onjung.suggestion.domain.service.CommentService; +import com.daon.onjung.suggestion.repository.mysql.BoardRepository; +import com.daon.onjung.suggestion.repository.mysql.CommentRepository; +import lombok.RequiredArgsConstructor; +import org.hibernate.dialect.lock.OptimisticEntityLockException; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class CommentV1Consumer { + + private final BoardRepository boardRepository; + private final CommentRepository commentRepository; + private final UserRepository userRepository; + + private final CommentService commentService; + private final BoardService boardService; + + @Transactional + @RabbitListener(queues = "comment-queue-1") + public void processCommentMessage1(CommentMessage commentMessage) { + try { + + // κ²Œμ‹œκΈ€ 쑰회 + Board board = boardRepository.findById(commentMessage.boardId()) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // μœ μ € 쑰회 + User user = userRepository.findById(commentMessage.userId()) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // λŒ“κΈ€ 생성 + Comment comment = commentService.createComment( + commentMessage.content(), + user, + board + ); + commentRepository.save(comment); + + // κ²Œμ‹œκΈ€ λŒ“κΈ€ 수 증가 + board = boardService.addCommentCount(board); + boardRepository.save(board); + } catch (OptimisticEntityLockException e) { + throw new CommonException(ErrorCode.OPTIMISTIC_EXCEPTION); + } + } + + @Transactional + @RabbitListener(queues = "comment-queue-2") + public void processCommentMessage2(CommentMessage commentMessage) { + try { + + // κ²Œμ‹œκΈ€ 쑰회 + Board board = boardRepository.findById(commentMessage.boardId()) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // μœ μ € 쑰회 + User user = userRepository.findById(commentMessage.userId()) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // λŒ“κΈ€ 생성 + Comment comment = commentService.createComment( + commentMessage.content(), + user, + board + ); + commentRepository.save(comment); + + // κ²Œμ‹œκΈ€ λŒ“κΈ€ 수 증가 + board = boardService.addCommentCount(board); + boardRepository.save(board); + } catch (OptimisticEntityLockException e) { + throw new CommonException(ErrorCode.OPTIMISTIC_EXCEPTION); + } + } + + +} diff --git a/src/main/java/com/daon/onjung/suggestion/application/controller/consumer/LikeV1Consumer.java b/src/main/java/com/daon/onjung/suggestion/application/controller/consumer/LikeV1Consumer.java new file mode 100644 index 0000000..e4a278d --- /dev/null +++ b/src/main/java/com/daon/onjung/suggestion/application/controller/consumer/LikeV1Consumer.java @@ -0,0 +1,69 @@ +package com.daon.onjung.suggestion.application.controller.consumer; + +import com.daon.onjung.account.domain.User; +import com.daon.onjung.account.repository.mysql.UserRepository; +import com.daon.onjung.core.exception.error.ErrorCode; +import com.daon.onjung.core.exception.type.CommonException; +import com.daon.onjung.suggestion.application.dto.request.LikeMessage; +import com.daon.onjung.suggestion.domain.Board; +import com.daon.onjung.suggestion.domain.Like; +import com.daon.onjung.suggestion.domain.service.BoardService; +import com.daon.onjung.suggestion.domain.service.LikeService; +import com.daon.onjung.suggestion.repository.mysql.BoardRepository; +import com.daon.onjung.suggestion.repository.mysql.LikeRepository; +import lombok.RequiredArgsConstructor; +import org.hibernate.dialect.lock.OptimisticEntityLockException; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class LikeV1Consumer { + + private final LikeRepository likeRepository; + private final BoardRepository boardRepository; + private final UserRepository userRepository; + + private final LikeService likeService; + private final BoardService boardService; + + @Transactional + @RabbitListener(queues = "like-queue") + public void processLikeMessage(LikeMessage likeMessage) { + try { + + // κ²Œμ‹œκΈ€ 쑰회 + Board board = boardRepository.findById(likeMessage.boardId()) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // μœ μ € 쑰회 + User user = userRepository.findById(likeMessage.userId()) + .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); + + // μ’‹μ•„μš”κ°€ μ‘΄μž¬ν•˜λŠ”μ§€ 확인 + Like like = likeRepository.findByBoardAndUser(board, user) + .orElse(null); + + if (like != null) { + + // μ’‹μ•„μš”κ°€ 이미 μ‘΄μž¬ν•˜λ©΄ μ‚­μ œ + likeRepository.delete(like); + // κ²Œμ‹œκΈ€ μ’‹μ•„μš” 수 κ°μ†Œ + board = boardService.subtractLikeCount(board); + boardRepository.save(board); + } else { + + // μ’‹μ•„μš”κ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ 생성 + likeRepository.save(likeService.createLike(user, board)); + + // κ²Œμ‹œκΈ€ μ’‹μ•„μš” 수 증가 + board = boardService.addLikeCount(board); + boardRepository.save(board); + } + } catch (OptimisticEntityLockException e) { + throw new CommonException(ErrorCode.OPTIMISTIC_EXCEPTION); + } + } + +} diff --git a/src/main/java/com/daon/onjung/suggestion/application/controller/producer/CommentV1Producer.java b/src/main/java/com/daon/onjung/suggestion/application/controller/producer/CommentV1Producer.java new file mode 100644 index 0000000..443ae49 --- /dev/null +++ b/src/main/java/com/daon/onjung/suggestion/application/controller/producer/CommentV1Producer.java @@ -0,0 +1,18 @@ +package com.daon.onjung.suggestion.application.controller.producer; + +import com.daon.onjung.suggestion.application.dto.request.CommentMessage; +import com.daon.onjung.suggestion.application.usecase.SendCommentRequestUseCase; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CommentV1Producer { + + private final SendCommentRequestUseCase sendCommentRequestUseCase; + + public void sendComment (CommentMessage commentMessage) { + sendCommentRequestUseCase.execute(commentMessage); + } + +} diff --git a/src/main/java/com/daon/onjung/suggestion/application/controller/producer/LikeV1Producer.java b/src/main/java/com/daon/onjung/suggestion/application/controller/producer/LikeV1Producer.java new file mode 100644 index 0000000..2da27c5 --- /dev/null +++ b/src/main/java/com/daon/onjung/suggestion/application/controller/producer/LikeV1Producer.java @@ -0,0 +1,18 @@ +package com.daon.onjung.suggestion.application.controller.producer; + +import com.daon.onjung.suggestion.application.dto.request.LikeMessage; +import com.daon.onjung.suggestion.application.usecase.SendLikeRequestUseCase; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class LikeV1Producer { + + private final SendLikeRequestUseCase sendLikeRequestUseCase; + + public void sendLike (LikeMessage likeMessage) { + sendLikeRequestUseCase.execute(likeMessage); + } + +} diff --git a/src/main/java/com/daon/onjung/suggestion/application/dto/request/CommentMessage.java b/src/main/java/com/daon/onjung/suggestion/application/dto/request/CommentMessage.java new file mode 100644 index 0000000..6617dc3 --- /dev/null +++ b/src/main/java/com/daon/onjung/suggestion/application/dto/request/CommentMessage.java @@ -0,0 +1,13 @@ +package com.daon.onjung.suggestion.application.dto.request; + +import lombok.Builder; + +import java.util.UUID; + +@Builder +public record CommentMessage( + String content, + Long boardId, + UUID userId +) { +} diff --git a/src/main/java/com/daon/onjung/suggestion/application/dto/request/LikeMessage.java b/src/main/java/com/daon/onjung/suggestion/application/dto/request/LikeMessage.java new file mode 100644 index 0000000..8f96453 --- /dev/null +++ b/src/main/java/com/daon/onjung/suggestion/application/dto/request/LikeMessage.java @@ -0,0 +1,12 @@ +package com.daon.onjung.suggestion.application.dto.request; + +import lombok.Builder; + +import java.util.UUID; + +@Builder +public record LikeMessage( + Long boardId, + UUID userId +) { +} diff --git a/src/main/java/com/daon/onjung/suggestion/application/service/CreateCommentService.java b/src/main/java/com/daon/onjung/suggestion/application/service/CreateCommentService.java index 452ebbd..d90fc7c 100644 --- a/src/main/java/com/daon/onjung/suggestion/application/service/CreateCommentService.java +++ b/src/main/java/com/daon/onjung/suggestion/application/service/CreateCommentService.java @@ -4,14 +4,12 @@ import com.daon.onjung.account.repository.mysql.UserRepository; import com.daon.onjung.core.exception.error.ErrorCode; import com.daon.onjung.core.exception.type.CommonException; +import com.daon.onjung.suggestion.application.controller.producer.CommentV1Producer; +import com.daon.onjung.suggestion.application.dto.request.CommentMessage; import com.daon.onjung.suggestion.application.dto.request.CreateCommentRequestDto; import com.daon.onjung.suggestion.application.usecase.CreateCommentUseCase; import com.daon.onjung.suggestion.domain.Board; -import com.daon.onjung.suggestion.domain.Comment; -import com.daon.onjung.suggestion.domain.service.BoardService; -import com.daon.onjung.suggestion.domain.service.CommentService; import com.daon.onjung.suggestion.repository.mysql.BoardRepository; -import com.daon.onjung.suggestion.repository.mysql.CommentRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -24,10 +22,8 @@ public class CreateCommentService implements CreateCommentUseCase { private final UserRepository userRepository; private final BoardRepository boardRepository; - private final CommentRepository commentRepository; - private final CommentService commentService; - private final BoardService boardService; + private final CommentV1Producer commentProducer; @Override @Transactional @@ -41,16 +37,12 @@ public void execute(UUID accountId, Long boardId, CreateCommentRequestDto reques Board board = boardRepository.findById(boardId) .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); - // λŒ“κΈ€ 생성 - Comment comment = commentService.createComment( - requestDto.content(), - user, - board + // λŒ“κΈ€ 생성 μš”μ²­ λ°œμ†‘ + commentProducer.sendComment(CommentMessage.builder() + .content(requestDto.content()) + .userId(user.getId()) + .boardId(board.getId()) + .build() ); - commentRepository.save(comment); - - // κ²Œμ‹œκΈ€ λŒ“κΈ€ 수 증가 - board = boardService.addCommentCount(board); - boardRepository.save(board); } } diff --git a/src/main/java/com/daon/onjung/suggestion/application/service/CreateOrDeleteLikeService.java b/src/main/java/com/daon/onjung/suggestion/application/service/CreateOrDeleteLikeService.java index 82e3350..6c0089d 100644 --- a/src/main/java/com/daon/onjung/suggestion/application/service/CreateOrDeleteLikeService.java +++ b/src/main/java/com/daon/onjung/suggestion/application/service/CreateOrDeleteLikeService.java @@ -1,16 +1,8 @@ package com.daon.onjung.suggestion.application.service; -import com.daon.onjung.account.domain.User; -import com.daon.onjung.account.repository.mysql.UserRepository; -import com.daon.onjung.core.exception.error.ErrorCode; -import com.daon.onjung.core.exception.type.CommonException; +import com.daon.onjung.suggestion.application.controller.producer.LikeV1Producer; +import com.daon.onjung.suggestion.application.dto.request.LikeMessage; import com.daon.onjung.suggestion.application.usecase.CreateOrDeleteLikeUseCase; -import com.daon.onjung.suggestion.domain.Board; -import com.daon.onjung.suggestion.domain.Like; -import com.daon.onjung.suggestion.domain.service.BoardService; -import com.daon.onjung.suggestion.domain.service.LikeService; -import com.daon.onjung.suggestion.repository.mysql.BoardRepository; -import com.daon.onjung.suggestion.repository.mysql.LikeRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -21,51 +13,16 @@ @RequiredArgsConstructor public class CreateOrDeleteLikeService implements CreateOrDeleteLikeUseCase { - private final BoardRepository boardRepository; - private final UserRepository userRepository; - private final LikeRepository likeRepository; - - private final BoardService boardService; - private final LikeService likeService; - + private final LikeV1Producer likeProducer; @Override @Transactional - public Boolean execute(UUID accountId, Long boardId) { - - // μœ μ € 쑰회 - User user = userRepository.findById(accountId) - .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); - - // κ²Œμ‹œκΈ€ 쑰회 - Board board = boardRepository.findById(boardId) - .orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE)); - - // μ’‹μ•„μš” μ—¬λΆ€ 확인 - Like like = likeRepository.findByBoardAndUser(board, user) - .orElse(null); - - // μ’‹μ•„μš” 생성 λ˜λŠ” μ‚­μ œ - if (like != null) { - - // μ’‹μ•„μš”κ°€ 이미 μ‘΄μž¬ν•˜λ©΄ μ‚­μ œ - likeRepository.delete(like); - - // κ²Œμ‹œκΈ€ μ’‹μ•„μš” 수 κ°μ†Œ - board = boardService.subtractLikeCount(board); - boardRepository.save(board); - - return false; - } else { - - // μ’‹μ•„μš”κ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ 생성 - likeRepository.save(likeService.createLike(user,board)); + public void execute(UUID accountId, Long boardId) { - // κ²Œμ‹œκΈ€ μ’‹μ•„μš” 수 증가 - board = boardService.addLikeCount(board); - boardRepository.save(board); + likeProducer.sendLike(LikeMessage.builder() + .boardId(boardId) + .userId(accountId) + .build()); - return true; - } } } diff --git a/src/main/java/com/daon/onjung/suggestion/application/service/SendCommentRequestService.java b/src/main/java/com/daon/onjung/suggestion/application/service/SendCommentRequestService.java new file mode 100644 index 0000000..fbe176b --- /dev/null +++ b/src/main/java/com/daon/onjung/suggestion/application/service/SendCommentRequestService.java @@ -0,0 +1,24 @@ +package com.daon.onjung.suggestion.application.service; + +import com.daon.onjung.suggestion.application.dto.request.CommentMessage; +import com.daon.onjung.suggestion.application.usecase.SendCommentRequestUseCase; +import lombok.RequiredArgsConstructor; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class SendCommentRequestService implements SendCommentRequestUseCase { + + private final RabbitTemplate rabbitTemplate; + + @Override + public void execute(CommentMessage commentMessage) { + + // λͺ¨λ“ˆλŸ¬ 연산을 μ‚¬μš©ν•˜μ—¬ Queue 뢄리. boardIdκ°€ 짝수인경우 board.0을 톡해 Queue2둜 λΌμš°νŒ… + // ν™€μˆ˜μΈκ²½μš° board.1을 톡해 Queue 1 둜 λΌμš°νŒ… + // Comment의 경우, ν•˜λ‚˜μ˜ κ²Œμ‹œλ¬Όμ— λŒ€ν•΄ μˆœμ„œκ°€ 보μž₯λ˜μ–΄μ•Ό ν•˜λ―€λ‘œ, routingKeyλ₯Ό μ΄μš©ν•΄ boardIdλ₯Ό 기반으둜 λΌμš°νŒ… + String routingKey = "board." + (commentMessage.boardId() % 2); + rabbitTemplate.convertAndSend("board-exchange", routingKey, commentMessage); + } +} diff --git a/src/main/java/com/daon/onjung/suggestion/application/service/SendLikeRequestService.java b/src/main/java/com/daon/onjung/suggestion/application/service/SendLikeRequestService.java new file mode 100644 index 0000000..7fea94b --- /dev/null +++ b/src/main/java/com/daon/onjung/suggestion/application/service/SendLikeRequestService.java @@ -0,0 +1,19 @@ +package com.daon.onjung.suggestion.application.service; + +import com.daon.onjung.suggestion.application.dto.request.LikeMessage; +import com.daon.onjung.suggestion.application.usecase.SendLikeRequestUseCase; +import lombok.RequiredArgsConstructor; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class SendLikeRequestService implements SendLikeRequestUseCase { + + private final RabbitTemplate rabbitTemplate; + + @Override + public void execute(LikeMessage likeMessage) { + rabbitTemplate.convertAndSend("like-queue", likeMessage); + } +} diff --git a/src/main/java/com/daon/onjung/suggestion/application/usecase/CreateOrDeleteLikeUseCase.java b/src/main/java/com/daon/onjung/suggestion/application/usecase/CreateOrDeleteLikeUseCase.java index dadff5f..17bdde5 100644 --- a/src/main/java/com/daon/onjung/suggestion/application/usecase/CreateOrDeleteLikeUseCase.java +++ b/src/main/java/com/daon/onjung/suggestion/application/usecase/CreateOrDeleteLikeUseCase.java @@ -7,5 +7,5 @@ @UseCase public interface CreateOrDeleteLikeUseCase { - Boolean execute(UUID accountId, Long boardId); + void execute(UUID accountId, Long boardId); } diff --git a/src/main/java/com/daon/onjung/suggestion/application/usecase/SendCommentRequestUseCase.java b/src/main/java/com/daon/onjung/suggestion/application/usecase/SendCommentRequestUseCase.java new file mode 100644 index 0000000..5115830 --- /dev/null +++ b/src/main/java/com/daon/onjung/suggestion/application/usecase/SendCommentRequestUseCase.java @@ -0,0 +1,9 @@ +package com.daon.onjung.suggestion.application.usecase; + +import com.daon.onjung.core.annotation.bean.UseCase; +import com.daon.onjung.suggestion.application.dto.request.CommentMessage; + +@UseCase +public interface SendCommentRequestUseCase { + void execute(CommentMessage commentMessage); +} diff --git a/src/main/java/com/daon/onjung/suggestion/application/usecase/SendLikeRequestUseCase.java b/src/main/java/com/daon/onjung/suggestion/application/usecase/SendLikeRequestUseCase.java new file mode 100644 index 0000000..4742a64 --- /dev/null +++ b/src/main/java/com/daon/onjung/suggestion/application/usecase/SendLikeRequestUseCase.java @@ -0,0 +1,9 @@ +package com.daon.onjung.suggestion.application.usecase; + +import com.daon.onjung.core.annotation.bean.UseCase; +import com.daon.onjung.suggestion.application.dto.request.LikeMessage; + +@UseCase +public interface SendLikeRequestUseCase { + void execute(LikeMessage likeMessage); +} diff --git a/src/main/java/com/daon/onjung/suggestion/domain/Board.java b/src/main/java/com/daon/onjung/suggestion/domain/Board.java index 70578ac..959eae7 100644 --- a/src/main/java/com/daon/onjung/suggestion/domain/Board.java +++ b/src/main/java/com/daon/onjung/suggestion/domain/Board.java @@ -39,6 +39,9 @@ public class Board { @Column(name = "comment_count", nullable = false) private Integer commentCount; + @Version // Optimistic Lock μ‚¬μš© + private Long version; + /* -------------------------------------------- */ /* Timestamp Column --------------------------- */ /* -------------------------------------------- */