diff --git a/user-service/.gitignore b/user-service/.gitignore index 8d2a6921..ae284061 100644 --- a/user-service/.gitignore +++ b/user-service/.gitignore @@ -4,6 +4,7 @@ build/ !gradle/wrapper/gradle-wrapper.jar !**/src/main/**/build/ !**/src/test/**/build/ +data/** ### STS ### .apt_generated diff --git a/user-service/build.gradle b/user-service/build.gradle index 175cc031..e68e38b9 100644 --- a/user-service/build.gradle +++ b/user-service/build.gradle @@ -65,6 +65,8 @@ dependencies { //Kafka implementation 'org.springframework.kafka:spring-kafka' + //Kafka Test + testImplementation 'org.springframework.kafka:spring-kafka-test' //Redis implementation 'org.springframework.boot:spring-boot-starter-data-redis' diff --git a/user-service/docker-compose.yml b/user-service/docker-compose.yml new file mode 100644 index 00000000..1e34244e --- /dev/null +++ b/user-service/docker-compose.yml @@ -0,0 +1,22 @@ +version: '3' + +services: + zookeeper: + container_name: zookeeper + image: wurstmeister/zookeeper + expose: + - "2181" + + kafka: + container_name: kafka + image: wurstmeister/kafka:latest + depends_on: + - "zookeeper" + ports: + - "9092:9092" + environment: + KAFKA_ADVERTISED_HOST_NAME: localhost + KAFKA_ADVERTISED_PORT: 9092 + KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 + volumes: + - /var/run/docker.sock:/var/run/docker.sock \ No newline at end of file diff --git a/user-service/src/main/java/com/waither/userservice/config/CorsConfig.java b/user-service/src/main/java/com/waither/userservice/config/CorsConfig.java index a57ce3e1..64846c5d 100644 --- a/user-service/src/main/java/com/waither/userservice/config/CorsConfig.java +++ b/user-service/src/main/java/com/waither/userservice/config/CorsConfig.java @@ -2,6 +2,7 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @@ -9,7 +10,7 @@ import java.util.ArrayList; -@NoArgsConstructor(access = AccessLevel.PRIVATE) +@Configuration public class CorsConfig implements WebMvcConfigurer { public static CorsConfigurationSource apiConfigurationSource() { diff --git a/user-service/src/main/java/com/waither/userservice/config/SecurityConfig.java b/user-service/src/main/java/com/waither/userservice/config/SecurityConfig.java index 82bde1d1..8c2b3bc4 100644 --- a/user-service/src/main/java/com/waither/userservice/config/SecurityConfig.java +++ b/user-service/src/main/java/com/waither/userservice/config/SecurityConfig.java @@ -77,8 +77,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti http .addFilterAt(loginFilter, UsernamePasswordAuthenticationFilter.class); - http - .addFilterBefore(new JwtAuthorizationFilter(jwtUtil, redisUtil), JwtAuthenticationFilter.class); +// http +// .addFilterBefore(new JwtAuthorizationFilter(jwtUtil, redisUtil), JwtAuthenticationFilter.class); http .addFilterBefore(new JwtExceptionFilter(), JwtAuthenticationFilter.class); diff --git a/user-service/src/main/java/com/waither/userservice/controller/UserController.java b/user-service/src/main/java/com/waither/userservice/controller/UserController.java index 8460b2fb..ee08b4b1 100644 --- a/user-service/src/main/java/com/waither/userservice/controller/UserController.java +++ b/user-service/src/main/java/com/waither/userservice/controller/UserController.java @@ -66,7 +66,7 @@ public ApiResponse submitTemporaryPassword(@RequestParam String email) { } // 닉네임 변경 - @PutMapping("/update-nickname") + @PutMapping("/nickname") public ApiResponse updateNickname(@AuthUser User user, @RequestBody UserReqDto.NicknameDto nicknameDto) { userService.updateNickname(user, nicknameDto.nickname()); @@ -82,7 +82,7 @@ public ApiResponse passwordCheckEmail(@AuthUser User user, } // 비밀번호 변경 - @PutMapping("/update-password") + @PutMapping("/password") public ApiResponse updatePassword(@AuthUser User user, @Valid @RequestBody UserReqDto.UpdatePasswordDto updatePasswordDto) { userService.updatePassword(user, updatePasswordDto.password()); diff --git a/user-service/src/main/java/com/waither/userservice/converter/SurveyConverter.java b/user-service/src/main/java/com/waither/userservice/converter/SurveyConverter.java index d76a0107..cff70c3f 100644 --- a/user-service/src/main/java/com/waither/userservice/converter/SurveyConverter.java +++ b/user-service/src/main/java/com/waither/userservice/converter/SurveyConverter.java @@ -7,9 +7,8 @@ import com.waither.userservice.global.response.ErrorCode; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import lombok.experimental.UtilityClass; -import static com.waither.userservice.util.CalculateUtil.calculateMedian; +import static com.waither.userservice.global.util.CalculateUtil.calculateMedian; @NoArgsConstructor(access = AccessLevel.PRIVATE) diff --git a/user-service/src/main/java/com/waither/userservice/dto/request/SurveyReqDto.java b/user-service/src/main/java/com/waither/userservice/dto/request/SurveyReqDto.java index 7163cddb..016a8e1a 100644 --- a/user-service/src/main/java/com/waither/userservice/dto/request/SurveyReqDto.java +++ b/user-service/src/main/java/com/waither/userservice/dto/request/SurveyReqDto.java @@ -6,6 +6,8 @@ public class SurveyReqDto { // Todo : DTO에서 날짜/시간 관련 필드는 String 타입으로 선언하고, 서비스 계층에서 원하는 형식으로 파싱하는 것이 좋은가 고민중. public record SurveyRequestDto( + + // level Integer ans, LocalDateTime time ) {} diff --git a/user-service/src/main/java/com/waither/userservice/entity/Setting.java b/user-service/src/main/java/com/waither/userservice/entity/Setting.java index b78b690a..d547a81f 100644 --- a/user-service/src/main/java/com/waither/userservice/entity/Setting.java +++ b/user-service/src/main/java/com/waither/userservice/entity/Setting.java @@ -10,7 +10,6 @@ import lombok.*; import org.hibernate.annotations.DynamicInsert; -import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.DynamicUpdate; // 코드 일부 생략 diff --git a/user-service/src/main/java/com/waither/userservice/entity/UserMedian.java b/user-service/src/main/java/com/waither/userservice/entity/UserMedian.java index b6b5e869..66a5fa3c 100644 --- a/user-service/src/main/java/com/waither/userservice/entity/UserMedian.java +++ b/user-service/src/main/java/com/waither/userservice/entity/UserMedian.java @@ -5,7 +5,7 @@ import jakarta.persistence.*; import lombok.*; -import static com.waither.userservice.util.CalculateUtil.calculateMedian; +import static com.waither.userservice.global.util.CalculateUtil.calculateMedian; @Builder @Getter diff --git a/user-service/src/main/java/com/waither/userservice/global/jwt/filter/JwtAuthorizationFilter.java b/user-service/src/main/java/com/waither/userservice/global/jwt/filter/JwtAuthorizationFilter.java index fcf2633c..04636856 100644 --- a/user-service/src/main/java/com/waither/userservice/global/jwt/filter/JwtAuthorizationFilter.java +++ b/user-service/src/main/java/com/waither/userservice/global/jwt/filter/JwtAuthorizationFilter.java @@ -12,26 +12,26 @@ import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; -@Slf4j -@RequiredArgsConstructor -public class JwtAuthorizationFilter extends OncePerRequestFilter { - - private final JwtUtil jwtUtil; - private final RedisUtil redisUtil; - - @Override - protected void doFilterInternal( - @NonNull HttpServletRequest request, - @NonNull HttpServletResponse response, - @NonNull FilterChain filterChain - ) throws ServletException, IOException { - log.info("[*] Jwt Filter"); - if (request.getServletPath().equals("/login")) { - filterChain.doFilter(request, response); - return; - } - - filterChain.doFilter(request, response); - - } -} \ No newline at end of file +//@Slf4j +//@RequiredArgsConstructor +//public class JwtAuthorizationFilter extends OncePerRequestFilter { +// +// private final JwtUtil jwtUtil; +// private final RedisUtil redisUtil; +// +// @Override +// protected void doFilterInternal( +// @NonNull HttpServletRequest request, +// @NonNull HttpServletResponse response, +// @NonNull FilterChain filterChain +// ) throws ServletException, IOException { +// log.info("[*] Jwt Filter"); +// if (request.getServletPath().equals("/login")) { +// filterChain.doFilter(request, response); +// return; +// } +// +// filterChain.doFilter(request, response); +// +// } +//} \ No newline at end of file diff --git a/user-service/src/main/java/com/waither/userservice/util/CalculateUtil.java b/user-service/src/main/java/com/waither/userservice/global/util/CalculateUtil.java similarity index 85% rename from user-service/src/main/java/com/waither/userservice/util/CalculateUtil.java rename to user-service/src/main/java/com/waither/userservice/global/util/CalculateUtil.java index 11b5633d..601f14ab 100644 --- a/user-service/src/main/java/com/waither/userservice/util/CalculateUtil.java +++ b/user-service/src/main/java/com/waither/userservice/global/util/CalculateUtil.java @@ -1,4 +1,4 @@ -package com.waither.userservice.util; +package com.waither.userservice.global.util; import lombok.AccessLevel; import lombok.NoArgsConstructor; diff --git a/user-service/src/main/java/com/waither/userservice/kafka/KafkaConfig.java b/user-service/src/main/java/com/waither/userservice/kafka/KafkaConfig.java new file mode 100644 index 00000000..fedea078 --- /dev/null +++ b/user-service/src/main/java/com/waither/userservice/kafka/KafkaConfig.java @@ -0,0 +1,86 @@ +package com.waither.userservice.kafka; + +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.*; +import org.springframework.kafka.listener.ContainerProperties; +import org.springframework.kafka.support.serializer.JsonDeserializer; +import org.springframework.kafka.support.serializer.JsonSerializer; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@EnableKafka +@Configuration +public class KafkaConfig { + + @Value("${spring.kafka.bootstrap-servers}") + private String bootstrapServer; + + @Value("${spring.kafka.consumer.group-id}") + private String groupId; + + // Producer 관련 설정 + private ProducerFactory producerFactory(Class valueClass) { + Map config = new HashMap<>(); + config.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServer); + config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + + if (valueClass == String.class) { + config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); + } else { + config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); + } + + return new DefaultKafkaProducerFactory<>(config); + } + + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory(Object.class)); + } + + @Bean + public KafkaTemplate kafkaStringTemplate() { + return new KafkaTemplate<>(producerFactory(String.class)); + } + + // Consumer 관련 설정 + private ConsumerFactory consumerFactory(Class valueClass) { + HashMap config = new HashMap<>(); + config.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServer); + config.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); + + return new DefaultKafkaConsumerFactory<>(config, new StringDeserializer(), + new JsonDeserializer<>(valueClass)); + } + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory(Object.class)); + factory.setConcurrency(3); + factory.setBatchListener(true); + factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.BATCH); + return factory; + } + + @Bean + public ConcurrentKafkaListenerContainerFactory kafkaStringListenerContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory(String.class)); + factory.setConcurrency(3); + factory.setBatchListener(true); + factory.getContainerProperties().setAckMode(ContainerProperties.AckMode.BATCH); + return factory; + } +} \ No newline at end of file diff --git a/user-service/src/main/java/com/waither/userservice/kafka/KafkaConsumer.java b/user-service/src/main/java/com/waither/userservice/kafka/KafkaConsumer.java new file mode 100644 index 00000000..83b8caa5 --- /dev/null +++ b/user-service/src/main/java/com/waither/userservice/kafka/KafkaConsumer.java @@ -0,0 +1,24 @@ +//package com.waither.userservice.kafka; +// +//import lombok.RequiredArgsConstructor; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.kafka.annotation.KafkaListener; +//import org.springframework.stereotype.Component; +// +//@Slf4j +//@Component +//@RequiredArgsConstructor +//public class KafkaConsumer { +// +// // @KafkaListener 통해 topic, group 구독 +// @KafkaListener(topics = "${spring.kafka.template.topic}", groupId = "${spring.kafka.consumer.group-id}") +// public void consume(KafkaMessage message) { +// log.info("[*] Kafka Consumer(Object) Message : {} ", message); +// } +// +// // @KafkaListener(topics = "${spring.kafka.template.default-topic}", groupId = "${spring.kafka.consumer.group-id}") +// // public void consume(String message) { +// // log.info("[*] Kafka Consumer(String) Message : {} ", message); +// // } +//} +// diff --git a/user-service/src/main/java/com/waither/userservice/kafka/KafkaConverter.java b/user-service/src/main/java/com/waither/userservice/kafka/KafkaConverter.java new file mode 100644 index 00000000..2db3f358 --- /dev/null +++ b/user-service/src/main/java/com/waither/userservice/kafka/KafkaConverter.java @@ -0,0 +1,48 @@ +package com.waither.userservice.kafka; + +import com.waither.userservice.entity.UserMedian; +import com.waither.userservice.entity.Setting; +import com.waither.userservice.entity.User; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class KafkaConverter { + + public static KafkaDto.InitialDataDto toInitialData(User user, Setting setting, UserMedian userMedian + ) { + return KafkaDto.InitialDataDto.builder() + .nickName(user.getNickname()) + .climateAlert(setting.isClimateAlert()) + .userAlert(setting.isUserAlert()) + .snowAlert(setting.isSnowAlert()) + .windAlert(setting.isWindAlert()) + .windDegree(setting.getWindDegree()) + .regionReport(setting.isRegionReport()) + .weight(setting.getWeight()) + .medianOf1And2(userMedian.getMedianOf1And2()) + .medianOf2And3(userMedian.getMedianOf2And3()) + .medianOf3And4(userMedian.getMedianOf3And4()) + .medianOf4And5(userMedian.getMedianOf4And5()) + .build(); + } + + public static KafkaDto.UserMedianDto toUserMedianDto(User user, UserMedian userMedian) { + List> medians = Arrays.asList( + Map.of("medianOf1And2", userMedian.getMedianOf1And2()), + Map.of("medianOf2And3", userMedian.getMedianOf2And3()), + Map.of("medianOf3And4", userMedian.getMedianOf3And4()), + Map.of("medianOf4And5", userMedian.getMedianOf4And5()) + ); + return new KafkaDto.UserMedianDto(user.getId(), medians); + } + + public static KafkaDto.UserSettingsDto toSettingDto(User user, String key, String value) { + return new KafkaDto.UserSettingsDto(user.getId(), key, value); + } + +} diff --git a/user-service/src/main/java/com/waither/userservice/kafka/KafkaDto.java b/user-service/src/main/java/com/waither/userservice/kafka/KafkaDto.java new file mode 100644 index 00000000..2a01abeb --- /dev/null +++ b/user-service/src/main/java/com/waither/userservice/kafka/KafkaDto.java @@ -0,0 +1,39 @@ +package com.waither.userservice.kafka; + +import lombok.Builder; + +import java.util.List; +import java.util.Map; + +public class KafkaDto { + + @Builder + 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 record UserMedianDto( + Long userId, + List> medians + + ) {} + + public record UserSettingsDto( + Long userId, + String key, + String value + ) {} + +} diff --git a/user-service/src/main/java/com/waither/userservice/kafka/KafkaProducer.java b/user-service/src/main/java/com/waither/userservice/kafka/KafkaProducer.java new file mode 100644 index 00000000..7e986147 --- /dev/null +++ b/user-service/src/main/java/com/waither/userservice/kafka/KafkaProducer.java @@ -0,0 +1,44 @@ +package com.waither.userservice.kafka; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.SendResult; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; + +import java.util.concurrent.CompletableFuture; + +@Slf4j +@Service +@RequiredArgsConstructor +public class KafkaProducer { + + private final KafkaTemplate kafkaTemplate; + + public void produceMessage(String topic, T message) { + long startTime = System.currentTimeMillis(); + + log.info("[*] Sending message to topic: {}", topic); + log.info("[*] Message content: {}", message); + + kafkaTemplate.send(topic, message); + + CompletableFuture> future = kafkaTemplate.send(topic, message); + + future.whenComplete(((result, throwable) -> { + if (throwable == null) { + // 해당 파티션의 offset + log.info("[*] offset : {}", result.getRecordMetadata().offset()); + // 메시지 전송 후의 시간 기록 + long endTime = System.currentTimeMillis(); + log.info("[*] Kafka Message(Object) sent successfully in {} ms", endTime - startTime); + } else { + log.error("[*] fail to publish", throwable); + } + })); + } +} + + diff --git a/user-service/src/main/java/com/waither/userservice/kafka/KafkaService.java b/user-service/src/main/java/com/waither/userservice/kafka/KafkaService.java new file mode 100644 index 00000000..e2b2252b --- /dev/null +++ b/user-service/src/main/java/com/waither/userservice/kafka/KafkaService.java @@ -0,0 +1,33 @@ +package com.waither.userservice.kafka; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class KafkaService { + + private final KafkaProducer kafkaProducer; + + @Value("${spring.kafka.template.initial-data-topic}") + private String initialDataTopic; + + @Value("${spring.kafka.template.user-settings-topic}") + private String userSettingTopic; + + @Value("${spring.kafka.template.user-median-topic}") + private String userMedianTopic; + + public void sendInitialData(KafkaDto.InitialDataDto initialDataDto) { + kafkaProducer.produceMessage(initialDataTopic, initialDataDto); + } + + public void sendUserSettings(KafkaDto.UserSettingsDto userSettingsDto) { + kafkaProducer.produceMessage(userSettingTopic, userSettingsDto); + } + + public void sendUserMedian(KafkaDto.UserMedianDto userMedianDto) { + kafkaProducer.produceMessage(userMedianTopic, userMedianDto); + } +} \ No newline at end of file diff --git a/user-service/src/main/java/com/waither/userservice/service/commandService/SettingService.java b/user-service/src/main/java/com/waither/userservice/service/commandService/SettingService.java index 81c226a9..e621a039 100644 --- a/user-service/src/main/java/com/waither/userservice/service/commandService/SettingService.java +++ b/user-service/src/main/java/com/waither/userservice/service/commandService/SettingService.java @@ -1,26 +1,25 @@ package com.waither.userservice.service.commandService; import com.waither.userservice.dto.request.SettingReqDto; -import com.waither.userservice.dto.request.SurveyReqDto; import com.waither.userservice.entity.Region; import com.waither.userservice.entity.Setting; import com.waither.userservice.entity.User; -import com.waither.userservice.entity.UserData; import com.waither.userservice.global.exception.CustomException; import com.waither.userservice.global.response.ErrorCode; +import com.waither.userservice.kafka.KafkaConverter; +import com.waither.userservice.kafka.KafkaDto; +import com.waither.userservice.kafka.KafkaService; import com.waither.userservice.repository.RegionRepository; import com.waither.userservice.repository.SettingRepository; import com.waither.userservice.repository.UserRepository; -import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.time.DayOfWeek; import java.util.EnumSet; import java.util.List; -import java.util.Optional; -import java.util.Set; import java.util.stream.Collectors; @Slf4j @@ -33,6 +32,8 @@ public class SettingService { private final SettingRepository settingRepository; private final RegionRepository regionRepository; + private final KafkaService kafkaService; + /* --------- Update --------- */ // 사용자 맞춤 서비스 제공 설정 변경 @@ -91,6 +92,12 @@ public void updateOutAlert(User user, SettingReqDto.OutAlertDto outAlertDto) { public void updateClimateAlert(User user, SettingReqDto.ClimateAlertDto climateAlertDto) { Setting setting = user.getSetting(); setting.setClimateAlert(climateAlertDto.climateAlert()); + + // Kafka 전송 + KafkaDto.UserSettingsDto settingDto = + KafkaConverter.toSettingDto(user, "climateAlert", String.valueOf(climateAlertDto.climateAlert())); + kafkaService.sendUserSettings(settingDto); + settingRepository.save(setting); } @@ -101,6 +108,12 @@ public void updateUserAlert(User user, SettingReqDto.UserAlertDto userAlertDto) } Setting setting = user.getSetting(); setting.setUserAlert(userAlertDto.userAlert()); + + // Kafka 전송 + KafkaDto.UserSettingsDto settingDto = + KafkaConverter.toSettingDto(user, "userAlert", String.valueOf(userAlertDto.userAlert())); + kafkaService.sendUserSettings(settingDto); + settingRepository.save(setting); } @@ -111,6 +124,12 @@ public void updateSnowAlert(User user, SettingReqDto.SnowAlertDto snowAlertDto) } Setting setting = user.getSetting(); setting.setSnowAlert(snowAlertDto.snowAlert()); + + // Kafka 전송 + KafkaDto.UserSettingsDto settingDto = + KafkaConverter.toSettingDto(user, "snowAlert", String.valueOf(snowAlertDto.snowAlert())); + kafkaService.sendUserSettings(settingDto); + settingRepository.save(setting); } @@ -121,11 +140,20 @@ public void updateWind(User user, SettingReqDto.WindDto windDto) { } Setting setting = user.getSetting(); if (windDto.windAlert() != null) { + // Kafka 전송 + KafkaDto.UserSettingsDto settingDto = + KafkaConverter.toSettingDto(user, "windAlert", String.valueOf(windDto.windAlert())); + kafkaService.sendUserSettings(settingDto); setting.setWindAlert(windDto.windAlert()); } if (windDto.windDegree() != null) { + // Kafka 전송 + KafkaDto.UserSettingsDto settingDto = + KafkaConverter.toSettingDto(user, "windDegree", String.valueOf(windDto.windDegree())); + kafkaService.sendUserSettings(settingDto); setting.setWindDegree(windDto.windDegree()); } + settingRepository.save(setting); } @@ -133,6 +161,12 @@ public void updateWind(User user, SettingReqDto.WindDto windDto) { public void updateRegionReport(User user, SettingReqDto.RegionReportDto regionReportDto) { Setting setting = user.getSetting(); setting.setRegionReport(regionReportDto.regionReport()); + + // Kafka 전송 + KafkaDto.UserSettingsDto settingDto = + KafkaConverter.toSettingDto(user, "regionReport", String.valueOf(regionReportDto.regionReport())); + kafkaService.sendUserSettings(settingDto); + settingRepository.save(setting); } @@ -147,6 +181,13 @@ public void updateRegion(User user, SettingReqDto.RegionDto regionDto) { public void updateWeight(User user, SettingReqDto.WeightDto weightDto) { Setting setting = user.getSetting(); setting.setWeight(weightDto.weight()); + + // Kafka 전송 + KafkaDto.UserSettingsDto settingDto = + KafkaConverter.toSettingDto(user, "weight", String.valueOf(weightDto.weight())); + kafkaService.sendUserSettings(settingDto); + settingRepository.save(setting); } + } diff --git a/user-service/src/main/java/com/waither/userservice/service/commandService/SurveyService.java b/user-service/src/main/java/com/waither/userservice/service/commandService/SurveyService.java index 8b88deda..f357dda4 100644 --- a/user-service/src/main/java/com/waither/userservice/service/commandService/SurveyService.java +++ b/user-service/src/main/java/com/waither/userservice/service/commandService/SurveyService.java @@ -6,6 +6,9 @@ import com.waither.userservice.entity.enums.Season; import com.waither.userservice.global.exception.CustomException; import com.waither.userservice.global.response.ErrorCode; +import com.waither.userservice.kafka.KafkaConverter; +import com.waither.userservice.kafka.KafkaDto; +import com.waither.userservice.kafka.KafkaService; import com.waither.userservice.repository.SurveyRepository; import com.waither.userservice.repository.UserDataRepository; import com.waither.userservice.repository.UserMedianRepository; @@ -29,6 +32,8 @@ public class SurveyService { private final UserDataRepository userDataRepository; private final UserMedianRepository userMedianRepository; + private final KafkaService kafkaService; + @Transactional public void createSurvey(User user, SurveyReqDto.SurveyRequestDto surveyRequestDto) { Double temp = getTemp(surveyRequestDto.time()); @@ -43,6 +48,10 @@ public void createSurvey(User user, SurveyReqDto.SurveyRequestDto surveyRequestD updateUserData(userData, surveyRequestDto.ans(), temp); updateUserMedian(userData, userMedian); + // Kafka 전송 + KafkaDto.UserMedianDto userMedianDto = KafkaConverter.toUserMedianDto(user, userMedian); + kafkaService.sendUserMedian(userMedianDto); + surveyRepository.save(survey); } @@ -55,6 +64,7 @@ private void updateUserData(UserData userData, Integer ans, Double temp) { } userData.updateLevelValue(ans, newValue); + userDataRepository.save(userData); } diff --git a/user-service/src/main/java/com/waither/userservice/service/commandService/UserService.java b/user-service/src/main/java/com/waither/userservice/service/commandService/UserService.java index 52ec96a7..38173117 100644 --- a/user-service/src/main/java/com/waither/userservice/service/commandService/UserService.java +++ b/user-service/src/main/java/com/waither/userservice/service/commandService/UserService.java @@ -10,9 +10,14 @@ import com.waither.userservice.global.jwt.dto.JwtDto; import com.waither.userservice.global.jwt.util.JwtUtil; import com.waither.userservice.global.util.RedisUtil; +import com.waither.userservice.kafka.KafkaConverter; +import com.waither.userservice.kafka.KafkaDto; +import com.waither.userservice.kafka.KafkaProducer; +import com.waither.userservice.kafka.KafkaService; import com.waither.userservice.repository.UserRepository; import com.waither.userservice.global.exception.CustomException; import com.waither.userservice.global.response.ErrorCode; +import org.springframework.kafka.core.KafkaTemplate; import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -26,6 +31,8 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import static com.waither.userservice.service.commandService.SurveyService.getCurrentSeason; + @Slf4j @RequiredArgsConstructor @Transactional @@ -38,6 +45,8 @@ public class UserService { private static final String VERIFIED_PREFIX = "Verified_"; private final EmailService emailService; + private final KafkaService kafkaService; + private final RedisUtil redisUtil; private final JwtUtil jwtUtil; @@ -72,12 +81,24 @@ public void signup(UserReqDto.SignUpRequestDto requestDto) { }) .toList(); + // 연관관계 설정 newSetting.setRegion(newRegion); newUser.setSetting(newSetting); newUser.setUserData(userDataList); newUser.setUserMedian(userMedianList); + // + Season currentSeason = getCurrentSeason(); + UserMedian currentUserMedian = userMedianList.stream() + .filter(userMedian -> userMedian.getSeason() == currentSeason) + .findFirst() + .orElseThrow(() -> new CustomException(ErrorCode.INVALID_SEASON)); + + // 초기값 Kafka 전송 + KafkaDto.InitialDataDto initialDataDto = KafkaConverter.toInitialData(newUser, newSetting, currentUserMedian); + kafkaService.sendInitialData(initialDataDto); + userRepository.save(newUser); } @@ -211,6 +232,11 @@ public void updatePassword(User user, String newPassword) { // 닉네임 변경 public void updateNickname(User user, String nickanme) { user.setNickname(nickanme); + + // Kafka 전송 + KafkaDto.UserSettingsDto settingDto = KafkaConverter.toSettingDto(user, "nickanme", nickanme); + kafkaService.sendUserSettings(settingDto); + userRepository.save(user); } diff --git a/user-service/src/main/resources/application-secret.yml b/user-service/src/main/resources/application-secret.yml deleted file mode 100644 index 89ae92ab..00000000 --- a/user-service/src/main/resources/application-secret.yml +++ /dev/null @@ -1,18 +0,0 @@ -#spring: -# datasource: -# driver-class-name: com.mysql.cj.jdbc.Driver -# url: jdbc:mysql://localhost:3306 -# username: root -# password: -# jpa: -# show-sql: true -# hibernate: -# ddl-auto: update -# properties: -# hibernate: -# dialect: org.hibernate.dialect.MySQL8Dialect -# show_sql: true # hibernate 로그 남길지 -# data: -# redis: -# host: localhost -# port: 6379 diff --git a/user-service/src/main/resources/application.yml b/user-service/src/main/resources/application.yml deleted file mode 100644 index a0914764..00000000 --- a/user-service/src/main/resources/application.yml +++ /dev/null @@ -1,4 +0,0 @@ -#spring: -# profiles: -# active: local -# include: secret