Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

πŸ”¨ Refactor/#177 - RabbitMQ의 RPC μš”μ²­-응닡 νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ—¬ λŒ“κΈ€ 및 μ’‹μ•„μš” 생성 μ‹œ, ResponseBody λ°˜ν™˜ν•˜κ²Œ λ³€κ²½ #178

Merged
merged 2 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ public Jackson2JsonMessageConverter jsonMessageConverter() {
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(jsonMessageConverter()); // JSON 컨버터 μ„€μ •
rabbitTemplate.setMessageConverter(jsonMessageConverter());
rabbitTemplate.setReplyTimeout(5000);
rabbitTemplate.setUseDirectReplyToContainer(true);
return rabbitTemplate;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.daon.onjung.core.dto.ResponseDto;
import com.daon.onjung.suggestion.application.dto.request.CreateBoardRequestDto;
import com.daon.onjung.suggestion.application.dto.request.CreateCommentRequestDto;
import com.daon.onjung.suggestion.application.dto.response.CreateCommentResponseDto;
import com.daon.onjung.suggestion.application.dto.response.CreateOrDeleteLikeResponseDto;
import com.daon.onjung.suggestion.application.usecase.CreateBoardUseCase;
import com.daon.onjung.suggestion.application.usecase.CreateCommentUseCase;
import com.daon.onjung.suggestion.application.usecase.CreateOrDeleteLikeUseCase;
Expand Down Expand Up @@ -34,21 +36,19 @@ public ResponseDto<Void> createBoard(
}

@PostMapping("/api/v1/boards/{id}/comments")
public ResponseDto<Void> createComment(
public ResponseDto<CreateCommentResponseDto> createComment(
@AccountID UUID accountId,
@PathVariable Long id,
@RequestBody @Valid CreateCommentRequestDto requestDto
) {
createCommentUseCase.execute(accountId, id, requestDto);
return ResponseDto.created(null);
return ResponseDto.created(createCommentUseCase.execute(accountId, id, requestDto));
}

@PutMapping("/api/v1/boards/{id}/likes")
public ResponseDto<Void> likeBoard(
public ResponseDto<CreateOrDeleteLikeResponseDto> likeBoard(
@AccountID UUID accountId,
@PathVariable Long id
) {
createOrDeleteLikeUseCase.execute(accountId, id);
return ResponseDto.ok(null);
return ResponseDto.ok(createOrDeleteLikeUseCase.execute(accountId, id));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
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.application.dto.response.CreateCommentResponseDto;
import com.daon.onjung.suggestion.domain.Board;
import com.daon.onjung.suggestion.domain.Comment;
import com.daon.onjung.suggestion.domain.service.BoardService;
Expand All @@ -14,6 +15,7 @@
import lombok.RequiredArgsConstructor;
import org.hibernate.dialect.lock.OptimisticEntityLockException;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -28,9 +30,11 @@ public class CommentV1Consumer {
private final CommentService commentService;
private final BoardService boardService;

private final RabbitTemplate rabbitTemplate;

@Transactional
@RabbitListener(queues = "comment-queue-1")
public void processCommentMessage1(CommentMessage commentMessage) {
public CreateCommentResponseDto processCommentMessage1(CommentMessage commentMessage) {
try {

// κ²Œμ‹œκΈ€ 쑰회
Expand All @@ -52,14 +56,16 @@ public void processCommentMessage1(CommentMessage commentMessage) {
// κ²Œμ‹œκΈ€ λŒ“κΈ€ 수 증가
board = boardService.addCommentCount(board);
boardRepository.save(board);

return CreateCommentResponseDto.of(user, true, comment);
} catch (OptimisticEntityLockException e) {
throw new CommonException(ErrorCode.OPTIMISTIC_EXCEPTION);
}
}

@Transactional
@RabbitListener(queues = "comment-queue-2")
public void processCommentMessage2(CommentMessage commentMessage) {
public CreateCommentResponseDto processCommentMessage2(CommentMessage commentMessage) {
try {

// κ²Œμ‹œκΈ€ 쑰회
Expand All @@ -81,6 +87,8 @@ public void processCommentMessage2(CommentMessage commentMessage) {
// κ²Œμ‹œκΈ€ λŒ“κΈ€ 수 증가
board = boardService.addCommentCount(board);
boardRepository.save(board);

return CreateCommentResponseDto.of(user, true, comment);
} catch (OptimisticEntityLockException e) {
throw new CommonException(ErrorCode.OPTIMISTIC_EXCEPTION);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
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.application.dto.response.CreateOrDeleteLikeResponseDto;
import com.daon.onjung.suggestion.domain.Board;
import com.daon.onjung.suggestion.domain.Like;
import com.daon.onjung.suggestion.domain.service.BoardService;
Expand All @@ -30,7 +31,7 @@ public class LikeV1Consumer {

@Transactional
@RabbitListener(queues = "like-queue")
public void processLikeMessage(LikeMessage likeMessage) {
public Boolean processLikeMessage(LikeMessage likeMessage) {
try {

// κ²Œμ‹œκΈ€ 쑰회
Expand All @@ -52,6 +53,7 @@ public void processLikeMessage(LikeMessage likeMessage) {
// κ²Œμ‹œκΈ€ μ’‹μ•„μš” 수 κ°μ†Œ
board = boardService.subtractLikeCount(board);
boardRepository.save(board);
return false;
} else {

// μ’‹μ•„μš”κ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμœΌλ©΄ 생성
Expand All @@ -60,6 +62,7 @@ public void processLikeMessage(LikeMessage likeMessage) {
// κ²Œμ‹œκΈ€ μ’‹μ•„μš” 수 증가
board = boardService.addLikeCount(board);
boardRepository.save(board);
return true;
}
} catch (OptimisticEntityLockException e) {
throw new CommonException(ErrorCode.OPTIMISTIC_EXCEPTION);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.daon.onjung.suggestion.application.controller.producer;

import com.daon.onjung.suggestion.application.dto.request.CommentMessage;
import com.daon.onjung.suggestion.application.dto.response.CreateCommentResponseDto;
import com.daon.onjung.suggestion.application.usecase.SendCommentRequestUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -11,8 +12,8 @@ public class CommentV1Producer {

private final SendCommentRequestUseCase sendCommentRequestUseCase;

public void sendComment (CommentMessage commentMessage) {
sendCommentRequestUseCase.execute(commentMessage);
public CreateCommentResponseDto sendComment (CommentMessage commentMessage) {
return sendCommentRequestUseCase.execute(commentMessage);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.daon.onjung.suggestion.application.controller.producer;

import com.daon.onjung.suggestion.application.dto.request.LikeMessage;
import com.daon.onjung.suggestion.application.dto.response.CreateOrDeleteLikeResponseDto;
import com.daon.onjung.suggestion.application.usecase.SendLikeRequestUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -11,8 +12,8 @@ public class LikeV1Producer {

private final SendLikeRequestUseCase sendLikeRequestUseCase;

public void sendLike (LikeMessage likeMessage) {
sendLikeRequestUseCase.execute(likeMessage);
public CreateOrDeleteLikeResponseDto sendLike (LikeMessage likeMessage) {
return sendLikeRequestUseCase.execute(likeMessage);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.daon.onjung.suggestion.application.dto.response;

import com.daon.onjung.account.domain.User;
import com.daon.onjung.core.dto.SelfValidating;
import com.daon.onjung.core.utility.DateTimeUtil;
import com.daon.onjung.suggestion.domain.Comment;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Getter;

@Getter
public class CreateCommentResponseDto extends SelfValidating<CreateCommentResponseDto> {

@JsonProperty("writer_info")
private final WriterInfoDto writerInfo;

@JsonProperty("comment_info")
private final CommentInfoDto commentInfo;

@Builder
public CreateCommentResponseDto(WriterInfoDto writerInfo, CommentInfoDto commentInfo) {
this.writerInfo = writerInfo;
this.commentInfo = commentInfo;

this.validateSelf();
}

@Getter
public static class WriterInfoDto extends SelfValidating<WriterInfoDto> {

@JsonProperty("profile_img_url")
private final String profileImgUrl;

@JsonProperty("masked_nickname")
private final String maskedNickname;

@JsonProperty("is_me")
private final Boolean isMe;

@Builder
public WriterInfoDto(String profileImgUrl, String maskedNickname, Boolean isMe) {
this.profileImgUrl = profileImgUrl;
this.maskedNickname = maskedNickname;
this.isMe = isMe;

this.validateSelf();
}

public static WriterInfoDto of(User user, Boolean isMe) {
String nickname = user.getNickName();
String maskedNickname;

if (nickname.length() == 1) {
maskedNickname = nickname;
} else if (nickname.length() == 2) {
maskedNickname = nickname.charAt(0) + "*";
} else {
String firstChar = nickname.substring(0, 1);
String lastChar = nickname.substring(nickname.length() - 1);
String middleMask = "*".repeat(nickname.length() - 2);
maskedNickname = firstChar + middleMask + lastChar;
}

return WriterInfoDto.builder()
.maskedNickname(maskedNickname)
.profileImgUrl(user.getProfileImgUrl())
.isMe(isMe)
.build();
}
}

@Getter
public static class CommentInfoDto extends SelfValidating<CommentInfoDto> {

@JsonProperty("id")
private final Long id;

@JsonProperty("content")
private final String content;

@JsonProperty("posted_at")
private final String postedAt;

@Builder
public CommentInfoDto(Long id, String content, String postedAt) {
this.id = id;
this.content = content;
this.postedAt = postedAt;

this.validateSelf();
}

public static CommentInfoDto fromEntity(Comment comment) {
return CommentInfoDto.builder()
.id(comment.getId())
.content(comment.getContent())
.postedAt(DateTimeUtil.calculatePostedAgo(comment.getCreatedAt()))
.build();
}
}

public static CreateCommentResponseDto of(User user, Boolean isMe, Comment comment) {
return CreateCommentResponseDto.builder()
.writerInfo(WriterInfoDto.of(user, isMe))
.commentInfo(CommentInfoDto.fromEntity(comment))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.daon.onjung.suggestion.application.dto.response;

import com.daon.onjung.core.dto.SelfValidating;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Getter;

@Getter
public class CreateOrDeleteLikeResponseDto extends SelfValidating<CreateOrDeleteLikeResponseDto> {

@JsonProperty("is_like")
private final Boolean isLike;

@Builder
public CreateOrDeleteLikeResponseDto(Boolean isLike) {
this.isLike = isLike;

this.validateSelf();
}

public static CreateOrDeleteLikeResponseDto of(Boolean isLike) {
return CreateOrDeleteLikeResponseDto.builder()
.isLike(isLike)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
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.dto.response.CreateCommentResponseDto;
import com.daon.onjung.suggestion.application.usecase.CreateCommentUseCase;
import com.daon.onjung.suggestion.domain.Board;
import com.daon.onjung.suggestion.repository.mysql.BoardRepository;
Expand All @@ -27,7 +28,7 @@ public class CreateCommentService implements CreateCommentUseCase {

@Override
@Transactional
public void execute(UUID accountId, Long boardId, CreateCommentRequestDto requestDto) {
public CreateCommentResponseDto execute(UUID accountId, Long boardId, CreateCommentRequestDto requestDto) {

// μœ μ € 쑰회
User user = userRepository.findById(accountId)
Expand All @@ -38,7 +39,7 @@ public void execute(UUID accountId, Long boardId, CreateCommentRequestDto reques
.orElseThrow(() -> new CommonException(ErrorCode.NOT_FOUND_RESOURCE));

// λŒ“κΈ€ 생성 μš”μ²­ λ°œμ†‘
commentProducer.sendComment(CommentMessage.builder()
return commentProducer.sendComment(CommentMessage.builder()
.content(requestDto.content())
.userId(user.getId())
.boardId(board.getId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.daon.onjung.suggestion.application.controller.producer.LikeV1Producer;
import com.daon.onjung.suggestion.application.dto.request.LikeMessage;
import com.daon.onjung.suggestion.application.dto.response.CreateOrDeleteLikeResponseDto;
import com.daon.onjung.suggestion.application.usecase.CreateOrDeleteLikeUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -17,9 +18,9 @@ public class CreateOrDeleteLikeService implements CreateOrDeleteLikeUseCase {

@Override
@Transactional
public void execute(UUID accountId, Long boardId) {
public CreateOrDeleteLikeResponseDto execute(UUID accountId, Long boardId) {

likeProducer.sendLike(LikeMessage.builder()
return likeProducer.sendLike(LikeMessage.builder()
.boardId(boardId)
.userId(accountId)
.build());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.daon.onjung.suggestion.application.service;

import com.daon.onjung.suggestion.application.dto.request.CommentMessage;
import com.daon.onjung.suggestion.application.dto.response.CreateCommentResponseDto;
import com.daon.onjung.suggestion.application.usecase.SendCommentRequestUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
Expand All @@ -13,12 +14,11 @@ public class SendCommentRequestService implements SendCommentRequestUseCase {
private final RabbitTemplate rabbitTemplate;

@Override
public void execute(CommentMessage commentMessage) {

public CreateCommentResponseDto 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);
return (CreateCommentResponseDto) rabbitTemplate.convertSendAndReceive("board-exchange", routingKey, commentMessage);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.daon.onjung.suggestion.application.service;

import com.daon.onjung.suggestion.application.dto.request.LikeMessage;
import com.daon.onjung.suggestion.application.dto.response.CreateOrDeleteLikeResponseDto;
import com.daon.onjung.suggestion.application.usecase.SendLikeRequestUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
Expand All @@ -13,7 +14,9 @@ public class SendLikeRequestService implements SendLikeRequestUseCase {
private final RabbitTemplate rabbitTemplate;

@Override
public void execute(LikeMessage likeMessage) {
rabbitTemplate.convertAndSend("like-queue", likeMessage);
public CreateOrDeleteLikeResponseDto execute(LikeMessage likeMessage) {

Boolean response = (Boolean) rabbitTemplate.convertSendAndReceive("like-queue", likeMessage);
return CreateOrDeleteLikeResponseDto.of(response);
}
}
Loading