diff --git a/team1-api/src/main/java/goorm/deepdive/team1/api/user/application/UserFacade.java b/team1-api/src/main/java/goorm/deepdive/team1/api/user/application/UserFacade.java index 48eebac..1211198 100644 --- a/team1-api/src/main/java/goorm/deepdive/team1/api/user/application/UserFacade.java +++ b/team1-api/src/main/java/goorm/deepdive/team1/api/user/application/UserFacade.java @@ -9,7 +9,6 @@ import java.util.List; import java.util.Map; -import java.util.Objects; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -26,16 +25,12 @@ import goorm.deepdive.team1.domain.address.application.AddressQueryService; import goorm.deepdive.team1.domain.address.application.KakaoApiAddressService; import goorm.deepdive.team1.domain.address.domain.Address; -import goorm.deepdive.team1.domain.addresshistory.application.AddressHistoryCommandService; -import goorm.deepdive.team1.domain.addresshistory.domain.AddressHistory; import goorm.deepdive.team1.domain.user.application.UserCommandService; import goorm.deepdive.team1.domain.user.application.UserQueryService; import goorm.deepdive.team1.domain.user.domain.User; import goorm.deepdive.team1.domain.user.domain.UserCache; import goorm.deepdive.team1.domain.user.domain.UserDocument; import goorm.deepdive.team1.domain.user.domain.enums.AgeGroups; -import goorm.deepdive.team1.infra.kafka.producer.AddressHistoryProducer; -import goorm.deepdive.team1.infra.kafka.producer.UserProducer; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -45,10 +40,7 @@ public class UserFacade { private final UserQueryService userQueryService; private final UserCommandService userCommandService; - private final AddressHistoryCommandService addressHistoryCommandService; private final AddressCommandService addressCommandService; - private final UserProducer userProducer; - private final AddressHistoryProducer addressHistoryProducer; private final KakaoApiAddressService kakaoApiAddressService; private final AddressQueryService addressQueryService; @@ -65,11 +57,6 @@ public UserPersistResponse create(UserCreateRequest request) { request.age() ); - AddressHistory addressHistory = addressHistoryCommandService.create(user, address); - - userProducer.sendMessageToCreate(user); - addressHistoryProducer.sendMessageToCreate(addressHistory); - return UserPersistResponse.from(user); } @@ -102,20 +89,9 @@ public PaginatedListResponse getAll(Pageable pageable) { @Transactional public void update(Long id, UserUpdateRequest request) { Address address = findOrCreateAddress(request.roadAddress()); - User user = userQueryService.getById(id); - - boolean isAddressChanged = !Objects.equals(address.getId(), user.getAddress().getId()); - userCommandService.update(user, request.name(), request.email(), request.phoneNumber(), request.gender(), request.age(), address); - - if (isAddressChanged) { - AddressHistory addressHistory = addressHistoryCommandService.create(user, address); - addressHistoryProducer.sendMessageToDelete(addressHistory); - } - - userProducer.sendMessageToUpdate(user); } @Transactional @@ -155,16 +131,15 @@ public List getUserHeatMap(List region, List ag } @Transactional - @Scheduled(cron = "0 0 0 * * *") + @Scheduled(cron = "20 18 15 * * *") public void cleanUpDeletedUsers() { - log.info("πŸ—‘οΈ μœ μ € μ‚­μ œ μŠ€μΌ€μ€„λ§ μž‘λ™..."); List userIdsToDelete = userQueryService.findIdsByDeletedAtIsNotNull(); if (userIdsToDelete.isEmpty()) { log.info("βœ… μ‚­μ œν•  μœ μ € 데이터가 μ—†μŠ΅λ‹ˆλ‹€."); return; } - addressHistoryCommandService.cleanUpDeletedAddressHistories(userIdsToDelete); + userCommandService.cleanUpDeletedUsers(userIdsToDelete); } diff --git a/team1-api/src/main/java/goorm/deepdive/team1/api/user/listener/UserEventListener.java b/team1-api/src/main/java/goorm/deepdive/team1/api/user/listener/UserEventListener.java new file mode 100644 index 0000000..4f3c015 --- /dev/null +++ b/team1-api/src/main/java/goorm/deepdive/team1/api/user/listener/UserEventListener.java @@ -0,0 +1,31 @@ +package goorm.deepdive.team1.api.user.listener; + +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import goorm.deepdive.team1.domain.addresshistory.application.AddressHistoryCommandService; +import goorm.deepdive.team1.domain.user.event.UserCreatedEvent; +import goorm.deepdive.team1.domain.user.event.UserDeletedEvent; +import goorm.deepdive.team1.domain.user.event.UserUpdatedEvent; +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +public class UserEventListener { + private final AddressHistoryCommandService addressHistoryCommandService; + + @EventListener + public void handleUserCreatedEvent(UserCreatedEvent event) { + addressHistoryCommandService.create(event.user()); + } + + @EventListener + public void handleUserUpdatedEvent(UserUpdatedEvent event) { + addressHistoryCommandService.update(event.user()); + } + + @EventListener + public void handleUserDeletedEvent(UserDeletedEvent event) { + addressHistoryCommandService.cleanUpDeletedAddressHistories(event.userIds()); + } +} diff --git a/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/application/AddressHistoryCommandService.java b/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/application/AddressHistoryCommandService.java index ca2cea5..7637220 100644 --- a/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/application/AddressHistoryCommandService.java +++ b/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/application/AddressHistoryCommandService.java @@ -5,8 +5,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import goorm.deepdive.team1.domain.address.domain.Address; import goorm.deepdive.team1.domain.addresshistory.domain.AddressHistory; +import goorm.deepdive.team1.domain.addresshistory.infrastructure.AddressHistoryProducer; import goorm.deepdive.team1.domain.addresshistory.infrastructure.AddressHistoryRepository; import goorm.deepdive.team1.domain.user.domain.User; import lombok.RequiredArgsConstructor; @@ -16,10 +16,16 @@ @Transactional public class AddressHistoryCommandService { private final AddressHistoryRepository addressHistoryRepository; + private final AddressHistoryProducer addressHistoryProducer; - public AddressHistory create(User user, Address address) { - AddressHistory addressHistory = AddressHistory.create(user, address); - return addressHistoryRepository.save(addressHistory); + public void create(User user) { + AddressHistory addressHistory = AddressHistory.create(user); + addressHistoryProducer.sendMessageToCreate(addressHistoryRepository.save(addressHistory)); + } + + public void update(User user) { + AddressHistory addressHistory = AddressHistory.create(user); + addressHistoryProducer.sendMessageToDelete(addressHistoryRepository.save(addressHistory)); } public void saveAll(List addressHistories) { diff --git a/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/domain/AddressHistory.java b/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/domain/AddressHistory.java index 30df94c..64ded0b 100644 --- a/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/domain/AddressHistory.java +++ b/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/domain/AddressHistory.java @@ -7,6 +7,7 @@ import goorm.deepdive.team1.domain.address.domain.Address; import goorm.deepdive.team1.domain.common.BaseTimeEntity; import goorm.deepdive.team1.domain.user.domain.User; +import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; @@ -32,7 +33,7 @@ public class AddressHistory extends BaseTimeEntity { @GeneratedValue(strategy = IDENTITY) private Long id; - @ManyToOne(fetch = LAZY) + @ManyToOne(fetch = LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "user_id", nullable = false) private User user; @@ -40,10 +41,10 @@ public class AddressHistory extends BaseTimeEntity { @JoinColumn(name = "address_id", nullable = false) private Address address; - public static AddressHistory create(User user, Address address) { + public static AddressHistory create(User user) { return AddressHistory.builder() .user(user) - .address(address) + .address(user.getAddress()) .build(); } } diff --git a/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/infrastructure/AddressHistoryProducer.java b/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/infrastructure/AddressHistoryProducer.java new file mode 100644 index 0000000..750bcbb --- /dev/null +++ b/team1-domain/src/main/java/goorm/deepdive/team1/domain/addresshistory/infrastructure/AddressHistoryProducer.java @@ -0,0 +1,9 @@ +package goorm.deepdive.team1.domain.addresshistory.infrastructure; + +import goorm.deepdive.team1.domain.addresshistory.domain.AddressHistory; + +public interface AddressHistoryProducer { + void sendMessageToCreate(AddressHistory addressHistory); + + void sendMessageToDelete(AddressHistory addressHistory); +} diff --git a/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/application/UserCommandService.java b/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/application/UserCommandService.java index 8b6fdd3..b430d97 100644 --- a/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/application/UserCommandService.java +++ b/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/application/UserCommandService.java @@ -1,13 +1,18 @@ package goorm.deepdive.team1.domain.user.application; import java.util.List; +import java.util.Objects; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import goorm.deepdive.team1.domain.address.domain.Address; import goorm.deepdive.team1.domain.user.domain.User; import goorm.deepdive.team1.domain.user.domain.UserCache; import goorm.deepdive.team1.domain.user.domain.enums.Gender; +import goorm.deepdive.team1.domain.user.event.UserCreatedEvent; +import goorm.deepdive.team1.domain.user.event.UserUpdatedEvent; +import goorm.deepdive.team1.domain.user.infrastructure.UserProducer; import goorm.deepdive.team1.domain.user.infrastructure.UserRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -17,10 +22,14 @@ @RequiredArgsConstructor public class UserCommandService { private final UserRepository userRepository; + private final ApplicationEventPublisher eventPublisher; + private final UserProducer userProducer; public User create(String name, String email, String phoneNumber, Address address, Gender gender, Integer age) { User user = User.create(name, email, phoneNumber, address, gender, age); - return userRepository.save(user); + userProducer.sendMessageToCreate(userRepository.save(user)); + eventPublisher.publishEvent(UserCreatedEvent.of(user)); + return user; } public void update(User user, String name, String email, String phoneNumber, Gender gender, Integer age, Address address) { @@ -29,7 +38,16 @@ public void update(User user, String name, String email, String phoneNumber, Gen user.updatePhoneNumber(phoneNumber); user.updateGender(gender); user.updateAge(age); + + if (!Objects.equals(user.getAddress().getId(), address.getId())) { + updateAddress(user, address); + } + } + + private void updateAddress(User user, Address address) { user.updateAddress(address); + userProducer.sendMessageToUpdate(user); + eventPublisher.publishEvent(UserUpdatedEvent.of(user)); } public void delete(User user) { @@ -43,6 +61,7 @@ public void saveCache(UserCache userCache) { public void cleanUpDeletedUsers(List ids) { userRepository.deleteScheduling(ids); log.info("βœ… {}λͺ…μ˜ μœ μ € 데이터가 μ‚­μ œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€", ids.size()); + eventPublisher.publishEvent(ids); } public void saveAllCaches(List userCaches) { diff --git a/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/event/UserCreatedEvent.java b/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/event/UserCreatedEvent.java new file mode 100644 index 0000000..df17b3a --- /dev/null +++ b/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/event/UserCreatedEvent.java @@ -0,0 +1,15 @@ +package goorm.deepdive.team1.domain.user.event; + +import goorm.deepdive.team1.domain.user.domain.User; +import lombok.Builder; + +@Builder +public record UserCreatedEvent( + User user +) { + public static UserCreatedEvent of(User user) { + return UserCreatedEvent.builder() + .user(user) + .build(); + } +} diff --git a/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/event/UserDeletedEvent.java b/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/event/UserDeletedEvent.java new file mode 100644 index 0000000..59c181f --- /dev/null +++ b/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/event/UserDeletedEvent.java @@ -0,0 +1,16 @@ +package goorm.deepdive.team1.domain.user.event; + +import java.util.List; + +import lombok.Builder; + +@Builder +public record UserDeletedEvent( + List userIds +) { + public static UserDeletedEvent of(List userIds) { + return UserDeletedEvent.builder() + .userIds(userIds) + .build(); + } +} diff --git a/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/event/UserUpdatedEvent.java b/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/event/UserUpdatedEvent.java new file mode 100644 index 0000000..9b4b803 --- /dev/null +++ b/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/event/UserUpdatedEvent.java @@ -0,0 +1,15 @@ +package goorm.deepdive.team1.domain.user.event; + +import goorm.deepdive.team1.domain.user.domain.User; +import lombok.Builder; + +@Builder +public record UserUpdatedEvent( + User user +) { + public static UserUpdatedEvent of(User user) { + return UserUpdatedEvent.builder() + .user(user) + .build(); + } +} diff --git a/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/infrastructure/UserProducer.java b/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/infrastructure/UserProducer.java new file mode 100644 index 0000000..76517db --- /dev/null +++ b/team1-domain/src/main/java/goorm/deepdive/team1/domain/user/infrastructure/UserProducer.java @@ -0,0 +1,9 @@ +package goorm.deepdive.team1.domain.user.infrastructure; + +import goorm.deepdive.team1.domain.user.domain.User; + +public interface UserProducer { + void sendMessageToCreate(User user); + + void sendMessageToUpdate(User user); +} diff --git a/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/consumer/UserConsumer.java b/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/consumer/KafkaUserConsumer.java similarity index 98% rename from team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/consumer/UserConsumer.java rename to team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/consumer/KafkaUserConsumer.java index 145b66b..82deff9 100644 --- a/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/consumer/UserConsumer.java +++ b/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/consumer/KafkaUserConsumer.java @@ -17,7 +17,7 @@ @Component @RequiredArgsConstructor -public class UserConsumer { +public class KafkaUserConsumer { private final RedisUserRepository redisUserRepository; private final ElasticUserRepository elasticUserRepository; private final ObjectMapper objectMapper; diff --git a/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/AddressHistoryProducer.java b/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/KafkaAddressHistoryProducer.java similarity index 87% rename from team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/AddressHistoryProducer.java rename to team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/KafkaAddressHistoryProducer.java index 96350f9..a73f9c8 100644 --- a/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/AddressHistoryProducer.java +++ b/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/KafkaAddressHistoryProducer.java @@ -7,17 +7,19 @@ import com.fasterxml.jackson.databind.ObjectMapper; import goorm.deepdive.team1.domain.addresshistory.domain.AddressHistory; +import goorm.deepdive.team1.domain.addresshistory.infrastructure.AddressHistoryProducer; import lombok.RequiredArgsConstructor; @Component @RequiredArgsConstructor -public class AddressHistoryProducer { +public class KafkaAddressHistoryProducer implements AddressHistoryProducer { private final KafkaTemplate kafkaTemplate; private final ObjectMapper objectMapper; private static final String CREATE_ADDRESS_HISTORY = "create-address-history"; private static final String DELETE_ADDRESS_HISTORY = "delete-address-history"; + @Override public void sendMessageToCreate(AddressHistory addressHistory) { try { String addressHistoryJson = objectMapper.writeValueAsString(addressHistory); @@ -27,6 +29,7 @@ public void sendMessageToCreate(AddressHistory addressHistory) { } } + @Override public void sendMessageToDelete(AddressHistory addressHistory) { try { String addressHistoryJson = objectMapper.writeValueAsString(addressHistory); diff --git a/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/UserProducer.java b/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/KafkaUserProducer.java similarity index 88% rename from team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/UserProducer.java rename to team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/KafkaUserProducer.java index 5af02fd..42fd6b2 100644 --- a/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/UserProducer.java +++ b/team1-infra/src/main/java/goorm/deepdive/team1/infra/kafka/producer/KafkaUserProducer.java @@ -6,18 +6,20 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import goorm.deepdive.team1.domain.user.infrastructure.UserProducer; import goorm.deepdive.team1.domain.user.domain.User; import lombok.RequiredArgsConstructor; @Component @RequiredArgsConstructor -public class UserProducer { +public class KafkaUserProducer implements UserProducer { private final KafkaTemplate kafkaTemplate; private final ObjectMapper objectMapper; private static final String CREATE_USER = "create-user"; private static final String UPDATE_USER = "update-user"; + @Override public void sendMessageToCreate(User user) { try { String userJson = objectMapper.writeValueAsString(user); @@ -27,6 +29,7 @@ public void sendMessageToCreate(User user) { } } + @Override public void sendMessageToUpdate(User user) { try { String userJson = objectMapper.writeValueAsString(user);