From b90346c45e2b4e5c6345aca89b779918eaaa3cdd Mon Sep 17 00:00:00 2001 From: LminWoo99 Date: Tue, 14 May 2024 00:17:22 +0900 Subject: [PATCH 1/7] =?UTF-8?q?=20feat=20:=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../KafkaProducerConfig.java | 11 +++- .../config/{ => auth}/JwtTokenUtil.java | 2 +- .../config/{ => auth}/SecurityConfig.java | 3 +- .../security/CustomAuthenticationFilter.java | 6 +-- .../controller/user/MemberController.java | 2 +- .../PlantProject/domain/NotifiTypeEnum.java | 19 +++++++ .../service/kakao/KaKaoController.java | 2 - .../service/kakao/KaKaoService.java | 4 +- .../notification/NotificationSender.java | 19 +++++++ .../tradeboard/DeleteTradeBoardProducer.java} | 6 +-- .../service/tradeboard/GoodsService.java | 25 +++++++++ .../service/tradeboard/TradeBoardService.java | 5 +- .../service/user/MemberService.java | 4 +- .../service/user/RefreshTokenService.java | 2 +- .../vo/response/NotificationEventDto.java | 22 ++++++++ .../client/error/FeignErrorDecoder.java | 2 +- .../config/kafka/ListenerConfiguration.java | 24 +++++++++ .../common/util/KafkaUtil.java | 2 + .../domain/NotifiTypeEnum.java | 4 +- .../notification/NotificationEventDto.java | 23 ++++++++ .../DeletePost.java} | 7 +-- .../service/chat/ChatService.java | 2 +- .../notification/NotificationReceiver.java | 27 ++++++++++ .../notification/NotificationService.java | 8 +-- .../service/chat/ChatServiceTest.java | 6 +-- plant-sns-service/build.gradle | 1 + .../config/kafka/ProducerConfiguration.java | 46 ++++++++++++++++ .../domain/NotifiTypeEnum.java | 19 +++++++ .../service/NotificationSender.java | 20 +++++++ .../service/SnsCommentService.java | 25 +++++++++ .../service/SnsPostService.java | 52 +++++++++++-------- .../vo/request/NotificationEventDto.java | 22 ++++++++ .../vo/request/SnsCommentRequestDto.java | 1 + 33 files changed, 361 insertions(+), 62 deletions(-) rename PlantBackend/src/main/java/Plant/PlantProject/common/{messagequeue => config}/KafkaProducerConfig.java (78%) rename PlantBackend/src/main/java/Plant/PlantProject/common/config/{ => auth}/JwtTokenUtil.java (98%) rename PlantBackend/src/main/java/Plant/PlantProject/common/config/{ => auth}/SecurityConfig.java (96%) create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/service/notification/NotificationSender.java rename PlantBackend/src/main/java/Plant/PlantProject/{common/messagequeue/KafkaProducer.java => service/tradeboard/DeleteTradeBoardProducer.java} (87%) create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/vo/response/NotificationEventDto.java create mode 100644 plant-chat-service/src/main/java/com/example/plantchatservice/dto/notification/NotificationEventDto.java rename plant-chat-service/src/main/java/com/example/plantchatservice/{common/config/kafka/KafkaConsumer.java => service/DeletePost.java} (91%) create mode 100644 plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationReceiver.java create mode 100644 plant-sns-service/src/main/java/com/example/plantsnsservice/common/config/kafka/ProducerConfiguration.java create mode 100644 plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java create mode 100644 plant-sns-service/src/main/java/com/example/plantsnsservice/service/NotificationSender.java create mode 100644 plant-sns-service/src/main/java/com/example/plantsnsservice/vo/request/NotificationEventDto.java diff --git a/PlantBackend/src/main/java/Plant/PlantProject/common/messagequeue/KafkaProducerConfig.java b/PlantBackend/src/main/java/Plant/PlantProject/common/config/KafkaProducerConfig.java similarity index 78% rename from PlantBackend/src/main/java/Plant/PlantProject/common/messagequeue/KafkaProducerConfig.java rename to PlantBackend/src/main/java/Plant/PlantProject/common/config/KafkaProducerConfig.java index 77cea41..5191a1b 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/common/messagequeue/KafkaProducerConfig.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/common/config/KafkaProducerConfig.java @@ -1,5 +1,6 @@ -package Plant.PlantProject.common.messagequeue; +package Plant.PlantProject.common.config; +import Plant.PlantProject.vo.response.NotificationEventDto; import com.google.common.collect.ImmutableMap; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; @@ -37,5 +38,13 @@ public Map producerConfigurations() { public KafkaTemplate kafkaTemplate() { return new KafkaTemplate<>(producerFactory()); } + @Bean + public ProducerFactory notificationProducerFactory() { + return new DefaultKafkaProducerFactory<>(producerConfigurations()); + } + @Bean + public KafkaTemplate notificationKafkaTemplate() { + return new KafkaTemplate<>(notificationProducerFactory()); + } } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/common/config/JwtTokenUtil.java b/PlantBackend/src/main/java/Plant/PlantProject/common/config/auth/JwtTokenUtil.java similarity index 98% rename from PlantBackend/src/main/java/Plant/PlantProject/common/config/JwtTokenUtil.java rename to PlantBackend/src/main/java/Plant/PlantProject/common/config/auth/JwtTokenUtil.java index 075ae24..4c739e8 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/common/config/JwtTokenUtil.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/common/config/auth/JwtTokenUtil.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.common.config; +package Plant.PlantProject.common.config.auth; import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/common/config/SecurityConfig.java b/PlantBackend/src/main/java/Plant/PlantProject/common/config/auth/SecurityConfig.java similarity index 96% rename from PlantBackend/src/main/java/Plant/PlantProject/common/config/SecurityConfig.java rename to PlantBackend/src/main/java/Plant/PlantProject/common/config/auth/SecurityConfig.java index 1ea1e4b..8fb2675 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/common/config/SecurityConfig.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/common/config/auth/SecurityConfig.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.common.config; +package Plant.PlantProject.common.config.auth; import Plant.PlantProject.repository.MemberRepository; @@ -17,7 +17,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import static org.springframework.http.HttpMethod.GET; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/common/security/CustomAuthenticationFilter.java b/PlantBackend/src/main/java/Plant/PlantProject/common/security/CustomAuthenticationFilter.java index a8bc86e..b72bb25 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/common/security/CustomAuthenticationFilter.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/common/security/CustomAuthenticationFilter.java @@ -1,18 +1,15 @@ package Plant.PlantProject.common.security; -import Plant.PlantProject.common.config.JwtTokenUtil; +import Plant.PlantProject.common.config.auth.JwtTokenUtil; import Plant.PlantProject.domain.Entity.Member; import Plant.PlantProject.common.exception.ErrorCode; import Plant.PlantProject.repository.MemberRepository; import Plant.PlantProject.service.user.RefreshTokenService; -import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationServiceException; @@ -28,7 +25,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/controller/user/MemberController.java b/PlantBackend/src/main/java/Plant/PlantProject/controller/user/MemberController.java index ce1e9e5..220221b 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/controller/user/MemberController.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/controller/user/MemberController.java @@ -1,6 +1,6 @@ package Plant.PlantProject.controller.user; -import Plant.PlantProject.common.config.JwtTokenUtil; +import Plant.PlantProject.common.config.auth.JwtTokenUtil; import Plant.PlantProject.vo.request.MemberRequestDto; import Plant.PlantProject.vo.response.MemberResponseDto; import Plant.PlantProject.service.user.MemberService; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java b/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java new file mode 100644 index 0000000..f1bae14 --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java @@ -0,0 +1,19 @@ +package Plant.PlantProject.domain; + +import lombok.Getter; + +@Getter +public enum NotifiTypeEnum { + SNS_COMMENT("snspostlist/","comment"), + TRADEBOARD_GOODS("bbsdetail/","goods"), + SNS_HEART("snspostlist/","reply"), + CHAT("chatroom/","chat"); + + private final String path; + private final String alias; + + NotifiTypeEnum(String path, String alias) { + this.path = path; + this.alias = alias; + } +} diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/kakao/KaKaoController.java b/PlantBackend/src/main/java/Plant/PlantProject/service/kakao/KaKaoController.java index be66374..d197a52 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/kakao/KaKaoController.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/kakao/KaKaoController.java @@ -1,9 +1,7 @@ package Plant.PlantProject.service.kakao; -import Plant.PlantProject.common.config.JwtTokenUtil; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.*; import java.io.IOException; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/kakao/KaKaoService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/kakao/KaKaoService.java index b8e900e..d09803e 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/kakao/KaKaoService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/kakao/KaKaoService.java @@ -1,9 +1,8 @@ package Plant.PlantProject.service.kakao; -import Plant.PlantProject.common.config.JwtTokenUtil; +import Plant.PlantProject.common.config.auth.JwtTokenUtil; import Plant.PlantProject.domain.Entity.Member; import Plant.PlantProject.common.exception.ErrorCode; -import Plant.PlantProject.domain.Entity.SocialLogin; import Plant.PlantProject.repository.MemberRepository; import Plant.PlantProject.service.user.RefreshTokenService; import com.nimbusds.jose.shaded.json.JSONObject; @@ -17,7 +16,6 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; import org.springframework.stereotype.Service; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/notification/NotificationSender.java b/PlantBackend/src/main/java/Plant/PlantProject/service/notification/NotificationSender.java new file mode 100644 index 0000000..3aee4b4 --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/notification/NotificationSender.java @@ -0,0 +1,19 @@ +package Plant.PlantProject.service.notification; + + +import Plant.PlantProject.vo.response.NotificationEventDto; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +@RequiredArgsConstructor +public class NotificationSender { + private final KafkaTemplate kafkaTemplate; + + public void send(String topic, NotificationEventDto notificationEventDto) { + kafkaTemplate.send(topic, notificationEventDto); + } +} diff --git a/PlantBackend/src/main/java/Plant/PlantProject/common/messagequeue/KafkaProducer.java b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java similarity index 87% rename from PlantBackend/src/main/java/Plant/PlantProject/common/messagequeue/KafkaProducer.java rename to PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java index 28dc3c3..e2270c6 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/common/messagequeue/KafkaProducer.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.common.messagequeue; +package Plant.PlantProject.service.tradeboard; import Plant.PlantProject.vo.request.TradeBoardRequestDto; import com.fasterxml.jackson.core.JsonProcessingException; @@ -10,10 +10,10 @@ @Service @Slf4j -public class KafkaProducer { +public class DeleteTradeBoardProducer { private KafkaTemplate kafkaTemplate; @Autowired - public KafkaProducer(KafkaTemplate kafkaTemplate) { + public DeleteTradeBoardProducer(KafkaTemplate kafkaTemplate) { this.kafkaTemplate = kafkaTemplate; } /** diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/GoodsService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/GoodsService.java index fb764d3..14224d6 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/GoodsService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/GoodsService.java @@ -2,9 +2,12 @@ import Plant.PlantProject.domain.Entity.Goods; import Plant.PlantProject.domain.Entity.TradeBoard; +import Plant.PlantProject.domain.NotifiTypeEnum; +import Plant.PlantProject.service.notification.NotificationSender; import Plant.PlantProject.vo.response.GoodsResponseDto; import Plant.PlantProject.vo.request.GoodsRequestDto; import Plant.PlantProject.common.exception.ErrorCode; +import Plant.PlantProject.vo.response.NotificationEventDto; import Plant.PlantProject.vo.response.TradeBoardResponseDto; import Plant.PlantProject.repository.tradeboard.GoodsRepository; import Plant.PlantProject.repository.MemberRepository; @@ -29,6 +32,7 @@ public class GoodsService { private final MemberRepository memberRepository; private final TradeBoardRepository tradeBoardRepository; private final GoodsRepository goodsRepository; + private final NotificationSender notificationSender; /** * 찜 저장 * @param : GoodsRequestDto goodsDto @@ -54,6 +58,9 @@ public GoodsResponseDto saveGoods(GoodsRequestDto goodsDto){ tradeBoard )); tradeBoard.increaseGoodsCount(); + + sendNotificationData(goodsDto.getMemberId().intValue(), tradeBoard.getMember().getId().intValue(), tradeBoard.getId()); + return convertGoodsToDto(goods); } } @@ -85,4 +92,22 @@ public void deleteGoods(TradeBoard tradeBoard) { goodsRepository.deleteAllByTradeBoard(tradeBoard); } + /** + * plant-chat-service로 kafka를 통한 + * 메세지 스트리밍 + * @Param SnsComment snsComment, Integer senderNo, Integer receiverNo + */ + private void sendNotificationData(Integer senderNo, Integer receiverNo, Long tradeBoardNo) { + NotificationEventDto notificationEventDto=NotificationEventDto.builder() + .senderNo(senderNo) + .receiverNo(receiverNo) + .type(NotifiTypeEnum.TRADEBOARD_GOODS) + .resource(tradeBoardNo.toString()) + .build(); + + // 알림 이벤트 발행 + notificationSender.send("notification", notificationEventDto); + + } + } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java index 8b7a329..22696c5 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java @@ -6,7 +6,6 @@ import Plant.PlantProject.vo.request.TradeBoardRequestDto; import Plant.PlantProject.vo.response.TradeBoardResponseDto; import Plant.PlantProject.common.exception.ErrorCode; -import Plant.PlantProject.common.messagequeue.KafkaProducer; import Plant.PlantProject.repository.MemberRepository; import Plant.PlantProject.repository.tradeboard.TradeBoardRepository; import lombok.RequiredArgsConstructor; @@ -32,7 +31,7 @@ public class TradeBoardService { private final MemberRepository memberRepository; private final ImageFileUploadService imageFileUploadService; private final GoodsService goodsService; - private final KafkaProducer kafkaProducer; + private final DeleteTradeBoardProducer deleteTradeBoardProducer; /** * 거래게시글 저장 @@ -155,7 +154,7 @@ public void deletePost(Long id) { /*send this deletePost to the kafka*/ - kafkaProducer.send("deletePost", tradeBoardRequestDto); + deleteTradeBoardProducer.send("deletePost", tradeBoardRequestDto); } /** * 유저가 올린 거래 게시글 조회 diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/user/MemberService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/user/MemberService.java index 8bc711c..74c09c9 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/user/MemberService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/user/MemberService.java @@ -1,17 +1,15 @@ package Plant.PlantProject.service.user; -import Plant.PlantProject.common.config.JwtTokenUtil; +import Plant.PlantProject.common.config.auth.JwtTokenUtil; import Plant.PlantProject.domain.Entity.Member; import Plant.PlantProject.domain.Entity.SocialLogin; import Plant.PlantProject.vo.request.MemberRequestDto; import Plant.PlantProject.common.exception.ErrorCode; import Plant.PlantProject.vo.response.MemberResponseDto; import Plant.PlantProject.repository.MemberRepository; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/user/RefreshTokenService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/user/RefreshTokenService.java index 1c54e1e..e6a945a 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/user/RefreshTokenService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/user/RefreshTokenService.java @@ -1,6 +1,6 @@ package Plant.PlantProject.service.user; -import Plant.PlantProject.common.config.JwtTokenUtil; +import Plant.PlantProject.common.config.auth.JwtTokenUtil; import Plant.PlantProject.domain.redis.RefreshToken; import Plant.PlantProject.repository.redis.RefreshTokenRepository; import lombok.RequiredArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/NotificationEventDto.java b/PlantBackend/src/main/java/Plant/PlantProject/vo/response/NotificationEventDto.java new file mode 100644 index 0000000..707203d --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/vo/response/NotificationEventDto.java @@ -0,0 +1,22 @@ +package Plant.PlantProject.vo.response; + +import Plant.PlantProject.domain.NotifiTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class NotificationEventDto implements Serializable { + private Integer senderNo; + private Integer receiverNo; + private NotifiTypeEnum type; + private String resource; + private String content; + +} diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/client/error/FeignErrorDecoder.java b/plant-chat-service/src/main/java/com/example/plantchatservice/client/error/FeignErrorDecoder.java index 57cc184..10173c8 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/client/error/FeignErrorDecoder.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/client/error/FeignErrorDecoder.java @@ -24,7 +24,7 @@ public Exception decode(String methodKey, Response response) { case 400: break; case 404: - if (methodKey.contains("findBy")) { + if (methodKey.contains("find")) { throw ErrorCode.throwMemberNotFound(); } if (methodKey.contains("boardContent")) { diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/ListenerConfiguration.java b/plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/ListenerConfiguration.java index daf7c31..106b08c 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/ListenerConfiguration.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/ListenerConfiguration.java @@ -2,6 +2,7 @@ import com.example.plantchatservice.dto.aggregation.AggregationDto; import com.example.plantchatservice.dto.chat.Message; +import com.example.plantchatservice.dto.notification.NotificationEventDto; import com.google.common.collect.ImmutableMap; import org.apache.kafka.clients.consumer.ConsumerConfig; import org.apache.kafka.common.serialization.StringDeserializer; @@ -90,4 +91,27 @@ public ConsumerFactory kafkaAggregationConsumer() { return new DefaultKafkaConsumerFactory<>(consumerConfigurations, new StringDeserializer(), deserializer); } + @Bean + ConcurrentKafkaListenerContainerFactory kafkaNotificationContainerFactory() { + ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(kafkaNotificationConsumer()); + return factory; + } + @Bean + public ConsumerFactory kafkaNotificationConsumer() { + JsonDeserializer deserializer = new JsonDeserializer<>(NotificationEventDto.class, false); + // 패키지 신뢰 오류로 인해 모든 패키지를 신뢰하도록 작성 + deserializer.addTrustedPackages("*"); + // Kafka Consumer 구성을 위한 설정값들을 설정 -> 변하지 않는 값이므로 ImmutableMap을 이용하여 설정 + Map consumerConfigurations = + ImmutableMap.builder() + .put(ConsumerConfig.GROUP_ID_CONFIG, "notification") + .put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaServerUrl) + .put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class) + .put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, deserializer) + .put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest") + .build(); + + return new DefaultKafkaConsumerFactory<>(consumerConfigurations, new StringDeserializer(), deserializer); + } } diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/common/util/KafkaUtil.java b/plant-chat-service/src/main/java/com/example/plantchatservice/common/util/KafkaUtil.java index 9d59511..1dac225 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/common/util/KafkaUtil.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/common/util/KafkaUtil.java @@ -3,4 +3,6 @@ public class KafkaUtil { public static final String KAFKA_TOPIC = "chat"; public static final String KAFKA_AGGREGATION = "aggregation"; + public static final String KAFKA_NOTIFICATION = "notification"; + } diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java b/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java index 92ddfd5..1e4055c 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java @@ -4,7 +4,9 @@ @Getter public enum NotifiTypeEnum { - NOTICE("notice/","announcement"), + SNS_COMMENT("snspostlist/","comment"), + TRADEBOARD_GOODS("bbsdetail/","goods"), + SNS_HEART("snspostlist/","reply"), CHAT("chatroom/","chat"); private final String path; diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/dto/notification/NotificationEventDto.java b/plant-chat-service/src/main/java/com/example/plantchatservice/dto/notification/NotificationEventDto.java new file mode 100644 index 0000000..0004947 --- /dev/null +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/dto/notification/NotificationEventDto.java @@ -0,0 +1,23 @@ +package com.example.plantchatservice.dto.notification; + +import com.example.plantchatservice.domain.NotifiTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class NotificationEventDto implements Serializable { + private Integer senderNo; + private Integer receiverNo; + private NotifiTypeEnum type; + private String resource; + private String content; + +} diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/KafkaConsumer.java b/plant-chat-service/src/main/java/com/example/plantchatservice/service/DeletePost.java similarity index 91% rename from plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/KafkaConsumer.java rename to plant-chat-service/src/main/java/com/example/plantchatservice/service/DeletePost.java index 82da77f..87433f1 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/KafkaConsumer.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/service/DeletePost.java @@ -1,9 +1,8 @@ -package com.example.plantchatservice.common.config.kafka; +package com.example.plantchatservice.service; import com.example.plantchatservice.service.chat.ChatService; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -11,18 +10,16 @@ import org.springframework.stereotype.Service; import java.util.HashMap; -import java.util.List; import java.util.Map; @Service @Slf4j @RequiredArgsConstructor -public class KafkaConsumer { +public class DeletePost { private final ChatService chatService; /** * plant-service 게시글에 속한 채팅 데이터 kafka를 통해 삭제 메서드 - * * @param : MemberDto memberDto, ChatRequestDto requestDto */ @KafkaListener(topics = "deletePost", containerFactory = "kafkaDeletePostContainerFactory") diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/service/chat/ChatService.java b/plant-chat-service/src/main/java/com/example/plantchatservice/service/chat/ChatService.java index 67b5d29..3fe4424 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/service/chat/ChatService.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/service/chat/ChatService.java @@ -215,7 +215,7 @@ public Message sendNotificationAndSaveMessage(Message message) { String sendUrl = getNotificationUrl(message.getTradeBoardNo(), message.getChatNo(), memberDto.getBody().getNickname()); //알림 전송 - notificationService.send(memberDto.getBody(), receiveMember.getBody(), NotifiTypeEnum.CHAT, sendUrl, content); + notificationService.send(memberDto.getBody().getId().intValue(), receiveMember.getBody().getId().intValue(), NotifiTypeEnum.CHAT, sendUrl, content); } // 보낸 사람일 경우에만 메시지를 저장 -> 중복 저장 방지 if (message.getSenderEmail().equals(memberDto.getBody().getEmail())) { diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationReceiver.java b/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationReceiver.java new file mode 100644 index 0000000..08fb5df --- /dev/null +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationReceiver.java @@ -0,0 +1,27 @@ +package com.example.plantchatservice.service.notification; + +import com.example.plantchatservice.common.util.KafkaUtil; +import com.example.plantchatservice.dto.chat.Message; +import com.example.plantchatservice.dto.notification.NotificationEventDto; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class NotificationReceiver { + private final NotificationService notificationService; + @KafkaListener(topics = KafkaUtil.KAFKA_NOTIFICATION, containerFactory = "kafkaNotificationContainerFactory") + public void receiveNotification(NotificationEventDto notificationEventDto) { + log.info("======알림 전송 type: {}======", notificationEventDto.getType()); + + notificationService.send(notificationEventDto.getSenderNo(), notificationEventDto.getReceiverNo(), + notificationEventDto.getType(), notificationEventDto.getResource(), notificationEventDto.getContent() + ); + + } + +} diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java b/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java index 86b4cc9..ac44cb0 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java @@ -75,11 +75,11 @@ public SseEmitter subscribe(String lastEventId, String jwtToken) { * @param : MemberDto sender, MemberDto receiver, NotifiTypeEnum type, String resource, String content */ @Transactional - public void send(MemberDto sender, MemberDto receiver, NotifiTypeEnum type, String resource, String content) { + public void send(Integer senderNo, Integer receiverNo, NotifiTypeEnum type, String resource, String content) { // 알림 생성 Notification notification = Notification.builder() - .senderNo(sender.getId().intValue()) - .receiverNo(receiver.getId().intValue()) + .senderNo(senderNo) + .receiverNo(receiverNo) .typeEnum(type) .url(PREFIX_URL + type.getPath() + resource) .content(content) @@ -88,7 +88,7 @@ public void send(MemberDto sender, MemberDto receiver, NotifiTypeEnum type, Stri .build(); CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker"); //보낸 사람 이름 찾기 위해 feignClient를 통해 호출 - ResponseEntity findMember = circuitBreaker.run(() -> plantServiceClient.findById(sender.getId()), + ResponseEntity findMember = circuitBreaker.run(() -> plantServiceClient.findById(senderNo.longValue()), throwable -> ResponseEntity.ok(null)); notification.setSenderName(findMember.getBody().getNickname()); diff --git a/plant-chat-service/src/test/java/com/example/plantchatservice/service/chat/ChatServiceTest.java b/plant-chat-service/src/test/java/com/example/plantchatservice/service/chat/ChatServiceTest.java index 95491d5..8578e2c 100644 --- a/plant-chat-service/src/test/java/com/example/plantchatservice/service/chat/ChatServiceTest.java +++ b/plant-chat-service/src/test/java/com/example/plantchatservice/service/chat/ChatServiceTest.java @@ -230,7 +230,7 @@ void sendNotificationAndSaveMessageTest() { //when chatService.sendNotificationAndSaveMessage(requestMessage); //then - verify(notificationService, times(1)).send(mockResponseEntity.getBody(),mockResponseEntity.getBody(), NotifiTypeEnum.CHAT,"1/2","거래 가능할까요?"); + verify(notificationService, times(1)).send(mockResponseEntity.getBody().getId().intValue(),mockResponseEntity.getBody().getId().intValue(), NotifiTypeEnum.CHAT,"1/2","거래 가능할까요?"); } @Test @@ -248,7 +248,7 @@ void sendNotificationAndSaveMessageReadTest() { CircuitBreaker circuitBreaker = mock(CircuitBreaker.class); when(circuitBreakerFactory.create(anyString())).thenReturn(circuitBreaker); - ResponseEntity mockResponseEntity = ResponseEntity.ok(new MemberDto(2L , "minu", "ee", "이민우", "pass", "xxxx@naver.com")); + ResponseEntity mockResponseEntity = ResponseEntity.ok(new MemberDto(2L , "minu", "ee", "이민우", "xxxx@naver.com")); when(circuitBreaker.run(any(), any())).thenReturn(mockResponseEntity); when(chatRoomService.isAllConnected(1)).thenReturn(true); @@ -256,7 +256,7 @@ void sendNotificationAndSaveMessageReadTest() { //when chatService.sendNotificationAndSaveMessage(requestMessage); //then - verify(notificationService, times(0)).send(mockResponseEntity.getBody(),mockResponseEntity.getBody(), NotifiTypeEnum.CHAT,"1/2","거래 가능할까요?"); + verify(notificationService, times(0)).send(mockResponseEntity.getBody().getId().intValue(),mockResponseEntity.getBody().getId().intValue(), NotifiTypeEnum.CHAT,"1/2","거래 가능할까요?"); } @Test diff --git a/plant-sns-service/build.gradle b/plant-sns-service/build.gradle index 51df19f..301d772 100644 --- a/plant-sns-service/build.gradle +++ b/plant-sns-service/build.gradle @@ -41,6 +41,7 @@ dependencies { implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '3.0.0' implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap' implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' + implementation 'org.springframework.kafka:spring-kafka' implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' diff --git a/plant-sns-service/src/main/java/com/example/plantsnsservice/common/config/kafka/ProducerConfiguration.java b/plant-sns-service/src/main/java/com/example/plantsnsservice/common/config/kafka/ProducerConfiguration.java new file mode 100644 index 0000000..a46ecee --- /dev/null +++ b/plant-sns-service/src/main/java/com/example/plantsnsservice/common/config/kafka/ProducerConfiguration.java @@ -0,0 +1,46 @@ +package com.example.plantsnsservice.common.config.kafka; + + +import com.example.plantsnsservice.vo.request.NotificationEventDto; +import com.google.common.collect.ImmutableMap; +import org.apache.kafka.clients.producer.ProducerConfig; +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.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.support.serializer.JsonSerializer; + +import java.util.Map; + +@EnableKafka +@Configuration +public class ProducerConfiguration { + @Value("${kafka.url}") + private String kafkaServerUrl; + //Kafka ProduceFactory를 생성하는 Bean 메서드 + @Bean + public ProducerFactory producerFactory() { + return new DefaultKafkaProducerFactory<>(producerConfigurations()); + } + // Kafka Producer 구성을 위한 설정값들을 포함한 맵을 반환하는 메서드 + @Bean + public Map producerConfigurations() { + return ImmutableMap.builder() + .put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaServerUrl) + .put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class) + .put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class) + .build(); + } + + // KafkaTemplate을 생성하는 Bean 메서드 + @Bean + public KafkaTemplate kafkaTemplate() { + return new KafkaTemplate<>(producerFactory()); + } + + +} diff --git a/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java b/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java new file mode 100644 index 0000000..8fba2b3 --- /dev/null +++ b/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java @@ -0,0 +1,19 @@ +package com.example.plantsnsservice.domain; + +import lombok.Getter; + +@Getter +public enum NotifiTypeEnum { + SNS_COMMENT("snspostlist/","comment"), + TRADEBOARD_GOODS("bbsdetail/","goods"), + SNS_HEART("snspostlist/","reply"), + CHAT("chatroom/","chat"); + + private final String path; + private final String alias; + + NotifiTypeEnum(String path, String alias) { + this.path = path; + this.alias = alias; + } +} diff --git a/plant-sns-service/src/main/java/com/example/plantsnsservice/service/NotificationSender.java b/plant-sns-service/src/main/java/com/example/plantsnsservice/service/NotificationSender.java new file mode 100644 index 0000000..84b6aed --- /dev/null +++ b/plant-sns-service/src/main/java/com/example/plantsnsservice/service/NotificationSender.java @@ -0,0 +1,20 @@ +package com.example.plantsnsservice.service; + +import com.example.plantsnsservice.domain.NotifiTypeEnum; +import com.example.plantsnsservice.vo.request.NotificationEventDto; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +@RequiredArgsConstructor +public class NotificationSender { + private final KafkaTemplate kafkaTemplate; + + public void send(String topic, NotificationEventDto notificationEventDto) { + kafkaTemplate.send(topic, notificationEventDto); + } +} diff --git a/plant-sns-service/src/main/java/com/example/plantsnsservice/service/SnsCommentService.java b/plant-sns-service/src/main/java/com/example/plantsnsservice/service/SnsCommentService.java index 01db6f0..d63af66 100644 --- a/plant-sns-service/src/main/java/com/example/plantsnsservice/service/SnsCommentService.java +++ b/plant-sns-service/src/main/java/com/example/plantsnsservice/service/SnsCommentService.java @@ -1,10 +1,12 @@ package com.example.plantsnsservice.service; import com.example.plantsnsservice.common.exception.ErrorCode; +import com.example.plantsnsservice.domain.NotifiTypeEnum; import com.example.plantsnsservice.domain.entity.SnsComment; import com.example.plantsnsservice.domain.entity.SnsPost; import com.example.plantsnsservice.repository.querydsl.SnsPostRepository; import com.example.plantsnsservice.repository.querydsl.SnsCommentRepository; +import com.example.plantsnsservice.vo.request.NotificationEventDto; import com.example.plantsnsservice.vo.request.SnsCommentRequestDto; import com.example.plantsnsservice.vo.response.SnsCommentResponseDto; import lombok.RequiredArgsConstructor; @@ -24,6 +26,7 @@ public class SnsCommentService { private final SnsCommentRepository snsCommentRepository; private final SnsPostRepository snsPostRepository; + private final NotificationSender notificationSender; /** * sns 댓글 저장 @@ -42,6 +45,9 @@ public SnsCommentResponseDto createComment(SnsCommentRequestDto snsCommentReques .build(); snsCommentRepository.save(snsComment); + + getNotificationData(snsComment, snsCommentRequestDto.getSenderNo(), snsPost.getMemberNo()); + return SnsCommentResponseDto.convertCommentToDto(snsComment); } /** @@ -98,5 +104,24 @@ private List convertNestedStructure(List findTop20PostsByMonth() { public List getSnsPostByCreated(String createdBy) { List snsPostList = snsPostRepository.findAllByCreatedBy(createdBy); - List snsPosts = snsPostList.stream().map(snsPost -> { - SnsPostResponseDto snsPostResponseDto = SnsPostResponseDto.builder() - .id(snsPost.getId()) - .snsPostTitle(snsPost.getSnsPostTitle()) - .snsPostContent(snsPost.getSnsPostContent()) - .createdBy(snsPost.getCreatedBy()) - .snsLikesCount(snsPost.getSnsLikesCount()) - .snsViewsCount(snsPost.getSnsViewsCount()) - .createdAt(snsPost.getCreatedAt()) - .hashTags(snsHashTagMapService.findHashTagListBySnsPost(snsPost)) - .commentCount(snsCommentService.findCommentListByPostId(snsPost.getId()).stream().count()) - .build(); - snsPostResponseDto.imageUrls(snsPost); - return snsPostResponseDto; - }).collect(Collectors.toList()); - - return snsPosts; + return getCollect(snsPostList); } /** @@ -189,24 +176,27 @@ public List getSnsPostByCreated(String createdBy) { * 실제락을 거는 시점은 퍼사드 패턴으로 분리하여 * 락의 범위가 트랜잭션 범위보다 크게 * 좋아요 중복관리는 redis set 자료구조를 활용 - * @param : Long snsPostId(게시글 번호), Integer memberNo + * @param : Long snsPostId(게시글 번호), Integer senderNo(좋아요 누른 사람) * @Transactional 바깥에서 락을 걸어줌 */ @Transactional - public void updateSnsLikesCount(Long snsPostId, Integer memberNo) { + public void updateSnsLikesCount(Long snsPostId, Integer senderNo) { SnsPost snsPost = snsPostRepository.findById(snsPostId).orElseThrow(ErrorCode::throwSnsPostNotFound); String key = "sns_likes:" + snsPostId; //좋아요 중복 관리 - boolean alreadyLiked = snsLikesCountRepository.isMember(key,memberNo); + boolean alreadyLiked = snsLikesCountRepository.isMember(key,senderNo); if (alreadyLiked) { // 특정 게시글에 특정 유저가 좋아요 누른적이 있을시 - snsLikesCountRepository.decrement(memberNo, snsPostId); + snsLikesCountRepository.decrement(senderNo, snsPostId); snsPost.likesCountDown(); } else { - snsLikesCountRepository.increment(memberNo, snsPostId); + snsLikesCountRepository.increment(senderNo, snsPostId); snsPost.likesCountUp(); + + getNotificationData(snsPost, senderNo); + } snsPostRepository.save(snsPost); @@ -231,4 +221,22 @@ private List getCollect(List snsPostList) { return snsPostResponseDto; }).collect(Collectors.toList()); } + + /** + * plant-chat-service로 kafka를 통한 + * 메세지 스트리밍 + * @Param SnsPost snsPost, Integer senderNo + */ + private void getNotificationData(SnsPost snsPost, Integer senderNo) { + NotificationEventDto notificationEventDto=NotificationEventDto.builder() + .senderNo(senderNo) + .receiverNo(snsPost.getMemberNo()) + .type(NotifiTypeEnum.SNS_HEART) + .resource(snsPost.getId().toString()) + .build(); + // 알림 이벤트 발행 + notificationSender.send("notification", notificationEventDto); + + } + } diff --git a/plant-sns-service/src/main/java/com/example/plantsnsservice/vo/request/NotificationEventDto.java b/plant-sns-service/src/main/java/com/example/plantsnsservice/vo/request/NotificationEventDto.java new file mode 100644 index 0000000..388f5bb --- /dev/null +++ b/plant-sns-service/src/main/java/com/example/plantsnsservice/vo/request/NotificationEventDto.java @@ -0,0 +1,22 @@ +package com.example.plantsnsservice.vo.request; + +import com.example.plantsnsservice.domain.NotifiTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class NotificationEventDto implements Serializable { + private Integer senderNo; + private Integer receiverNo; + private NotifiTypeEnum type; + private String resource; + private String content; + +} diff --git a/plant-sns-service/src/main/java/com/example/plantsnsservice/vo/request/SnsCommentRequestDto.java b/plant-sns-service/src/main/java/com/example/plantsnsservice/vo/request/SnsCommentRequestDto.java index b1bf769..2a40562 100644 --- a/plant-sns-service/src/main/java/com/example/plantsnsservice/vo/request/SnsCommentRequestDto.java +++ b/plant-sns-service/src/main/java/com/example/plantsnsservice/vo/request/SnsCommentRequestDto.java @@ -21,6 +21,7 @@ public class SnsCommentRequestDto { private String content; @NotNull private String createdBy; + private Integer senderNo; private Long parentId; private List children = new ArrayList<>(); From 39f8ccc8e4a5fa638fc78daaccada431b3cfc5e5 Mon Sep 17 00:00:00 2001 From: LminWoo99 Date: Tue, 14 May 2024 17:11:15 +0900 Subject: [PATCH 2/7] =?UTF-8?q?=20feat=20:=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A8=EB=91=90=20=EA=B0=9C=EB=B0=9C=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/NotifiTypeEnum.java | 8 +++---- .../notification/NotificationResponse.java | 6 ++--- .../notification/NotificationRepository.java | 3 +-- .../notification/NotificationService.java | 23 +++++++++++-------- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java b/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java index 1e4055c..afb1a67 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java @@ -4,10 +4,10 @@ @Getter public enum NotifiTypeEnum { - SNS_COMMENT("snspostlist/","comment"), - TRADEBOARD_GOODS("bbsdetail/","goods"), - SNS_HEART("snspostlist/","reply"), - CHAT("chatroom/","chat"); + SNS_COMMENT("snspostlist/","댓글"), + TRADEBOARD_GOODS("bbsdetail/","찜"), + SNS_HEART("snspostlist/","좋아요"), + CHAT("chatroom/","채팅"); private final String path; private final String alias; diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/dto/notification/NotificationResponse.java b/plant-chat-service/src/main/java/com/example/plantchatservice/dto/notification/NotificationResponse.java index 10d3340..041c88c 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/dto/notification/NotificationResponse.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/dto/notification/NotificationResponse.java @@ -26,9 +26,9 @@ public class NotificationResponse { private boolean del; @Builder - public NotificationResponse(Long id, NotifiTypeEnum type, String content, String url, LocalDateTime publishedAt, Integer senderNo, boolean read, boolean del) { + public NotificationResponse(Long id, String type, String content, String url, LocalDateTime publishedAt, Integer senderNo, boolean read, boolean del) { this.id = id; - this.type = type.getAlias(); + this.type = type; this.content = content; this.url = url; this.publishedAt = LocalDateTimeUtils.toArray(publishedAt); @@ -40,7 +40,7 @@ public NotificationResponse(Long id, NotifiTypeEnum type, String content, String public static NotificationResponse toDto(Notification notification) { return NotificationResponse.builder() .id(notification.getNotifiNo()) - .type(notification.getTypeEnum()) + .type(notification.getTypeEnum().getAlias()) .content(notification.getContent()) .url(notification.getUrl()) .publishedAt(notification.getRegDate()) diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/repository/notification/NotificationRepository.java b/plant-chat-service/src/main/java/com/example/plantchatservice/repository/notification/NotificationRepository.java index b5bbad4..dc76900 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/repository/notification/NotificationRepository.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/repository/notification/NotificationRepository.java @@ -14,10 +14,9 @@ public interface NotificationRepository extends JpaRepository findChatByReceiver(Integer memberNo); + List findByReceiver(Integer memberNo); //자동으로 영속성 컨텍스트를 clear(조회시 바로 db) @Modifying(clearAutomatically = true) diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java b/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java index ac44cb0..b14c5f6 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java @@ -28,7 +28,7 @@ @Slf4j public class NotificationService { private static final Long DEFAULT_TIMEOUT = 1000L * 60 * 29 ;// 29분 - public static final String PREFIX_URL = "https://sikguhaza.site/"; + public static final String PREFIX_URL = "http://localhost:3000/"; private final NotificationRepository notificationRepository; private final EmitterRepository emitterRepository; @@ -100,14 +100,17 @@ public void send(Integer senderNo, Integer receiverNo, NotifiTypeEnum type, Stri // 로그인 한 유저의 SseEmitter 모두 가져오기 Map sseEmitterMap = emitterRepository.findAllStartWithById(id); - sseEmitterMap.forEach( - (key, emitter) -> { - //캐시 저장(유실한 데이터를 처리) - emitterRepository.saveCache(key, notification); - //데아터 전송 - sendToClient(emitter, key, NotificationResponse.toDto(notification)); - } - ); + //채팅일때만 SSE 알림 전송 + if (notification.getTypeEnum().equals(NotifiTypeEnum.CHAT)) { + sseEmitterMap.forEach( + (key, emitter) -> { + //캐시 저장(유실한 데이터를 처리) + emitterRepository.saveCache(key, notification); + //데아터 전송 + sendToClient(emitter, key, NotificationResponse.toDto(notification)); + } + ); + } } /** * 클라이언트에 SSE + 알림 데이터 전송 메서드 @@ -135,7 +138,7 @@ private void sendToClient(SseEmitter emitter, String id, Object data) { public List findAllById(Long memberNo) { // 채팅의 마지막 알림 조회 List chat - = notificationRepository.findChatByReceiver(memberNo.intValue()); + = notificationRepository.findByReceiver(memberNo.intValue()); return chat.stream() .map(NotificationResponse::toDto) From 439e53d71f8f83fb45025cda84342a3834f96dcb Mon Sep 17 00:00:00 2001 From: LminWoo99 Date: Tue, 14 May 2024 17:12:01 +0900 Subject: [PATCH 3/7] =?UTF-8?q?=20feat=20:=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A8=EB=91=90=20=EA=B0=9C=EB=B0=9C=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/Plant/PlantProject/domain/NotifiTypeEnum.java | 8 ++++---- .../example/plantsnsservice/domain/NotifiTypeEnum.java | 8 ++++---- .../plantsnsservice/service/SnsCommentService.java | 9 +++++---- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java b/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java index f1bae14..3b53f7a 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java @@ -4,10 +4,10 @@ @Getter public enum NotifiTypeEnum { - SNS_COMMENT("snspostlist/","comment"), - TRADEBOARD_GOODS("bbsdetail/","goods"), - SNS_HEART("snspostlist/","reply"), - CHAT("chatroom/","chat"); + SNS_COMMENT("snspostlist/","댓글"), + TRADEBOARD_GOODS("bbsdetail/","찜"), + SNS_HEART("snspostlist/","좋아요"), + CHAT("chatroom/","채팅"); private final String path; private final String alias; diff --git a/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java b/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java index 8fba2b3..cd5b84b 100644 --- a/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java +++ b/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java @@ -4,10 +4,10 @@ @Getter public enum NotifiTypeEnum { - SNS_COMMENT("snspostlist/","comment"), - TRADEBOARD_GOODS("bbsdetail/","goods"), - SNS_HEART("snspostlist/","reply"), - CHAT("chatroom/","chat"); + SNS_COMMENT("snspostlist/","댓글"), + TRADEBOARD_GOODS("bbsdetail/","찜"), + SNS_HEART("snspostlist/","좋아요"), + CHAT("chatroom/","채팅"); private final String path; private final String alias; diff --git a/plant-sns-service/src/main/java/com/example/plantsnsservice/service/SnsCommentService.java b/plant-sns-service/src/main/java/com/example/plantsnsservice/service/SnsCommentService.java index d63af66..5d85831 100644 --- a/plant-sns-service/src/main/java/com/example/plantsnsservice/service/SnsCommentService.java +++ b/plant-sns-service/src/main/java/com/example/plantsnsservice/service/SnsCommentService.java @@ -45,9 +45,10 @@ public SnsCommentResponseDto createComment(SnsCommentRequestDto snsCommentReques .build(); snsCommentRepository.save(snsComment); - - getNotificationData(snsComment, snsCommentRequestDto.getSenderNo(), snsPost.getMemberNo()); - + //게시글에는 본인도 댓글을 달수있기떄문에, 다른 사람이 댓글달때만 알림 전송 + if (!(snsCommentRequestDto.getSenderNo().equals(snsComment.getSnsPost().getMemberNo()))) { + getNotificationData(snsComment, snsCommentRequestDto.getSenderNo(), snsPost.getMemberNo()); + } return SnsCommentResponseDto.convertCommentToDto(snsComment); } /** @@ -115,7 +116,7 @@ private void getNotificationData(SnsComment snsComment, Integer senderNo, Intege .receiverNo(receiverNo) .type(NotifiTypeEnum.SNS_COMMENT) .content(snsComment.getContent()) - .resource(receiverNo.toString()) + .resource(snsComment.getSnsPost().getId().toString()) .build(); // 알림 이벤트 발행 From ed165ad30906aa80f62dca8be0c24c40c551fe4b Mon Sep 17 00:00:00 2001 From: LminWoo99 Date: Tue, 14 May 2024 18:47:07 +0900 Subject: [PATCH 4/7] =?UTF-8?q?=20feat=20:=20=EC=8B=9D=EB=AC=BC=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=ED=95=84=ED=84=B0=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PlantProject/common/util/SearchParam.java | 21 +++ .../controller/plantinfo/PlantController.java | 27 ++-- .../PlantProject/domain/Entity/KeyWord.java | 3 - .../plantinfo/CustomPlantRepository.java | 14 ++ .../{ => plantinfo}/PlantRepository.java | 4 +- .../plantinfo/PlantRepositoryImpl.java | 50 +++++++ .../service/plantinfo/PlantApi.java | 78 +++++++++++ .../service/plantinfo/PlantService.java | 126 +++++------------- 8 files changed, 212 insertions(+), 111 deletions(-) create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/common/util/SearchParam.java create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/CustomPlantRepository.java rename PlantBackend/src/main/java/Plant/PlantProject/repository/{ => plantinfo}/PlantRepository.java (85%) create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepositoryImpl.java create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantApi.java diff --git a/PlantBackend/src/main/java/Plant/PlantProject/common/util/SearchParam.java b/PlantBackend/src/main/java/Plant/PlantProject/common/util/SearchParam.java new file mode 100644 index 0000000..5d6ec10 --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/common/util/SearchParam.java @@ -0,0 +1,21 @@ +package Plant.PlantProject.common.util; + +import com.querydsl.core.types.Order; +import lombok.Data; +import lombok.Getter; + +@Getter +public enum SearchParam { + MANAGE("manage"), + CATEGORY("category"); + + + + + private final String paramKey; + + SearchParam(String paramKey) { + this.paramKey = paramKey; + } + +} diff --git a/PlantBackend/src/main/java/Plant/PlantProject/controller/plantinfo/PlantController.java b/PlantBackend/src/main/java/Plant/PlantProject/controller/plantinfo/PlantController.java index 013c827..550cec4 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/controller/plantinfo/PlantController.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/controller/plantinfo/PlantController.java @@ -1,7 +1,8 @@ package Plant.PlantProject.controller.plantinfo; -import Plant.PlantProject.vo.response.PlantResponseDto; import Plant.PlantProject.service.plantinfo.PlantService; +import Plant.PlantProject.vo.response.PlantResponseDto; +import Plant.PlantProject.service.plantinfo.PlantApi; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; @@ -11,6 +12,9 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.List; +import java.util.Map; + @RestController @RequestMapping("/api") @RequiredArgsConstructor @@ -18,20 +22,23 @@ public class PlantController { private final PlantService plantService; @GetMapping("plantList") @Operation(summary = "식구 도감- 식물 조회", description = "식물 전체 정보를 조회 할 수 있는 API") - private ResponseEntity> plantList(@RequestParam(required = false, defaultValue = "") String search, @PageableDefault(size = 15, sort = "id", direction = Sort.Direction.DESC) - Pageable pageable) { - Page plantDtos = plantService.plantList(search, pageable); - return ResponseEntity.ok(plantDtos); + private ResponseEntity> plantList(@RequestParam(required = false, defaultValue = "") String search + , @PageableDefault(size = 15, sort = "id", direction = Sort.Direction.DESC) Pageable pageable) { + + Page plantResponseDtoList = plantService.plantList(search, pageable); + return ResponseEntity.ok().body(plantResponseDtoList); } @GetMapping("/plantList/{id}") @Operation(summary = "식구 도감- 식물 자세한 정보 조회", description = "식물에 관한 자세한 정보를 조회 할 수 있는 API") private ResponseEntity plantDetail(@PathVariable("id") Long id) { - System.out.println("plant 호출"); return ResponseEntity.ok().body(plantService.plantDetail(id)); } -// @GetMapping("/plant") -// private void start() throws IOException { -// plantService.start(); -// } + @GetMapping("/plantList/condition") + @Operation(summary = "식구 도감- 식물 조건 별 정보 조회", description = "식물에 관한 정보를 동적 쿼리를 활용하여 조건 별로 조회 할 수 있는 API") + public ResponseEntity> getPlantByCondition(@RequestParam Map searchCondition){ + List plantResponseDtoList = plantService.getPlantByCondition(searchCondition); + + return ResponseEntity.ok().body(plantResponseDtoList); + } } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/KeyWord.java b/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/KeyWord.java index 53f5c59..791ad11 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/KeyWord.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/KeyWord.java @@ -16,7 +16,6 @@ public class KeyWord { @Id @GeneratedValue //jpa 어노테이션인데 그냥 기본키 어노테이션으로 알고있으면됨 - @Column(name = "keyId") private Long id; //고유번호 @CreatedDate private LocalDateTime createdAt; @@ -25,9 +24,7 @@ public class KeyWord { private String keyContent; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "tPostId") private TradeBoard tradeBoard; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "id") private Member member; } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/CustomPlantRepository.java b/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/CustomPlantRepository.java new file mode 100644 index 0000000..70d14bb --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/CustomPlantRepository.java @@ -0,0 +1,14 @@ +package Plant.PlantProject.repository.plantinfo; + +import Plant.PlantProject.domain.Entity.Plant; +import Plant.PlantProject.vo.response.PlantResponseDto; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import java.util.List; +import java.util.Map; + +public interface CustomPlantRepository { + List search(final Map searchCondition); + +} diff --git a/PlantBackend/src/main/java/Plant/PlantProject/repository/PlantRepository.java b/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepository.java similarity index 85% rename from PlantBackend/src/main/java/Plant/PlantProject/repository/PlantRepository.java rename to PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepository.java index dc94e2a..c85836d 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/repository/PlantRepository.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepository.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.repository; +package Plant.PlantProject.repository.plantinfo; import Plant.PlantProject.domain.Entity.Plant; import org.springframework.data.domain.Page; @@ -7,7 +7,7 @@ import org.springframework.stereotype.Repository; @Repository -public interface PlantRepository extends JpaRepository { +public interface PlantRepository extends JpaRepository, CustomPlantRepository { Page findByPlantNameContaining(String plantName, Pageable pageable); Plant findByContentNum(String contentNum); diff --git a/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepositoryImpl.java b/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepositoryImpl.java new file mode 100644 index 0000000..4b5ab2c --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepositoryImpl.java @@ -0,0 +1,50 @@ +package Plant.PlantProject.repository.plantinfo; + + +import Plant.PlantProject.domain.Entity.Plant; +import Plant.PlantProject.vo.response.PlantResponseDto; +import com.querydsl.core.BooleanBuilder; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.Map; + +import static Plant.PlantProject.common.util.SearchParam.CATEGORY; +import static Plant.PlantProject.common.util.SearchParam.MANAGE; +import static Plant.PlantProject.domain.Entity.QPlant.plant; +import static com.querydsl.core.types.Projections.list; + +@RequiredArgsConstructor +public class PlantRepositoryImpl implements CustomPlantRepository{ + private final JPAQueryFactory jpaQueryFactory; + @Override + public List search(final Map searchCondition) { + return jpaQueryFactory + .selectFrom(plant) + .where(allCond(searchCondition)) + .fetch(); + } + + // BooleanBuilder 검색 동적 쿼리 + private BooleanBuilder allCond(Map searchCondition) { + BooleanBuilder builder = new BooleanBuilder(); + + return builder + .and(snsCategoryLike(searchCondition.getOrDefault(CATEGORY.getParamKey(), null))) + .and(manageEq(searchCondition.getOrDefault(MANAGE.getParamKey(), null))); + } + // 검색 동적 쿼리 조건1 + private BooleanExpression snsCategoryLike(String category) { + return StringUtils.hasText(category) ? plant.category.contains(category) : null; + } + // 검색 동적 쿼리 조건2 + private BooleanExpression manageEq(String manage) { + return StringUtils.hasText(manage) ? plant.manage.eq(manage) : null; + } + + +} diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantApi.java b/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantApi.java new file mode 100644 index 0000000..68a3ee4 --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantApi.java @@ -0,0 +1,78 @@ +package Plant.PlantProject.service.plantinfo; + + +import Plant.PlantProject.domain.Entity.Plant; +import Plant.PlantProject.vo.response.PlantResponseDto; +import Plant.PlantProject.common.exception.ErrorCode; +import Plant.PlantProject.repository.plantinfo.PlantRepository; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +import lombok.RequiredArgsConstructor; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.json.XML; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; + +@Service +@RequiredArgsConstructor +@Transactional +public class PlantApi { + private final PlantRepository plantRepository; + + private static final String API_KEY = "202212290SGQFNOOOQJTTHHYQIRA"; + private static final String DETAIL_URL = "http://api.nongsaro.go.kr/service/garden/gardenDtl?apiKey=" + API_KEY + "&cntntsNo="; + + + public void getPlantDetail(String item) throws IOException { + String pageURL = DETAIL_URL + item; + URL url = new URL(pageURL); + try (BufferedReader bf = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"))) { + StringBuilder rs = new StringBuilder(); + String line; + while ((line = bf.readLine()) != null) { + rs.append(line); + } + JSONObject jObject = XML.toJSONObject(rs.toString()); + ObjectMapper mapper = new ObjectMapper(); + mapper.enable(SerializationFeature.INDENT_OUTPUT); + Object json = mapper.readValue(jObject.toString(), Object.class); + String output = mapper.writeValueAsString(json); + JSONObject jsonObject = new JSONObject(output); + JSONObject response = jsonObject.getJSONObject("response"); + JSONObject body = response.getJSONObject("body"); + JSONObject items = body.getJSONObject("item"); + //식물학명 + String cntntsNo = items.optString("cntntsNo", "null"); + String postngplaceCodeNm = items.optString("postngplaceCodeNm", "null"); + String hdCodeNm = items.optString("hdCodeNm", "null"); + String lighttdemanddoCodeNm = items.optString("lighttdemanddoCodeNm", "null"); + String speclmanageInfo = items.optString("speclmanageInfo", "null"); + Plant byContentNum = plantRepository.findByContentNum(cntntsNo); + System.out.println("byContentNum = " + byContentNum); + if(byContentNum !=null){ + byContentNum.addInfo(hdCodeNm, lighttdemanddoCodeNm, speclmanageInfo, speclmanageInfo); + + plantRepository.save(byContentNum); + } + + + + } catch (Exception e) { + e.printStackTrace(); + } + } + + + } + + diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantService.java index cb1bae7..2d567fe 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantService.java @@ -1,129 +1,63 @@ package Plant.PlantProject.service.plantinfo; - +import Plant.PlantProject.common.exception.ErrorCode; import Plant.PlantProject.domain.Entity.Plant; +import Plant.PlantProject.repository.plantinfo.PlantRepository; import Plant.PlantProject.vo.response.PlantResponseDto; -import Plant.PlantProject.common.exception.ErrorCode; -import Plant.PlantProject.repository.PlantRepository; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; - import lombok.RequiredArgsConstructor; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.json.XML; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor +@Slf4j @Transactional public class PlantService { private final PlantRepository plantRepository; - private static final String API_KEY = "202212290SGQFNOOOQJTTHHYQIRA"; - private static final String LIST_URL = "http://api.nongsaro.go.kr/service/garden/gardenList?apiKey=" + API_KEY + "&pageNo="; - private static final String DETAIL_URL = "http://api.nongsaro.go.kr/service/garden/gardenDtl?apiKey=" + API_KEY + "&cntntsNo="; - private static final String IMAGE_URL ="http://api.nongsaro.go.kr/service/garden/gardenFileList?apiKey="+ API_KEY + "&cntntsNo="; - - - + /** + * 식물 전체 조회 + * @param : String search(식물 이름 포함), Pageable pageable + */ public Page plantList(String search, Pageable pageable) { Page plants = plantRepository.findByPlantNameContaining(search, pageable); return plants.map(plant -> PlantResponseDto.convertPlantToDto(plant)); } - + /** + * 식물 정보 자세히 보기 + * @param : Long id(식물 pk) + */ public PlantResponseDto plantDetail(Long id) { Plant plant = plantRepository.findById(id).orElseThrow(ErrorCode::throwPlantNotFound); return PlantResponseDto.convertPlantToDto(plant); } - public void getPlantDetail(String item) throws IOException { - String pageURL = DETAIL_URL + item; - URL url = new URL(pageURL); - try (BufferedReader bf = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"))) { - StringBuilder rs = new StringBuilder(); - String line; - while ((line = bf.readLine()) != null) { - rs.append(line); - } - JSONObject jObject = XML.toJSONObject(rs.toString()); - ObjectMapper mapper = new ObjectMapper(); - mapper.enable(SerializationFeature.INDENT_OUTPUT); - Object json = mapper.readValue(jObject.toString(), Object.class); - String output = mapper.writeValueAsString(json); - JSONObject jsonObject = new JSONObject(output); - JSONObject response = jsonObject.getJSONObject("response"); - JSONObject body = response.getJSONObject("body"); - JSONObject items = body.getJSONObject("item"); - //식물학명 - String cntntsNo = items.optString("cntntsNo", "null"); - String postngplaceCodeNm = items.optString("postngplaceCodeNm", "null"); - String hdCodeNm = items.optString("hdCodeNm", "null"); - String lighttdemanddoCodeNm = items.optString("lighttdemanddoCodeNm", "null"); - String speclmanageInfo = items.optString("speclmanageInfo", "null"); - Plant byContentNum = plantRepository.findByContentNum(cntntsNo); - System.out.println("byContentNum = " + byContentNum); - if(byContentNum !=null){ - byContentNum.addInfo(hdCodeNm, lighttdemanddoCodeNm, speclmanageInfo, speclmanageInfo); + /** + * 식물 조회 동적 쿼리 + * 조건 1: 식물 카테고리 별(부분일치) + * 조건 2 : 식물 관리 난이도 (완전일치) + * @param : Map searchCondition + */ + public List getPlantByCondition(Map searchCondition) { + List plantList = plantRepository.search(searchCondition); - plantRepository.save(byContentNum); - } + List plantResponseDtoList = plantList.stream().map(plant -> { + PlantResponseDto plantResponseDto = PlantResponseDto.convertPlantToDto(plant); + return plantResponseDto; + }).collect(Collectors.toList()); + return plantResponseDtoList; - } catch (Exception e) { - e.printStackTrace(); - } } - public void getPlantNumbers(JSONArray itemArray, String key) { - try { - JSONArray array = new JSONArray(itemArray); - for (int i = 0; i < array.length(); i++) { - JSONObject jsO = array.getJSONObject(i); - String item = jsO.getString(key); - getPlantDetail(item); - } - } catch (Exception e) { - e.printStackTrace(); - } - } -//// public void start() throws IOException { -//// for (int i = 1; i < 23; i++) { -//// String pageURL = LIST_URL + i; -//// URL url = new URL(pageURL); -//// try (BufferedReader bf = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"))) { -//// StringBuilder rs = new StringBuilder(); -//// String line; -//// while ((line = bf.readLine()) != null) { -//// rs.append(line); -//// } -//// JSONObject jObject = XML.toJSONObject(rs.toString()); -//// ObjectMapper mapper = new ObjectMapper(); -//// mapper.enable(SerializationFeature.INDENT_OUTPUT); -//// Object json = mapper.readValue(jObject.toString(), Object.class); -//// String output = mapper.writeValueAsString(json); -//// JSONObject jsonObject = new JSONObject(output); -//// JSONObject response = jsonObject.getJSONObject("response"); -//// JSONObject body = response.getJSONObject("body"); -//// JSONObject items = body.getJSONObject("items"); -//// JSONArray item = items.getJSONArray("item"); -//// -//// getPlantNumbers(item, "cntntsNo"); -//// } catch (Exception e) { -//// e.printStackTrace(); -//// } -//// } -// -// } - } + +} From 61ad76f08ecc8d20e66c81a8b373413aa5a20b3f Mon Sep 17 00:00:00 2001 From: LminWoo99 Date: Wed, 15 May 2024 18:34:25 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20keyword=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20kafka=EB=A5=BC=20=ED=86=B5?= =?UTF-8?q?=ED=95=9C=20=EC=95=8C=EB=A6=BC=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{ => kafka}/KafkaProducerConfig.java | 5 +- .../common/exception/ErrorCode.java | 7 +- .../controller/keyword/KeywordController.java | 39 ++++++++ .../controller/plantinfo/PlantController.java | 3 +- .../tradeboard/GoodsController.java | 7 +- .../tradeboard/TradeBoardController.java | 4 +- .../controller/user/AuthController.java | 4 +- .../controller/user/EmailController.java | 2 +- .../controller/user/MemberController.java | 4 +- .../Entity/{KeyWord.java => Keyword.java} | 20 ++-- .../domain/Entity/TradeBoard.java | 4 +- .../PlantProject/domain/NotifiTypeEnum.java | 1 + .../{vo => dto}/request/GoodsRequestDto.java | 2 +- .../dto/request/KeywordRequestDto.java | 15 +++ .../{vo => dto}/request/MemberRequestDto.java | 2 +- .../request/TradeBoardRequestDto.java | 7 +- .../response/ChatRoomResponseDto.java | 2 +- .../{vo => dto}/response/EmailReq.java | 2 +- .../response/GoodsResponseDto.java | 2 +- .../response/ImageResponseDto.java | 2 +- .../dto/response/KeywordResponseDto.java | 34 +++++++ .../response/MemberResponseDto.java | 2 +- .../response/NotificationEventDto.java | 2 +- .../response/PlantResponseDto.java | 2 +- .../response/TokenResponseStatus.java | 2 +- .../response/TradeBoardResponseDto.java | 5 +- .../plantinfo/CustomPlantRepository.java | 3 - .../plantinfo/PlantRepositoryImpl.java | 2 - .../tradeboard/KeywordRepository.java | 16 ++++ .../tradeboard/TradeBoardRepository.java | 2 +- .../service/keyword/KeywordService.java | 94 +++++++++++++++++++ .../notification/NotificationSender.java | 2 +- .../service/plantinfo/PlantApi.java | 5 - .../service/plantinfo/PlantService.java | 2 +- .../tradeboard/DeleteTradeBoardProducer.java | 2 +- .../service/tradeboard/GoodsService.java | 10 +- .../service/tradeboard/TradeBoardService.java | 17 +++- .../service/user/MemberService.java | 4 +- .../config/kafka/ListenerConfiguration.java | 3 +- .../domain/NotifiTypeEnum.java | 1 + .../notification/NotificationService.java | 12 ++- .../service/chat/ChatServiceTest.java | 1 - .../domain/NotifiTypeEnum.java | 1 + 43 files changed, 285 insertions(+), 73 deletions(-) rename PlantBackend/src/main/java/Plant/PlantProject/common/config/{ => kafka}/KafkaProducerConfig.java (93%) create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/controller/keyword/KeywordController.java rename PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/{KeyWord.java => Keyword.java} (63%) rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/request/GoodsRequestDto.java (86%) create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/dto/request/KeywordRequestDto.java rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/request/MemberRequestDto.java (93%) rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/request/TradeBoardRequestDto.java (85%) rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/response/ChatRoomResponseDto.java (97%) rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/response/EmailReq.java (81%) rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/response/GoodsResponseDto.java (92%) rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/response/ImageResponseDto.java (89%) create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/dto/response/KeywordResponseDto.java rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/response/MemberResponseDto.java (94%) rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/response/NotificationEventDto.java (91%) rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/response/PlantResponseDto.java (97%) rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/response/TokenResponseStatus.java (89%) rename PlantBackend/src/main/java/Plant/PlantProject/{vo => dto}/response/TradeBoardResponseDto.java (91%) create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/repository/tradeboard/KeywordRepository.java create mode 100644 PlantBackend/src/main/java/Plant/PlantProject/service/keyword/KeywordService.java diff --git a/PlantBackend/src/main/java/Plant/PlantProject/common/config/KafkaProducerConfig.java b/PlantBackend/src/main/java/Plant/PlantProject/common/config/kafka/KafkaProducerConfig.java similarity index 93% rename from PlantBackend/src/main/java/Plant/PlantProject/common/config/KafkaProducerConfig.java rename to PlantBackend/src/main/java/Plant/PlantProject/common/config/kafka/KafkaProducerConfig.java index 5191a1b..3cf6a96 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/common/config/KafkaProducerConfig.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/common/config/kafka/KafkaProducerConfig.java @@ -1,6 +1,6 @@ -package Plant.PlantProject.common.config; +package Plant.PlantProject.common.config.kafka; -import Plant.PlantProject.vo.response.NotificationEventDto; +import Plant.PlantProject.dto.response.NotificationEventDto; import com.google.common.collect.ImmutableMap; import org.apache.kafka.clients.producer.ProducerConfig; import org.apache.kafka.common.serialization.StringSerializer; @@ -13,6 +13,7 @@ import org.springframework.kafka.core.ProducerFactory; import org.springframework.kafka.support.serializer.JsonSerializer; +import java.util.List; import java.util.Map; @EnableKafka diff --git a/PlantBackend/src/main/java/Plant/PlantProject/common/exception/ErrorCode.java b/PlantBackend/src/main/java/Plant/PlantProject/common/exception/ErrorCode.java index dbc3987..f23b96c 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/common/exception/ErrorCode.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/common/exception/ErrorCode.java @@ -21,7 +21,8 @@ public enum ErrorCode { PLANT_NOT_FOUND(NOT_FOUND, "식물 정보를 조회할 수 없습니다", "017"), USER_DUPLICATED_ID(CONFLICT, "이미 가입된 아이디입니다", "018"), USER_DUPLICATED_EMAIL(CONFLICT, "이미 가입된 이메일입니다", "019"), - MAX_FILE_SIZE_EXCEEDED(PAYLOAD_TOO_LARGE, "파일 크기가 허용되는 최대치를 초과하였습니다.", "025"); + MAX_FILE_SIZE_EXCEEDED(PAYLOAD_TOO_LARGE, "파일 크기가 허용되는 최대치를 초과하였습니다.", "025"), + KEYWORD_NOT_FOUND(NOT_FOUND, "파일 크기가 허용되는 최대치를 초과하였습니다.", "027"); private final HttpStatus httpStatus; @@ -67,4 +68,8 @@ public static CustomException throwMaxFileSizeExceeded() { throw new CustomException(MAX_FILE_SIZE_EXCEEDED); } + public static CustomException throwKeywordNotFound() { + throw new CustomException(KEYWORD_NOT_FOUND); + } + } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/controller/keyword/KeywordController.java b/PlantBackend/src/main/java/Plant/PlantProject/controller/keyword/KeywordController.java new file mode 100644 index 0000000..0ea2bf8 --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/controller/keyword/KeywordController.java @@ -0,0 +1,39 @@ +package Plant.PlantProject.controller.keyword; + +import Plant.PlantProject.dto.request.KeywordRequestDto; +import Plant.PlantProject.dto.response.KeywordResponseDto; +import Plant.PlantProject.service.keyword.KeywordService; +import io.swagger.v3.oas.annotations.Operation; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +public class KeywordController { + private final KeywordService keywordService; + + @GetMapping("/keyword/{memberNo}") + @Operation(summary = "유저 기능- 설정한 키워드 조회", description = "유저가 설정한 키워드 조회 조회 할 수 있는 API") + private ResponseEntity> getKeywordList(@PathVariable("memberNo") Integer memberNo) { + + List keywordList = keywordService.getKeywordList(memberNo); + return ResponseEntity.ok().body(keywordList); + } + @PostMapping("/keyword") + @Operation(summary = "유저 기능- 키워드 설정", description = "유저가 알림을 받기 위한 키워드 설정 할 수 있는 API") + private ResponseEntity saveKeyWord(@RequestBody KeywordRequestDto keywordRequestDto) { + + Long keyWordId = keywordService.saveKeyWord(keywordRequestDto); + return ResponseEntity.ok().body(keyWordId); + } + @DeleteMapping("/keyword/{keywordId}") + @Operation(summary = "유저 기능- 설정한 키워드 삭제", description = "유저가 설정한 키워드 삭제할 수 있는 API") + private void getKeywordList(@PathVariable("keywordId") Long keywordId) { + + keywordService.deleteKeyWord(keywordId); + } + +} diff --git a/PlantBackend/src/main/java/Plant/PlantProject/controller/plantinfo/PlantController.java b/PlantBackend/src/main/java/Plant/PlantProject/controller/plantinfo/PlantController.java index 550cec4..928cc20 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/controller/plantinfo/PlantController.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/controller/plantinfo/PlantController.java @@ -1,8 +1,7 @@ package Plant.PlantProject.controller.plantinfo; import Plant.PlantProject.service.plantinfo.PlantService; -import Plant.PlantProject.vo.response.PlantResponseDto; -import Plant.PlantProject.service.plantinfo.PlantApi; +import Plant.PlantProject.dto.response.PlantResponseDto; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/controller/tradeboard/GoodsController.java b/PlantBackend/src/main/java/Plant/PlantProject/controller/tradeboard/GoodsController.java index d7a04e3..f997b8b 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/controller/tradeboard/GoodsController.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/controller/tradeboard/GoodsController.java @@ -1,10 +1,9 @@ package Plant.PlantProject.controller.tradeboard; -import Plant.PlantProject.vo.response.GoodsResponseDto; -import Plant.PlantProject.vo.request.GoodsRequestDto; -import Plant.PlantProject.vo.response.TradeBoardResponseDto; +import Plant.PlantProject.dto.response.GoodsResponseDto; +import Plant.PlantProject.dto.request.GoodsRequestDto; +import Plant.PlantProject.dto.response.TradeBoardResponseDto; import Plant.PlantProject.service.tradeboard.GoodsService; -import Plant.PlantProject.service.tradeboard.TradeBoardService; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/controller/tradeboard/TradeBoardController.java b/PlantBackend/src/main/java/Plant/PlantProject/controller/tradeboard/TradeBoardController.java index b89beac..23f97c8 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/controller/tradeboard/TradeBoardController.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/controller/tradeboard/TradeBoardController.java @@ -1,7 +1,7 @@ package Plant.PlantProject.controller.tradeboard; -import Plant.PlantProject.vo.request.TradeBoardRequestDto; -import Plant.PlantProject.vo.response.TradeBoardResponseDto; +import Plant.PlantProject.dto.request.TradeBoardRequestDto; +import Plant.PlantProject.dto.response.TradeBoardResponseDto; import Plant.PlantProject.service.tradeboard.TradeBoardService; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/controller/user/AuthController.java b/PlantBackend/src/main/java/Plant/PlantProject/controller/user/AuthController.java index 2efe404..3c54a3c 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/controller/user/AuthController.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/controller/user/AuthController.java @@ -1,7 +1,7 @@ package Plant.PlantProject.controller.user; import Plant.PlantProject.service.user.RefreshTokenService; -import Plant.PlantProject.vo.response.TokenResponseStatus; +import Plant.PlantProject.dto.response.TokenResponseStatus; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; @@ -10,8 +10,6 @@ import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; -import java.util.Optional; - @Slf4j @RestController @RequiredArgsConstructor diff --git a/PlantBackend/src/main/java/Plant/PlantProject/controller/user/EmailController.java b/PlantBackend/src/main/java/Plant/PlantProject/controller/user/EmailController.java index 5407856..b6fd078 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/controller/user/EmailController.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/controller/user/EmailController.java @@ -1,6 +1,6 @@ package Plant.PlantProject.controller.user; -import Plant.PlantProject.vo.response.EmailReq; +import Plant.PlantProject.dto.response.EmailReq; import Plant.PlantProject.service.user.RegisterMail; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/controller/user/MemberController.java b/PlantBackend/src/main/java/Plant/PlantProject/controller/user/MemberController.java index 220221b..495b69e 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/controller/user/MemberController.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/controller/user/MemberController.java @@ -1,8 +1,8 @@ package Plant.PlantProject.controller.user; import Plant.PlantProject.common.config.auth.JwtTokenUtil; -import Plant.PlantProject.vo.request.MemberRequestDto; -import Plant.PlantProject.vo.response.MemberResponseDto; +import Plant.PlantProject.dto.request.MemberRequestDto; +import Plant.PlantProject.dto.response.MemberResponseDto; import Plant.PlantProject.service.user.MemberService; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/KeyWord.java b/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/Keyword.java similarity index 63% rename from PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/KeyWord.java rename to PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/Keyword.java index 791ad11..0c81a49 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/KeyWord.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/Keyword.java @@ -1,6 +1,7 @@ package Plant.PlantProject.domain.Entity; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.springframework.data.annotation.CreatedDate; @@ -13,7 +14,7 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class KeyWord { +public class Keyword { @Id @GeneratedValue //jpa 어노테이션인데 그냥 기본키 어노테이션으로 알고있으면됨 private Long id; //고유번호 @@ -22,9 +23,16 @@ public class KeyWord { @LastModifiedDate private LocalDateTime updatedAt; - private String keyContent; - @ManyToOne(fetch = FetchType.LAZY) - private TradeBoard tradeBoard; - @ManyToOne(fetch = FetchType.LAZY) - private Member member; + private String keywordContent; + + private Integer memberNo; + @Builder + public Keyword(String keywordContent, Integer memberNo) { + this.keywordContent = keywordContent; + this.memberNo = memberNo; + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + + + } } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/TradeBoard.java b/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/TradeBoard.java index 2f0327e..55f6649 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/TradeBoard.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/domain/Entity/TradeBoard.java @@ -52,6 +52,7 @@ public class TradeBoard { private Integer goodCount; private String buyer; + private String keywordContent; @Builder public TradeBoard(Long id, String createBy, Member member, String title, String content, Status status, int view) { this.id = id; @@ -77,7 +78,7 @@ public void updateBuyer(String buyer, Status status) { } public static TradeBoard createTradeBoard(Member member, String title, String content, - String createBy, int price){ + String createBy, int price, String keywordContent){ TradeBoard tradeBoard = new TradeBoard(); tradeBoard.member=member; tradeBoard.title=title; @@ -87,6 +88,7 @@ public static TradeBoard createTradeBoard(Member member, String title, String co tradeBoard.status=Status.판매중; tradeBoard.goodCount = 0; tradeBoard.view = 0; + tradeBoard.keywordContent = keywordContent; return tradeBoard; } /** diff --git a/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java b/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java index 3b53f7a..259a964 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/domain/NotifiTypeEnum.java @@ -7,6 +7,7 @@ public enum NotifiTypeEnum { SNS_COMMENT("snspostlist/","댓글"), TRADEBOARD_GOODS("bbsdetail/","찜"), SNS_HEART("snspostlist/","좋아요"), + KEYWORD("bbsdetail/", "키워드"), CHAT("chatroom/","채팅"); private final String path; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/request/GoodsRequestDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/request/GoodsRequestDto.java similarity index 86% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/request/GoodsRequestDto.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/request/GoodsRequestDto.java index d7a46bd..306bcbe 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/request/GoodsRequestDto.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/request/GoodsRequestDto.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.request; +package Plant.PlantProject.dto.request; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/dto/request/KeywordRequestDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/request/KeywordRequestDto.java new file mode 100644 index 0000000..980cfb9 --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/request/KeywordRequestDto.java @@ -0,0 +1,15 @@ +package Plant.PlantProject.dto.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class KeywordRequestDto { + private String keywordContent; + private Integer memberNo; + + +} diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/request/MemberRequestDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/request/MemberRequestDto.java similarity index 93% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/request/MemberRequestDto.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/request/MemberRequestDto.java index ca800d8..40d8fd3 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/request/MemberRequestDto.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/request/MemberRequestDto.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.request; +package Plant.PlantProject.dto.request; import Plant.PlantProject.domain.Entity.Member; import lombok.AllArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/request/TradeBoardRequestDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/request/TradeBoardRequestDto.java similarity index 85% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/request/TradeBoardRequestDto.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/request/TradeBoardRequestDto.java index 9e647a4..1c6b61d 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/request/TradeBoardRequestDto.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/request/TradeBoardRequestDto.java @@ -1,9 +1,6 @@ -package Plant.PlantProject.vo.request; +package Plant.PlantProject.dto.request; -import Plant.PlantProject.domain.Entity.Member; import Plant.PlantProject.domain.Entity.Status; -import Plant.PlantProject.domain.Entity.TradeBoard; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; @@ -41,6 +38,8 @@ public class TradeBoardRequestDto { private String username; private String buyer; + private String keyWordContent; + } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/ChatRoomResponseDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/ChatRoomResponseDto.java similarity index 97% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/response/ChatRoomResponseDto.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/response/ChatRoomResponseDto.java index 195d61d..c97b0bd 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/ChatRoomResponseDto.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/ChatRoomResponseDto.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.response; +package Plant.PlantProject.dto.response; import lombok.AllArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/EmailReq.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/EmailReq.java similarity index 81% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/response/EmailReq.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/response/EmailReq.java index 52dd125..f57beb8 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/EmailReq.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/EmailReq.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.response; +package Plant.PlantProject.dto.response; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/GoodsResponseDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/GoodsResponseDto.java similarity index 92% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/response/GoodsResponseDto.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/response/GoodsResponseDto.java index ae1a524..e4deb98 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/GoodsResponseDto.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/GoodsResponseDto.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.response; +package Plant.PlantProject.dto.response; import Plant.PlantProject.domain.Entity.Goods; import lombok.AllArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/ImageResponseDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/ImageResponseDto.java similarity index 89% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/response/ImageResponseDto.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/response/ImageResponseDto.java index b20a3fe..b72c3ba 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/ImageResponseDto.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/ImageResponseDto.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.response; +package Plant.PlantProject.dto.response; import Plant.PlantProject.domain.Entity.TradeBoard; import lombok.AllArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/dto/response/KeywordResponseDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/KeywordResponseDto.java new file mode 100644 index 0000000..1f072ba --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/KeywordResponseDto.java @@ -0,0 +1,34 @@ +package Plant.PlantProject.dto.response; + +import Plant.PlantProject.domain.Entity.Keyword; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; +import java.util.stream.Collectors; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class KeywordResponseDto { + private Long keywordId; + private String keywordContent; + private Integer memberNo; + + public static List listToDto(List keywordList) { + List keywordResponseDtoList = keywordList.stream().map(keyword -> { + KeywordResponseDto keywordResponseDto = KeywordResponseDto.builder() + .keywordId(keyword.getId()) + .keywordContent(keyword.getKeywordContent()) + .memberNo(keyword.getMemberNo()) + .build(); + return keywordResponseDto; + }).collect(Collectors.toList()); + + return keywordResponseDtoList; + + } +} diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/MemberResponseDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/MemberResponseDto.java similarity index 94% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/response/MemberResponseDto.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/response/MemberResponseDto.java index 97ec4f2..23d3e7d 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/MemberResponseDto.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/MemberResponseDto.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.response; +package Plant.PlantProject.dto.response; import Plant.PlantProject.domain.Entity.Member; import lombok.AllArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/NotificationEventDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/NotificationEventDto.java similarity index 91% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/response/NotificationEventDto.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/response/NotificationEventDto.java index 707203d..7996920 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/NotificationEventDto.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/NotificationEventDto.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.response; +package Plant.PlantProject.dto.response; import Plant.PlantProject.domain.NotifiTypeEnum; import lombok.AllArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/PlantResponseDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/PlantResponseDto.java similarity index 97% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/response/PlantResponseDto.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/response/PlantResponseDto.java index dd26c17..0df1b62 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/PlantResponseDto.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/PlantResponseDto.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.response; +package Plant.PlantProject.dto.response; import Plant.PlantProject.domain.Entity.Plant; import lombok.AllArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/TokenResponseStatus.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/TokenResponseStatus.java similarity index 89% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/response/TokenResponseStatus.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/response/TokenResponseStatus.java index 932b1d4..c485206 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/TokenResponseStatus.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/TokenResponseStatus.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.response; +package Plant.PlantProject.dto.response; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/TradeBoardResponseDto.java b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/TradeBoardResponseDto.java similarity index 91% rename from PlantBackend/src/main/java/Plant/PlantProject/vo/response/TradeBoardResponseDto.java rename to PlantBackend/src/main/java/Plant/PlantProject/dto/response/TradeBoardResponseDto.java index 292f942..8ba9827 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/vo/response/TradeBoardResponseDto.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/dto/response/TradeBoardResponseDto.java @@ -1,4 +1,4 @@ -package Plant.PlantProject.vo.response; +package Plant.PlantProject.dto.response; import Plant.PlantProject.domain.Entity.TradeBoard; import lombok.AllArgsConstructor; @@ -25,6 +25,7 @@ public class TradeBoardResponseDto { private int price; private int goodCount; private String buyer; + private String keywordContent; private List imageUrls; public static TradeBoardResponseDto convertTradeBoardToDto(TradeBoard tradeBoard) { @@ -35,7 +36,7 @@ public static TradeBoardResponseDto convertTradeBoardToDto(TradeBoard tradeBoard return new TradeBoardResponseDto(tradeBoard.getId(), tradeBoard.getTitle(),tradeBoard.getContent(),tradeBoard.getCreateBy(), tradeBoard.getMember().getId(), tradeBoard.getView(),tradeBoard.getStatus().name(), tradeBoard.getCreatedAt(), tradeBoard.getUpdatedAt(), tradeBoard.getPrice(), - tradeBoard.getGoodCount(), tradeBoard.getBuyer(), imageList + tradeBoard.getGoodCount(), tradeBoard.getBuyer(), tradeBoard.getKeywordContent(), imageList ); } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/CustomPlantRepository.java b/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/CustomPlantRepository.java index 70d14bb..79f06ab 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/CustomPlantRepository.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/CustomPlantRepository.java @@ -1,9 +1,6 @@ package Plant.PlantProject.repository.plantinfo; import Plant.PlantProject.domain.Entity.Plant; -import Plant.PlantProject.vo.response.PlantResponseDto; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import java.util.List; import java.util.Map; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepositoryImpl.java b/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepositoryImpl.java index 4b5ab2c..6326636 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepositoryImpl.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/repository/plantinfo/PlantRepositoryImpl.java @@ -2,9 +2,7 @@ import Plant.PlantProject.domain.Entity.Plant; -import Plant.PlantProject.vo.response.PlantResponseDto; import com.querydsl.core.BooleanBuilder; -import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/repository/tradeboard/KeywordRepository.java b/PlantBackend/src/main/java/Plant/PlantProject/repository/tradeboard/KeywordRepository.java new file mode 100644 index 0000000..a04ff06 --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/repository/tradeboard/KeywordRepository.java @@ -0,0 +1,16 @@ +package Plant.PlantProject.repository.tradeboard; + +import Plant.PlantProject.domain.Entity.Keyword; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface KeywordRepository extends JpaRepository { + @Query("SELECT k.memberNo FROM Keyword k WHERE k.keywordContent = :keywordContent") + List findMemberNosByKeywordContent(String keywordContent); + + List findByMemberNo(Integer memberNo); +} diff --git a/PlantBackend/src/main/java/Plant/PlantProject/repository/tradeboard/TradeBoardRepository.java b/PlantBackend/src/main/java/Plant/PlantProject/repository/tradeboard/TradeBoardRepository.java index 256fb4f..ad3b0af 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/repository/tradeboard/TradeBoardRepository.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/repository/tradeboard/TradeBoardRepository.java @@ -17,7 +17,7 @@ 특이 사항: 없음 */ public interface TradeBoardRepository extends JpaRepository{ - Page findByTitleContainingOrContentContaining(String title, String content, Pageable pageable); + Page findByTitleContainingOrContentContainingOrKeywordContentContaining(String title, String content,String keywordContent, Pageable pageable); List findTradeBoardByMemberId(Long memberId); List findTradeBoardByBuyer(String buyer); diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/keyword/KeywordService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/keyword/KeywordService.java new file mode 100644 index 0000000..42f8408 --- /dev/null +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/keyword/KeywordService.java @@ -0,0 +1,94 @@ +package Plant.PlantProject.service.keyword; + +import Plant.PlantProject.common.exception.ErrorCode; +import Plant.PlantProject.domain.Entity.Keyword; +import Plant.PlantProject.domain.NotifiTypeEnum; +import Plant.PlantProject.dto.request.KeywordRequestDto; +import Plant.PlantProject.dto.response.KeywordResponseDto; +import Plant.PlantProject.dto.response.NotificationEventDto; +import Plant.PlantProject.repository.tradeboard.KeywordRepository; +import Plant.PlantProject.service.notification.NotificationSender; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@Transactional +@Slf4j +public class KeywordService { + private final KeywordRepository keyWordRepository; + private final NotificationSender notificationSender; + /** + * 유저가 설정한 키워드 조회 + * @param : Integer memberNo + */ + public List getKeywordList(Integer memberNo) { + List keywordList = keyWordRepository.findByMemberNo(memberNo); + if (keywordList.isEmpty()) { + throw ErrorCode.throwKeywordNotFound(); + } + List keywordResponseDtoList = KeywordResponseDto.listToDto(keywordList); + return keywordResponseDtoList; + + } + /** + * 유저가 알림을 받을 키워드 저장 + * 저장후 카프카 중앙 토픽에 이벤트 발송 + * @param : GoodsRequestDto goodsDto + */ + public Long saveKeyWord(KeywordRequestDto keyWordRequestDto) { + Keyword keyWord = Keyword.builder() + .keywordContent(keyWordRequestDto.getKeywordContent()) + .memberNo(keyWordRequestDto.getMemberNo()) + .build(); + + return keyWordRepository.save(keyWord).getId(); + } + /** + * 키워드 삭제 + * @param : Long keywordId + */ + public void deleteKeyWord(Long keywordId) { + keyWordRepository.deleteById(keywordId); + } + /** + * 게시글에서 키워드 설정후 해당 키워드를 가지고있는 + * 유저 조회 + * @param : Integer tradeBoardNo, String keywordContent + */ + public void getMembersByKeyword(Integer tradeBoardNo, String keywordContent) { + List memberList = keyWordRepository.findMemberNosByKeywordContent(keywordContent); + if (!memberList.isEmpty()) { + sendKeywordNotificationData(tradeBoardNo, memberList); + } + } + /** + * 게시글에서 키워드 설정후 해당 키워드를 가지고있는 유저 리스트를 받고 + * kafka를 통한 plant-chat-service에 전달 + * @param : Integer tradeBoardNo, List memberList + */ + private void sendKeywordNotificationData(Integer tradeBoardNo, List memberList) { + + List notificationEventDtoList = memberList.stream().map(memberNo -> { + NotificationEventDto notificationEventDto = NotificationEventDto.builder() + .receiverNo(memberNo) + .senderNo(tradeBoardNo) + .type(NotifiTypeEnum.KEYWORD) + .resource(tradeBoardNo.toString()) + .build(); + return notificationEventDto; + }).collect(Collectors.toList()); + + // 키워드 이벤트 + for (NotificationEventDto notificationEventDto : notificationEventDtoList) { + notificationSender.send("notification", notificationEventDto); + } + + } +} diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/notification/NotificationSender.java b/PlantBackend/src/main/java/Plant/PlantProject/service/notification/NotificationSender.java index 3aee4b4..097380f 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/notification/NotificationSender.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/notification/NotificationSender.java @@ -1,7 +1,7 @@ package Plant.PlantProject.service.notification; -import Plant.PlantProject.vo.response.NotificationEventDto; +import Plant.PlantProject.dto.response.NotificationEventDto; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.kafka.core.KafkaTemplate; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantApi.java b/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantApi.java index 68a3ee4..37b0f3a 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantApi.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantApi.java @@ -2,19 +2,14 @@ import Plant.PlantProject.domain.Entity.Plant; -import Plant.PlantProject.vo.response.PlantResponseDto; -import Plant.PlantProject.common.exception.ErrorCode; import Plant.PlantProject.repository.plantinfo.PlantRepository; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import lombok.RequiredArgsConstructor; -import org.json.JSONArray; import org.json.JSONObject; import org.json.XML; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantService.java index 2d567fe..a4b482d 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/plantinfo/PlantService.java @@ -3,7 +3,7 @@ import Plant.PlantProject.common.exception.ErrorCode; import Plant.PlantProject.domain.Entity.Plant; import Plant.PlantProject.repository.plantinfo.PlantRepository; -import Plant.PlantProject.vo.response.PlantResponseDto; +import Plant.PlantProject.dto.response.PlantResponseDto; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java index e2270c6..003f31f 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java @@ -1,6 +1,6 @@ package Plant.PlantProject.service.tradeboard; -import Plant.PlantProject.vo.request.TradeBoardRequestDto; +import Plant.PlantProject.dto.request.TradeBoardRequestDto; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/GoodsService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/GoodsService.java index 14224d6..0282599 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/GoodsService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/GoodsService.java @@ -4,11 +4,11 @@ import Plant.PlantProject.domain.Entity.TradeBoard; import Plant.PlantProject.domain.NotifiTypeEnum; import Plant.PlantProject.service.notification.NotificationSender; -import Plant.PlantProject.vo.response.GoodsResponseDto; -import Plant.PlantProject.vo.request.GoodsRequestDto; +import Plant.PlantProject.dto.response.GoodsResponseDto; +import Plant.PlantProject.dto.request.GoodsRequestDto; import Plant.PlantProject.common.exception.ErrorCode; -import Plant.PlantProject.vo.response.NotificationEventDto; -import Plant.PlantProject.vo.response.TradeBoardResponseDto; +import Plant.PlantProject.dto.response.NotificationEventDto; +import Plant.PlantProject.dto.response.TradeBoardResponseDto; import Plant.PlantProject.repository.tradeboard.GoodsRepository; import Plant.PlantProject.repository.MemberRepository; import Plant.PlantProject.repository.tradeboard.TradeBoardRepository; @@ -21,7 +21,7 @@ import java.util.Optional; import java.util.stream.Collectors; -import static Plant.PlantProject.vo.response.GoodsResponseDto.convertGoodsToDto; +import static Plant.PlantProject.dto.response.GoodsResponseDto.convertGoodsToDto; @Service diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java index 22696c5..ee7501e 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java @@ -3,11 +3,12 @@ import Plant.PlantProject.domain.Entity.Member; import Plant.PlantProject.domain.Entity.Status; import Plant.PlantProject.domain.Entity.TradeBoard; -import Plant.PlantProject.vo.request.TradeBoardRequestDto; -import Plant.PlantProject.vo.response.TradeBoardResponseDto; +import Plant.PlantProject.dto.request.TradeBoardRequestDto; +import Plant.PlantProject.dto.response.TradeBoardResponseDto; import Plant.PlantProject.common.exception.ErrorCode; import Plant.PlantProject.repository.MemberRepository; import Plant.PlantProject.repository.tradeboard.TradeBoardRepository; +import Plant.PlantProject.service.keyword.KeywordService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -21,7 +22,7 @@ import java.util.Optional; import java.util.stream.Collectors; -import static Plant.PlantProject.vo.response.TradeBoardResponseDto.convertTradeBoardToDto; +import static Plant.PlantProject.dto.response.TradeBoardResponseDto.convertTradeBoardToDto; @Service @Slf4j @@ -32,6 +33,7 @@ public class TradeBoardService { private final ImageFileUploadService imageFileUploadService; private final GoodsService goodsService; private final DeleteTradeBoardProducer deleteTradeBoardProducer; + private final KeywordService keywordService; /** * 거래게시글 저장 @@ -46,13 +48,18 @@ public Long saveTradePost(TradeBoardRequestDto tradeBoardRequestDto, List pageList(String search, Pageable pageable) { - Page tradeBoards = tradeBoardRepository.findByTitleContainingOrContentContaining(search, search, pageable); + Page tradeBoards = tradeBoardRepository.findByTitleContainingOrContentContainingOrKeywordContentContaining(search, search,search, pageable); return tradeBoards.map(tradeBoard -> TradeBoardResponseDto.convertTradeBoardToDto(tradeBoard)); } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/user/MemberService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/user/MemberService.java index 74c09c9..9427bbd 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/user/MemberService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/user/MemberService.java @@ -3,9 +3,9 @@ import Plant.PlantProject.common.config.auth.JwtTokenUtil; import Plant.PlantProject.domain.Entity.Member; import Plant.PlantProject.domain.Entity.SocialLogin; -import Plant.PlantProject.vo.request.MemberRequestDto; +import Plant.PlantProject.dto.request.MemberRequestDto; import Plant.PlantProject.common.exception.ErrorCode; -import Plant.PlantProject.vo.response.MemberResponseDto; +import Plant.PlantProject.dto.response.MemberResponseDto; import Plant.PlantProject.repository.MemberRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/ListenerConfiguration.java b/plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/ListenerConfiguration.java index 106b08c..6867653 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/ListenerConfiguration.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/common/config/kafka/ListenerConfiguration.java @@ -14,7 +14,7 @@ import org.springframework.kafka.core.ConsumerFactory; import org.springframework.kafka.core.DefaultKafkaConsumerFactory; import org.springframework.kafka.support.serializer.JsonDeserializer; - +import java.util.List; import java.util.Map; @EnableKafka @@ -114,4 +114,5 @@ public ConsumerFactory kafkaNotificationConsumer() return new DefaultKafkaConsumerFactory<>(consumerConfigurations, new StringDeserializer(), deserializer); } + } diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java b/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java index afb1a67..6b2361f 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/domain/NotifiTypeEnum.java @@ -7,6 +7,7 @@ public enum NotifiTypeEnum { SNS_COMMENT("snspostlist/","댓글"), TRADEBOARD_GOODS("bbsdetail/","찜"), SNS_HEART("snspostlist/","좋아요"), + KEYWORD("bbsdetail/", "키워드"), CHAT("chatroom/","채팅"); private final String path; diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java b/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java index b14c5f6..23570de 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java @@ -86,12 +86,14 @@ public void send(Integer senderNo, Integer receiverNo, NotifiTypeEnum type, Stri .isRead(false) .isDel(false) .build(); - CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker"); - //보낸 사람 이름 찾기 위해 feignClient를 통해 호출 - ResponseEntity findMember = circuitBreaker.run(() -> plantServiceClient.findById(senderNo.longValue()), - throwable -> ResponseEntity.ok(null)); + if (type != NotifiTypeEnum.KEYWORD) { + CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker"); + //보낸 사람 이름 찾기 위해 feignClient를 통해 호출 + ResponseEntity findMember = circuitBreaker.run(() -> plantServiceClient.findById(senderNo.longValue()), + throwable -> ResponseEntity.ok(null)); - notification.setSenderName(findMember.getBody().getNickname()); + notification.setSenderName(findMember.getBody().getNickname()); + } // SseEmitter 캐시 조회를 위해 key의 prefix 생성 String id = String.valueOf(notification.getReceiverNo()); diff --git a/plant-chat-service/src/test/java/com/example/plantchatservice/service/chat/ChatServiceTest.java b/plant-chat-service/src/test/java/com/example/plantchatservice/service/chat/ChatServiceTest.java index 8578e2c..db73b8b 100644 --- a/plant-chat-service/src/test/java/com/example/plantchatservice/service/chat/ChatServiceTest.java +++ b/plant-chat-service/src/test/java/com/example/plantchatservice/service/chat/ChatServiceTest.java @@ -11,7 +11,6 @@ import com.example.plantchatservice.dto.vo.*; import com.example.plantchatservice.repository.chat.ChatRepository; import com.example.plantchatservice.repository.mongo.MongoChatRepository; -import com.example.plantchatservice.service.AggregationSender; import com.example.plantchatservice.service.notification.NotificationService; import com.example.plantchatservice.testUser.WithMockCustomAccount; import org.junit.jupiter.api.DisplayName; diff --git a/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java b/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java index cd5b84b..b19c7f8 100644 --- a/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java +++ b/plant-sns-service/src/main/java/com/example/plantsnsservice/domain/NotifiTypeEnum.java @@ -7,6 +7,7 @@ public enum NotifiTypeEnum { SNS_COMMENT("snspostlist/","댓글"), TRADEBOARD_GOODS("bbsdetail/","찜"), SNS_HEART("snspostlist/","좋아요"), + KEYWORD("bbsdetail/", "키워드"), CHAT("chatroom/","채팅"); private final String path; From c533c77d6d8ffd1addcbfa550d1eda36e692e14b Mon Sep 17 00:00:00 2001 From: LminWoo99 Date: Thu, 16 May 2024 18:11:04 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20keyword=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20kafka=EB=A5=BC=20=ED=86=B5?= =?UTF-8?q?=ED=95=9C=20=EC=95=8C=EB=A6=BC=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/kafka/KafkaProducerConfig.java | 8 ++++++ .../service/keyword/KeywordService.java | 5 ++-- .../tradeboard/DeleteTradeBoardProducer.java | 21 +++++----------- .../service/tradeboard/TradeBoardService.java | 2 +- .../plantchatservice/service/DeletePost.java | 25 ++++--------------- 5 files changed, 23 insertions(+), 38 deletions(-) diff --git a/PlantBackend/src/main/java/Plant/PlantProject/common/config/kafka/KafkaProducerConfig.java b/PlantBackend/src/main/java/Plant/PlantProject/common/config/kafka/KafkaProducerConfig.java index 3cf6a96..8070fa8 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/common/config/kafka/KafkaProducerConfig.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/common/config/kafka/KafkaProducerConfig.java @@ -47,5 +47,13 @@ public ProducerFactory notificationProducerFactory public KafkaTemplate notificationKafkaTemplate() { return new KafkaTemplate<>(notificationProducerFactory()); } + @Bean + public ProducerFactory deletePostProducerFactory() { + return new DefaultKafkaProducerFactory<>(producerConfigurations()); + } + @Bean + public KafkaTemplate deletePostKafkaTemplate() { + return new KafkaTemplate<>(deletePostProducerFactory()); + } } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/keyword/KeywordService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/keyword/KeywordService.java index 42f8408..d0beb3e 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/keyword/KeywordService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/keyword/KeywordService.java @@ -65,7 +65,7 @@ public void deleteKeyWord(Long keywordId) { public void getMembersByKeyword(Integer tradeBoardNo, String keywordContent) { List memberList = keyWordRepository.findMemberNosByKeywordContent(keywordContent); if (!memberList.isEmpty()) { - sendKeywordNotificationData(tradeBoardNo, memberList); + sendKeywordNotificationData(tradeBoardNo, memberList, keywordContent); } } /** @@ -73,11 +73,12 @@ public void getMembersByKeyword(Integer tradeBoardNo, String keywordContent) { * kafka를 통한 plant-chat-service에 전달 * @param : Integer tradeBoardNo, List memberList */ - private void sendKeywordNotificationData(Integer tradeBoardNo, List memberList) { + private void sendKeywordNotificationData(Integer tradeBoardNo, List memberList, String keywordContent) { List notificationEventDtoList = memberList.stream().map(memberNo -> { NotificationEventDto notificationEventDto = NotificationEventDto.builder() .receiverNo(memberNo) + .content(keywordContent) .senderNo(tradeBoardNo) .type(NotifiTypeEnum.KEYWORD) .resource(tradeBoardNo.toString()) diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java index 003f31f..fe1d65b 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/DeleteTradeBoardProducer.java @@ -11,27 +11,18 @@ @Service @Slf4j public class DeleteTradeBoardProducer { - private KafkaTemplate kafkaTemplate; + private KafkaTemplate kafkaTemplate; @Autowired - public DeleteTradeBoardProducer(KafkaTemplate kafkaTemplate) { + public DeleteTradeBoardProducer(KafkaTemplate kafkaTemplate) { this.kafkaTemplate = kafkaTemplate; } /** * 중고 거래 게시글 삭제시 카프카를 통해 plant-chat-service 마이크로서비스에 전달 - * @param : String topic, TradeBoardDto tradeBoardDto + * @param : Long tradeBoardNo */ - public TradeBoardRequestDto send(String topic, TradeBoardRequestDto tradeBoardRequestDto) { - ObjectMapper mapper = new ObjectMapper(); - String jsonInString = ""; - try{ + public void send(String topic,Long tradeBoardNo) { - jsonInString = mapper.writeValueAsString(tradeBoardRequestDto); - - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - kafkaTemplate.send(topic, jsonInString); - log.info("Kafka Producer send data from the Plant microservice " + tradeBoardRequestDto); - return tradeBoardRequestDto; + kafkaTemplate.send(topic, tradeBoardNo); + log.info("Kafka Producer send data from the Plant microservice " + tradeBoardNo); } } diff --git a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java index ee7501e..36e668e 100644 --- a/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java +++ b/PlantBackend/src/main/java/Plant/PlantProject/service/tradeboard/TradeBoardService.java @@ -161,7 +161,7 @@ public void deletePost(Long id) { /*send this deletePost to the kafka*/ - deleteTradeBoardProducer.send("deletePost", tradeBoardRequestDto); + deleteTradeBoardProducer.send("deletePost", tradeBoardRequestDto.getId()); } /** * 유저가 올린 거래 게시글 조회 diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/service/DeletePost.java b/plant-chat-service/src/main/java/com/example/plantchatservice/service/DeletePost.java index 87433f1..5f1d99a 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/service/DeletePost.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/service/DeletePost.java @@ -1,5 +1,6 @@ package com.example.plantchatservice.service; +import com.example.plantchatservice.dto.vo.TradeBoardResponseDto; import com.example.plantchatservice.service.chat.ChatService; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; @@ -23,28 +24,12 @@ public class DeletePost { * @param : MemberDto memberDto, ChatRequestDto requestDto */ @KafkaListener(topics = "deletePost", containerFactory = "kafkaDeletePostContainerFactory") - public void deleteChat(String kafkaMessage) { + public void deleteChat(String kafkaMessage, Long tradeBoardNo) { log.info("Kafka Message : ->" + kafkaMessage); - - Map map = new HashMap<>(); - ObjectMapper mapper = new ObjectMapper(); - try { - map = mapper.readValue(kafkaMessage, new TypeReference>() { - }); - //TradeBoard id값 가져오기 - Integer tradeBoardNo = (Integer) map.get("id"); - if (tradeBoardNo == null) { - throw new IllegalArgumentException("TradeBoard ID is missing in the Kafka message"); - } - chatService.deleteChatRoom(tradeBoardNo); - - } catch (JsonProcessingException e) { - log.error("Error parsing Kafka message: {}", kafkaMessage, e); - } catch (IllegalArgumentException e) { - log.error("Validation error for Kafka message: {}", kafkaMessage, e); - } catch (Exception e) { - log.error("Error processing Kafka message: {}", kafkaMessage, e); + if (tradeBoardNo == null) { + throw new IllegalArgumentException("TradeBoard ID is missing in the Kafka message"); } + chatService.deleteChatRoom(tradeBoardNo.intValue()); } } \ No newline at end of file From 90f940f07d48a41b0a7b0adb041f2f0ee678f790 Mon Sep 17 00:00:00 2001 From: LminWoo99 Date: Thu, 16 May 2024 18:14:09 +0900 Subject: [PATCH 7/7] fix : update domain url --- .../service/notification/NotificationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java b/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java index 23570de..3e8d9ee 100644 --- a/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java +++ b/plant-chat-service/src/main/java/com/example/plantchatservice/service/notification/NotificationService.java @@ -28,7 +28,7 @@ @Slf4j public class NotificationService { private static final Long DEFAULT_TIMEOUT = 1000L * 60 * 29 ;// 29분 - public static final String PREFIX_URL = "http://localhost:3000/"; + public static final String PREFIX_URL = "https://sikguhaza.site/"; private final NotificationRepository notificationRepository; private final EmitterRepository emitterRepository;