From dbd87fb9c0004efe85cc160dbb8b896da1da0293 Mon Sep 17 00:00:00 2001 From: seheonnn Date: Sun, 12 May 2024 00:06:13 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20Kafka=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weatherservice/kafka/Consumer.java | 4 +-- .../kafka/DailyWeatherKafkaMessage.java | 1 + .../weatherservice/kafka/KafkaConfig.java | 34 +++++++++---------- .../weatherservice/kafka/Producer.java | 9 +++-- .../service/WeatherService.java | 5 ++- 5 files changed, 25 insertions(+), 28 deletions(-) diff --git a/weather-service/src/main/java/com/waither/weatherservice/kafka/Consumer.java b/weather-service/src/main/java/com/waither/weatherservice/kafka/Consumer.java index 247cc81a..b846262f 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/kafka/Consumer.java +++ b/weather-service/src/main/java/com/waither/weatherservice/kafka/Consumer.java @@ -11,8 +11,8 @@ @RequiredArgsConstructor public class Consumer { - @KafkaListener(topics = "${spring.kafka.template.default-topic}", groupId = "${spring.kafka.consumer.group-id}", containerFactory = "dailyWeatherConcurrentKafkaListenerContainerFactory") - public void dailyWeatherConsume(DailyWeatherKafkaMessage message) { + @KafkaListener(topics = "${spring.kafka.template.topic}", groupId = "${spring.kafka.consumer.group-id}") + public void dailyWeatherConsume(String message) { log.info("Consumer Test ========================== "); log.info("[*] Consumer Message {} ", message); diff --git a/weather-service/src/main/java/com/waither/weatherservice/kafka/DailyWeatherKafkaMessage.java b/weather-service/src/main/java/com/waither/weatherservice/kafka/DailyWeatherKafkaMessage.java index 59e2a524..cb942b12 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/kafka/DailyWeatherKafkaMessage.java +++ b/weather-service/src/main/java/com/waither/weatherservice/kafka/DailyWeatherKafkaMessage.java @@ -4,6 +4,7 @@ import lombok.Builder; +// 우선 문자열로 바람 세기만. 추후 변경 가능성 @Builder public record DailyWeatherKafkaMessage( String pop, diff --git a/weather-service/src/main/java/com/waither/weatherservice/kafka/KafkaConfig.java b/weather-service/src/main/java/com/waither/weatherservice/kafka/KafkaConfig.java index 28afe049..d1a1a2c0 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/kafka/KafkaConfig.java +++ b/weather-service/src/main/java/com/waither/weatherservice/kafka/KafkaConfig.java @@ -11,15 +11,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.kafka.annotation.EnableKafka; -import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; import org.springframework.kafka.core.ConsumerFactory; import org.springframework.kafka.core.DefaultKafkaConsumerFactory; import org.springframework.kafka.core.DefaultKafkaProducerFactory; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.kafka.core.ProducerFactory; -import org.springframework.kafka.listener.ContainerProperties; import org.springframework.kafka.support.serializer.JsonDeserializer; -import org.springframework.kafka.support.serializer.JsonSerializer; import lombok.extern.slf4j.Slf4j; @@ -35,36 +32,37 @@ public class KafkaConfig { private String groupId; @Bean - public ProducerFactory dailyWeatherProducerFactory() { + public ProducerFactory producerFactory() { Map config = new HashMap<>(); config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServer); config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); - config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); + config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); return new DefaultKafkaProducerFactory<>(config); } @Bean - public KafkaTemplate dailyWeatherKafkaTemplate() { - return new KafkaTemplate<>(dailyWeatherProducerFactory()); + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); } @Bean - public ConsumerFactory dailyWeatherConsumerFactory() { + public ConsumerFactory consumerStringFactory() { HashMap config = new HashMap<>(); config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServer); + // Consumer Group config.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); return new DefaultKafkaConsumerFactory<>(config, new StringDeserializer(), - new JsonDeserializer<>(DailyWeatherKafkaMessage.class)); + new JsonDeserializer<>(String.class)); } - @Bean - public ConcurrentKafkaListenerContainerFactory dailyWeatherConcurrentKafkaListenerContainerFactory() { - ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); - factory.setConsumerFactory(dailyWeatherConsumerFactory()); - factory.setConcurrency(3); - factory.setBatchListener(true); - factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.BATCH); - return factory; - } + // @Bean + // public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { + // ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + // factory.setConsumerFactory(dailyWeatherConsumerFactory()); + // factory.setConcurrency(3); + // factory.setBatchListener(true); + // factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.BATCH); + // return factory; + // } } diff --git a/weather-service/src/main/java/com/waither/weatherservice/kafka/Producer.java b/weather-service/src/main/java/com/waither/weatherservice/kafka/Producer.java index 3a701c8c..057fa514 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/kafka/Producer.java +++ b/weather-service/src/main/java/com/waither/weatherservice/kafka/Producer.java @@ -12,14 +12,13 @@ @RequiredArgsConstructor public class Producer { - private final KafkaTemplate DailyWeatherKafkaTemplate; + private final KafkaTemplate kafkaTemplate; - @Value("${spring.kafka.template.default-topic}") + @Value("${spring.kafka.template.topic}") private String topic; - public void dailyWeatherProduceMessage(DailyWeatherKafkaMessage message) { - log.info("=================== Topic : {} ===================", topic); + public void dailyWeatherProduceMessage(String message) { log.info("[*] Producer Message : {}", message); - DailyWeatherKafkaTemplate.send(topic, message); + kafkaTemplate.send(topic, message); } } diff --git a/weather-service/src/main/java/com/waither/weatherservice/service/WeatherService.java b/weather-service/src/main/java/com/waither/weatherservice/service/WeatherService.java index 3d19623b..fa7603b6 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/service/WeatherService.java +++ b/weather-service/src/main/java/com/waither/weatherservice/service/WeatherService.java @@ -11,7 +11,6 @@ import com.waither.weatherservice.entity.DailyWeather; import com.waither.weatherservice.entity.DisasterMessage; import com.waither.weatherservice.entity.ExpectedWeather; -import com.waither.weatherservice.kafka.DailyWeatherKafkaMessage; import com.waither.weatherservice.kafka.Producer; import com.waither.weatherservice.openapi.ForeCastOpenApiResponse; import com.waither.weatherservice.openapi.MsgOpenApiResponse; @@ -96,9 +95,9 @@ public void createDailyWeather(int nx, .windDegree(wsd) .build(); - DailyWeatherKafkaMessage kafkaMessage = DailyWeatherKafkaMessage.from(dailyWeather); + // DailyWeatherKafkaMessage kafkaMessage = DailyWeatherKafkaMessage.from(dailyWeather); - producer.dailyWeatherProduceMessage(kafkaMessage); + producer.dailyWeatherProduceMessage(wsd); // DailyWeather save = dailyWeatherRepository.save(dailyWeather); log.info("[*] 하루 온도 : {}", dailyWeather); From 6c2acb6cf18346ec946dcd9fe7bd24ff355b6aa9 Mon Sep 17 00:00:00 2001 From: seheonnn Date: Sun, 12 May 2024 00:46:46 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=E2=9C=A8=20=20feat:=20Api=20Docs=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- weather-service/build.gradle | 15 +++ weather-service/docs/weather.json | 182 ++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 weather-service/docs/weather.json diff --git a/weather-service/build.gradle b/weather-service/build.gradle index 33758a4f..ee0a9f34 100644 --- a/weather-service/build.gradle +++ b/weather-service/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'org.springframework.boot' version '3.2.3' id 'io.spring.dependency-management' version '1.1.4' + id "org.springdoc.openapi-gradle-plugin" version '1.8.0' } group = 'com.waither' @@ -45,6 +46,20 @@ dependencies { // Redis implementation 'org.springframework.boot:spring-boot-starter-data-redis' + + //Springdoc + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' +} + +openApi { + apiDocsUrl.set("http://localhost:3000") // Document URL + outputDir.set(file("$rootDir/docs")) // Build Result Path + outputFileName.set("weather.json") // Build Result File Name + groupedApiMappings.set(Map.of("http://localhost:8081/weather/api-docs", "weather.json")) + waitTimeInSeconds.set(60) // Timeout + customBootRun { + args.add("--spring.profiles.active=dev") + } } dependencyManagement { diff --git a/weather-service/docs/weather.json b/weather-service/docs/weather.json new file mode 100644 index 00000000..765d6691 --- /dev/null +++ b/weather-service/docs/weather.json @@ -0,0 +1,182 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost:8081", + "description": "Generated server url" + } + ], + "paths": { + "/api/v1/weather/short": { + "post": { + "tags": [ + "weather-test-controller" + ], + "operationId": "createExpectedWeatherTest", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForeCastTestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/weather/msg": { + "post": { + "tags": [ + "weather-test-controller" + ], + "operationId": "createDisasterMsgTest", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MsgTestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/weather/daily": { + "post": { + "tags": [ + "weather-test-controller" + ], + "operationId": "createDailyWeatherTest", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ForeCastTestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/weather/air": { + "post": { + "tags": [ + "weather-test-controller" + ], + "operationId": "airKoreaTest", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AirTestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/api/v1/weather/accuweather": { + "post": { + "tags": [ + "weather-test-controller" + ], + "operationId": "accuweatherTest", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccuweatherTestRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "ForeCastTestRequest": { + "type": "object", + "properties": { + "nx": { + "type": "integer", + "format": "int32" + }, + "ny": { + "type": "integer", + "format": "int32" + }, + "baseDate": { + "type": "string" + }, + "baseTime": { + "type": "string" + } + } + }, + "MsgTestRequest": { + "type": "object", + "properties": { + "location": { + "type": "string" + } + } + }, + "AirTestRequest": { + "type": "object", + "properties": { + "searchDate": { + "type": "string" + } + } + }, + "AccuweatherTestRequest": { + "type": "object", + "properties": { + "latitude": { + "type": "number", + "format": "double" + }, + "longitude": { + "type": "number", + "format": "double" + } + } + } + } + } +} \ No newline at end of file From d69073b2486862ab68a289eb33a697442c1cd75c Mon Sep 17 00:00:00 2001 From: seheonnn Date: Mon, 13 May 2024 11:42:46 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor:=20Kafka=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=9A=A9=20Consumer=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=EC=A0=84=EC=86=A1?= =?UTF-8?q?=20=EB=82=B4=EC=9A=A9=20=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weatherservice/kafka/Consumer.java | 31 ++++++++----------- .../weatherservice/kafka/Producer.java | 2 +- .../service/WeatherService.java | 5 ++- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/weather-service/src/main/java/com/waither/weatherservice/kafka/Consumer.java b/weather-service/src/main/java/com/waither/weatherservice/kafka/Consumer.java index b846262f..4afd624a 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/kafka/Consumer.java +++ b/weather-service/src/main/java/com/waither/weatherservice/kafka/Consumer.java @@ -1,20 +1,15 @@ package com.waither.weatherservice.kafka; -import org.springframework.kafka.annotation.KafkaListener; -import org.springframework.stereotype.Component; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -@Component -@RequiredArgsConstructor -public class Consumer { - - @KafkaListener(topics = "${spring.kafka.template.topic}", groupId = "${spring.kafka.consumer.group-id}") - public void dailyWeatherConsume(String message) { - - log.info("Consumer Test ========================== "); - log.info("[*] Consumer Message {} ", message); - } -} +// 테스트용 Consumer +// @Slf4j +// @Component +// @RequiredArgsConstructor +// public class Consumer { +// +// @KafkaListener(topics = "${spring.kafka.template.topic}", groupId = "${spring.kafka.consumer.group-id}") +// public void dailyWeatherConsume(String message) { +// +// log.info("Consumer Test ========================== "); +// log.info("[*] Consumer Message {} ", message); +// } +// } diff --git a/weather-service/src/main/java/com/waither/weatherservice/kafka/Producer.java b/weather-service/src/main/java/com/waither/weatherservice/kafka/Producer.java index 057fa514..868c2298 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/kafka/Producer.java +++ b/weather-service/src/main/java/com/waither/weatherservice/kafka/Producer.java @@ -17,7 +17,7 @@ public class Producer { @Value("${spring.kafka.template.topic}") private String topic; - public void dailyWeatherProduceMessage(String message) { + public void produceMessage(String message) { log.info("[*] Producer Message : {}", message); kafkaTemplate.send(topic, message); } diff --git a/weather-service/src/main/java/com/waither/weatherservice/service/WeatherService.java b/weather-service/src/main/java/com/waither/weatherservice/service/WeatherService.java index fa7603b6..8d120d2c 100644 --- a/weather-service/src/main/java/com/waither/weatherservice/service/WeatherService.java +++ b/weather-service/src/main/java/com/waither/weatherservice/service/WeatherService.java @@ -61,7 +61,6 @@ public void createExpectedWeather( .expectedSky(expectedSkyList) .build(); - // TODO 조회 테스트 후 삭제 예정 ExpectedWeather save = expectedWeatherRepository.save(expectedWeather); log.info("[*] 예상 기후 : {}", save); } @@ -97,7 +96,8 @@ public void createDailyWeather(int nx, // DailyWeatherKafkaMessage kafkaMessage = DailyWeatherKafkaMessage.from(dailyWeather); - producer.dailyWeatherProduceMessage(wsd); + // 바람 세기 Kafka 전송 + producer.produceMessage(wsd); // DailyWeather save = dailyWeatherRepository.save(dailyWeather); log.info("[*] 하루 온도 : {}", dailyWeather); @@ -117,7 +117,6 @@ public void createDisasterMsg(String location) throws URISyntaxException, IOExce .message(msg) .build(); - // TODO 조회 테스트 후 삭제 예정 DisasterMessage save = disasterMessageRepository.save(disasterMessage); log.info("[*] 재난 문자 : {}", save); }