From 3ce2c1414d72a3d4c73f7f4d0725450b66d0054e Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 16:27:48 +0900 Subject: [PATCH 01/24] =?UTF-8?q?=F0=9F=93=9Ddocs=20:=20kafka=20yml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- noti-service/src/main/resources/bootstrap.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noti-service/src/main/resources/bootstrap.yml b/noti-service/src/main/resources/bootstrap.yml index 92e343bd..9d5208bd 100644 --- a/noti-service/src/main/resources/bootstrap.yml +++ b/noti-service/src/main/resources/bootstrap.yml @@ -9,7 +9,7 @@ spring: cloud: config: uri: http://localhost:8888 - name: database-noti,redis + name: database-noti, redis, kafka kafka: bootstrap-servers: "localhost:9092" From 38272499a07f0fcc372d4a4733889dcbc8da2b37 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 16:28:38 +0900 Subject: [PATCH 02/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Fkafka=20:=20User-servic?= =?UTF-8?q?e=20Kafka=20=EB=8F=99=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/KafkaConsumerConfig.java | 44 ++++++++---- .../notiservice/domain/UserMedian.java | 17 +++-- .../notiservice/dto/kafka/KafkaDto.java | 68 +++++++++++++++++++ .../notiservice/dto/kafka/TokenDto.java | 24 ------- .../notiservice/dto/kafka/UserMedianDto.java | 20 ------ .../dto/kafka/UserSettingsDto.java | 19 ------ .../notiservice/service/KafkaConsumer.java | 66 ++++++++++-------- 7 files changed, 145 insertions(+), 113 deletions(-) create mode 100644 noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java delete mode 100644 noti-service/src/main/java/com/waither/notiservice/dto/kafka/TokenDto.java delete mode 100644 noti-service/src/main/java/com/waither/notiservice/dto/kafka/UserMedianDto.java delete mode 100644 noti-service/src/main/java/com/waither/notiservice/dto/kafka/UserSettingsDto.java diff --git a/noti-service/src/main/java/com/waither/notiservice/config/KafkaConsumerConfig.java b/noti-service/src/main/java/com/waither/notiservice/config/KafkaConsumerConfig.java index 0accca1e..bfb71eae 100644 --- a/noti-service/src/main/java/com/waither/notiservice/config/KafkaConsumerConfig.java +++ b/noti-service/src/main/java/com/waither/notiservice/config/KafkaConsumerConfig.java @@ -1,8 +1,6 @@ package com.waither.notiservice.config; -import com.waither.notiservice.dto.kafka.TokenDto; -import com.waither.notiservice.dto.kafka.UserMedianDto; -import com.waither.notiservice.dto.kafka.UserSettingsDto; +import com.waither.notiservice.dto.kafka.KafkaDto; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.common.serialization.StringDeserializer; import org.springframework.beans.factory.annotation.Value; @@ -81,8 +79,8 @@ public ConsumerFactory stringConsumerFactory() { @Bean("userMedianKafkaListenerContainerFactory") - public ConcurrentKafkaListenerContainerFactory userMedianDtoConcurrentKafkaListenerContainerFactory(){ - ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + public ConcurrentKafkaListenerContainerFactory userMedianDtoConcurrentKafkaListenerContainerFactory(){ + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); factory.setConsumerFactory(userMedianConsumerFactory()); factory.setConcurrency(3); factory.setBatchListener(true); @@ -90,16 +88,16 @@ public ConcurrentKafkaListenerContainerFactory userMedian return factory; } - private ConsumerFactory userMedianConsumerFactory() { + private ConsumerFactory userMedianConsumerFactory() { Map props = dtoSettings(); - return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(UserMedianDto.class)); + return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(KafkaDto.UserMedianDto.class)); } @Bean("firebaseTokenKafkaListenerContainerFactory") - public ConcurrentKafkaListenerContainerFactory firebaseTokenConcurrentKafkaListenerContainerFactory(){ - ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + public ConcurrentKafkaListenerContainerFactory firebaseTokenConcurrentKafkaListenerContainerFactory(){ + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); factory.setConsumerFactory(firebaseTokenConsumerFactory()); factory.setConcurrency(3); factory.setBatchListener(true); @@ -107,16 +105,16 @@ public ConcurrentKafkaListenerContainerFactory firebaseTokenCo return factory; } - private ConsumerFactory firebaseTokenConsumerFactory() { + private ConsumerFactory firebaseTokenConsumerFactory() { Map props = dtoSettings(); - return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(TokenDto.class)); + return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(KafkaDto.TokenDto.class)); } @Bean("userSettingsKafkaListenerContainerFactory") - public ConcurrentKafkaListenerContainerFactory userSettingsConcurrentKafkaListenerContainerFactory(){ - ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + public ConcurrentKafkaListenerContainerFactory userSettingsConcurrentKafkaListenerContainerFactory(){ + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); factory.setConsumerFactory(userSettingsConsumerFactory()); factory.setConcurrency(3); factory.setBatchListener(true); @@ -124,9 +122,25 @@ public ConcurrentKafkaListenerContainerFactory userSett return factory; } - private ConsumerFactory userSettingsConsumerFactory() { + private ConsumerFactory userSettingsConsumerFactory() { Map props = dtoSettings(); - return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(UserSettingsDto.class)); + return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(KafkaDto.UserSettingsDto.class)); + } + + + @Bean("initialDataKafkaListenerContainerFactory") + public ConcurrentKafkaListenerContainerFactory initialDataConcurrentKafkaListenerContainerFactory(){ + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(initialDataConsumerFactory()); + factory.setConcurrency(3); + factory.setBatchListener(true); + factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.BATCH); + return factory; + } + + private ConsumerFactory initialDataConsumerFactory() { + Map props = dtoSettings(); + return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(KafkaDto.InitialDataDto.class)); } diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java b/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java index cdb757b7..b3a12a28 100644 --- a/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java +++ b/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java @@ -1,6 +1,7 @@ package com.waither.notiservice.domain; import com.waither.notiservice.domain.type.Season; +import com.waither.notiservice.dto.kafka.KafkaDto; import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.DynamicInsert; @@ -24,12 +25,18 @@ public class UserMedian { @Enumerated(value = EnumType.STRING) public Season season; - public void setLevel(int level, double value) { + public void setLevel(String level, Double value) { switch (level) { - case 1 -> medianOf1And2 = value; - case 2 -> medianOf2And3 = value; - case 3 -> medianOf3And4 = value; - case 4 -> medianOf4And5 = value; + case "medianOf1And2" -> medianOf1And2 = value; + case "medianOf2And3" -> medianOf2And3 = value; + case "medianOf3And4" -> medianOf3And4 = value; + case "medianOf4And5" -> medianOf4And5 = value; } } + + public void setLevel(KafkaDto.UserMedianDto userMedianDto) { + userMedianDto.medians().forEach(median -> + median.forEach(this::setLevel) + ); + } } diff --git a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java new file mode 100644 index 00000000..9f336404 --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java @@ -0,0 +1,68 @@ +package com.waither.notiservice.dto.kafka; + +import com.waither.notiservice.domain.UserData; +import com.waither.notiservice.domain.UserMedian; +import com.waither.notiservice.utils.TemperatureUtils; +import lombok.Builder; + +import java.util.List; +import java.util.Map; + +public class KafkaDto { + + public record InitialDataDto( + + String nickName, + boolean climateAlert, + boolean userAlert, + boolean snowAlert, + boolean windAlert, + Integer windDegree, + boolean regionReport, + Double weight, + Double medianOf1And2, + Double medianOf2And3, + Double medianOf3And4, + Double medianOf4And5 + ) { + public UserData toUserDataEntity() { + return UserData.builder() + .userId(0L) + .climateAlert(climateAlert) + .userAlert(userAlert) + .snowAlert(snowAlert) + .windAlert(windAlert) + .windDegree(windDegree) + .regionReport(regionReport) + .build(); + } + + public UserMedian toUserMedianEntity() { + return UserMedian.builder() + .season(TemperatureUtils.getCurrentSeason()) + .medianOf1And2(medianOf1And2 + weight) + .medianOf2And3(medianOf2And3 + weight) + .medianOf3And4(medianOf3And4 + weight) + .medianOf4And5(medianOf4And5 + weight) + .build(); + } + } + + public record UserMedianDto( + Long userId, + List> medians + + ) {} + + public record UserSettingsDto( + Long userId, + String key, + String value + ) {} + + public record TokenDto( + Long userId, + String token + ){} + +} diff --git a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/TokenDto.java b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/TokenDto.java deleted file mode 100644 index 4fdc256e..00000000 --- a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/TokenDto.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.waither.notiservice.dto.kafka; - -import com.waither.notiservice.domain.FireBaseToken; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class TokenDto { - - public Long userId; - public String token; - - public FireBaseToken toEntity() { - return FireBaseToken.builder() - .userId(userId) - .token(token) - .build(); - } -} diff --git a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/UserMedianDto.java b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/UserMedianDto.java deleted file mode 100644 index f3cfd341..00000000 --- a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/UserMedianDto.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.waither.notiservice.dto.kafka; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@AllArgsConstructor -@NoArgsConstructor -@Builder -@Getter -public class UserMedianDto { - - public Long userId; - - public int level; - - public double temperature; - -} diff --git a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/UserSettingsDto.java b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/UserSettingsDto.java deleted file mode 100644 index 4b32fa4f..00000000 --- a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/UserSettingsDto.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.waither.notiservice.dto.kafka; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class UserSettingsDto { - - public Long userId; - - public String key; - - public String value; -} diff --git a/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java b/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java index 2f6fb3ac..07eb0dcf 100644 --- a/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java +++ b/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java @@ -3,9 +3,7 @@ import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; import com.waither.notiservice.domain.type.Season; -import com.waither.notiservice.dto.kafka.TokenDto; -import com.waither.notiservice.dto.kafka.UserMedianDto; -import com.waither.notiservice.dto.kafka.UserSettingsDto; +import com.waither.notiservice.dto.kafka.KafkaDto; import com.waither.notiservice.global.exception.CustomException; import com.waither.notiservice.global.response.ErrorCode; import com.waither.notiservice.repository.UserDataRepository; @@ -31,34 +29,33 @@ public class KafkaConsumer { private final UserDataRepository userDataRepository; private final UserMedianRepository userMedianRepository; - private final RedisUtils redisUtils; /** * 중앙값 동기화 Listener * */ - @KafkaListener(topics = "user-median", containerFactory = "userMedianKafkaListenerContainerFactory") - public void consumeUserMedian(UserMedianDto userMedianDto) { + @KafkaListener(topics = "${spring.kafka.template.user-median-topic}", containerFactory = "userMedianKafkaListenerContainerFactory") + public void consumeUserMedian(KafkaDto.UserMedianDto userMedianDto) { Season season = TemperatureUtils.getCurrentSeason(); log.info("[ Kafka Listener ] 사용자 중앙값 데이터 동기화"); log.info("[ Kafka Listener ] Season : -- {} ", season.name()); - log.info("[ Kafka Listener ] User Id : --> {}", userMedianDto.getUserId()); - log.info("[ Kafka Listener ] Level : --> {}", userMedianDto.getLevel()); - log.info("[ Kafka Listener ] Temperature : --> {}", userMedianDto.getTemperature()); + log.info("[ Kafka Listener ] User Id : --> {}", userMedianDto.userId()); + - Optional userMedian = userMedianRepository.findById(userMedianDto.getUserId()); - if (userMedian.isPresent()) { + Optional optionalUserMedian = userMedianRepository.findById(userMedianDto.userId()); + if (optionalUserMedian.isPresent()) { //User Median 이미 있을 경우 - userMedian.get() - .setLevel(userMedianDto.getLevel(), userMedianDto.getTemperature()); + UserMedian userMedian = optionalUserMedian.get(); + userMedian.setLevel(userMedianDto); + userMedianRepository.save(userMedian); + } else { - //User Median 없을 경우 (생성) + //User Median 없을 경우 생성 UserMedian newUserMedian = UserMedian.builder() - .userId(userMedianDto.getUserId()) + .userId(userMedianDto.userId()) .build(); - newUserMedian.setLevel(userMedianDto.getLevel(), - userMedianDto.getTemperature()); + newUserMedian.setLevel(userMedianDto); userMedianRepository.save(newUserMedian); } @@ -70,42 +67,50 @@ public void consumeUserMedian(UserMedianDto userMedianDto) { * Firebase Token Listener * */ @KafkaListener(topics = "firebase-token", containerFactory = "firebaseTokenKafkaListenerContainerFactory") - public void consumeFirebaseToken(TokenDto tokenDto) { + public void consumeFirebaseToken(KafkaDto.TokenDto tokenDto) { log.info("[ Kafka Listener ] Firebase Token 동기화"); - log.info("[ Kafka Listener ] User Id : --> {}", tokenDto.getUserId()); - log.info("[ Kafka Listener ] Token : --> {}", tokenDto.getToken()); + log.info("[ Kafka Listener ] User Id : --> {}", tokenDto.userId()); + log.info("[ Kafka Listener ] Token : --> {}", tokenDto.token()); //토큰 Redis 저장 - redisUtils.save(String.valueOf(tokenDto.getUserId()), tokenDto.getToken()); + redisUtils.save(String.valueOf(tokenDto.userId()), tokenDto.token()); } /** * User Settings Listener * */ - @KafkaListener(topics = "user-settings", containerFactory = "userSettingsKafkaListenerContainerFactory") - public void consumeUserSettings(UserSettingsDto userSettingsDto) { + @KafkaListener(topics = "${spring.kafka.template.user-settings-topic}", containerFactory = "userSettingsKafkaListenerContainerFactory") + public void consumeUserSettings(KafkaDto.UserSettingsDto userSettingsDto) { log.info("[ Kafka Listener ] 사용자 설정값 데이터 동기화"); - log.info("[ Kafka Listener ] User Id : --> {}", userSettingsDto.getUserId()); - log.info("[ Kafka Listener ] Key : --> {}", userSettingsDto.getKey()); - log.info("[ Kafka Listener ] Value : --> {}", userSettingsDto.getValue()); + log.info("[ Kafka Listener ] User Id : --> {}", userSettingsDto.userId()); + log.info("[ Kafka Listener ] Key : --> {}", userSettingsDto.key()); + log.info("[ Kafka Listener ] Value : --> {}", userSettingsDto.value()); - Optional userData = userDataRepository.findById(userSettingsDto.getUserId()); + Optional userData = userDataRepository.findById(userSettingsDto.userId()); if (userData.isPresent()) { - userData.get().updateValue(userSettingsDto.getKey(), userSettingsDto.getValue()); + userData.get().updateValue(userSettingsDto.key(), userSettingsDto.value()); userDataRepository.save(userData.get()); } else { UserData newUserData = UserData.builder() - .userId(userSettingsDto.getUserId()) + .userId(userSettingsDto.userId()) .build(); - newUserData.updateValue(userSettingsDto.getKey(), userSettingsDto.getValue()); + newUserData.updateValue(userSettingsDto.key(), userSettingsDto.value()); userDataRepository.save(newUserData); } } + @KafkaListener(topics = "${spring.kafka.template.initial-data-topic}", containerFactory = "initialDataKafkaListenerContainerFactory") + public void consumeUserInit(KafkaDto.InitialDataDto initialDataDto) { + + log.info("[ Kafka Listener ] 초기 설정값 세팅"); + log.info("[ Kafka Listener ] user --> {}", initialDataDto.nickName()); + userDataRepository.save(initialDataDto.toUserDataEntity()); + userMedianRepository.save(initialDataDto.toUserMedianEntity()); + } @@ -185,4 +190,5 @@ private void sendAlarms(List userIds, String message) { System.out.printf("[ 푸시알림 ] message ---> {%s}", message); }); } + } From 4bf454049736a01aea46cec4f1693c9ed51b6be2 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 16:33:50 +0900 Subject: [PATCH 03/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Fkafka=20:=20Kafka=20Dto?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/KafkaConsumerTest.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java b/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java index 43eaa0f1..bbb4ff1f 100644 --- a/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java +++ b/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java @@ -1,9 +1,7 @@ package com.waither.notiservice.service; import com.waither.notiservice.domain.UserData; -import com.waither.notiservice.dto.kafka.TokenDto; -import com.waither.notiservice.dto.kafka.UserMedianDto; -import com.waither.notiservice.dto.kafka.UserSettingsDto; +import com.waither.notiservice.dto.kafka.KafkaDto; import com.waither.notiservice.repository.UserDataRepository; import com.waither.notiservice.repository.UserMedianRepository; import com.waither.notiservice.utils.RedisUtils; @@ -26,6 +24,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -75,16 +74,17 @@ static void beforeAll() { @Transactional //Transaction 후 Rollback (작동하지 않음. Listener 로 작동해서?) void userMedianTest() throws InterruptedException { //Given - ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); - KafkaTemplate template = new KafkaTemplate<>(pf); + ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); + KafkaTemplate template = new KafkaTemplate<>(pf); //when - UserMedianDto userMedianDto = UserMedianDto.builder() + KafkaDto.UserMedianDto userMedianDto = KafkaDto.UserMedianDto.builder() .userId(0L) - .level(1) - .temperature(10.5) + .medians(List.of( + Map.of("medianOf1And2", 10.5)) + ) .build(); - CompletableFuture> future = template.send("user-median", userMedianDto); + CompletableFuture> future = template.send("user-median", userMedianDto); //then future.whenComplete(((result, throwable) -> { @@ -112,15 +112,15 @@ void userMedianTest() throws InterruptedException { @Transactional //Transaction 후 Rollback (작동하지 않음. Listener 로 작동해서?) void firebaseTokenTest() throws InterruptedException { //Given - ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); - KafkaTemplate template = new KafkaTemplate<>(pf); + ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); + KafkaTemplate template = new KafkaTemplate<>(pf); //when - TokenDto tokenDto = TokenDto.builder() + KafkaDto.TokenDto tokenDto = KafkaDto.TokenDto.builder() .userId(0L) .token("test token") .build(); - CompletableFuture> future = template.send("firebase-token", tokenDto); + CompletableFuture> future = template.send("firebase-token", tokenDto); //then future.whenComplete(((result, throwable) -> { @@ -143,21 +143,21 @@ void firebaseTokenTest() throws InterruptedException { @Transactional //Transaction 후 Rollback (작동하지 않음. Listener 로 작동해서?) void userSettingsWindDegreeTest() throws InterruptedException { //Given - ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); - KafkaTemplate template = new KafkaTemplate<>(pf); + ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); + KafkaTemplate template = new KafkaTemplate<>(pf); //when userDataRepository.save(UserData.builder() .windDegree(11) .userId(0L) .build()); - UserSettingsDto userSettingsDto = UserSettingsDto.builder() + KafkaDto.UserSettingsDto userSettingsDto = KafkaDto.UserSettingsDto.builder() .userId(0L) .key("windDegree") .value("11") .build(); - CompletableFuture> future = template.send("user-settings", userSettingsDto); + CompletableFuture> future = template.send("user-settings", userSettingsDto); //then future.whenComplete(((result, throwable) -> { From 54051cf533440547cbb81faea409cf73880bf9ed Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 16:34:06 +0900 Subject: [PATCH 04/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Fkafka=20:=20Kafka=20Dto?= =?UTF-8?q?=20Builder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/waither/notiservice/dto/kafka/KafkaDto.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java index 9f336404..a5823ac1 100644 --- a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java +++ b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java @@ -48,18 +48,21 @@ public UserMedian toUserMedianEntity() { } } + @Builder public record UserMedianDto( Long userId, List> medians ) {} + @Builder public record UserSettingsDto( Long userId, String key, String value ) {} + @Builder public record TokenDto( Long userId, String token From aa6510b6ed5342b68430eebaa59199b478d83a42 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 19:31:44 +0900 Subject: [PATCH 05/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20@AuthUse?= =?UTF-8?q?r=20=EC=9D=B8=EA=B0=80=EA=B3=BC=EC=A0=95=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/NotificationController.java | 18 +++--- .../global/annotation/AuthUser.java | 14 +++++ .../annotation/AuthUserArgumentResolver.java | 33 ++++++++++ .../service/NotificationService.java | 63 +++++++++++++------ 4 files changed, 100 insertions(+), 28 deletions(-) create mode 100644 noti-service/src/main/java/com/waither/notiservice/global/annotation/AuthUser.java create mode 100644 noti-service/src/main/java/com/waither/notiservice/global/annotation/AuthUserArgumentResolver.java diff --git a/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java b/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java index 80a13357..549c37b2 100644 --- a/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java +++ b/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java @@ -1,6 +1,7 @@ package com.waither.notiservice.api; import com.waither.notiservice.api.request.LocationDto; +import com.waither.notiservice.global.annotation.AuthUser; import com.waither.notiservice.global.response.ApiResponse; import com.waither.notiservice.service.NotificationService; import com.waither.notiservice.utils.RedisUtils; @@ -17,31 +18,30 @@ public class NotificationController { private final NotificationService notificationService; - private final RedisUtils redisUtils; @Operation(summary = "Get notification", description = "알림 목록 조회하기") @GetMapping("") - public ApiResponse getNotifications(Long userId) { - return ApiResponse.onSuccess(notificationService.getNotifications(userId)); + public ApiResponse getNotifications(@AuthUser String email) { + return ApiResponse.onSuccess(notificationService.getNotifications(email)); } @Operation(summary = "Delete notification", description = "알림 삭제하기") @DeleteMapping("") - public ApiResponse deleteNotification(@RequestParam("id") String notificationId) { - notificationService.deleteNotification(notificationId); + public ApiResponse deleteNotification(@AuthUser String email, @RequestParam("id") String notificationId) { + notificationService.deleteNotification(email, notificationId); return ApiResponse.onSuccess(HttpStatus.OK); } @Operation(summary = "Send Go Out Alarm", description = "외출 알림 전송하기") @PostMapping("/goOut") - public void sendGoOutAlarm(Long userId) { - notificationService.sendGoOutAlarm(userId); + public void sendGoOutAlarm(@AuthUser String email) { + notificationService.sendGoOutAlarm(email); } @Operation(summary = "Current Location", description = "현재 위치 전송") @PostMapping("/location") - public void checkCurrentAlarm(@RequestBody @Valid LocationDto locationDto) { - notificationService.checkCurrentAlarm(locationDto); + public void checkCurrentAlarm(@AuthUser String email, @RequestBody @Valid LocationDto locationDto) { + notificationService.checkCurrentAlarm(email, locationDto); } } diff --git a/noti-service/src/main/java/com/waither/notiservice/global/annotation/AuthUser.java b/noti-service/src/main/java/com/waither/notiservice/global/annotation/AuthUser.java new file mode 100644 index 00000000..c6ff4143 --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/global/annotation/AuthUser.java @@ -0,0 +1,14 @@ +package com.waither.notiservice.global.annotation; + +import io.swagger.v3.oas.annotations.Parameter; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@Parameter(hidden = true) //Swagger에서 파라미터 숨기기 +public @interface AuthUser { +} diff --git a/noti-service/src/main/java/com/waither/notiservice/global/annotation/AuthUserArgumentResolver.java b/noti-service/src/main/java/com/waither/notiservice/global/annotation/AuthUserArgumentResolver.java new file mode 100644 index 00000000..e49fa5e7 --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/global/annotation/AuthUserArgumentResolver.java @@ -0,0 +1,33 @@ +package com.waither.notiservice.global.annotation; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +@Component +@RequiredArgsConstructor +@Transactional +public class AuthUserArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter parameter) { + boolean hasParameterAnnotation = parameter.hasParameterAnnotation(AuthUser.class); + boolean isUserParameterType = parameter.getParameterType().isAssignableFrom(String.class); + return hasParameterAnnotation && isUserParameterType; + } + + @Override + public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { + HttpServletRequest httpServletRequest = (HttpServletRequest) webRequest.getNativeRequest(); + + return httpServletRequest.getHeader("email"); + } +} diff --git a/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java b/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java index ec416767..73ca1ca5 100644 --- a/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java +++ b/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java @@ -1,18 +1,23 @@ package com.waither.notiservice.service; import com.waither.notiservice.api.response.NotificationResponse; +import com.waither.notiservice.domain.Notification; import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; import com.waither.notiservice.api.request.LocationDto; +import com.waither.notiservice.domain.redis.NotificationRecord; +import com.waither.notiservice.domain.type.Season; import com.waither.notiservice.global.exception.CustomException; import com.waither.notiservice.global.response.ErrorCode; -import com.waither.notiservice.repository.NotificationRepository; -import com.waither.notiservice.repository.UserDataRepository; -import com.waither.notiservice.repository.UserMedianRepository; +import com.waither.notiservice.repository.jpa.NotificationRepository; +import com.waither.notiservice.repository.jpa.UserDataRepository; +import com.waither.notiservice.repository.jpa.UserMedianRepository; +import com.waither.notiservice.repository.redis.NotificationRecordRepository; import com.waither.notiservice.utils.TemperatureUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @@ -22,28 +27,38 @@ public class NotificationService { private final NotificationRepository notificationRepository; - private final UserMedianRepository userMedianRepository; - private final UserDataRepository userDataRepository; + private final NotificationRecordRepository notificationRecordRepository; - public List getNotifications(Long userId) { + @Transactional(readOnly = true) + public List getNotifications(String email) { - return notificationRepository.findAllByUserId(userId) + return notificationRepository.findAllByEmail(email) .stream().map(NotificationResponse::of).toList(); } - public void deleteNotification(String notificationId) { - notificationRepository.deleteById(notificationId); + @Transactional + public void deleteNotification(String email, String notificationId) { + Notification notification = notificationRepository.findById(notificationId).orElseThrow(() -> new CustomException(ErrorCode.NOT_FOUND_404)); + + if (!notification.getEmail().equals(email)) { + throw new CustomException(ErrorCode.UNAUTHORIZED_401); + } + + notificationRepository.delete(notification); } - public String sendGoOutAlarm(Long userId) { + @Transactional + public String sendGoOutAlarm(String email) { - UserData userData = userDataRepository.findById(userId).orElseThrow( + UserData userData = userDataRepository.findByEmail(email).orElseThrow( () -> new CustomException(ErrorCode.NO_USER_DATA_REGISTERED)); + Season currentSeason = TemperatureUtils.getCurrentSeason(); + String finalMessage = ""; /** @@ -59,10 +74,12 @@ public String sendGoOutAlarm(Long userId) { * {@link com.waither.notiservice.enums.Expressions} 참고 */ double temperature = 10.8; + if (userData.isUserAlert()) { //사용자 맞춤 알림이 on이라면 -> 계산 후 전용 정보 제공 - UserMedian userMedian = userMedianRepository.findById(userId).orElseThrow( + UserMedian userMedian = userMedianRepository.findByEmailAndSeason(email, currentSeason).orElseThrow( () -> new CustomException(ErrorCode.NO_USER_MEDIAN_REGISTERED)); + finalMessage += TemperatureUtils.createUserDataMessage(userMedian, temperature); } else { //사용자 맞춤 알림이 off라면 -> 하루 평균 온도 정보 제공 @@ -94,19 +111,27 @@ public String sendGoOutAlarm(Long userId) { //TODO : FireBase 알림 보내기 log.info("[ Notification Service ] Final Message ---> {}", finalMessage); + //알림 저장 + notificationRepository.save(Notification.builder() + .email(email) + .title("출근 날씨 알림") + .content(finalMessage) + .build()); + return finalMessage; } - //현재 위치 공유 -> 상시 알림 검사 - public void checkCurrentAlarm(LocationDto locationDto) { + //현재 위치 업데이트 + @Transactional + public void checkCurrentAlarm(String email, LocationDto locationDto) { + + log.info("[ Notification Service ] email ---> {}", email); + log.info("[ Notification Service ] 현재 위치 위도 (x) ---> {}", locationDto.getX()); + log.info("[ Notification Service ] 현재 위치 경도 (y) ---> {}", locationDto.getY()); - log.info("[ Notification Service ] 현재 위치 공유 위도 (x) ---> {}", locationDto.getX()); - log.info("[ Notification Service ] 현재 위치 공유 위도 (y) ---> {}", locationDto.getY()); + notificationRecordRepository.findByEmail(email); - //TODO : 현재 지역에 강수량 정보가 있는지? - //TODO : 현재 지역에 바람 세기 정보는 있는지? - //TODO : 만약 알림 내용이 있다면 전송하기 } } From e82198e7f56f3d68b0483b231f1bd5481749ae58 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 19:32:24 +0900 Subject: [PATCH 06/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=20=EC=8B=9D=EB=B3=84=EC=9E=90=20email?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/waither/notiservice/domain/FireBaseToken.java | 2 +- .../com/waither/notiservice/domain/Notification.java | 2 +- .../java/com/waither/notiservice/domain/UserData.java | 2 +- .../com/waither/notiservice/domain/UserMedian.java | 2 +- .../com/waither/notiservice/dto/kafka/KafkaDto.java | 11 ++++++----- .../repository/{ => jpa}/NotificationRepository.java | 5 +++-- .../repository/{ => jpa}/UserDataRepository.java | 8 ++++++-- .../repository/{ => jpa}/UserMedianRepository.java | 9 +++++++-- .../notiservice/service/KafkaConsumerTest.java | 4 ++-- 9 files changed, 28 insertions(+), 17 deletions(-) rename noti-service/src/main/java/com/waither/notiservice/repository/{ => jpa}/NotificationRepository.java (69%) rename noti-service/src/main/java/com/waither/notiservice/repository/{ => jpa}/UserDataRepository.java (62%) rename noti-service/src/main/java/com/waither/notiservice/repository/{ => jpa}/UserMedianRepository.java (52%) diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/FireBaseToken.java b/noti-service/src/main/java/com/waither/notiservice/domain/FireBaseToken.java index 29f459da..22f77668 100644 --- a/noti-service/src/main/java/com/waither/notiservice/domain/FireBaseToken.java +++ b/noti-service/src/main/java/com/waither/notiservice/domain/FireBaseToken.java @@ -11,7 +11,7 @@ public class FireBaseToken { @Id - private Long userId; + private String email; private String token; } diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/Notification.java b/noti-service/src/main/java/com/waither/notiservice/domain/Notification.java index fb17100b..810b8adf 100644 --- a/noti-service/src/main/java/com/waither/notiservice/domain/Notification.java +++ b/noti-service/src/main/java/com/waither/notiservice/domain/Notification.java @@ -20,6 +20,6 @@ public class Notification extends BaseEntity { private String content; - private Long userId; + private String email; } diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/UserData.java b/noti-service/src/main/java/com/waither/notiservice/domain/UserData.java index 246c2df8..112badec 100644 --- a/noti-service/src/main/java/com/waither/notiservice/domain/UserData.java +++ b/noti-service/src/main/java/com/waither/notiservice/domain/UserData.java @@ -16,7 +16,7 @@ public class UserData { @Id - private Long userId; + private String email; private String nickName; diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java b/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java index b3a12a28..e6a8580d 100644 --- a/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java +++ b/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java @@ -16,7 +16,7 @@ public class UserMedian { @Id - private Long userId; + private String email; private Double medianOf1And2; private Double medianOf2And3; private Double medianOf3And4; diff --git a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java index a5823ac1..31aeb2ea 100644 --- a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java +++ b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java @@ -12,7 +12,7 @@ public class KafkaDto { public record InitialDataDto( - String nickName, + String email, boolean climateAlert, boolean userAlert, boolean snowAlert, @@ -27,7 +27,7 @@ public record InitialDataDto( ) { public UserData toUserDataEntity() { return UserData.builder() - .userId(0L) + .email(email) .climateAlert(climateAlert) .userAlert(userAlert) .snowAlert(snowAlert) @@ -39,6 +39,7 @@ public UserData toUserDataEntity() { public UserMedian toUserMedianEntity() { return UserMedian.builder() + .email(email) .season(TemperatureUtils.getCurrentSeason()) .medianOf1And2(medianOf1And2 + weight) .medianOf2And3(medianOf2And3 + weight) @@ -50,21 +51,21 @@ public UserMedian toUserMedianEntity() { @Builder public record UserMedianDto( - Long userId, + String email, List> medians ) {} @Builder public record UserSettingsDto( - Long userId, + String email, String key, String value ) {} @Builder public record TokenDto( - Long userId, + String email, String token ){} diff --git a/noti-service/src/main/java/com/waither/notiservice/repository/NotificationRepository.java b/noti-service/src/main/java/com/waither/notiservice/repository/jpa/NotificationRepository.java similarity index 69% rename from noti-service/src/main/java/com/waither/notiservice/repository/NotificationRepository.java rename to noti-service/src/main/java/com/waither/notiservice/repository/jpa/NotificationRepository.java index 231055ed..add74278 100644 --- a/noti-service/src/main/java/com/waither/notiservice/repository/NotificationRepository.java +++ b/noti-service/src/main/java/com/waither/notiservice/repository/jpa/NotificationRepository.java @@ -1,13 +1,14 @@ -package com.waither.notiservice.repository; +package com.waither.notiservice.repository.jpa; import com.waither.notiservice.domain.Notification; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.List; +import java.util.Optional; @Repository public interface NotificationRepository extends JpaRepository { - List findAllByUserId(Long userId); + List findAllByEmail(String email); } diff --git a/noti-service/src/main/java/com/waither/notiservice/repository/UserDataRepository.java b/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserDataRepository.java similarity index 62% rename from noti-service/src/main/java/com/waither/notiservice/repository/UserDataRepository.java rename to noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserDataRepository.java index 5b021e68..854d974e 100644 --- a/noti-service/src/main/java/com/waither/notiservice/repository/UserDataRepository.java +++ b/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserDataRepository.java @@ -1,9 +1,13 @@ -package com.waither.notiservice.repository; +package com.waither.notiservice.repository.jpa; import com.waither.notiservice.domain.UserData; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository -public interface UserDataRepository extends JpaRepository { +public interface UserDataRepository extends JpaRepository { + + Optional findByEmail(String email); } diff --git a/noti-service/src/main/java/com/waither/notiservice/repository/UserMedianRepository.java b/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserMedianRepository.java similarity index 52% rename from noti-service/src/main/java/com/waither/notiservice/repository/UserMedianRepository.java rename to noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserMedianRepository.java index 469ea553..d2162633 100644 --- a/noti-service/src/main/java/com/waither/notiservice/repository/UserMedianRepository.java +++ b/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserMedianRepository.java @@ -1,9 +1,14 @@ -package com.waither.notiservice.repository; +package com.waither.notiservice.repository.jpa; import com.waither.notiservice.domain.UserMedian; +import com.waither.notiservice.domain.type.Season; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository -public interface UserMedianRepository extends JpaRepository { +public interface UserMedianRepository extends JpaRepository { + + Optional findByEmailAndSeason(String email, Season season); } diff --git a/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java b/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java index bbb4ff1f..8e1eebdb 100644 --- a/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java +++ b/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java @@ -2,8 +2,8 @@ import com.waither.notiservice.domain.UserData; import com.waither.notiservice.dto.kafka.KafkaDto; -import com.waither.notiservice.repository.UserDataRepository; -import com.waither.notiservice.repository.UserMedianRepository; +import com.waither.notiservice.repository.jpa.UserDataRepository; +import com.waither.notiservice.repository.jpa.UserMedianRepository; import com.waither.notiservice.utils.RedisUtils; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; From ee0e4d734b390e07b88dfb930541f25e9688a185 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 19:33:11 +0900 Subject: [PATCH 07/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20OAuthCon?= =?UTF-8?q?troller=20Swagger=20hidden?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/redis/NotificationRecord.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java b/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java new file mode 100644 index 00000000..22d2ebb5 --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java @@ -0,0 +1,30 @@ +package com.waither.notiservice.domain.redis; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; +import org.springframework.data.redis.core.RedisHash; + +import java.time.LocalDateTime; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +@RedisHash +public class NotificationRecord { + + //유저 식별자 + private String email; + + //마지막 강수 알림 받은 시간 + private LocalDateTime lastRainAlarmReceived; + + //마지막 바람세기 알림 받은 시간 + private LocalDateTime lastWindAlarmReceived; + + //사용자 마지막 위치 (위도) + private Double lat; + + //사용자 마지막 위치 (경도) + private Double lon; +} From cf988ac48d1e76f2ce622eb42298873597d02ddf Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 19:33:19 +0900 Subject: [PATCH 08/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20OAuthCon?= =?UTF-8?q?troller=20Swagger=20hidden?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/waither/userservice/controller/OAuthController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user-service/src/main/java/com/waither/userservice/controller/OAuthController.java b/user-service/src/main/java/com/waither/userservice/controller/OAuthController.java index 84a72f4e..970a40bd 100644 --- a/user-service/src/main/java/com/waither/userservice/controller/OAuthController.java +++ b/user-service/src/main/java/com/waither/userservice/controller/OAuthController.java @@ -4,6 +4,7 @@ import com.waither.userservice.global.response.ApiResponse; import com.waither.userservice.service.KakaoService; import com.waither.userservice.service.commandService.UserService; +import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -19,6 +20,7 @@ public class OAuthController { private final UserService userService; + @Operation(hidden = true) @GetMapping("/kakao/callback") public ApiResponse callback(@RequestParam("code") String code) { From 3b128f08fb24049720100a14fbcfb3dd1341a101 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 19:35:18 +0900 Subject: [PATCH 09/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=20=EC=8B=9D=EB=B3=84=EC=9E=90=20Email?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notiservice/service/KafkaConsumer.java | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java b/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java index 07eb0dcf..0de0fd0b 100644 --- a/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java +++ b/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java @@ -6,8 +6,8 @@ import com.waither.notiservice.dto.kafka.KafkaDto; import com.waither.notiservice.global.exception.CustomException; import com.waither.notiservice.global.response.ErrorCode; -import com.waither.notiservice.repository.UserDataRepository; -import com.waither.notiservice.repository.UserMedianRepository; +import com.waither.notiservice.repository.jpa.UserDataRepository; +import com.waither.notiservice.repository.jpa.UserMedianRepository; import com.waither.notiservice.utils.RedisUtils; import com.waither.notiservice.utils.TemperatureUtils; import lombok.RequiredArgsConstructor; @@ -37,13 +37,13 @@ public class KafkaConsumer { @KafkaListener(topics = "${spring.kafka.template.user-median-topic}", containerFactory = "userMedianKafkaListenerContainerFactory") public void consumeUserMedian(KafkaDto.UserMedianDto userMedianDto) { - Season season = TemperatureUtils.getCurrentSeason(); + Season currentSeason = TemperatureUtils.getCurrentSeason(); log.info("[ Kafka Listener ] 사용자 중앙값 데이터 동기화"); - log.info("[ Kafka Listener ] Season : -- {} ", season.name()); - log.info("[ Kafka Listener ] User Id : --> {}", userMedianDto.userId()); + log.info("[ Kafka Listener ] Season : -- {} ", currentSeason.name()); + log.info("[ Kafka Listener ] Email : --> {}", userMedianDto.email()); - Optional optionalUserMedian = userMedianRepository.findById(userMedianDto.userId()); + Optional optionalUserMedian = userMedianRepository.findByEmailAndSeason(userMedianDto.email(), currentSeason); if (optionalUserMedian.isPresent()) { //User Median 이미 있을 경우 UserMedian userMedian = optionalUserMedian.get(); @@ -52,14 +52,14 @@ public void consumeUserMedian(KafkaDto.UserMedianDto userMedianDto) { } else { //User Median 없을 경우 생성 + //TODO : 계절당 초기값 받아야 함 UserMedian newUserMedian = UserMedian.builder() - .userId(userMedianDto.userId()) + .email(userMedianDto.email()) + .season(currentSeason) .build(); newUserMedian.setLevel(userMedianDto); userMedianRepository.save(newUserMedian); } - - } @@ -70,11 +70,11 @@ public void consumeUserMedian(KafkaDto.UserMedianDto userMedianDto) { public void consumeFirebaseToken(KafkaDto.TokenDto tokenDto) { log.info("[ Kafka Listener ] Firebase Token 동기화"); - log.info("[ Kafka Listener ] User Id : --> {}", tokenDto.userId()); + log.info("[ Kafka Listener ] Email : --> {}", tokenDto.email()); log.info("[ Kafka Listener ] Token : --> {}", tokenDto.token()); //토큰 Redis 저장 - redisUtils.save(String.valueOf(tokenDto.userId()), tokenDto.token()); + redisUtils.save(tokenDto.email(), tokenDto.token()); } @@ -85,17 +85,18 @@ public void consumeFirebaseToken(KafkaDto.TokenDto tokenDto) { public void consumeUserSettings(KafkaDto.UserSettingsDto userSettingsDto) { log.info("[ Kafka Listener ] 사용자 설정값 데이터 동기화"); - log.info("[ Kafka Listener ] User Id : --> {}", userSettingsDto.userId()); + log.info("[ Kafka Listener ] Email : --> {}", userSettingsDto.email()); log.info("[ Kafka Listener ] Key : --> {}", userSettingsDto.key()); log.info("[ Kafka Listener ] Value : --> {}", userSettingsDto.value()); - Optional userData = userDataRepository.findById(userSettingsDto.userId()); + Optional userData = userDataRepository.findByEmail(userSettingsDto.email()); if (userData.isPresent()) { userData.get().updateValue(userSettingsDto.key(), userSettingsDto.value()); userDataRepository.save(userData.get()); } else { + log.warn("[ Kafka Listener ] User Data 초기값이 없었습니다."); UserData newUserData = UserData.builder() - .userId(userSettingsDto.userId()) + .email(userSettingsDto.email()) .build(); newUserData.updateValue(userSettingsDto.key(), userSettingsDto.value()); userDataRepository.save(newUserData); @@ -107,7 +108,7 @@ public void consumeUserSettings(KafkaDto.UserSettingsDto userSettingsDto) { public void consumeUserInit(KafkaDto.InitialDataDto initialDataDto) { log.info("[ Kafka Listener ] 초기 설정값 세팅"); - log.info("[ Kafka Listener ] user --> {}", initialDataDto.nickName()); + log.info("[ Kafka Listener ] email --> {}", initialDataDto.email()); userDataRepository.save(initialDataDto.toUserDataEntity()); userMedianRepository.save(initialDataDto.toUserMedianEntity()); } @@ -120,7 +121,8 @@ public void consumeUserInit(KafkaDto.InitialDataDto initialDataDto) { * */ @KafkaListener(topics = "alarm-wind") public void consumeWindAlarm(@Payload String message) { - String resultMessage = ""; + StringBuilder sb = new StringBuilder(); + Long windStrength = Long.valueOf(message); //바람세기 log.info("[ Kafka Listener ] 바람 세기"); @@ -130,10 +132,10 @@ public void consumeWindAlarm(@Payload String message) { List userIds = new ArrayList<>(); //TODO : 바람 세기 알림 멘트 정리 - resultMessage += "현재 바람 세기가 " + windStrength + "m/s 이상입니다. 강풍에 주의하세요."; + sb.append("현재 바람 세기가 ").append(windStrength).append("m/s 이상입니다. 강풍에 주의하세요."); System.out.println("[ 푸시알림 ] 바람 세기 알림"); - sendAlarms(userIds, resultMessage); + sendAlarms(userIds, sb.toString()); } @@ -178,15 +180,15 @@ public void consumeClimateAlarm(@Payload String message) { } - private void sendAlarms(List userIds, String message) { - userIds.forEach(id ->{ - String token = String.valueOf(redisUtils.get(String.valueOf(id))); + private void sendAlarms(List userEmails, String message) { + userEmails.forEach(email ->{ + String token = String.valueOf(redisUtils.get(String.valueOf(email))); if (token == null) { //token을 찾지 못했을 경우 throw new CustomException(ErrorCode.FIREBASE_TOKEN_NOT_FOUND); } - System.out.printf("[ 푸시알림 ] userId ---> {%d}", id); + System.out.printf("[ 푸시알림 ] Email ---> {%d}", email); System.out.printf("[ 푸시알림 ] message ---> {%s}", message); }); } From 783901677fc066a7b1f36005ce45c321ba177a8b Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 19:35:32 +0900 Subject: [PATCH 10/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=20=EC=8B=9D=EB=B3=84=EC=9E=90=20Email?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../redis/NotificationRecordRepository.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 noti-service/src/main/java/com/waither/notiservice/repository/redis/NotificationRecordRepository.java diff --git a/noti-service/src/main/java/com/waither/notiservice/repository/redis/NotificationRecordRepository.java b/noti-service/src/main/java/com/waither/notiservice/repository/redis/NotificationRecordRepository.java new file mode 100644 index 00000000..6dc0fcee --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/repository/redis/NotificationRecordRepository.java @@ -0,0 +1,12 @@ +package com.waither.notiservice.repository.redis; + +import com.waither.notiservice.domain.redis.NotificationRecord; +import org.springframework.data.repository.CrudRepository; + +import javax.swing.text.html.Option; +import java.util.Optional; + +public interface NotificationRecordRepository extends CrudRepository { + + Optional findByEmail(String email); +} From ae443f9a2d58245d92db7227795f4480b27fe8d0 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 19:43:12 +0900 Subject: [PATCH 11/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20Test=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=9E=AC=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/KafkaConsumerTest.java | 31 ++++++++------ .../service/NotificationServiceTest.java | 42 +++++++++++-------- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java b/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java index 8e1eebdb..32772553 100644 --- a/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java +++ b/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java @@ -1,10 +1,12 @@ package com.waither.notiservice.service; import com.waither.notiservice.domain.UserData; +import com.waither.notiservice.domain.type.Season; import com.waither.notiservice.dto.kafka.KafkaDto; import com.waither.notiservice.repository.jpa.UserDataRepository; import com.waither.notiservice.repository.jpa.UserMedianRepository; import com.waither.notiservice.utils.RedisUtils; +import com.waither.notiservice.utils.TemperatureUtils; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; import org.junit.jupiter.api.BeforeAll; @@ -76,12 +78,15 @@ void userMedianTest() throws InterruptedException { //Given ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); KafkaTemplate template = new KafkaTemplate<>(pf); + Season currentSeason = TemperatureUtils.getCurrentSeason(); + String tempEmail = "kafkaTest@gmail.com"; //when KafkaDto.UserMedianDto userMedianDto = KafkaDto.UserMedianDto.builder() - .userId(0L) + .email(tempEmail) .medians(List.of( - Map.of("medianOf1And2", 10.5)) + Map.of("medianOf1And2", 10.5), + Map.of("medianOf2And3", 12.5)) ) .build(); CompletableFuture> future = template.send("user-median", userMedianDto); @@ -96,13 +101,13 @@ void userMedianTest() throws InterruptedException { Thread.sleep(2000); //2초 대기 userMedianRepository.findAll().forEach(userMedian -> { - System.out.println(" userId : " + userMedian.getUserId()); + System.out.println(" email : " + userMedian.getEmail()); }); - assertThat(userMedianRepository.findById(0L).get().getMedianOf1And2()).isEqualTo(10.5); + assertThat(userMedianRepository.findByEmailAndSeason(tempEmail, currentSeason).get().getMedianOf1And2()).isEqualTo(10.5); //끝나고 삭제 -> Rollback 일어나지 않아서 - userMedianRepository.deleteById(0L); + userMedianRepository.deleteById(tempEmail); } @@ -114,10 +119,11 @@ void firebaseTokenTest() throws InterruptedException { //Given ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); KafkaTemplate template = new KafkaTemplate<>(pf); + String tempEmail = "kafkaTest@gmail.com"; //when KafkaDto.TokenDto tokenDto = KafkaDto.TokenDto.builder() - .userId(0L) + .email(tempEmail) .token("test token") .build(); CompletableFuture> future = template.send("firebase-token", tokenDto); @@ -132,10 +138,10 @@ void firebaseTokenTest() throws InterruptedException { Thread.sleep(2000); //2초 대기 - assertThat(String.valueOf(redisUtils.get("0"))).isEqualTo("test token"); + assertThat(String.valueOf(redisUtils.get(tempEmail))).isEqualTo("test token"); //끝나고 삭제 -> Rollback 일어나지 않아서 - redisUtils.delete("0"); + redisUtils.delete(tempEmail); } @Test @@ -145,14 +151,15 @@ void userSettingsWindDegreeTest() throws InterruptedException { //Given ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); KafkaTemplate template = new KafkaTemplate<>(pf); + String tempEmail = "kafkaTest@gmail.com"; //when userDataRepository.save(UserData.builder() .windDegree(11) - .userId(0L) + .email(tempEmail) .build()); KafkaDto.UserSettingsDto userSettingsDto = KafkaDto.UserSettingsDto.builder() - .userId(0L) + .email(tempEmail) .key("windDegree") .value("11") .build(); @@ -169,10 +176,10 @@ void userSettingsWindDegreeTest() throws InterruptedException { Thread.sleep(2000); //2초 대기 - assertThat(userDataRepository.findById(0L).get().getWindDegree()).isEqualTo(11); + assertThat(userDataRepository.findByEmail(tempEmail).get().getWindDegree()).isEqualTo(11); //끝나고 삭제 -> Rollback 일어나지 않아서 - userDataRepository.deleteById(0L); + userDataRepository.deleteById(tempEmail); } @Test diff --git a/noti-service/src/test/java/com/waither/notiservice/service/NotificationServiceTest.java b/noti-service/src/test/java/com/waither/notiservice/service/NotificationServiceTest.java index b1685532..1c99e25b 100644 --- a/noti-service/src/test/java/com/waither/notiservice/service/NotificationServiceTest.java +++ b/noti-service/src/test/java/com/waither/notiservice/service/NotificationServiceTest.java @@ -4,20 +4,18 @@ import com.waither.notiservice.domain.Notification; import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; -import com.waither.notiservice.repository.NotificationRepository; -import com.waither.notiservice.repository.UserDataRepository; -import com.waither.notiservice.repository.UserMedianRepository; +import com.waither.notiservice.domain.type.Season; +import com.waither.notiservice.repository.jpa.NotificationRepository; +import com.waither.notiservice.repository.jpa.UserDataRepository; +import com.waither.notiservice.repository.jpa.UserMedianRepository; +import com.waither.notiservice.repository.redis.NotificationRecordRepository; import com.waither.notiservice.utils.TemperatureUtils; import org.junit.jupiter.api.*; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Optional; @@ -41,10 +39,13 @@ public class NotificationServiceTest { @MockBean NotificationRepository notificationRepository; + @MockBean + NotificationRecordRepository notificationRecordRepository; + @BeforeEach void setUp() { //가짜 객체 주입 - notificationService = new NotificationService(notificationRepository, userMedianRepository, userDataRepository); + notificationService = new NotificationService(notificationRepository, userMedianRepository, userDataRepository, notificationRecordRepository); } @Test @@ -53,8 +54,12 @@ void goOutAlarm() { //Given System.out.println("DB Mock 데이터 생성.. userid : 0"); + + String tempEmail = "serviceTest@gmail.com"; + Season currentSeason = TemperatureUtils.getCurrentSeason(); + UserData newUser = UserData.builder() - .userId(0L) + .email(tempEmail) .nickName("추워하는 곰탱이") .climateAlert(true) .regionReport(true) @@ -63,25 +68,25 @@ void goOutAlarm() { .windAlert(true) .windDegree(0) .build(); - Mockito.when(userDataRepository.findById(0L)).thenReturn(Optional.of(newUser)); // (Mock) find시 Return + Mockito.when(userDataRepository.findByEmail(tempEmail)).thenReturn(Optional.of(newUser)); // (Mock) find시 Return UserMedian newUserMedian = UserMedian.builder() - .userId(0L) + .email(tempEmail) .medianOf1And2(12.0) .medianOf2And3(15.0) .medianOf3And4(20.0) .medianOf4And5(25.0) .season(TemperatureUtils.getCurrentSeason()) //현재 계절로 저장 .build(); - Mockito.when(userMedianRepository.findById(0L)).thenReturn(Optional.of(newUserMedian)); // (Mock) find시 Return + Mockito.when(userMedianRepository.findByEmailAndSeason(tempEmail, currentSeason)).thenReturn(Optional.of(newUserMedian)); // (Mock) find시 Return //when - String resultMessage = notificationService.sendGoOutAlarm(0L); + String resultMessage = notificationService.sendGoOutAlarm(tempEmail); //then System.out.println("[ Notification Service Test ] result Message --> "+resultMessage); - assertThat(userDataRepository.findById(0L)).isNotNull(); - assertThat(userMedianRepository.findById(0L)).isNotNull(); + assertThat(userDataRepository.findByEmail(tempEmail)).isNotNull(); + assertThat(userMedianRepository.findByEmailAndSeason(tempEmail, currentSeason)).isNotNull(); assertThat(resultMessage).isNotBlank(); } @@ -89,16 +94,17 @@ void goOutAlarm() { @DisplayName("알림 조회 테스트") void getAlarm() { //given + String tempEmail = "serviceTest@gmail.com"; Notification newNotification = Notification.builder() - .userId(0L) + .email(tempEmail) .title("test title") .content("test content") .build(); notificationRepository.save(newNotification); - Mockito.when(notificationRepository.findAllByUserId(0L)).thenReturn(List.of(newNotification)); // (Mock) find시 Return + Mockito.when(notificationRepository.findAllByEmail(tempEmail)).thenReturn(List.of(newNotification)); // (Mock) find시 Return //when - List notifications = notificationService.getNotifications(0L); + List notifications = notificationService.getNotifications(tempEmail); //then assertEquals(1, notifications.size()); // 예상되는 알림 개수가 맞는지 확인 From e423ea04c3b12e8b1376d9ab5ac1e9b6c90481d7 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 31 May 2024 21:13:33 +0900 Subject: [PATCH 12/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20Test=20?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/redis/NotificationRecord.java | 2 ++ .../service/KafkaConsumerTest.java | 28 +++++++++++-------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java b/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java index 22d2ebb5..4126a674 100644 --- a/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java +++ b/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java @@ -3,6 +3,7 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; import org.springframework.data.redis.core.RedisHash; import java.time.LocalDateTime; @@ -14,6 +15,7 @@ public class NotificationRecord { //유저 식별자 + @Id private String email; //마지막 강수 알림 받은 시간 diff --git a/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java b/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java index 32772553..cb4a2ad4 100644 --- a/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java +++ b/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java @@ -1,6 +1,7 @@ package com.waither.notiservice.service; import com.waither.notiservice.domain.UserData; +import com.waither.notiservice.domain.UserMedian; import com.waither.notiservice.domain.type.Season; import com.waither.notiservice.dto.kafka.KafkaDto; import com.waither.notiservice.repository.jpa.UserDataRepository; @@ -9,10 +10,7 @@ import com.waither.notiservice.utils.TemperatureUtils; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -28,6 +26,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import static org.assertj.core.api.Assertions.assertThat; @@ -41,7 +40,7 @@ public class KafkaConsumerTest { Map stringProps; @BeforeEach - void setUp() { + void setUp() throws InterruptedException { jsonProps = new HashMap<>(); jsonProps.put(ProducerConfig.ACKS_CONFIG, "all"); jsonProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); @@ -64,10 +63,8 @@ static void beforeAll() { @Autowired private UserMedianRepository userMedianRepository; - @Autowired private RedisUtils redisUtils; - @Autowired private UserDataRepository userDataRepository; @@ -75,9 +72,10 @@ static void beforeAll() { @DisplayName("User Median Consumer Test") @Transactional //Transaction 후 Rollback (작동하지 않음. Listener 로 작동해서?) void userMedianTest() throws InterruptedException { + //Given - ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); - KafkaTemplate template = new KafkaTemplate<>(pf); + ProducerFactory pf = new DefaultKafkaProducerFactory<>(jsonProps); + KafkaTemplate template = new KafkaTemplate<>(pf); Season currentSeason = TemperatureUtils.getCurrentSeason(); String tempEmail = "kafkaTest@gmail.com"; @@ -89,7 +87,8 @@ void userMedianTest() throws InterruptedException { Map.of("medianOf2And3", 12.5)) ) .build(); - CompletableFuture> future = template.send("user-median", userMedianDto); + System.out.println("[ Kafka Test ] data --> "+ userMedianDto); + CompletableFuture> future = template.send("user-median", userMedianDto); //then future.whenComplete(((result, throwable) -> { @@ -98,13 +97,17 @@ void userMedianTest() throws InterruptedException { System.out.println("offset : "+ result.getRecordMetadata().offset()); } )); - Thread.sleep(2000); //2초 대기 + + System.out.println("5초 대기"); + Thread.sleep(5000); userMedianRepository.findAll().forEach(userMedian -> { System.out.println(" email : " + userMedian.getEmail()); }); - assertThat(userMedianRepository.findByEmailAndSeason(tempEmail, currentSeason).get().getMedianOf1And2()).isEqualTo(10.5); + Optional byEmailAndSeason = userMedianRepository.findByEmailAndSeason(tempEmail, currentSeason); + assertThat(byEmailAndSeason.isPresent()).isTrue(); + assertThat(byEmailAndSeason.get().getMedianOf1And2()).isEqualTo(10.5); //끝나고 삭제 -> Rollback 일어나지 않아서 userMedianRepository.deleteById(tempEmail); @@ -158,6 +161,7 @@ void userSettingsWindDegreeTest() throws InterruptedException { .windDegree(11) .email(tempEmail) .build()); + KafkaDto.UserSettingsDto userSettingsDto = KafkaDto.UserSettingsDto.builder() .email(tempEmail) .key("windDegree") From 5e23d8ea0141b820caad0537408eb3c33d3de711 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Sat, 1 Jun 2024 02:16:52 +0900 Subject: [PATCH 13/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20Topic=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20Dto=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/waither/notiservice/config/KafkaTopicConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/noti-service/src/main/java/com/waither/notiservice/config/KafkaTopicConfig.java b/noti-service/src/main/java/com/waither/notiservice/config/KafkaTopicConfig.java index 2b803cec..d2b40ad5 100644 --- a/noti-service/src/main/java/com/waither/notiservice/config/KafkaTopicConfig.java +++ b/noti-service/src/main/java/com/waither/notiservice/config/KafkaTopicConfig.java @@ -29,7 +29,7 @@ public KafkaAdmin kafkaAdmin() { *

