diff --git a/src/main/java/com/siliconvalley/domain/canvas/controller/CanvasController.java b/src/main/java/com/siliconvalley/domain/canvas/controller/CanvasController.java index ae08894..42f3b4b 100644 --- a/src/main/java/com/siliconvalley/domain/canvas/controller/CanvasController.java +++ b/src/main/java/com/siliconvalley/domain/canvas/controller/CanvasController.java @@ -27,7 +27,8 @@ public ResponseEntity convertSketchToCanvas( @RequestParam Long profileId, @RequestParam Long subjectId ) throws IOException { - Response response = canvasConvertService.convertSketchToCanvas(profileId, subjectId, sketchFile); + String sketch = s3ImageUploadService.uploadFile(sketchFile, s3PathBuildService.buildPath(profileId, "sketch")); + Response response = canvasConvertService.convertSketchToCanvas(profileId, subjectId, sketch); return ResponseEntity.status(HttpStatus.CREATED).body(response); } @@ -37,7 +38,8 @@ public ResponseEntity updateSketchAndCanvas( @RequestParam Long profileId, @PathVariable Long canvasId ) throws IOException { - Response response = canvasConvertService.updateSketchAndCanvas(profileId, canvasId, sketchFile); + String sketch = s3ImageUploadService.uploadFile(sketchFile, s3PathBuildService.buildPath(profileId, "sketch")); + Response response = canvasConvertService.updateSketchAndCanvas(profileId, canvasId, sketch); return ResponseEntity.status(HttpStatus.NO_CONTENT).body(response); } diff --git a/src/main/java/com/siliconvalley/domain/canvas/dto/CanvasConvertResponse.java b/src/main/java/com/siliconvalley/domain/canvas/dto/CanvasConvertResponse.java index c13dcfb..1665f6f 100644 --- a/src/main/java/com/siliconvalley/domain/canvas/dto/CanvasConvertResponse.java +++ b/src/main/java/com/siliconvalley/domain/canvas/dto/CanvasConvertResponse.java @@ -1,6 +1,5 @@ package com.siliconvalley.domain.canvas.dto; -import com.siliconvalley.domain.canvas.service.CanvasConvertService; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; diff --git a/src/main/java/com/siliconvalley/domain/canvas/dto/ConvertEventDto.java b/src/main/java/com/siliconvalley/domain/canvas/dto/ConvertEventDto.java new file mode 100644 index 0000000..92bd9b9 --- /dev/null +++ b/src/main/java/com/siliconvalley/domain/canvas/dto/ConvertEventDto.java @@ -0,0 +1,19 @@ +package com.siliconvalley.domain.canvas.dto; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ConvertEventDto { + + private Long canvasId; + private String canvasUrl; + + public ConvertEventDto(Long canvasId, String canvasUrl){ + this.canvasId = canvasId; + this.canvasUrl = canvasUrl; + } + +} diff --git a/src/main/java/com/siliconvalley/domain/canvas/service/CanvasConvertService.java b/src/main/java/com/siliconvalley/domain/canvas/service/CanvasConvertService.java index 0cfdf9e..7f8f553 100644 --- a/src/main/java/com/siliconvalley/domain/canvas/service/CanvasConvertService.java +++ b/src/main/java/com/siliconvalley/domain/canvas/service/CanvasConvertService.java @@ -3,6 +3,7 @@ import com.siliconvalley.domain.canvas.dao.CanvasFindDao; import com.siliconvalley.domain.canvas.domain.Canvas; import com.siliconvalley.domain.canvas.dto.CanvasCreateDto; +import com.siliconvalley.domain.canvas.dto.ConvertEventDto; import com.siliconvalley.domain.image.service.S3ImageUploadService; import com.siliconvalley.domain.image.service.S3PathBuildService; import com.siliconvalley.domain.item.subject.dao.SubjectFindDao; @@ -11,6 +12,8 @@ import com.siliconvalley.domain.profile.domain.Profile; import com.siliconvalley.domain.rabbitMQ.dto.SketchConversionResponse; import com.siliconvalley.domain.rabbitMQ.service.ConvertRequestSender; +import com.siliconvalley.domain.sse.application.SseEmitterFinder; +import com.siliconvalley.domain.sse.application.SseEmitterSender; import com.siliconvalley.global.common.dto.Response; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -34,23 +37,26 @@ public class CanvasConvertService { private final CanvasCreateService canvasCreateService; private final S3ImageUploadService s3ImageUploadService; private final S3PathBuildService s3PathBuildService; + private final SseEmitterSender sseEmitterSender; + private final SseEmitterFinder sseEmitterFinder; - public Response convertSketchToCanvas(Long profileId, Long subjectId, MultipartFile sketchFile) throws IOException{ - String sketch = s3ImageUploadService.uploadFile(sketchFile, s3PathBuildService.buildPath(profileId, "sketch")); + public Response convertSketchToCanvas(Long profileId, Long subjectId, String sketch){ Profile profile = profileFindDao.findById(profileId); Subject subject = subjectFindDao.findById(subjectId); Canvas canvas = canvasCreateService.createCanvas(CanvasCreateDto.builder().subject(subject).sketchUrl(sketch).profile(profile).build()); return convertRequestSender.sendSketchConversionRequest(sketch, canvas.getId(), profileId, subjectId); } - public Response updateSketchAndCanvas(Long profileId, Long canvasId, MultipartFile sketchFile) throws IOException{ - String sketch = s3ImageUploadService.uploadFile(sketchFile, s3PathBuildService.buildPath(profileId, "sketch")); + public Response updateSketchAndCanvas(Long profileId, Long canvasId, String sketch){ Canvas canvas = canvasFindDao.findById(canvasId); return canvasUpdateService.updateSketchAndCanvas(canvas, sketch, profileId); } - public void updateConvertedData(SketchConversionResponse response){ + public void updateConvertedData(SketchConversionResponse response){ Canvas canvas = canvasFindDao.findById(response.getCanvasId()); - canvas.updateSketch(response.getCanvasUrl()); + Long profileId = canvas.getProfile().getId(); + String id = profileId + "_" + System.currentTimeMillis(); + canvas.updateCanvas(response.getCanvasUrl()); + sseEmitterSender.send(sseEmitterFinder.findByProfileId(profileId), id, new ConvertEventDto(canvas.getId(), response.getCanvasUrl()), profileId); } } diff --git a/src/main/java/com/siliconvalley/domain/post/code/RankingCode.java b/src/main/java/com/siliconvalley/domain/post/code/RankingCode.java index 9f82fd3..7b7a0c2 100644 --- a/src/main/java/com/siliconvalley/domain/post/code/RankingCode.java +++ b/src/main/java/com/siliconvalley/domain/post/code/RankingCode.java @@ -4,7 +4,7 @@ import org.springframework.http.HttpStatus; public enum RankingCode implements ResponseCode { - UPDATE_RANKING(204, "랭킹이 업데이트 되었습니다.", HttpStatus.NO_CONTENT), + UPDATE_RANKING(201, "랭킹이 업데이트 되었습니다.", HttpStatus.CREATED), GET_RANKING_SUCCESS(200, "랭킹 조회에 성공하였습니다.", HttpStatus.OK); private final int code; diff --git a/src/main/java/com/siliconvalley/domain/post/controller/PostController.java b/src/main/java/com/siliconvalley/domain/post/controller/PostController.java index bf0754d..5c30f23 100644 --- a/src/main/java/com/siliconvalley/domain/post/controller/PostController.java +++ b/src/main/java/com/siliconvalley/domain/post/controller/PostController.java @@ -41,9 +41,11 @@ public ResponseEntity getAllPosts( return ResponseEntity.ok(response); } - @GetMapping("/posts/ranking") - public ResponseEntity getRankingThisWeek(){ - Response response = rankCachingService.getRankingThisWeek(); + @GetMapping("/subjects/{subjectId}/posts/ranking") + public ResponseEntity getRankingThisWeek( + @PathVariable Long subjectId + ){ + Response response = rankCachingService.getRankingThisWeekBySubject(subjectId); return ResponseEntity.ok(response); } diff --git a/src/main/java/com/siliconvalley/domain/post/dao/PostCustomRepository.java b/src/main/java/com/siliconvalley/domain/post/dao/PostCustomRepository.java index b404314..822e809 100644 --- a/src/main/java/com/siliconvalley/domain/post/dao/PostCustomRepository.java +++ b/src/main/java/com/siliconvalley/domain/post/dao/PostCustomRepository.java @@ -24,7 +24,7 @@ public class PostCustomRepository { private final JPAQueryFactory jpaQueryFactory; - public List getSubjectRankingThisWeek(){ + public List getSubjectRankingThisWeek(Long subjectId){ QPost post = QPost.post; QEmotion emotion = QEmotion.emotion; QCanvas canvas = QCanvas.canvas1; @@ -38,7 +38,8 @@ public List getSubjectRankingThisWeek(){ .from(emotion) .join(emotion.post, post) .join(post.canvas, canvas) - .where(emotion.createdAt.between(startOfWeek, endOfWeek)) // 감정 표현의 생성 시간을 기준으로 필터링 + .where(emotion.createdAt.between(startOfWeek, endOfWeek). + and(canvas.subject.id.eq(subjectId))) .groupBy(post.id, canvas.id, canvas.canvas) .orderBy(emotion.count().desc(), post.createdAt.asc()) // 추가된 정렬 기준 .limit(8) diff --git a/src/main/java/com/siliconvalley/domain/post/dto/RankingCachingDto.java b/src/main/java/com/siliconvalley/domain/post/dto/RankingCachingDto.java index 02b8de6..1309903 100644 --- a/src/main/java/com/siliconvalley/domain/post/dto/RankingCachingDto.java +++ b/src/main/java/com/siliconvalley/domain/post/dto/RankingCachingDto.java @@ -11,11 +11,13 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class RankingCachingDto { private String time; + private String subjectName; private List rankerList; - public RankingCachingDto(List dto){ + public RankingCachingDto(List dto, String subjectName){ this.time = "Update Time : " + LocalTime.now().getHour() + ":" + LocalTime.now().getMinute(); this.rankerList = dto; + this.subjectName = subjectName; } } diff --git a/src/main/java/com/siliconvalley/domain/post/service/PostRankingService.java b/src/main/java/com/siliconvalley/domain/post/service/PostRankingService.java index acf61c8..427b066 100644 --- a/src/main/java/com/siliconvalley/domain/post/service/PostRankingService.java +++ b/src/main/java/com/siliconvalley/domain/post/service/PostRankingService.java @@ -1,11 +1,11 @@ package com.siliconvalley.domain.post.service; +import com.siliconvalley.domain.item.subject.dao.SubjectFindDao; +import com.siliconvalley.domain.item.subject.domain.Subject; import com.siliconvalley.domain.notification.application.NotificationPushService; -import com.siliconvalley.domain.notification.domain.NotificationType; import com.siliconvalley.domain.post.dao.PostCustomRepository; import com.siliconvalley.domain.post.dto.PostRankingDto; import com.siliconvalley.domain.post.dto.RankingCachingDto; -import com.siliconvalley.domain.sse.application.SseEmitterFinder; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; @@ -15,24 +15,27 @@ import java.util.List; @Service -@Transactional(readOnly = true) +@Transactional @RequiredArgsConstructor @Slf4j public class PostRankingService { private final RankCachingService rankCachingService; private final PostCustomRepository postCustomRepository; - + private final SubjectFindDao subjectFindDao; private final NotificationPushService notificationPushService; @Scheduled(cron = "0 0 * * * *") public void updateRanking(){ - List postRankingDtoList = postCustomRepository.getSubjectRankingThisWeek(); - log.info("랭킹 개수" + postRankingDtoList.size()); - for (PostRankingDto postRankingDto : postRankingDtoList){ - log.info(postRankingDto.getPostId() + "번 포스트"); - notificationPushService.pushNotification(postRankingDto); + List subjects = subjectFindDao.findAllSubjects(); + for (Subject subject : subjects){ + List postRankingDtoList = postCustomRepository.getSubjectRankingThisWeek(subject.getId()); + log.info("랭킹 개수" + postRankingDtoList.size()); + for (PostRankingDto postRankingDto : postRankingDtoList){ + log.info(postRankingDto.getPostId() + "번 포스트"); + notificationPushService.pushNotification(postRankingDto); + } + rankCachingService.cachingRankToRedis(new RankingCachingDto(postRankingDtoList, subject.getSubjectName())); } - rankCachingService.cachingRankToRedis(new RankingCachingDto(postRankingDtoList)); } } diff --git a/src/main/java/com/siliconvalley/domain/post/service/RankCachingService.java b/src/main/java/com/siliconvalley/domain/post/service/RankCachingService.java index e22119c..230f227 100644 --- a/src/main/java/com/siliconvalley/domain/post/service/RankCachingService.java +++ b/src/main/java/com/siliconvalley/domain/post/service/RankCachingService.java @@ -1,5 +1,7 @@ package com.siliconvalley.domain.post.service; +import com.siliconvalley.domain.item.subject.dao.SubjectFindDao; +import com.siliconvalley.domain.item.subject.domain.Subject; import com.siliconvalley.domain.post.code.RankingCode; import com.siliconvalley.domain.post.dto.RankingCachingDto; import com.siliconvalley.domain.post.dto.RankingPeriodDto; @@ -19,28 +21,30 @@ public class RankCachingService { private final RedisTemplate redisTemplate; + private final SubjectFindDao subjectFindDao; - public Response getRankingThisWeek(){ - RankingCachingDto rankingCachingDto = redisTemplate.opsForList().index(generateRedisKey(), -1); + public Response getRankingThisWeekBySubject(Long subjectId){ + Subject subject = subjectFindDao.findById(subjectId); + RankingCachingDto rankingCachingDto = redisTemplate.opsForList().index(generateRedisKey(subject.getSubjectName()), -1); return Response.of(RankingCode.GET_RANKING_SUCCESS, rankingCachingDto); } public void cachingRankToRedis(RankingCachingDto rankingCachingDto){ - redisTemplate.opsForList().rightPush(generateRedisKey(), rankingCachingDto); + redisTemplate.opsForList().rightPush(generateRedisKey(rankingCachingDto.getSubjectName()), rankingCachingDto); // 키의 만료 시간을 4주로 설정 - redisTemplate.expire(generateRedisKey(), 28, TimeUnit.DAYS); + redisTemplate.expire(generateRedisKey(rankingCachingDto.getSubjectName()), 28, TimeUnit.DAYS); } - public String getTopPostThisWeek(){ - RankingCachingDto rankingCachingDto = redisTemplate.opsForList().index(generateRedisKey(), -1); + public String getTopPostThisWeek(String subjectName){ + RankingCachingDto rankingCachingDto = redisTemplate.opsForList().index(generateRedisKey(subjectName), -1); log.info(rankingCachingDto.getRankerList().size() + "개의 리스트"); log.info(rankingCachingDto.getRankerList().get(0).getCanvasUrl()); log.info(rankingCachingDto.getRankerList().get(0).getPostId() + "번 게시물"); return rankingCachingDto.getRankerList().get(0).getCanvasUrl(); } - private String generateRedisKey() { + private String generateRedisKey(String subjectName) { RankingPeriodDto dateDto = RankingPeriodDto.builder().build(); - return "week:" + dateDto.getWeekOfYear() + ":day:" + dateDto.getDayOfWeek() + ":rank"; + return "week:" + dateDto.getWeekOfYear() + ":day:" + dateDto.getDayOfWeek() + ':' + subjectName + ":rank"; } } diff --git a/src/main/java/com/siliconvalley/domain/rabbitMQ/dto/SketchConversionRequest.java b/src/main/java/com/siliconvalley/domain/rabbitMQ/dto/SketchConversionRequest.java index 7a809c6..9ae3d00 100644 --- a/src/main/java/com/siliconvalley/domain/rabbitMQ/dto/SketchConversionRequest.java +++ b/src/main/java/com/siliconvalley/domain/rabbitMQ/dto/SketchConversionRequest.java @@ -10,10 +10,12 @@ public class SketchConversionRequest { private String sketchUrl; private Long canvasId; private Long profileId; + private String subjectName; - public SketchConversionRequest(String sketchUrl, Long canvasId, Long profileId){ + public SketchConversionRequest(String sketchUrl, Long canvasId, Long profileId, String subjectName){ this.sketchUrl = sketchUrl; this.canvasId = canvasId; this.profileId = profileId; + this.subjectName = subjectName; } } diff --git a/src/main/java/com/siliconvalley/domain/rabbitMQ/service/ConvertRequestSender.java b/src/main/java/com/siliconvalley/domain/rabbitMQ/service/ConvertRequestSender.java index 20a51df..b6ef0a6 100644 --- a/src/main/java/com/siliconvalley/domain/rabbitMQ/service/ConvertRequestSender.java +++ b/src/main/java/com/siliconvalley/domain/rabbitMQ/service/ConvertRequestSender.java @@ -1,6 +1,8 @@ package com.siliconvalley.domain.rabbitMQ.service; import com.siliconvalley.domain.canvas.dto.CanvasConvertResponse; +import com.siliconvalley.domain.item.subject.dao.SubjectFindDao; +import com.siliconvalley.domain.item.subject.domain.Subject; import com.siliconvalley.domain.post.service.RankCachingService; import com.siliconvalley.domain.rabbitMQ.code.RabbitMQCode; import com.siliconvalley.domain.rabbitMQ.dto.SketchConversionRequest; @@ -16,17 +18,15 @@ public class ConvertRequestSender { private final RabbitTemplate rabbitTemplate; private final RankCachingService rankCachingService; - private final GenerateRoutingKeyService generateRoutingKeyService; + private final SubjectFindDao subjectFindDao; @Value("${rabbitmq.exchange}") private String exchange; - public Response sendSketchConversionRequest(String sketchUrl, Long canvasId, Long profileId, Long subjectId) { - SketchConversionRequest request = new SketchConversionRequest(sketchUrl, canvasId, profileId); - rabbitTemplate.convertAndSend(exchange, generateRoutingKeyService.generateRoutingKey(subjectId), request); - return Response.of(RabbitMQCode.CONVERSION_REQUEST_SUCCESS, - new CanvasConvertResponse(canvasId, rankCachingService.getTopPostThisWeek())); + String subjectName = subjectFindDao.findById(subjectId).getSubjectName(); + SketchConversionRequest request = new SketchConversionRequest(sketchUrl, canvasId, profileId, subjectName); + rabbitTemplate.convertAndSend(exchange, "sketch_conversion_request_queue" , request); + return Response.of(RabbitMQCode.CONVERSION_REQUEST_SUCCESS, new CanvasConvertResponse(canvasId, rankCachingService.getTopPostThisWeek(subjectName))); } - } diff --git a/src/main/java/com/siliconvalley/domain/rabbitMQ/service/GenerateRoutingKeyService.java b/src/main/java/com/siliconvalley/domain/rabbitMQ/service/GenerateRoutingKeyService.java deleted file mode 100644 index 249417b..0000000 --- a/src/main/java/com/siliconvalley/domain/rabbitMQ/service/GenerateRoutingKeyService.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.siliconvalley.domain.rabbitMQ.service; - -import com.siliconvalley.domain.item.subject.dao.SubjectFindDao; -import com.siliconvalley.domain.item.subject.domain.Subject; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -@Transactional(readOnly = true) -public class GenerateRoutingKeyService { - - private final SubjectFindDao subjectFindDao; - public String generateRoutingKey(Long subjectId){ - Subject subject = subjectFindDao.findById(subjectId); - return subject.getSubjectName() + ".*"; - } -} diff --git a/src/main/java/com/siliconvalley/domain/rabbitMQ/service/QueueBindingService.java b/src/main/java/com/siliconvalley/domain/rabbitMQ/service/QueueBindingService.java deleted file mode 100644 index 54959c9..0000000 --- a/src/main/java/com/siliconvalley/domain/rabbitMQ/service/QueueBindingService.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.siliconvalley.domain.rabbitMQ.service; - -import com.siliconvalley.domain.item.subject.dao.SubjectFindDao; -import com.siliconvalley.domain.item.subject.domain.Subject; -import lombok.RequiredArgsConstructor; -import org.springframework.amqp.core.Binding; -import org.springframework.amqp.core.BindingBuilder; -import org.springframework.amqp.core.Queue; -import org.springframework.amqp.core.TopicExchange; -import org.springframework.amqp.rabbit.core.RabbitAdmin; -import org.springframework.stereotype.Service; - -import javax.annotation.PostConstruct; -import java.util.List; - -@Service -@RequiredArgsConstructor -public class QueueBindingService { - private final RabbitAdmin rabbitAdmin; - private final TopicExchange topicExchange; - private final SubjectFindDao subjectFindDao; - - @PostConstruct - public void setupQueueAndBindings(){ - List subjects = subjectFindDao.findAllSubjects(); - for (Subject subject : subjects){ - createQueueAndBinding(subject.getSubjectName()); - } - } - - public void createQueueAndBinding(String subjectName) { - String queueName = subjectName + "_queue"; - String routingKey = subjectName + ".*"; - - Queue queue = new Queue(queueName, true); - rabbitAdmin.declareQueue(queue); - - Binding binding = BindingBuilder.bind(queue).to(topicExchange).with(routingKey); - rabbitAdmin.declareBinding(binding); - } - - -} diff --git a/src/main/java/com/siliconvalley/domain/sse/application/SseEmitterFinder.java b/src/main/java/com/siliconvalley/domain/sse/application/SseEmitterFinder.java index 54f765f..4ca1455 100644 --- a/src/main/java/com/siliconvalley/domain/sse/application/SseEmitterFinder.java +++ b/src/main/java/com/siliconvalley/domain/sse/application/SseEmitterFinder.java @@ -12,7 +12,7 @@ @RequiredArgsConstructor public class SseEmitterFinder { - private final SseEmitterRepository sseEmitterRepository; + private final SseEmitterRepository sseEmitterRepository; public SseEmitter findByProfileId(Long profileId) { return sseEmitterRepository.findById(profileId); diff --git a/src/main/java/com/siliconvalley/global/config/RabbitMqConfig.java b/src/main/java/com/siliconvalley/global/config/RabbitMqConfig.java index c853d15..e26589b 100644 --- a/src/main/java/com/siliconvalley/global/config/RabbitMqConfig.java +++ b/src/main/java/com/siliconvalley/global/config/RabbitMqConfig.java @@ -67,4 +67,14 @@ ConnectionFactory connectionFactory() { MessageConverter messageConverter() { return new Jackson2JsonMessageConverter(); } + + @Bean + public Binding bindingRequestQueue(Queue requestQueue, TopicExchange topicExchange) { + return BindingBuilder.bind(requestQueue).to(topicExchange).with("sketch_conversion_request_queue"); + } + + @Bean + public Binding bindingResponseQueue(Queue responseQueue, TopicExchange topicExchange) { + return BindingBuilder.bind(responseQueue).to(topicExchange).with("sketch_conversion_response_queue"); + } } diff --git a/src/main/java/com/siliconvalley/global/config/security/config/SecurityConfig.java b/src/main/java/com/siliconvalley/global/config/security/config/SecurityConfig.java index 5b85257..1139119 100644 --- a/src/main/java/com/siliconvalley/global/config/security/config/SecurityConfig.java +++ b/src/main/java/com/siliconvalley/global/config/security/config/SecurityConfig.java @@ -58,7 +58,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws .authorizeHttpRequests(authorize -> authorize .antMatchers(HttpMethod.OPTIONS).permitAll() // OPTIONS 메서드는 모두 허용 .antMatchers("/api/members/**").authenticated() - .antMatchers("/api/profiles/**").authenticated() +// .antMatchers("/api/profiles/**").authenticated() .anyRequest().permitAll() );