From 108a8fba8196a1eecc221cd516e8f1d947533f7e Mon Sep 17 00:00:00 2001 From: yeezze Date: Mon, 8 May 2023 18:58:43 +0900 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20gitignore=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 48d5102..37563e7 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,5 @@ out/ application*.properties schema -test.html \ No newline at end of file +test.html +TestController.java \ No newline at end of file From b8654ffae1818fc844bf0bcbe3aa5387d70ce289 Mon Sep 17 00:00:00 2001 From: yeezze Date: Mon, 8 May 2023 18:59:12 +0900 Subject: [PATCH 2/3] =?UTF-8?q?chore:=20rabbitmq=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index 43ac43f..1c2968b 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,10 @@ dependencies { testImplementation 'org.awaitility:awaitility' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + + // rabbitmq + implementation 'org.springframework.boot:spring-boot-starter-amqp' + testImplementation 'org.springframework.amqp:spring-rabbit-test' } tasks.named('test') { From fc1dd9b9be16fc3709f7ca60f25b1a18132bf0e6 Mon Sep 17 00:00:00 2001 From: yeezze Date: Mon, 8 May 2023 19:14:03 +0900 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20rabbitmq=20=ED=99=9C=EC=9A=A9=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 이후 AnswerList 데이터를 외부 MQ로 옮기는 작업 때 활용 예정 --- .../AnswerQueueListRequestDto.java | 18 +++++ .../messagingQueue/AnswerQueueRequestDto.java | 25 ++++++ .../domain/messagingQueue/Consumer.java | 44 +++++++++++ .../domain/messagingQueue/Producer.java | 18 +++++ .../global/config/RabbitmqConfig.java | 77 +++++++++++++++++++ 5 files changed, 182 insertions(+) create mode 100644 src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/AnswerQueueListRequestDto.java create mode 100644 src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/AnswerQueueRequestDto.java create mode 100644 src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/Consumer.java create mode 100644 src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/Producer.java create mode 100644 src/main/java/com/example/fffserver/global/config/RabbitmqConfig.java diff --git a/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/AnswerQueueListRequestDto.java b/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/AnswerQueueListRequestDto.java new file mode 100644 index 0000000..df33298 --- /dev/null +++ b/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/AnswerQueueListRequestDto.java @@ -0,0 +1,18 @@ +package com.example.fffserver.domain.answer.domain.messagingQueue; + +import java.util.List; +import lombok.Getter; + +@Getter +public class AnswerQueueListRequestDto { + + private List answerList; + + // 필드 1개인 경우 Jackson 이슈 + public AnswerQueueListRequestDto() { + } + + public AnswerQueueListRequestDto(List answerList) { + this.answerList = answerList; + } +} diff --git a/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/AnswerQueueRequestDto.java b/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/AnswerQueueRequestDto.java new file mode 100644 index 0000000..eb64cbd --- /dev/null +++ b/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/AnswerQueueRequestDto.java @@ -0,0 +1,25 @@ +package com.example.fffserver.domain.answer.domain.messagingQueue; + +import lombok.Getter; + +@Getter +public class AnswerQueueRequestDto { + + private String answerId; + private String userId; + private String content; + private String formId; + private String questionId; + + public AnswerQueueRequestDto() { + } + + public AnswerQueueRequestDto(String answerId, String userId, String content, String formId, + String questionId) { + this.answerId = answerId; + this.userId = userId; + this.content = content; + this.formId = formId; + this.questionId = questionId; + } +} diff --git a/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/Consumer.java b/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/Consumer.java new file mode 100644 index 0000000..5418573 --- /dev/null +++ b/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/Consumer.java @@ -0,0 +1,44 @@ +package com.example.fffserver.domain.answer.domain.messagingQueue; + +import com.example.fffserver.domain.answer.application.AnswerService; +import com.example.fffserver.domain.answer.domain.entity.Answer; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.nio.charset.StandardCharsets; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.springframework.amqp.core.Message; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Component; + +// TODO: RabbitMQ -> 카프카로 변경 +@Component +@Slf4j +public class Consumer { + + private AnswerService answerService; + + public Consumer(AnswerService answerService) { + this.answerService = answerService; + } + + @RabbitListener(queues = "answer.queue") + public void consume(Message message) throws JsonProcessingException { + String messageString = new String(message.getBody(), StandardCharsets.UTF_8); + + ObjectMapper objectMapper = new ObjectMapper(); + AnswerQueueListRequestDto answerQueueListRequestDto = objectMapper.readValue(messageString, + AnswerQueueListRequestDto.class); + + log.info("answerId: {}", answerQueueListRequestDto.getAnswerList().get(0).getAnswerId()); + log.info("userId: {}", answerQueueListRequestDto.getAnswerList().get(0).getUserId()); + log.info("content: {}", answerQueueListRequestDto.getAnswerList().get(0).getContent()); + + // TODO: DB 삽입 + } + + // DB insert + public void insert(List answerList) { + answerService.mappedQuestionAndInsert(answerList); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/Producer.java b/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/Producer.java new file mode 100644 index 0000000..61d660e --- /dev/null +++ b/src/main/java/com/example/fffserver/domain/answer/domain/messagingQueue/Producer.java @@ -0,0 +1,18 @@ +package com.example.fffserver.domain.answer.domain.messagingQueue; + +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.stereotype.Component; + +@Component +public class Producer { + + private final RabbitTemplate rabbitTemplate; + + public Producer(RabbitTemplate rabbitTemplate) { + this.rabbitTemplate = rabbitTemplate; + } + + public void sendMessage(AnswerQueueListRequestDto message) { + rabbitTemplate.convertAndSend("answer.exchange", "answer.key", message); + } +} diff --git a/src/main/java/com/example/fffserver/global/config/RabbitmqConfig.java b/src/main/java/com/example/fffserver/global/config/RabbitmqConfig.java new file mode 100644 index 0000000..29a12d8 --- /dev/null +++ b/src/main/java/com/example/fffserver/global/config/RabbitmqConfig.java @@ -0,0 +1,77 @@ +package com.example.fffserver.global.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.config.SimpleRabbitListenerContainerFactory; +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class RabbitmqConfig { + + @Value("${spring.rabbitmq.host}") + private String host; + + @Value("${spring.rabbitmq.username}") + private String username; + + @Value("${spring.rabbitmq.password}") + private String password; + + @Value("${spring.rabbitmq.port}") + private int port; + + @Bean + Queue queue() { + return new Queue("answer.queue", false); + } + + @Bean + DirectExchange directExchange() { + return new DirectExchange("answer.exchange"); + } + + @Bean + Binding binding(DirectExchange directExchange, Queue queue) { + return BindingBuilder.bind(queue).to(directExchange).with("answer.key"); + } + + @Bean + RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) { + RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + rabbitTemplate.setMessageConverter(messageConverter); + return rabbitTemplate; + } + + @Bean + ConnectionFactory connectionFactory() { + CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); + connectionFactory.setHost(host); + connectionFactory.setPort(port); + connectionFactory.setUsername(username); + connectionFactory.setPassword(password); + return connectionFactory; + } + + @Bean + MessageConverter messageConverter() { + return new Jackson2JsonMessageConverter(); + } + + @Bean + SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory(ConnectionFactory connectionFactory) { + final SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); + factory.setConnectionFactory(connectionFactory); + factory.setMessageConverter(messageConverter()); + return factory; + } +}