userMedian 동기화 토픽

* @Producer : user-service * @Consumer : noti-service - * @MessageObject : {@link com.waither.notiservice.dto.kafka.UserMedianDto} + * @MessageObject : {@link com.waither.notiservice.dto.kafka.KafkaDto.UserMedianDto} * @Description : noti-service의 userMedian 테이블의 데이터를 동기화 하기 위해 사용합니다. * 계절은 자동으로 계산합니다. *
@@ -48,7 +48,7 @@ public NewTopic userMedianTopic(){ *

Firebase Token 동기화 토픽

* @Producer : user-service * @Consumer : noti-service - * @MessageObject : {@link com.waither.notiservice.dto.kafka.TokenDto} + * @MessageObject : {@link com.waither.notiservice.dto.kafka.KafkaDto.TokenDto} * @Description : noti-service의 firebase 토큰을 저장을 위해 사용됩니다. * */ @@ -64,7 +64,7 @@ public NewTopic fireBaseTokenTopic(){ *

User Settings 동기화 토픽

* @Producer : user-service * @Consumer : noti-service - * @MessageObject : {@link com.waither.notiservice.dto.kafka.UserSettingsDto} + * @MessageObject : {@link com.waither.notiservice.dto.kafka.KafkaDto.UserSettingsDto} * @Description : noti-service의 User Data 데이터 동기화를 위해 사용됩니다. * */ From cd11b5aa6a0852a7a7559c53bdf6dc0e5ef1b245 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Sat, 1 Jun 2024 02:17:20 +0900 Subject: [PATCH 14/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20?= =?UTF-8?q?=EC=9C=84=EB=8F=84,=20=EA=B2=BD=EB=8F=84=20=ED=91=9C=ED=98=84?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notiservice/api/request/LocationDto.java | 17 +++++++---------- .../service/NotificationService.java | 5 ++--- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/noti-service/src/main/java/com/waither/notiservice/api/request/LocationDto.java b/noti-service/src/main/java/com/waither/notiservice/api/request/LocationDto.java index 4c1deb25..d5bd4088 100644 --- a/noti-service/src/main/java/com/waither/notiservice/api/request/LocationDto.java +++ b/noti-service/src/main/java/com/waither/notiservice/api/request/LocationDto.java @@ -1,12 +1,9 @@ package com.waither.notiservice.api.request; -import jakarta.validation.Valid; import jakarta.validation.constraints.DecimalMax; import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -15,13 +12,13 @@ @NoArgsConstructor public class LocationDto { - @NotBlank(message = " 위도(x) 값은 필수입니다.") - @DecimalMax(value = "132.0", inclusive = true, message = "위도(x)는 대한민국 내에서만 가능합니다.") - @DecimalMin(value = "124.0", inclusive = true, message = "위도(x)는 대한민국 내에서만 가능합니다.") - public double x; + @NotBlank(message = " 위도(lat) 값은 필수입니다.") + @DecimalMax(value = "132.0", inclusive = true, message = "위도(lat)는 대한민국 내에서만 가능합니다.") + @DecimalMin(value = "124.0", inclusive = true, message = "위도(lat)는 대한민국 내에서만 가능합니다.") + public double lat; @NotBlank(message = " 경도(y) 값은 필수입니다.") - @DecimalMax(value = "43.0", inclusive = true, message = "경도(y)는 대한민국 내에서만 가능합니다.") - @DecimalMin(value = "33.0", inclusive = true, message = "경도(y)는 대한민국 내에서만 가능합니다.") - public double y; + @DecimalMax(value = "43.0", inclusive = true, message = "경도(lon)는 대한민국 내에서만 가능합니다.") + @DecimalMin(value = "33.0", inclusive = true, message = "경도(lon)는 대한민국 내에서만 가능합니다.") + public double lon; } diff --git a/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java b/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java index 73ca1ca5..3f4b4e9e 100644 --- a/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java +++ b/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java @@ -5,7 +5,6 @@ import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; import com.waither.notiservice.api.request.LocationDto; -import com.waither.notiservice.domain.redis.NotificationRecord; import com.waither.notiservice.domain.type.Season; import com.waither.notiservice.global.exception.CustomException; import com.waither.notiservice.global.response.ErrorCode; @@ -126,8 +125,8 @@ public String sendGoOutAlarm(String email) { public void checkCurrentAlarm(String email, LocationDto locationDto) { log.info("[ Notification Service ] email ---> {}", email); - log.info("[ Notification Service ] 현재 위치 위도 (x) ---> {}", locationDto.getX()); - log.info("[ Notification Service ] 현재 위치 경도 (y) ---> {}", locationDto.getY()); + log.info("[ Notification Service ] 현재 위치 위도 (lat) ---> {}", locationDto.getLat()); + log.info("[ Notification Service ] 현재 위치 경도 (lon) ---> {}", locationDto.getLon()); notificationRecordRepository.findByEmail(email); From bc6f48c24404ff89836c6bdc58411f5a3e07dd7a Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Sat, 1 Jun 2024 02:17:31 +0900 Subject: [PATCH 15/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20ApiRespo?= =?UTF-8?q?nse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/waither/notiservice/api/NotificationController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java b/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java index 549c37b2..74f115bd 100644 --- a/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java +++ b/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java @@ -34,14 +34,16 @@ public ApiResponse deleteNotification(@AuthUser String email, @RequestParam(" @Operation(summary = "Send Go Out Alarm", description = "외출 알림 전송하기") @PostMapping("/goOut") - public void sendGoOutAlarm(@AuthUser String email) { + public ApiResponse sendGoOutAlarm(@AuthUser String email) { notificationService.sendGoOutAlarm(email); + return ApiResponse.onSuccess(HttpStatus.OK); } @Operation(summary = "Current Location", description = "현재 위치 전송") @PostMapping("/location") - public void checkCurrentAlarm(@AuthUser String email, @RequestBody @Valid LocationDto locationDto) { + public ApiResponse checkCurrentAlarm(@AuthUser String email, @RequestBody @Valid LocationDto locationDto) { notificationService.checkCurrentAlarm(email, locationDto); + return ApiResponse.onSuccess(HttpStatus.OK); } } From 7aa4b65280bc511b7bdbc32cf62724083940e8a2 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Fri, 7 Jun 2024 22:09:50 +0900 Subject: [PATCH 16/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20Kafka=20?= =?UTF-8?q?Dto=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../waither/notiservice/domain/UserData.java | 6 ++- .../notiservice/domain/UserMedian.java | 21 +++++---- .../notiservice/domain/type/Season.java | 8 ---- .../notiservice/dto/kafka/KafkaDto.java | 44 +++++++++++-------- .../notiservice/enums/Expressions.java | 1 - .../com/waither/notiservice/enums/Season.java | 9 ++++ .../repository/jpa/UserMedianRepository.java | 2 +- .../notiservice/service/KafkaConsumer.java | 13 ++++-- .../service/NotificationService.java | 2 +- .../notiservice/utils/TemperatureUtils.java | 2 +- .../service/KafkaConsumerTest.java | 9 ++-- .../service/NotificationServiceTest.java | 2 +- 12 files changed, 70 insertions(+), 49 deletions(-) delete mode 100644 noti-service/src/main/java/com/waither/notiservice/domain/type/Season.java create mode 100644 noti-service/src/main/java/com/waither/notiservice/enums/Season.java diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/UserData.java b/noti-service/src/main/java/com/waither/notiservice/domain/UserData.java index 112badec..6debf4d8 100644 --- a/noti-service/src/main/java/com/waither/notiservice/domain/UserData.java +++ b/noti-service/src/main/java/com/waither/notiservice/domain/UserData.java @@ -1,9 +1,7 @@ package com.waither.notiservice.domain; -import com.waither.notiservice.domain.type.Season; import jakarta.persistence.*; import lombok.*; -import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.DynamicInsert; @Builder @@ -38,6 +36,9 @@ public class UserData { // 직장 지역 레포트 알림 받기 private boolean regionReport; + //가중치 + private Double weight; + public void updateValue(String key, String value) { switch (key) { case "nickName" -> nickName = value; @@ -47,6 +48,7 @@ public void updateValue(String key, String value) { case "windAlert" -> windAlert = Boolean.parseBoolean(value); case "regionReport" -> regionReport = Boolean.parseBoolean(value); case "windDegree" -> windDegree = Integer.valueOf(value); + case "weight" -> weight = Double.valueOf(value); } } diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java b/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java index e6a8580d..0b40d182 100644 --- a/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java +++ b/noti-service/src/main/java/com/waither/notiservice/domain/UserMedian.java @@ -1,6 +1,6 @@ package com.waither.notiservice.domain; -import com.waither.notiservice.domain.type.Season; +import com.waither.notiservice.enums.Season; import com.waither.notiservice.dto.kafka.KafkaDto; import jakarta.persistence.*; import lombok.*; @@ -25,18 +25,21 @@ public class UserMedian { @Enumerated(value = EnumType.STRING) public Season season; - public void setLevel(String level, Double value) { + public void setLevel(int level, Double value) { switch (level) { - case "medianOf1And2" -> medianOf1And2 = value; - case "medianOf2And3" -> medianOf2And3 = value; - case "medianOf3And4" -> medianOf3And4 = value; - case "medianOf4And5" -> medianOf4And5 = value; + case 1 -> medianOf1And2 = value; + case 2 -> medianOf2And3 = value; + case 3 -> medianOf3And4 = value; + case 4 -> medianOf4And5 = value; } } public void setLevel(KafkaDto.UserMedianDto userMedianDto) { - userMedianDto.medians().forEach(median -> - median.forEach(this::setLevel) - ); + KafkaDto.SeasonData seasonData = userMedianDto.seasonData(); + medianOf1And2 = seasonData.medianOf1And2(); + medianOf2And3 = seasonData.medianOf2And3(); + medianOf3And4 = seasonData.medianOf3And4(); + medianOf4And5 = seasonData.medianOf4And5(); + } } diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/type/Season.java b/noti-service/src/main/java/com/waither/notiservice/domain/type/Season.java deleted file mode 100644 index c1c6a2b3..00000000 --- a/noti-service/src/main/java/com/waither/notiservice/domain/type/Season.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.waither.notiservice.domain.type; - -public enum Season { - SPRING, - SUMMER, - AUTUMN, - WINTER -} \ No newline at end of file diff --git a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java index 31aeb2ea..5af47db1 100644 --- a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java +++ b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java @@ -2,6 +2,7 @@ import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; +import com.waither.notiservice.enums.Season; import com.waither.notiservice.utils.TemperatureUtils; import lombok.Builder; @@ -10,20 +11,26 @@ public class KafkaDto { - public record InitialDataDto( + @Builder + public record SeasonData( + Double medianOf1And2, + Double medianOf2And3, + Double medianOf3And4, + Double medianOf4And5 + ) {} + @Builder + public record InitialDataDto( String email, + String nickName, boolean climateAlert, boolean userAlert, boolean snowAlert, boolean windAlert, - Integer windDegree, + int windDegree, boolean regionReport, - Double weight, - Double medianOf1And2, - Double medianOf2And3, - Double medianOf3And4, - Double medianOf4And5 + double weight, + Map seasonData ) { public UserData toUserDataEntity() { return UserData.builder() @@ -37,23 +44,24 @@ public UserData toUserDataEntity() { .build(); } - public UserMedian toUserMedianEntity() { - return UserMedian.builder() - .email(email) - .season(TemperatureUtils.getCurrentSeason()) - .medianOf1And2(medianOf1And2 + weight) - .medianOf2And3(medianOf2And3 + weight) - .medianOf3And4(medianOf3And4 + weight) - .medianOf4And5(medianOf4And5 + weight) - .build(); + public List toUserMedianList() { + return seasonData.entrySet().stream() + .map(entry -> UserMedian.builder() + .email(email) + .season(Season.valueOf(entry.getKey())) + .medianOf1And2(entry.getValue().medianOf1And2()) + .medianOf2And3(entry.getValue().medianOf2And3()) + .medianOf3And4(entry.getValue().medianOf3And4()) + .medianOf4And5(entry.getValue().medianOf4And5()) + .build()) + .toList(); } } @Builder public record UserMedianDto( String email, - List> medians - + SeasonData seasonData ) {} @Builder diff --git a/noti-service/src/main/java/com/waither/notiservice/enums/Expressions.java b/noti-service/src/main/java/com/waither/notiservice/enums/Expressions.java index 2708e6aa..c49678be 100644 --- a/noti-service/src/main/java/com/waither/notiservice/enums/Expressions.java +++ b/noti-service/src/main/java/com/waither/notiservice/enums/Expressions.java @@ -1,6 +1,5 @@ package com.waither.notiservice.enums; -import com.waither.notiservice.domain.type.Season; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/noti-service/src/main/java/com/waither/notiservice/enums/Season.java b/noti-service/src/main/java/com/waither/notiservice/enums/Season.java new file mode 100644 index 00000000..775e2033 --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/enums/Season.java @@ -0,0 +1,9 @@ +package com.waither.notiservice.enums; + +public enum Season { + SPRING, + SUMMER, + AUTUMN, + WINTER, + SPRING_AUTUMN +} \ No newline at end of file diff --git a/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserMedianRepository.java b/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserMedianRepository.java index d2162633..b39cfb5a 100644 --- a/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserMedianRepository.java +++ b/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserMedianRepository.java @@ -1,7 +1,7 @@ package com.waither.notiservice.repository.jpa; import com.waither.notiservice.domain.UserMedian; -import com.waither.notiservice.domain.type.Season; +import com.waither.notiservice.enums.Season; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java b/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java index 0de0fd0b..9bd9545e 100644 --- a/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java +++ b/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java @@ -2,7 +2,7 @@ import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; -import com.waither.notiservice.domain.type.Season; +import com.waither.notiservice.enums.Season; import com.waither.notiservice.dto.kafka.KafkaDto; import com.waither.notiservice.global.exception.CustomException; import com.waither.notiservice.global.response.ErrorCode; @@ -24,7 +24,6 @@ @Slf4j @RequiredArgsConstructor @Component -@Transactional public class KafkaConsumer { private final UserDataRepository userDataRepository; @@ -34,6 +33,7 @@ public class KafkaConsumer { /** * 중앙값 동기화 Listener * */ + @Transactional @KafkaListener(topics = "${spring.kafka.template.user-median-topic}", containerFactory = "userMedianKafkaListenerContainerFactory") public void consumeUserMedian(KafkaDto.UserMedianDto userMedianDto) { @@ -53,6 +53,7 @@ public void consumeUserMedian(KafkaDto.UserMedianDto userMedianDto) { } else { //User Median 없을 경우 생성 //TODO : 계절당 초기값 받아야 함 + log.warn("[ Kafka Listener ] User Median 초기값이 없었습니다."); UserMedian newUserMedian = UserMedian.builder() .email(userMedianDto.email()) .season(currentSeason) @@ -66,6 +67,7 @@ public void consumeUserMedian(KafkaDto.UserMedianDto userMedianDto) { /** * Firebase Token Listener * */ + @Transactional @KafkaListener(topics = "firebase-token", containerFactory = "firebaseTokenKafkaListenerContainerFactory") public void consumeFirebaseToken(KafkaDto.TokenDto tokenDto) { @@ -81,6 +83,7 @@ public void consumeFirebaseToken(KafkaDto.TokenDto tokenDto) { /** * User Settings Listener * */ + @Transactional @KafkaListener(topics = "${spring.kafka.template.user-settings-topic}", containerFactory = "userSettingsKafkaListenerContainerFactory") public void consumeUserSettings(KafkaDto.UserSettingsDto userSettingsDto) { @@ -104,13 +107,14 @@ public void consumeUserSettings(KafkaDto.UserSettingsDto userSettingsDto) { } + @Transactional @KafkaListener(topics = "${spring.kafka.template.initial-data-topic}", containerFactory = "initialDataKafkaListenerContainerFactory") public void consumeUserInit(KafkaDto.InitialDataDto initialDataDto) { log.info("[ Kafka Listener ] 초기 설정값 세팅"); log.info("[ Kafka Listener ] email --> {}", initialDataDto.email()); userDataRepository.save(initialDataDto.toUserDataEntity()); - userMedianRepository.save(initialDataDto.toUserMedianEntity()); + userMedianRepository.saveAll(initialDataDto.toUserMedianList()); } @@ -119,6 +123,7 @@ public void consumeUserInit(KafkaDto.InitialDataDto initialDataDto) { /** * 바람 세기 알림 Listener * */ + @Transactional @KafkaListener(topics = "alarm-wind") public void consumeWindAlarm(@Payload String message) { StringBuilder sb = new StringBuilder(); @@ -142,6 +147,7 @@ public void consumeWindAlarm(@Payload String message) { /** * 강설 정보 알림 Listener * */ + @Transactional @KafkaListener(topics = "alarm-snow") public void consumeSnow(@Payload String message) { String resultMessage = ""; @@ -163,6 +169,7 @@ public void consumeSnow(@Payload String message) { /** * 기상 특보 알림 Listener * */ + @Transactional @KafkaListener(topics = "alarm-climate") public void consumeClimateAlarm(@Payload String message) { String resultMessage = ""; diff --git a/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java b/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java index 3f4b4e9e..fd1cefd6 100644 --- a/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java +++ b/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java @@ -5,7 +5,7 @@ import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; import com.waither.notiservice.api.request.LocationDto; -import com.waither.notiservice.domain.type.Season; +import com.waither.notiservice.enums.Season; import com.waither.notiservice.global.exception.CustomException; import com.waither.notiservice.global.response.ErrorCode; import com.waither.notiservice.repository.jpa.NotificationRepository; diff --git a/noti-service/src/main/java/com/waither/notiservice/utils/TemperatureUtils.java b/noti-service/src/main/java/com/waither/notiservice/utils/TemperatureUtils.java index 9bb2ea32..efafe93e 100644 --- a/noti-service/src/main/java/com/waither/notiservice/utils/TemperatureUtils.java +++ b/noti-service/src/main/java/com/waither/notiservice/utils/TemperatureUtils.java @@ -1,7 +1,7 @@ package com.waither.notiservice.utils; import com.waither.notiservice.domain.UserMedian; -import com.waither.notiservice.domain.type.Season; +import com.waither.notiservice.enums.Season; import com.waither.notiservice.enums.*; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; diff --git a/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java b/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java index cb4a2ad4..f6bd0023 100644 --- a/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java +++ b/noti-service/src/test/java/com/waither/notiservice/service/KafkaConsumerTest.java @@ -2,7 +2,7 @@ import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; -import com.waither.notiservice.domain.type.Season; +import com.waither.notiservice.enums.Season; import com.waither.notiservice.dto.kafka.KafkaDto; import com.waither.notiservice.repository.jpa.UserDataRepository; import com.waither.notiservice.repository.jpa.UserMedianRepository; @@ -82,9 +82,10 @@ void userMedianTest() throws InterruptedException { //when KafkaDto.UserMedianDto userMedianDto = KafkaDto.UserMedianDto.builder() .email(tempEmail) - .medians(List.of( - Map.of("medianOf1And2", 10.5), - Map.of("medianOf2And3", 12.5)) + .seasonData(KafkaDto.SeasonData.builder() + .medianOf1And2(10.5) + .medianOf2And3(12.5) + .build() ) .build(); System.out.println("[ Kafka Test ] data --> "+ userMedianDto); diff --git a/noti-service/src/test/java/com/waither/notiservice/service/NotificationServiceTest.java b/noti-service/src/test/java/com/waither/notiservice/service/NotificationServiceTest.java index 1c99e25b..c1e5a509 100644 --- a/noti-service/src/test/java/com/waither/notiservice/service/NotificationServiceTest.java +++ b/noti-service/src/test/java/com/waither/notiservice/service/NotificationServiceTest.java @@ -4,7 +4,7 @@ import com.waither.notiservice.domain.Notification; import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; -import com.waither.notiservice.domain.type.Season; +import com.waither.notiservice.enums.Season; import com.waither.notiservice.repository.jpa.NotificationRepository; import com.waither.notiservice.repository.jpa.UserDataRepository; import com.waither.notiservice.repository.jpa.UserMedianRepository; From d44b9ea15bf0108e81c699216d53a23bf3326ecf Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Tue, 18 Jun 2024 23:22:24 +0900 Subject: [PATCH 17/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20FCM=20?= =?UTF-8?q?=ED=86=A0=ED=81=B0=20=ED=99=98=EA=B2=BD=20=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- noti-service/build.gradle | 3 + .../notiservice/config/FirebaseConfig.java | 32 ++++++++ .../notiservice/utils/FireBaseUtils.java | 77 +++++++++++++++++++ noti-service/src/main/resources/bootstrap.yml | 2 +- 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 noti-service/src/main/java/com/waither/notiservice/config/FirebaseConfig.java create mode 100644 noti-service/src/main/java/com/waither/notiservice/utils/FireBaseUtils.java diff --git a/noti-service/build.gradle b/noti-service/build.gradle index ae41b641..ef63bff8 100644 --- a/noti-service/build.gradle +++ b/noti-service/build.gradle @@ -60,6 +60,9 @@ dependencies { //JUnit + AssertJ testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' testImplementation 'org.assertj:assertj-core:3.23.1' + + //firebase + implementation 'com.google.firebase:firebase-admin:9.2.0' } //openApi { diff --git a/noti-service/src/main/java/com/waither/notiservice/config/FirebaseConfig.java b/noti-service/src/main/java/com/waither/notiservice/config/FirebaseConfig.java new file mode 100644 index 00000000..3bf9e337 --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/config/FirebaseConfig.java @@ -0,0 +1,32 @@ +package com.waither.notiservice.config; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import java.io.FileInputStream; +import java.io.IOException; + +@Configuration +@RequiredArgsConstructor +public class FirebaseConfig { + + @Value("${firebase.key.path}") + private final String keyPath; + + @PostConstruct + public void initializeApp() throws IOException { + FileInputStream serviceAccount = + new FileInputStream(keyPath); + + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(GoogleCredentials.fromStream(serviceAccount)) + .build(); + + FirebaseApp.initializeApp(options); + } +} diff --git a/noti-service/src/main/java/com/waither/notiservice/utils/FireBaseUtils.java b/noti-service/src/main/java/com/waither/notiservice/utils/FireBaseUtils.java new file mode 100644 index 00000000..ab37a78c --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/utils/FireBaseUtils.java @@ -0,0 +1,77 @@ +package com.waither.notiservice.utils; + +import com.google.firebase.messaging.*; +import com.waither.notiservice.global.exception.CustomException; +import com.waither.notiservice.global.response.ErrorCode; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.retry.annotation.Retryable; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class FireBaseUtils { + + //특정 기기에 메시지 전송 +// @Retryable(maxAttempts = 3) + public void sendSingleMessage(String token, String title, String body) { + try { + Message message = Message.builder() + .setNotification(Notification.builder() + .setTitle(title) + .setBody(body) + .build()) + .setToken(token) + .build(); + + String response = FirebaseMessaging.getInstance().send(message); + + log.info("[ FireBaseUtils ] Successfully sent message --> {}", response); + + } catch (FirebaseMessagingException ex) { + ex.printStackTrace(); + throw new CustomException(ErrorCode.FIREBASE_ERROR); + } + } + + // 일괄 메세지 전송 + // 호출당 최대 500기기 등록 가능 + public void sendAllMessages(List tokens, String title, String body) { + try { + + log.info("[ FireBaseUtils ] Try Sending Messages, Count ---> {}", tokens.size()); + + List messages = tokens.stream().map( + token -> Message.builder() + .setNotification(Notification.builder() + .setTitle(title) + .setBody(body) + .build()) + .setToken(token) + .build() + ).toList(); + + //send All 은 deprecated. 대신 sendEach 사용 + BatchResponse response = FirebaseMessaging.getInstance().sendEach(messages); + + log.info("[ FireBaseUtils ] Successfully Sent Messages, Count ---> {}", response.getSuccessCount()); + + if (response.getFailureCount() > 0) { + response.getResponses() + .forEach( singleResponse -> { + if (!singleResponse.isSuccessful()) { + log.warn("[ FireBaseUtils ] Failed to send message, id ---> {}", singleResponse.getMessageId()); + } + }); + } + + } catch (FirebaseMessagingException ex) { + ex.printStackTrace(); + throw new CustomException(ErrorCode.FIREBASE_ERROR); + } + } +} diff --git a/noti-service/src/main/resources/bootstrap.yml b/noti-service/src/main/resources/bootstrap.yml index 9d5208bd..7e27fa7f 100644 --- a/noti-service/src/main/resources/bootstrap.yml +++ b/noti-service/src/main/resources/bootstrap.yml @@ -9,7 +9,7 @@ spring: cloud: config: uri: http://localhost:8888 - name: database-noti, redis, kafka + name: database-noti, redis, kafka, firebase kafka: bootstrap-servers: "localhost:9092" From 67746d47a1dcb8903958b8af5a988530f5034d93 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Tue, 18 Jun 2024 23:24:33 +0900 Subject: [PATCH 18/24] =?UTF-8?q?=E2=9C=A8feat=20:=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EC=B5=9C=EC=8B=A0=ED=99=94=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notiservice/api/TokenContoller.java | 28 +++++++++ .../notiservice/service/AlarmService.java | 59 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 noti-service/src/main/java/com/waither/notiservice/api/TokenContoller.java create mode 100644 noti-service/src/main/java/com/waither/notiservice/service/AlarmService.java diff --git a/noti-service/src/main/java/com/waither/notiservice/api/TokenContoller.java b/noti-service/src/main/java/com/waither/notiservice/api/TokenContoller.java new file mode 100644 index 00000000..15d9dfab --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/api/TokenContoller.java @@ -0,0 +1,28 @@ +package com.waither.notiservice.api; + +import com.waither.notiservice.api.request.TokenDto; +import com.waither.notiservice.global.annotation.AuthUser; +import com.waither.notiservice.global.response.ApiResponse; +import com.waither.notiservice.service.AlarmService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequiredArgsConstructor +@RequestMapping("/noti") +@RestController +public class TokenContoller { + + private final AlarmService alarmService; + + @Operation(summary = "Firebase Token 업데이트", description = "Request Body에 발급한 FCM토큰 값을 넣어서 주시면 됩니다.") + @PostMapping("/token") + public ApiResponse updateToken(@AuthUser String email, @RequestBody TokenDto tokenDto) { + alarmService.updateToken(email, tokenDto); + return ApiResponse.onSuccess("토큰 업로드가 완료되었습니다."); + } +} diff --git a/noti-service/src/main/java/com/waither/notiservice/service/AlarmService.java b/noti-service/src/main/java/com/waither/notiservice/service/AlarmService.java new file mode 100644 index 00000000..8797476a --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/service/AlarmService.java @@ -0,0 +1,59 @@ +package com.waither.notiservice.service; + +import com.waither.notiservice.api.request.TokenDto; +import com.waither.notiservice.domain.Notification; +import com.waither.notiservice.global.exception.CustomException; +import com.waither.notiservice.global.response.ErrorCode; +import com.waither.notiservice.repository.jpa.NotificationRepository; +import com.waither.notiservice.utils.FireBaseUtils; +import com.waither.notiservice.utils.RedisUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@RequiredArgsConstructor +@Service +public class AlarmService { + + private final RedisUtils redisUtils; + private final FireBaseUtils fireBaseUtils; + private final NotificationRepository notificationRepository; + + public void updateToken(String email, TokenDto tokenDto) { + redisUtils.save(email, tokenDto.token()); + } + + public void sendSingleAlarm(String email, String title, String message) { + String token = String.valueOf(redisUtils.get(email)); + fireBaseUtils.sendSingleMessage(token, title, message); + notificationRepository.save(Notification.builder() + .email(email) + .title(title) + .content(message) + .build()); + } + + public void sendAlarms(List userEmails, String title, String message) { + List tokens = userEmails.stream() + .map(email -> String.valueOf(redisUtils.get(email))) + .toList(); + + log.info("[ 푸시알림 ] Email ---> {}", userEmails); + log.info("[ 푸시알림 ] message ---> {}", message); + + fireBaseUtils.sendAllMessages(tokens,title, message); + + List notifications = userEmails.stream() + .map(email -> Notification.builder() + .email(email) + .title(title) + .content(message) + .build()) + .toList(); + + notificationRepository.saveAll(notifications); + } +} From 10a11f42b9cb6d0600508534a13f503090b6223d Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Tue, 18 Jun 2024 23:25:01 +0900 Subject: [PATCH 19/24] =?UTF-8?q?=E2=9C=A8feat=20:=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EC=B5=9C=EC=8B=A0=ED=99=94=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notiservice/api/request/LocationDto.java | 23 +++++++++---------- .../notiservice/api/request/TokenDto.java | 7 ++++++ 2 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 noti-service/src/main/java/com/waither/notiservice/api/request/TokenDto.java diff --git a/noti-service/src/main/java/com/waither/notiservice/api/request/LocationDto.java b/noti-service/src/main/java/com/waither/notiservice/api/request/LocationDto.java index d5bd4088..16d8f080 100644 --- a/noti-service/src/main/java/com/waither/notiservice/api/request/LocationDto.java +++ b/noti-service/src/main/java/com/waither/notiservice/api/request/LocationDto.java @@ -7,18 +7,17 @@ import lombok.Getter; import lombok.NoArgsConstructor; -@Getter -@AllArgsConstructor -@NoArgsConstructor -public class LocationDto { +public record LocationDto ( + @NotBlank(message = " 위도(lat) 값은 필수입니다.") + @DecimalMax(value = "132.0", inclusive = true, message = "위도(lat)는 대한민국 내에서만 가능합니다.") + @DecimalMin(value = "124.0", inclusive = true, message = "위도(lat)는 대한민국 내에서만 가능합니다.") + double lat, + + @NotBlank(message = " 경도(y) 값은 필수입니다.") + @DecimalMax(value = "43.0", inclusive = true, message = "경도(lon)는 대한민국 내에서만 가능합니다.") + @DecimalMin(value = "33.0", inclusive = true, message = "경도(lon)는 대한민국 내에서만 가능합니다.") + double lon +) { - @NotBlank(message = " 위도(lat) 값은 필수입니다.") - @DecimalMax(value = "132.0", inclusive = true, message = "위도(lat)는 대한민국 내에서만 가능합니다.") - @DecimalMin(value = "124.0", inclusive = true, message = "위도(lat)는 대한민국 내에서만 가능합니다.") - public double lat; - @NotBlank(message = " 경도(y) 값은 필수입니다.") - @DecimalMax(value = "43.0", inclusive = true, message = "경도(lon)는 대한민국 내에서만 가능합니다.") - @DecimalMin(value = "33.0", inclusive = true, message = "경도(lon)는 대한민국 내에서만 가능합니다.") - public double lon; } diff --git a/noti-service/src/main/java/com/waither/notiservice/api/request/TokenDto.java b/noti-service/src/main/java/com/waither/notiservice/api/request/TokenDto.java new file mode 100644 index 00000000..5d5e098f --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/api/request/TokenDto.java @@ -0,0 +1,7 @@ +package com.waither.notiservice.api.request; + +public record TokenDto( + String token + +) { +} From 110cb357ecca0ebcb9a069329a6560c1fa9342ad Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Tue, 18 Jun 2024 23:25:39 +0900 Subject: [PATCH 20/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20?= =?UTF-8?q?=EC=95=8C=EB=A6=BC=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?&=20=EB=A0=88=EC=BD=94=EB=93=9C=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/redis/NotificationRecord.java | 23 ++++--- .../global/response/ErrorCode.java | 6 +- .../repository/jpa/UserDataRepository.java | 7 +++ .../redis/NotificationRecordRepository.java | 4 ++ .../service/NotificaitonRecordService.java | 30 +++++++++ .../service/NotificationService.java | 61 +++++++++++++------ 6 files changed, 104 insertions(+), 27 deletions(-) create mode 100644 noti-service/src/main/java/com/waither/notiservice/service/NotificaitonRecordService.java diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java b/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java index 4126a674..eec7eb44 100644 --- a/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java +++ b/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java @@ -1,13 +1,12 @@ package com.waither.notiservice.domain.redis; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.NoArgsConstructor; +import lombok.*; import org.springframework.data.annotation.Id; import org.springframework.data.redis.core.RedisHash; import java.time.LocalDateTime; +@Getter @Builder @AllArgsConstructor @NoArgsConstructor @@ -24,9 +23,19 @@ public class NotificationRecord { //마지막 바람세기 알림 받은 시간 private LocalDateTime lastWindAlarmReceived; - //사용자 마지막 위치 (위도) - private Double lat; + //사용자 마지막 위치 (지역) + private String region; + + public void setLastRainAlarmReceived(LocalDateTime lastRainAlarmReceived) { + this.lastRainAlarmReceived = lastRainAlarmReceived; + } + + public void setLastWindAlarmReceived(LocalDateTime lastWindAlarmReceived) { + this.lastWindAlarmReceived = lastWindAlarmReceived; + } + + public void setRegion(String region) { + this.region = region; + } - //사용자 마지막 위치 (경도) - private Double lon; } diff --git a/noti-service/src/main/java/com/waither/notiservice/global/response/ErrorCode.java b/noti-service/src/main/java/com/waither/notiservice/global/response/ErrorCode.java index 4b5b3c4e..c0805b83 100644 --- a/noti-service/src/main/java/com/waither/notiservice/global/response/ErrorCode.java +++ b/noti-service/src/main/java/com/waither/notiservice/global/response/ErrorCode.java @@ -34,11 +34,13 @@ public enum ErrorCode implements BaseErrorCode { // 데이터 관련 에러 NO_USER_MEDIAN_REGISTERED(HttpStatus.NOT_FOUND, "USER404_0", "사용자 설정값이 존재하지 않습니다."), NO_USER_DATA_REGISTERED(HttpStatus.NOT_FOUND, "USER404_1", "사용자 데이터 값이 존재하지 않습니다."), - FIREBASE_TOKEN_NOT_FOUND(HttpStatus.NOT_FOUND, "TOKEN404", "푸시알림 토큰이 존재하지 않습니다."), //통신 과정 에러 - COMMUNICATION_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500_1", "통신 과정에서 문제가 발생했습니다.") + COMMUNICATION_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON500_1", "통신 과정에서 문제가 발생했습니다."), + //FirebaseError + FIREBASE_TOKEN_NOT_FOUND(HttpStatus.NOT_FOUND, "FB404", "푸시알림 토큰이 존재하지 않습니다."), + FIREBASE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "FB500", "Firebase 메세지 전송 오류가 발생했습니다.") ; diff --git a/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserDataRepository.java b/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserDataRepository.java index 854d974e..f555c14a 100644 --- a/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserDataRepository.java +++ b/noti-service/src/main/java/com/waither/notiservice/repository/jpa/UserDataRepository.java @@ -4,10 +4,17 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository public interface UserDataRepository extends JpaRepository { Optional findByEmail(String email); + + List findAllByClimateAlertIsTrue(); + + List findAllByWindAlertIsTrue(); + + List findAllBySnowAlertIsTrue(); } diff --git a/noti-service/src/main/java/com/waither/notiservice/repository/redis/NotificationRecordRepository.java b/noti-service/src/main/java/com/waither/notiservice/repository/redis/NotificationRecordRepository.java index 6dc0fcee..da8b52d2 100644 --- a/noti-service/src/main/java/com/waither/notiservice/repository/redis/NotificationRecordRepository.java +++ b/noti-service/src/main/java/com/waither/notiservice/repository/redis/NotificationRecordRepository.java @@ -4,9 +4,13 @@ import org.springframework.data.repository.CrudRepository; import javax.swing.text.html.Option; +import java.util.List; import java.util.Optional; public interface NotificationRecordRepository extends CrudRepository { Optional findByEmail(String email); + + + } diff --git a/noti-service/src/main/java/com/waither/notiservice/service/NotificaitonRecordService.java b/noti-service/src/main/java/com/waither/notiservice/service/NotificaitonRecordService.java new file mode 100644 index 00000000..d5599ca6 --- /dev/null +++ b/noti-service/src/main/java/com/waither/notiservice/service/NotificaitonRecordService.java @@ -0,0 +1,30 @@ +package com.waither.notiservice.service; + +import com.waither.notiservice.domain.redis.NotificationRecord; +import com.waither.notiservice.global.exception.CustomException; +import com.waither.notiservice.repository.redis.NotificationRecordRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Optional; + +@RequiredArgsConstructor +@Service +public class NotificaitonRecordService { + + private final NotificationRecordRepository notificationRecordRepository; + + public void updateWindAlarm(String email) { + Optional notificationRecord = notificationRecordRepository.findByEmail(email); + + notificationRecord.ifPresentOrElse(record -> record.setLastWindAlarmReceived(LocalDateTime.now()), null); + } + + public void updateRainAlarm(String email) { + Optional notificationRecord = notificationRecordRepository.findByEmail(email); + notificationRecord.ifPresent(record -> record.setLastRainAlarmReceived(LocalDateTime.now())); + } + + +} diff --git a/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java b/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java index fd1cefd6..b06613c9 100644 --- a/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java +++ b/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java @@ -5,6 +5,7 @@ import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; import com.waither.notiservice.api.request.LocationDto; +import com.waither.notiservice.domain.redis.NotificationRecord; import com.waither.notiservice.enums.Season; import com.waither.notiservice.global.exception.CustomException; import com.waither.notiservice.global.response.ErrorCode; @@ -18,7 +19,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; @Slf4j @RequiredArgsConstructor @@ -30,6 +33,8 @@ public class NotificationService { private final UserDataRepository userDataRepository; private final NotificationRecordRepository notificationRecordRepository; + private final AlarmService alarmService; + @Transactional(readOnly = true) public List getNotifications(String email) { @@ -58,14 +63,16 @@ public String sendGoOutAlarm(String email) { Season currentSeason = TemperatureUtils.getCurrentSeason(); - String finalMessage = ""; + LocalDateTime now = LocalDateTime.now(); + String title = now.getMonth() + "월 " + now.getDayOfMonth() + "일 날씨 정보입니다."; + StringBuilder sb = new StringBuilder(); /** * 1. 기본 메세지 시작 형식 */ //TODO : 날씨 정보 가져오기 & 날씨별 멘트 정리 String nickName = userData.getNickName(); - finalMessage += nickName + "님, 오늘은 "; + sb.append(nickName).append("님, 오늘은 "); /** @@ -79,10 +86,10 @@ public String sendGoOutAlarm(String email) { UserMedian userMedian = userMedianRepository.findByEmailAndSeason(email, currentSeason).orElseThrow( () -> new CustomException(ErrorCode.NO_USER_MEDIAN_REGISTERED)); - finalMessage += TemperatureUtils.createUserDataMessage(userMedian, temperature); + sb.append(TemperatureUtils.createUserDataMessage(userMedian, temperature)); } else { //사용자 맞춤 알림이 off라면 -> 하루 평균 온도 정보 제공 - finalMessage += "평균 온도가 "+temperature+"도예요."; + sb.append("평균 온도가 ").append(temperature).append("도입니다."); } @@ -96,28 +103,23 @@ public String sendGoOutAlarm(String email) { * 3. 강수 정보 가져오기 - Weather Service */ //TODO : 강수량 확인, 멘트 - finalMessage += " 오후 6시부터 8시까지 120mm의 비가 올 예정입니다."; + sb.append(" 오후 6시부터 8시까지 120mm의 비가 올 예정입니다."); /** * 4. 꽃가루 정보 가져오기 - Weather Service */ //TODO : 꽃가루 확인 - finalMessage += " 꽃가루는 없습니다. "; + sb.append(" 꽃가루는 없습니다. ") ; /** * 알림 전송 */ //TODO : FireBase 알림 보내기 - log.info("[ Notification Service ] Final Message ---> {}", finalMessage); - - //알림 저장 - notificationRepository.save(Notification.builder() - .email(email) - .title("출근 날씨 알림") - .content(finalMessage) - .build()); + log.info("[ Notification Service ] Final Message ---> {}", sb.toString()); - return finalMessage; + //알림 보내기 + alarmService.sendSingleAlarm(email, title, sb.toString()); + return sb.toString(); } //현재 위치 업데이트 @@ -125,10 +127,33 @@ public String sendGoOutAlarm(String email) { public void checkCurrentAlarm(String email, LocationDto locationDto) { log.info("[ Notification Service ] email ---> {}", email); - log.info("[ Notification Service ] 현재 위치 위도 (lat) ---> {}", locationDto.getLat()); - log.info("[ Notification Service ] 현재 위치 경도 (lon) ---> {}", locationDto.getLon()); + log.info("[ Notification Service ] 현재 위치 위도 (lat) ---> {}", locationDto.lat()); + log.info("[ Notification Service ] 현재 위치 경도 (lon) ---> {}", locationDto.lon()); + + Optional notiRecord = notificationRecordRepository.findByEmail(email); + + //TODO : 위도 경도 -> 지역 변환 + String region = "서울특별시"; + + if (notiRecord.isPresent()) { + NotificationRecord notificationRecord = notiRecord.get(); + + if (!notiRecord.get().getRegion().equals(region)) { + //만약 위치가 이동됐다면 알림 시간 초기화 + notificationRecord.setLastWindAlarmReceived(LocalDateTime.now().minusHours(4)); + notificationRecord.setLastRainAlarmReceived(LocalDateTime.now().minusHours(4)); + } + notificationRecord.setRegion(region); + + } else notificationRecordRepository.save( + NotificationRecord.builder() + .email(email) + .region(region) + .lastRainAlarmReceived(LocalDateTime.now().minusHours(4)) + .lastWindAlarmReceived(LocalDateTime.now().minusHours(4)) + .build() + ); - notificationRecordRepository.findByEmail(email); From 824988c369c870b32584692b684828a1bb574142 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Tue, 18 Jun 2024 23:25:56 +0900 Subject: [PATCH 21/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20Kafka=20?= =?UTF-8?q?ConsumerConfig=20&=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/KafkaConsumerConfig.java | 15 ++ .../notiservice/dto/kafka/KafkaDto.java | 7 +- .../notiservice/service/KafkaConsumer.java | 182 ++++++++++++++---- 3 files changed, 161 insertions(+), 43 deletions(-) diff --git a/noti-service/src/main/java/com/waither/notiservice/config/KafkaConsumerConfig.java b/noti-service/src/main/java/com/waither/notiservice/config/KafkaConsumerConfig.java index bfb71eae..35a685c1 100644 --- a/noti-service/src/main/java/com/waither/notiservice/config/KafkaConsumerConfig.java +++ b/noti-service/src/main/java/com/waither/notiservice/config/KafkaConsumerConfig.java @@ -143,6 +143,21 @@ private ConsumerFactory initialDataConsumerFact return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(KafkaDto.InitialDataDto.class)); } + @Bean("weatherKafkaListenerContainerFactory") + public ConcurrentKafkaListenerContainerFactory weatherConcurrentKafkaListenerContainerFactory(){ + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(weatherConsumerFactory()); + factory.setConcurrency(3); + factory.setBatchListener(true); + factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.BATCH); + return factory; + } + + private ConsumerFactory weatherConsumerFactory() { + Map props = dtoSettings(); + return new DefaultKafkaConsumerFactory<>(props, new StringDeserializer(), new JsonDeserializer<>(KafkaDto.WeatherDto.class)); + } + diff --git a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java index 5af47db1..e752b2a9 100644 --- a/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java +++ b/noti-service/src/main/java/com/waither/notiservice/dto/kafka/KafkaDto.java @@ -3,7 +3,6 @@ import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; import com.waither.notiservice.enums.Season; -import com.waither.notiservice.utils.TemperatureUtils; import lombok.Builder; import java.util.List; @@ -77,4 +76,10 @@ public record TokenDto( String token ){} + @Builder + public record WeatherDto( + String region, + String message + ) {} + } diff --git a/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java b/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java index 9bd9545e..88fbae82 100644 --- a/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java +++ b/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java @@ -2,22 +2,21 @@ import com.waither.notiservice.domain.UserData; import com.waither.notiservice.domain.UserMedian; +import com.waither.notiservice.domain.redis.NotificationRecord; import com.waither.notiservice.enums.Season; import com.waither.notiservice.dto.kafka.KafkaDto; -import com.waither.notiservice.global.exception.CustomException; -import com.waither.notiservice.global.response.ErrorCode; import com.waither.notiservice.repository.jpa.UserDataRepository; import com.waither.notiservice.repository.jpa.UserMedianRepository; +import com.waither.notiservice.repository.redis.NotificationRecordRepository; import com.waither.notiservice.utils.RedisUtils; import com.waither.notiservice.utils.TemperatureUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.kafka.annotation.KafkaListener; -import org.springframework.messaging.handler.annotation.Payload; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -26,8 +25,10 @@ @Component public class KafkaConsumer { + private final AlarmService alarmService; private final UserDataRepository userDataRepository; private final UserMedianRepository userMedianRepository; + private final NotificationRecordRepository notificationRecordRepository; private final RedisUtils redisUtils; /** @@ -122,82 +123,179 @@ public void consumeUserInit(KafkaDto.InitialDataDto initialDataDto) { /** * 바람 세기 알림 Listener - * */ + * @Query : 0200, 0500, 0800, 1100, 1400, 1700, 2000, 2300 */ @Transactional - @KafkaListener(topics = "alarm-wind") - public void consumeWindAlarm(@Payload String message) { + @KafkaListener(topics = "alarm-wind", containerFactory = "weatherKafkaListenerContainerFactory") + public void consumeWindAlarm(KafkaDto.WeatherDto weatherDto) { + + int currentHour = LocalDateTime.now().getHour(); + // 22:00 ~ 07:00 는 알림을 전송하지 않음 + if (currentHour >= 22 || currentHour <= 7) { + return; + } + + String title = "Waither 바람 세기 알림"; StringBuilder sb = new StringBuilder(); - Long windStrength = Long.valueOf(message); //바람세기 + String region = weatherDto.region(); + Double windStrength = Double.valueOf(weatherDto.message()); //바람세기 log.info("[ Kafka Listener ] 바람 세기"); log.info("[ Kafka Listener ] Wind Strength : --> {}", windStrength); - //TODO : 알림 보낼 사용자 정보 가져오기 (Redis) - List userIds = new ArrayList<>(); + // Wind Alert를 True로 설정한 User Query + List userData = userDataRepository.findAllByWindAlertIsTrue(); + + // 1. 현재 windStrength 보다 작게 설정한 유저 필터 + // 2. 이메일 추출 + // 3. 지역 일치 & 마지막 알림 3시간 경과했는지 필터 + List userEmails = userData.stream() + .filter(data -> data.getWindDegree() <= windStrength) + .map(UserData::getEmail) + .filter(email -> { + Optional notiRecord = notificationRecordRepository + .findByEmail(email); + if (notiRecord.isPresent()) { + //지역 일치 검사 + if (!notiRecord.get().getRegion().equals(region)) { + return false; + } + //경과 시간 검사 + int diff = notiRecord.get().getLastWindAlarmReceived().getHour() - currentHour; + if (Math.abs(diff) >= 3) { //3시간 이상 경과했는지? + return true; + } + } + log.warn(" [ Kafka Listener ] Notification Record 존재하지 않습니다. Email ---> {}", email); + return false; + }) + .toList(); //TODO : 바람 세기 알림 멘트 정리 sb.append("현재 바람 세기가 ").append(windStrength).append("m/s 이상입니다. 강풍에 주의하세요."); System.out.println("[ 푸시알림 ] 바람 세기 알림"); - sendAlarms(userIds, sb.toString()); + + alarmService.sendAlarms(userEmails,title, sb.toString()); + //TODO : Notification Record 저장 } /** - * 강설 정보 알림 Listener - * */ + * 강설 정보 알림 Listener
+ * 기상청 기준
+ * 약한 비 1~3mm
+ * 보통 비 3~15mm
+ * 강한 비 15~30mm
+ * 매우 강한 비 30mm 이상
+ * 참고 + */ @Transactional - @KafkaListener(topics = "alarm-snow") - public void consumeSnow(@Payload String message) { - String resultMessage = ""; - Double snow = Double.valueOf(message); //강수량 + @KafkaListener(topics = "alarm-snow", containerFactory = "weatherKafkaListenerContainerFactory") + public void consumeSnow(KafkaDto.WeatherDto weatherDto) { + + int currentHour = LocalDateTime.now().getHour(); + // 22:00 ~ 07:00 는 알림을 전송하지 않음 + if (currentHour >= 22 || currentHour <= 7) { + return; + } + + String title = "Waither 강수 정보 알림"; + StringBuilder sb = new StringBuilder(); + + String region = weatherDto.region(); + Double prediction = Double.valueOf(weatherDto.message()); //강수량 + + log.info("[ Kafka Listener ] 강수량 지역 --> {}", region); + log.info("[ Kafka Listener ] 걍수량 --> {}", prediction); - log.info("[ Kafka Listener ] 강수량"); - log.info("[ Kafka Listener ] Snow : --> {}", snow); + List userData = userDataRepository.findAllBySnowAlertIsTrue(); - //TODO : 알림 보낼 사용자 정보 가져오기 (Redis) - List userIds = new ArrayList<>(); + //예시 : 현재 서울특별시 지역에 2mm의 약한 비가 내릴 예정입니다. + //TODO: 언제 내리는지? 확인 필요 + sb.append("현재 ").append(region).append(" 지역에 ").append(prediction).append("mm의 ") + .append(getExpression(prediction)).append("가 내릴 예정입니다."); + + //알림 보낼 사용자 이메일 + List userEmails = filterRegionAndAlarm(region, userData, currentHour); - //TODO : 알림 멘트 정리 - resultMessage += "현재 강수량 " + snow + "m/s 이상입니다."; System.out.println("[ 푸시알림 ] 강수량 알림"); - sendAlarms(userIds, resultMessage); + alarmService.sendAlarms(userEmails, title, sb.toString()); + } /** * 기상 특보 알림 Listener * */ @Transactional - @KafkaListener(topics = "alarm-climate") - public void consumeClimateAlarm(@Payload String message) { - String resultMessage = ""; + @KafkaListener(topics = "alarm-climate", containerFactory = "weatherKafkaListenerContainerFactory") + public void consumeClimateAlarm(KafkaDto.WeatherDto weatherDto) { + int currentHour = LocalDateTime.now().getHour(); + // 22:00 ~ 07:00 는 알림을 전송하지 않음 + if (currentHour >= 22 || currentHour <= 7) { + return; + } + + String title = "Waither 기상 특보 알림"; + StringBuilder sb = new StringBuilder(); log.info("[ Kafka Listener ] 기상 특보"); - //TODO : 알림 보낼 사용자 정보 가져오기 (Redis) - List userIds = new ArrayList<>(); + String region = weatherDto.region(); + String message = weatherDto.message(); - resultMessage += "[기상청 기상 특보] " + message; + // Wind Climate를 True로 설정한 User Query + List userData = userDataRepository.findAllByClimateAlertIsTrue(); + + // 알림 보낼 사용자 이메일 + List userEmails = filterRegion(region, userData); + + sb.append("[기상청 기상 특보] ").append(message); - //TODO : 푸시알림 전송 System.out.println("[ 푸시알림 ] 기상 특보 알림"); - sendAlarms(userIds, resultMessage); + alarmService.sendAlarms(userEmails, title, sb.toString()); } - private void sendAlarms(List userEmails, String message) { - userEmails.forEach(email ->{ - String token = String.valueOf(redisUtils.get(String.valueOf(email))); - if (token == null) { //token을 찾지 못했을 경우 - throw new CustomException(ErrorCode.FIREBASE_TOKEN_NOT_FOUND); - } - + //지역 필터링 & 알림 규칙 검사 + private List filterRegionAndAlarm(String region, List userData, int currentHour) { + return userData.stream() + .filter(data -> { + Optional notiRecord = notificationRecordRepository.findByEmail(data.getEmail()); + return notiRecord.map(notificationRecord -> + (Math.abs(notiRecord.get().getLastWindAlarmReceived().getHour() - currentHour) >=3 + && notificationRecord.getRegion().equals(region) ) + ).orElse(false); + }) + .map(UserData::getEmail) + .toList(); + } - System.out.printf("[ 푸시알림 ] Email ---> {%d}", email); - System.out.printf("[ 푸시알림 ] message ---> {%s}", message); - }); + private List filterRegion(String region, List userData) { + return userData.stream() + .filter(data -> { + Optional notiRecord = notificationRecordRepository.findByEmail(data.getEmail()); + return notiRecord.map(notificationRecord -> notificationRecord.getRegion().equals(region)).orElse(false); + }) + .map(UserData::getEmail) + .toList(); } + //강수 표현 + private String getExpression(double prediction) { + //1~3mm : 약한 비 + if (prediction > 1 && prediction < 3) { + return "약한 비"; + //3~15mm : 비 + } else if (prediction >=3 && prediction < 15) { + return "비"; + //15~30mm 강한 비 + } else if (prediction >= 15 &&prediction <= 30) { + return "강한 비"; + //30mm~ 매우 강한 비 + } else if (prediction >= 30) { + return "매우 강한 비"; + } else return "비"; + } } From b0005ab48aead64d1230dadee91cedb2ff7a9c66 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Wed, 19 Jun 2024 19:12:05 +0900 Subject: [PATCH 22/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20Kafka=20?= =?UTF-8?q?Consumer=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/redis/NotificationRecord.java | 9 +++ .../notiservice/service/KafkaConsumer.java | 62 ++++++++++--------- 2 files changed, 42 insertions(+), 29 deletions(-) diff --git a/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java b/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java index eec7eb44..18d8b8d3 100644 --- a/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java +++ b/noti-service/src/main/java/com/waither/notiservice/domain/redis/NotificationRecord.java @@ -5,6 +5,7 @@ import org.springframework.data.redis.core.RedisHash; import java.time.LocalDateTime; +import java.util.Date; @Getter @Builder @@ -26,6 +27,14 @@ public class NotificationRecord { //사용자 마지막 위치 (지역) private String region; + public void initializeWindTime() { + lastWindAlarmReceived = LocalDateTime.now(); + } + + public void initializeRainTime() { + lastRainAlarmReceived = LocalDateTime.now(); + } + public void setLastRainAlarmReceived(LocalDateTime lastRainAlarmReceived) { this.lastRainAlarmReceived = lastRainAlarmReceived; } diff --git a/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java b/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java index 88fbae82..a51b8ae5 100644 --- a/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java +++ b/noti-service/src/main/java/com/waither/notiservice/service/KafkaConsumer.java @@ -146,38 +146,21 @@ public void consumeWindAlarm(KafkaDto.WeatherDto weatherDto) { // Wind Alert를 True로 설정한 User Query List userData = userDataRepository.findAllByWindAlertIsTrue(); - // 1. 현재 windStrength 보다 작게 설정한 유저 필터 - // 2. 이메일 추출 - // 3. 지역 일치 & 마지막 알림 3시간 경과했는지 필터 - List userEmails = userData.stream() - .filter(data -> data.getWindDegree() <= windStrength) - .map(UserData::getEmail) - .filter(email -> { - Optional notiRecord = notificationRecordRepository - .findByEmail(email); - if (notiRecord.isPresent()) { - //지역 일치 검사 - if (!notiRecord.get().getRegion().equals(region)) { - return false; - } - //경과 시간 검사 - int diff = notiRecord.get().getLastWindAlarmReceived().getHour() - currentHour; - if (Math.abs(diff) >= 3) { //3시간 이상 경과했는지? - return true; - } - } - log.warn(" [ Kafka Listener ] Notification Record 존재하지 않습니다. Email ---> {}", email); - return false; - }) - .toList(); + //알림 보낼 사용자 이메일 + List userEmails = filterRegionAndWindAlarm(region, userData, currentHour); - //TODO : 바람 세기 알림 멘트 정리 - sb.append("현재 바람 세기가 ").append(windStrength).append("m/s 이상입니다. 강풍에 주의하세요."); + sb.append("현재 바람 세기가 ").append(windStrength).append("m/s 이상입니다."); System.out.println("[ 푸시알림 ] 바람 세기 알림"); alarmService.sendAlarms(userEmails,title, sb.toString()); - //TODO : Notification Record 저장 + + //Record 알림 시간 초기화 + userEmails + .forEach(email -> { + Optional notificationRecord = notificationRecordRepository.findByEmail(email); + notificationRecord.ifPresent(NotificationRecord::initializeWindTime); + }); } @@ -217,12 +200,19 @@ public void consumeSnow(KafkaDto.WeatherDto weatherDto) { .append(getExpression(prediction)).append("가 내릴 예정입니다."); //알림 보낼 사용자 이메일 - List userEmails = filterRegionAndAlarm(region, userData, currentHour); + List userEmails = filterRegionAndRainAlarm(region, userData, currentHour); System.out.println("[ 푸시알림 ] 강수량 알림"); alarmService.sendAlarms(userEmails, title, sb.toString()); + //Record 알림 시간 초기화 + userEmails + .forEach(email -> { + Optional notificationRecord = notificationRecordRepository.findByEmail(email); + notificationRecord.ifPresent(NotificationRecord::initializeRainTime); + }); + } /** @@ -259,7 +249,7 @@ public void consumeClimateAlarm(KafkaDto.WeatherDto weatherDto) { //지역 필터링 & 알림 규칙 검사 - private List filterRegionAndAlarm(String region, List userData, int currentHour) { + private List filterRegionAndWindAlarm(String region, List userData, int currentHour) { return userData.stream() .filter(data -> { Optional notiRecord = notificationRecordRepository.findByEmail(data.getEmail()); @@ -272,6 +262,20 @@ private List filterRegionAndAlarm(String region, List userData .toList(); } + //지역 필터링 & 알림 규칙 검사 + private List filterRegionAndRainAlarm(String region, List userData, int currentHour) { + return userData.stream() + .filter(data -> { + Optional notiRecord = notificationRecordRepository.findByEmail(data.getEmail()); + return notiRecord.map(notificationRecord -> + (Math.abs(notiRecord.get().getLastRainAlarmReceived().getHour() - currentHour) >=3 + && notificationRecord.getRegion().equals(region) ) + ).orElse(false); + }) + .map(UserData::getEmail) + .toList(); + } + private List filterRegion(String region, List userData) { return userData.stream() .filter(data -> { From 62989de306b217457d10830aa38931975dcc792b Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Wed, 19 Jun 2024 19:17:29 +0900 Subject: [PATCH 23/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20Token=20?= =?UTF-8?q?controller=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/waither/notiservice/api/NotificationController.java | 5 ++--- .../com/waither/notiservice/service/NotificationService.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java b/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java index 74f115bd..cb343d52 100644 --- a/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java +++ b/noti-service/src/main/java/com/waither/notiservice/api/NotificationController.java @@ -4,7 +4,6 @@ import com.waither.notiservice.global.annotation.AuthUser; import com.waither.notiservice.global.response.ApiResponse; import com.waither.notiservice.service.NotificationService; -import com.waither.notiservice.utils.RedisUtils; import io.swagger.v3.oas.annotations.Operation; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -41,8 +40,8 @@ public ApiResponse sendGoOutAlarm(@AuthUser String email) { @Operation(summary = "Current Location", description = "현재 위치 전송") @PostMapping("/location") - public ApiResponse checkCurrentAlarm(@AuthUser String email, @RequestBody @Valid LocationDto locationDto) { - notificationService.checkCurrentAlarm(email, locationDto); + public ApiResponse updateLocation(@AuthUser String email, @RequestBody @Valid LocationDto locationDto) { + notificationService.updateLocation(email, locationDto); return ApiResponse.onSuccess(HttpStatus.OK); } diff --git a/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java b/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java index b06613c9..2b4bf4e0 100644 --- a/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java +++ b/noti-service/src/main/java/com/waither/notiservice/service/NotificationService.java @@ -124,7 +124,7 @@ public String sendGoOutAlarm(String email) { //현재 위치 업데이트 @Transactional - public void checkCurrentAlarm(String email, LocationDto locationDto) { + public void updateLocation(String email, LocationDto locationDto) { log.info("[ Notification Service ] email ---> {}", email); log.info("[ Notification Service ] 현재 위치 위도 (lat) ---> {}", locationDto.lat()); From 49b2fd36f0f718bde1d5b924cb1fb976889ea727 Mon Sep 17 00:00:00 2001 From: DDonghyeo Date: Sat, 22 Jun 2024 20:49:16 +0900 Subject: [PATCH 24/24] =?UTF-8?q?=E2=99=BB=EF=B8=8Frefactor=20:=20FireBase?= =?UTF-8?q?Utils=20Error=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/waither/notiservice/utils/FireBaseUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/noti-service/src/main/java/com/waither/notiservice/utils/FireBaseUtils.java b/noti-service/src/main/java/com/waither/notiservice/utils/FireBaseUtils.java index ab37a78c..fc8d83c9 100644 --- a/noti-service/src/main/java/com/waither/notiservice/utils/FireBaseUtils.java +++ b/noti-service/src/main/java/com/waither/notiservice/utils/FireBaseUtils.java @@ -34,7 +34,7 @@ public void sendSingleMessage(String token, String title, String body) { } catch (FirebaseMessagingException ex) { ex.printStackTrace(); - throw new CustomException(ErrorCode.FIREBASE_ERROR); + log.error("[ FireBaseUtils ] Failed to send message : {}",ex.getMessage()); } } @@ -71,7 +71,7 @@ public void sendAllMessages(List tokens, String title, String body) { } catch (FirebaseMessagingException ex) { ex.printStackTrace(); - throw new CustomException(ErrorCode.FIREBASE_ERROR); + log.error("[ FireBaseUtils ] Failed to send message : {}",ex.getMessage()); } } }