diff --git a/build.gradle b/build.gradle index 2e9a9c0..f08846d 100644 --- a/build.gradle +++ b/build.gradle @@ -45,9 +45,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'io.jsonwebtoken:jjwt-api:0.11.2' - implementation 'io.jsonwebtoken:jjwt-impl:0.11.2' - implementation 'io.jsonwebtoken:jjwt-jackson:0.11.2' + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' + implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' + implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' // implementation "org.springframework.cloud:spring-cloud-starter-bootstrap" implementation 'org.springframework.boot:spring-boot-starter-actuator' @@ -59,24 +59,24 @@ dependencies { annotationProcessor "jakarta.persistence:jakarta.persistence-api" // Jwt - implementation 'io.jsonwebtoken:jjwt-api:0.11.2' - implementation 'io.jsonwebtoken:jjwt-jackson:0.11.2' - implementation 'io.jsonwebtoken:jjwt-impl:0.11.2' + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' + implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5' + implementation 'io.jsonwebtoken:jjwt-impl:0.11.5' // WebClient implementation 'org.springframework.boot:spring-boot-starter-webflux' // Feign - implementation 'io.github.openfeign:feign-httpclient:12.1' - implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:3.1.4' + implementation 'io.github.openfeign:feign-httpclient:12.2' + implementation 'org.springframework.cloud:spring-cloud-starter-openfeign:4.0.1' implementation 'org.springframework.boot:spring-boot-starter-data-redis' // 형태소 implementation 'com.github.shin285:KOMORAN:3.3.4' - implementation 'org.json:json:20210307' - implementation 'com.googlecode.json-simple:json-simple:1.1' + implementation 'org.json:json:20230227' + implementation 'com.googlecode.json-simple:json-simple:1.1.1' @@ -90,12 +90,14 @@ dependencies { implementation 'commons-logging:commons-logging:1.2' implementation group: 'log4j', name: 'log4j', version: '1.2.17' + implementation group: 'org.springframework.cloud', name: 'spring-cloud-stream-binder-kafka', version: '3.2.1' implementation 'org.springframework.cloud:spring-cloud-stream' implementation group: 'org.springframework.cloud', name: 'spring-cloud-stream-binder-kafka', version: '3.2.1' implementation 'org.springframework.cloud:spring-cloud-stream:3.2.1' + } dependencyManagement { diff --git a/src/main/java/gwangjang/server/KeywordServiceApplication.java b/src/main/java/gwangjang/server/KeywordServiceApplication.java index 79770ac..789d2c0 100644 --- a/src/main/java/gwangjang/server/KeywordServiceApplication.java +++ b/src/main/java/gwangjang/server/KeywordServiceApplication.java @@ -1,9 +1,11 @@ package gwangjang.server; + import gwangjang.server.domain.Issue.adapter.in.web.dto.get.SubscribeData; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.stream.annotation.EnableBinding; diff --git a/src/main/java/gwangjang/server/domain/Issue/application/dto/res/BubbleChartRes.java b/src/main/java/gwangjang/server/domain/Issue/application/dto/res/BubbleChartRes.java index a8c92ec..d566228 100644 --- a/src/main/java/gwangjang/server/domain/Issue/application/dto/res/BubbleChartRes.java +++ b/src/main/java/gwangjang/server/domain/Issue/application/dto/res/BubbleChartRes.java @@ -1,4 +1,8 @@ package gwangjang.server.domain.Issue.application.dto.res; +import java.util.List; + public class BubbleChartRes { + String topic; + List issueList; } diff --git a/src/main/java/gwangjang/server/domain/Issue/application/dto/res/IssueBySubscribersRes.java b/src/main/java/gwangjang/server/domain/Issue/application/dto/res/IssueBySubscribersRes.java new file mode 100644 index 0000000..bb29944 --- /dev/null +++ b/src/main/java/gwangjang/server/domain/Issue/application/dto/res/IssueBySubscribersRes.java @@ -0,0 +1,24 @@ +package gwangjang.server.domain.Issue.application.dto.res; + +import lombok.*; + +@Builder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class IssueBySubscribersRes { + + private Long categoryId; + private String category; //영역 + private Long titleId; + private String title; //주제 + private Long subscribeCount; + private String imgUrl; + + public IssueBySubscribersRes(Long titleId, Long subscribeCount) { + this.titleId = titleId; + this.subscribeCount = subscribeCount; + } + +} diff --git a/src/main/java/gwangjang/server/domain/Issue/application/dto/res/issueList.java b/src/main/java/gwangjang/server/domain/Issue/application/dto/res/issueList.java new file mode 100644 index 0000000..9b3a5ce --- /dev/null +++ b/src/main/java/gwangjang/server/domain/Issue/application/dto/res/issueList.java @@ -0,0 +1,7 @@ +package gwangjang.server.domain.Issue.application.dto.res; + +public class issueList { + String name; + Long value; + +} diff --git a/src/main/java/gwangjang/server/domain/Issue/application/service/KeywordSubscribeUseCase.java b/src/main/java/gwangjang/server/domain/Issue/application/service/KeywordSubscribeUseCase.java index 012eefc..eb34a15 100644 --- a/src/main/java/gwangjang/server/domain/Issue/application/service/KeywordSubscribeUseCase.java +++ b/src/main/java/gwangjang/server/domain/Issue/application/service/KeywordSubscribeUseCase.java @@ -1,47 +1,91 @@ package gwangjang.server.domain.Issue.application.service; +import gwangjang.server.domain.Issue.application.dto.res.IssueBySubscribersRes; import gwangjang.server.domain.Issue.application.dto.res.MainBubbleData; import gwangjang.server.domain.Issue.application.dto.res.MainBubbleRes; +import gwangjang.server.domain.Issue.domain.service.IssueService; +import gwangjang.server.global.feign.FindMemberFeignClient; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; @Service @Transactional @RequiredArgsConstructor public class KeywordSubscribeUseCase { - + private final IssueService issueService; + private final FindMemberFeignClient findMemberFeignClient; +// public List getBubbleData() { +//// List mainBubbleRes = new ArrayList<>(); +//// List mainBubbleData1 = new ArrayList<>(); +//// mainBubbleData1.add(new MainBubbleData("후쿠시마 오염수", 356L)); +//// mainBubbleData1.add(new MainBubbleData("일회용품 사용 규제 시행", 123L)); +//// mainBubbleRes.add(new MainBubbleRes("환경", mainBubbleData1)); +//// +//// List mainBubbleData2 = new ArrayList<>(); +//// mainBubbleData2.add(new MainBubbleData("SPC 불매 운동", 335L)); +//// mainBubbleData2.add(new MainBubbleData("쿠팡 노동자 사망", 121L)); +//// mainBubbleData2.add(new MainBubbleData("주 69시간 근로시간 제도 개편", 50L)); +//// mainBubbleRes.add(new MainBubbleRes("일자리/노동", mainBubbleData2)); +//// +//// List mainBubbleData3 = new ArrayList<>(); +//// mainBubbleData3.add(new MainBubbleData("이태원 참사", 90L)); +//// mainBubbleData3.add(new MainBubbleData("국민연금 개혁", 323L)); +//// mainBubbleRes.add(new MainBubbleRes("주거/사회안전망", mainBubbleData3)); +//// +//// List mainBubbleData4 = new ArrayList<>(); +//// mainBubbleData4.add(new MainBubbleData("의대 정원 확대", 156L)); +//// mainBubbleData4.add(new MainBubbleData("서이초 교사 사건", 400L)); +//// mainBubbleRes.add(new MainBubbleRes("교육", mainBubbleData4)); +// +// +// +// +// return null; +// } public List getBubbleData() { - List mainBubbleRes = new ArrayList<>(); + List subscribersRes = findMemberFeignClient.getIssuesBySubscribers("guest").getBody().getData(); + return mapToMainBubbleResList(subscribersRes); + } - List mainBubbleData2 = new ArrayList<>(); - mainBubbleData2.add(new MainBubbleData("SPC 불매 운동", 335L)); - mainBubbleData2.add(new MainBubbleData("쿠팡 노동자 사망", 121L)); - mainBubbleData2.add(new MainBubbleData("주 69시간 근로시간 제도 개편", 50L)); - mainBubbleRes.add(new MainBubbleRes("일자리/노동", mainBubbleData2)); + public List mapToMainBubbleResList(List subscribersRes) { + return subscribersRes.stream() + .collect(Collectors.groupingBy(IssueBySubscribersRes::getCategory)) + .entrySet().stream() + .map(entry -> { + MainBubbleRes mainBubbleRes = new MainBubbleRes(); + mainBubbleRes.setName(entry.getKey()); - List mainBubbleData3 = new ArrayList<>(); - mainBubbleData3.add(new MainBubbleData("이태원 참사", 90L)); - mainBubbleData3.add(new MainBubbleData("국민연금 개혁", 323L)); - mainBubbleRes.add(new MainBubbleRes("주거/사회안전망", mainBubbleData3)); + List mainBubbleDataList = entry.getValue().stream() + .map(this::mapToMainBubbleData) + .collect(Collectors.toList()); + mainBubbleRes.setData(mainBubbleDataList); + return mainBubbleRes; + }) + .collect(Collectors.toList()); + } + private MainBubbleData mapToMainBubbleData(IssueBySubscribersRes issueBySubscribersRes) { + MainBubbleData mainBubbleData = new MainBubbleData(); + mainBubbleData.setName(issueBySubscribersRes.getTitle()); - List mainBubbleData1 = new ArrayList<>(); - mainBubbleData1.add(new MainBubbleData("후쿠시마 오염", 356L)); - mainBubbleData1.add(new MainBubbleData("일회용품 사용 규제 시행", 123L)); - mainBubbleRes.add(new MainBubbleRes("환경", mainBubbleData1)); + // Calculate subscriber count within the specified ratio (e.g., 50%) + mainBubbleData.setValue((long) calculateRatioBasedSubscriberCount(0.5)); + return mainBubbleData; + } + private int calculateRatioBasedSubscriberCount(double ratio) { + int minSubscriberCount = 100; + int maxSubscriberCount = 400; - List mainBubbleData4 = new ArrayList<>(); - mainBubbleData4.add(new MainBubbleData("의대 정원 확대", 156L)); - mainBubbleData4.add(new MainBubbleData("서이초 교사 사건", 400L)); - mainBubbleRes.add(new MainBubbleRes("교육", mainBubbleData4)); + // Calculate subscriber count within the specified ratio + return (int) (minSubscriberCount + (maxSubscriberCount - minSubscriberCount + 1) * ratio); - return mainBubbleRes; } } diff --git a/src/main/java/gwangjang/server/domain/Issue/application/service/NaverTrendByIssueUseCase.java b/src/main/java/gwangjang/server/domain/Issue/application/service/NaverTrendByIssueUseCase.java index 3f79ffc..433bffa 100644 --- a/src/main/java/gwangjang/server/domain/Issue/application/service/NaverTrendByIssueUseCase.java +++ b/src/main/java/gwangjang/server/domain/Issue/application/service/NaverTrendByIssueUseCase.java @@ -8,8 +8,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; +import java.util.*; @Service @Transactional @@ -29,7 +28,6 @@ public NaverTrendDto getNaverTrend(String issue) { TrendRes trendRes = naverTrendUtil.main(replace); - String [] month = new String[] {"5월 1주차", "5월 2주차", "5월 3주차", "5월 4주차", "5월 5주차", "6월 1주차", "6월 2주차", "6월 3주차", "6월 4주차", "7월 1주차", "7월 2주차", "7월 3주차", "7월 4주차","7월 5주차", "8월 1주차", "8월 2주차", "8월 3주차", "8월 4주차", "8월 5주차", "9월 1주차", "9월 2주차", "9월 3주차", @@ -37,6 +35,7 @@ public NaverTrendDto getNaverTrend(String issue) { List trendList = new ArrayList<>(); + List data = trendRes.getResults().get(0).getData(); data.stream().forEach( diff --git a/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueRepositoryImpl.java b/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueRepositoryImpl.java index 1624b30..dc93810 100644 --- a/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueRepositoryImpl.java +++ b/src/main/java/gwangjang/server/domain/Issue/domain/repository/IssueRepositoryImpl.java @@ -146,5 +146,5 @@ public List findRandomIssues() { return resultList; } - //분석된 결과 다ㅓㅅ개 + //분석된 결과 다 } diff --git a/src/main/java/gwangjang/server/domain/Issue/domain/service/IssueService.java b/src/main/java/gwangjang/server/domain/Issue/domain/service/IssueService.java index 5274080..6ed2607 100644 --- a/src/main/java/gwangjang/server/domain/Issue/domain/service/IssueService.java +++ b/src/main/java/gwangjang/server/domain/Issue/domain/service/IssueService.java @@ -10,6 +10,7 @@ import gwangjang.server.domain.Issue.domain.repository.KeywordRepository; import gwangjang.server.domain.Issue.domain.repository.TopicRepository; import gwangjang.server.domain.Issue.exception.NotFoundIssueException; +import gwangjang.server.global.feign.FindMemberFeignClient; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -30,6 +31,8 @@ public class IssueService { private final IssueMapper issueMapper = new IssueMapper(); + + public IssueRes findIssueAndTopicById(Long issueId) { return issueQueryRepository.findIssueAndTopicById(issueId).orElseThrow(NotFoundIssueException::new); } @@ -138,5 +141,4 @@ public SearchRes search(String keyword) { public List findRandomIssues(){ return issueRepository.findRandomIssues(); } - } diff --git a/src/main/java/gwangjang/server/domain/Issue/presentation/IssueController.java b/src/main/java/gwangjang/server/domain/Issue/presentation/IssueController.java index 491def5..dcbb96e 100644 --- a/src/main/java/gwangjang/server/domain/Issue/presentation/IssueController.java +++ b/src/main/java/gwangjang/server/domain/Issue/presentation/IssueController.java @@ -53,4 +53,5 @@ public ResponseEntity>> getRandomIssue() { return ResponseEntity.ok(SuccessResponse.create(IssueResponseMessage.GET_ISSUE_SUCCESS.getMessage(),this.issueService.findRandomIssues())); } + } diff --git a/src/main/java/gwangjang/server/domain/Issue/presentation/KeywordController.java b/src/main/java/gwangjang/server/domain/Issue/presentation/KeywordController.java index d7b2316..e0839ed 100644 --- a/src/main/java/gwangjang/server/domain/Issue/presentation/KeywordController.java +++ b/src/main/java/gwangjang/server/domain/Issue/presentation/KeywordController.java @@ -1,6 +1,6 @@ package gwangjang.server.domain.Issue.presentation; - +import gwangjang.server.domain.Issue.application.dto.res.*; import gwangjang.server.domain.Issue.application.dto.res.MainBubbleRes; import gwangjang.server.domain.Issue.application.dto.res.NaverTrendDto; import gwangjang.server.domain.Issue.application.dto.res.TrendIssueGraphRes; @@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; +import java.util.stream.Collectors; import static gwangjang.server.domain.Issue.presentation.constant.IssueResponseMessage.GET_MAIN_BUBBLE_CHART; diff --git a/src/main/java/gwangjang/server/global/feign/FindMemberFeignClient.java b/src/main/java/gwangjang/server/global/feign/FindMemberFeignClient.java new file mode 100644 index 0000000..45f9221 --- /dev/null +++ b/src/main/java/gwangjang/server/global/feign/FindMemberFeignClient.java @@ -0,0 +1,16 @@ +package gwangjang.server.global.feign; + +import gwangjang.server.domain.Issue.application.dto.res.IssueBySubscribersRes; +import gwangjang.server.global.response.SuccessResponse; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; + +import java.util.List; + +@FeignClient(name="MEMBERSERVICE") +public interface FindMemberFeignClient { + @GetMapping("/subscribe/issue") + ResponseEntity>> getIssuesBySubscribers(@RequestHeader(value = "user-id") String socialId); +} \ No newline at end of file diff --git a/src/main/java/gwangjang/server/global/rabbitMQ/Email.java b/src/main/java/gwangjang/server/global/rabbitMQ/Email.java new file mode 100644 index 0000000..13da122 --- /dev/null +++ b/src/main/java/gwangjang/server/global/rabbitMQ/Email.java @@ -0,0 +1,37 @@ +package gwangjang.server.global.rabbitMQ; + +public class Email { + + private String to; + private String body; + + public Email() { + } + + public Email(String to, String body) { + this.to = to; + this.body = body; + } + + public String getTo() { + return to; + } + + public void setTo(String to) { + this.to = to; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + @Override + public String toString() { + return String.format("Email{to=%s, body=%s}", getTo(), getBody()); + } + +} diff --git a/src/main/java/gwangjang/server/global/rabbitMQ/RabbitMQConfig.java b/src/main/java/gwangjang/server/global/rabbitMQ/RabbitMQConfig.java new file mode 100644 index 0000000..0965c0f --- /dev/null +++ b/src/main/java/gwangjang/server/global/rabbitMQ/RabbitMQConfig.java @@ -0,0 +1,29 @@ +package gwangjang.server.global.rabbitMQ; + +import org.springframework.amqp.core.TopicExchange; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class RabbitMQConfig { + + @Bean + public TopicExchange topic() { + return new TopicExchange("amq.topic"); + } + + @Bean + public Jackson2JsonMessageConverter producerJackson2MessageConverter() { + return new Jackson2JsonMessageConverter(); + } + + @Bean + public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) { + final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); + rabbitTemplate.setMessageConverter(producerJackson2MessageConverter()); + return rabbitTemplate; + } +} diff --git a/src/main/java/gwangjang/server/global/rabbitMQ/Receiver.java b/src/main/java/gwangjang/server/global/rabbitMQ/Receiver.java new file mode 100644 index 0000000..8cdfcc5 --- /dev/null +++ b/src/main/java/gwangjang/server/global/rabbitMQ/Receiver.java @@ -0,0 +1,43 @@ +package gwangjang.server.global.rabbitMQ; + +import org.springframework.amqp.rabbit.annotation.Exchange; +import org.springframework.amqp.rabbit.annotation.Queue; +import org.springframework.amqp.rabbit.annotation.QueueBinding; +import org.springframework.amqp.rabbit.annotation.RabbitListener; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class Receiver { + + @RabbitListener(bindings = @QueueBinding( + value = @Queue, + exchange = @Exchange(value = "amq.topic", type = "topic", durable = "true"), // + key = "test")) + public void handleMsg1(Email in) { + System.out.println(in.toString()); + } + + @RabbitListener(bindings = @QueueBinding( + value = @Queue(value = "kkaok", durable = "true"), + exchange = @Exchange(value = "amq.topic", type = "topic", durable = "true"), // + key = "test.0001")) + public void handleMsg2(Email in) { + System.out.println(in.toString()); + } + + @RabbitListener(bindings = @QueueBinding( + value = @Queue(value = "subscribe.data.queue", durable = "true"), + exchange = @Exchange(value = "amq.topic", type = "topic", durable = "true"), // + key = "subscribe.data")) + public void handleSubscribeData(SubscribeDataMessage message) { + List subscribeDataList = message.getSubscribeDataList(); + // Process the received subscribeDataList + for (SubscribeData subscribeData : subscribeDataList) { + System.out.println(subscribeData.toString()); + // Add your logic to handle each SubscribeData object + } + } + +} diff --git a/src/main/java/gwangjang/server/global/rabbitMQ/SubscribeData.java b/src/main/java/gwangjang/server/global/rabbitMQ/SubscribeData.java new file mode 100644 index 0000000..404e0c1 --- /dev/null +++ b/src/main/java/gwangjang/server/global/rabbitMQ/SubscribeData.java @@ -0,0 +1,13 @@ +package gwangjang.server.global.rabbitMQ; + +import lombok.*; + +@Setter +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SubscribeData { + private Long issueId; + private Long count; +} diff --git a/src/main/java/gwangjang/server/global/rabbitMQ/SubscribeDataMessage.java b/src/main/java/gwangjang/server/global/rabbitMQ/SubscribeDataMessage.java new file mode 100644 index 0000000..d32252d --- /dev/null +++ b/src/main/java/gwangjang/server/global/rabbitMQ/SubscribeDataMessage.java @@ -0,0 +1,24 @@ +package gwangjang.server.global.rabbitMQ; + +import java.io.Serializable; +import java.util.List; + +public class SubscribeDataMessage implements Serializable { + private List subscribeDataList; + + public SubscribeDataMessage() { + // Default constructor needed for deserialization + } + + public SubscribeDataMessage(List subscribeDataList) { + this.subscribeDataList = subscribeDataList; + } + + public List getSubscribeDataList() { + return subscribeDataList; + } + + public void setSubscribeDataList(List subscribeDataList) { + this.subscribeDataList = subscribeDataList; + } +} diff --git a/src/test/java/gwangjang/server/KeywordServiceApplicationTests.java b/src/test/java/gwangjang/server/KeywordServiceApplicationTests.java index d946c03..525dd0f 100644 --- a/src/test/java/gwangjang/server/KeywordServiceApplicationTests.java +++ b/src/test/java/gwangjang/server/KeywordServiceApplicationTests.java @@ -1,8 +1,10 @@ package gwangjang.server; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; + @SpringBootTest class KeywordServiceApplicationTests {