From 782ecfbab6c16411cc23fb82ae667310e21b9612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Sun, 28 Jul 2024 13:21:00 +0900 Subject: [PATCH 01/57] =?UTF-8?q?Chore:=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index d001300..2f56f52 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-web' + + implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.1") + implementation 'io.awspring.cloud:spring-cloud-aws-starter-sqs' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' From 9fd34739a3c04d13440e90db18158c9458622d24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Sun, 28 Jul 2024 13:22:21 +0900 Subject: [PATCH 02/57] =?UTF-8?q?feat:=20SqsClient=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../goormy/hackathon/config/AwsConfig.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/config/AwsConfig.java diff --git a/src/main/java/com/goormy/hackathon/config/AwsConfig.java b/src/main/java/com/goormy/hackathon/config/AwsConfig.java new file mode 100644 index 0000000..811fab9 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/config/AwsConfig.java @@ -0,0 +1,32 @@ +package com.goormy.hackathon.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.sqs.SqsClient; + +@Configuration +public class AwsConfig { + + + @Value("${spring.cloud.aws.credentials.access-key}") + private String accessKey; + + @Value("${spring.cloud.aws.credentials.secret-key}") + private String secretKey; + + @Value("${spring.cloud.aws.region.static}") + private String region; + + @Bean + public SqsClient sqsClient() { + return SqsClient.builder() + .region(Region.of(region)) + .credentialsProvider(StaticCredentialsProvider.create( + AwsBasicCredentials.create(accessKey, secretKey))) + .build(); + } +} From b48f2734b0f6adaee6cf96a8b29ac07aff367c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Sun, 28 Jul 2024 13:24:48 +0900 Subject: [PATCH 03/57] =?UTF-8?q?feat:=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=A0=84=EC=86=A1=20=EB=A1=9C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hackathon/service/FollowService.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/service/FollowService.java diff --git a/src/main/java/com/goormy/hackathon/service/FollowService.java b/src/main/java/com/goormy/hackathon/service/FollowService.java new file mode 100644 index 0000000..09dc2da --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/FollowService.java @@ -0,0 +1,39 @@ +package com.goormy.hackathon.service; + +import jakarta.transaction.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.SendMessageRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.model.SendMessageResponse; + +@Service +public class FollowService { + private static final Logger logger = LoggerFactory.getLogger(FollowService.class); + + + @Autowired + private SqsClient sqsClient; + + @Value("${spring.cloud.aws.sqs.queue-url}") + private String queueUrl; + + public void sendFollowRequest(String userId, String hashtagId) { + String messageBody = String.format("{\"userId\": \"%s\", \"hashtagId\": \"%s\"}", userId, hashtagId); + SendMessageRequest sendMsgRequest = SendMessageRequest.builder() + .queueUrl(queueUrl) + .messageBody(messageBody) + .build(); + logger.info("Received follow request - userId: {}, hashtagId: {}", userId, hashtagId); + try { + SendMessageResponse sendMsgResponse = sqsClient.sendMessage(sendMsgRequest); + logger.info("Message sent to SQS: {}, Message ID: {}, HTTP Status: {}", + messageBody, sendMsgResponse.messageId(), sendMsgResponse.sdkHttpResponse().statusCode()); + } catch (Exception e) { + logger.error("Failed to send message to SQS: {}", messageBody, e); + } + } +} From f5850b10c8f2b58fd4bbfcae2c9da6c66ac223d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:29:15 +0900 Subject: [PATCH 04/57] =?UTF-8?q?fix:=20messageBody=20=ED=98=95=EC=8B=9D?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hackathon/service/FollowService.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/service/FollowService.java b/src/main/java/com/goormy/hackathon/service/FollowService.java index 09dc2da..dac6db2 100644 --- a/src/main/java/com/goormy/hackathon/service/FollowService.java +++ b/src/main/java/com/goormy/hackathon/service/FollowService.java @@ -1,6 +1,6 @@ package com.goormy.hackathon.service; -import jakarta.transaction.Transactional; +import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @@ -10,6 +10,8 @@ import org.slf4j.LoggerFactory; import software.amazon.awssdk.services.sqs.model.SendMessageResponse; +import java.util.Map; + @Service public class FollowService { private static final Logger logger = LoggerFactory.getLogger(FollowService.class); @@ -22,18 +24,22 @@ public class FollowService { private String queueUrl; public void sendFollowRequest(String userId, String hashtagId) { - String messageBody = String.format("{\"userId\": \"%s\", \"hashtagId\": \"%s\"}", userId, hashtagId); + try{ + ObjectMapper objectMapper = new ObjectMapper(); + String messageBody = objectMapper.writeValueAsString(Map.of( + "userId", userId, + "hashtagId", hashtagId + )); SendMessageRequest sendMsgRequest = SendMessageRequest.builder() .queueUrl(queueUrl) .messageBody(messageBody) .build(); logger.info("Received follow request - userId: {}, hashtagId: {}", userId, hashtagId); - try { - SendMessageResponse sendMsgResponse = sqsClient.sendMessage(sendMsgRequest); - logger.info("Message sent to SQS: {}, Message ID: {}, HTTP Status: {}", - messageBody, sendMsgResponse.messageId(), sendMsgResponse.sdkHttpResponse().statusCode()); + SendMessageResponse sendMsgResponse = sqsClient.sendMessage(sendMsgRequest); + logger.info("Message sent to SQS: {}, Message ID: {}, HTTP Status: {}", + messageBody, sendMsgResponse.messageId(), sendMsgResponse.sdkHttpResponse().statusCode()); } catch (Exception e) { - logger.error("Failed to send message to SQS: {}", messageBody, e); + logger.error("Failed to send message to SQS", e); } } } From e0c06c0a9d60e8fbf22b27423676cb4ca39688c9 Mon Sep 17 00:00:00 2001 From: seonghooni Date: Mon, 29 Jul 2024 22:36:34 +0900 Subject: [PATCH 05/57] =?UTF-8?q?feat:=20=EC=A2=8B=EC=95=84=EC=9A=94=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EB=A0=88=ED=8F=AC=EC=A7=80=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/goormy/hackathon/config/dummy.txt | 0 .../repository/LikeRedisRepository.java | 60 +++++++++++++++++++ .../hackathon/repository/LikeRepository.java | 15 +++++ .../com/goormy/hackathon/repository/dummy.txt | 0 .../com/goormy/hackathon/service/dummy.txt | 0 5 files changed, 75 insertions(+) delete mode 100644 src/main/java/com/goormy/hackathon/config/dummy.txt create mode 100644 src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/LikeRepository.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/dummy.txt delete mode 100644 src/main/java/com/goormy/hackathon/service/dummy.txt diff --git a/src/main/java/com/goormy/hackathon/config/dummy.txt b/src/main/java/com/goormy/hackathon/config/dummy.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java new file mode 100644 index 0000000..ab409fe --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java @@ -0,0 +1,60 @@ +package com.goormy.hackathon.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.*; +import org.springframework.stereotype.Repository; + +import java.util.Map; +import java.util.Set; + +@Repository +@RequiredArgsConstructor +public class LikeRedisRepository { + + private final RedisTemplate redisTemplate; + + public void update(Long postId, Long userId, Integer value) { + String key = "postlike:" + postId.toString(); + String field = userId.toString(); + + redisTemplate.opsForHash().put(key, field, value); + } + + + public void delete(Long postId, Long userId){ + String key = "postlike:" + postId.toString(); + String field = userId.toString(); + + redisTemplate.opsForHash().delete(key, field); + } + + public Integer findPostLikeFromCache(Long postId, Long userId) { + String key = "postlike:" + postId.toString(); + String field = userId.toString(); + + return (Integer) redisTemplate.opsForHash().get(key, field); + } + + public Map findByKey(String key) { + return redisTemplate.opsForHash().entries(key); + } + + public Set findKeys() { + Set keys = redisTemplate.keys("postlike:*"); + + System.out.println(keys); + return keys; + } + + // # PostId로 조회하는 함수 +// public Map findByPostId(Long postId) { +// String key = "postlike:" + postId.toString(); +// Map entries = redisTemplate.opsForHash().entries(key); +// +// return entries.entrySet().stream() +// .collect(Collectors.toMap( +// entry -> Long.valueOf((String) entry.getKey()), +// entry -> (Integer) entry.getValue() +// )); +// } +} diff --git a/src/main/java/com/goormy/hackathon/repository/LikeRepository.java b/src/main/java/com/goormy/hackathon/repository/LikeRepository.java new file mode 100644 index 0000000..6f9aa40 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/LikeRepository.java @@ -0,0 +1,15 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.Like; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +public interface LikeRepository extends JpaRepository { + + @Modifying + @Query("delete from Like l where l.post.id = :postId and l.user.id = :userId") + void deleteByPostIdAndUserId(@Param("postId") Long postId, @Param("userId")Long userId); +} diff --git a/src/main/java/com/goormy/hackathon/repository/dummy.txt b/src/main/java/com/goormy/hackathon/repository/dummy.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/goormy/hackathon/service/dummy.txt b/src/main/java/com/goormy/hackathon/service/dummy.txt deleted file mode 100644 index e69de29..0000000 From b4edb3c035c18b8b532da89587e12401ba118def Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Tue, 30 Jul 2024 17:15:22 +0900 Subject: [PATCH 06/57] =?UTF-8?q?feat:=20Follow=20api=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 6148 bytes build.gradle | 28 +++++++++++ gradlew | 0 .../controller/FollowController.java | 22 +++++++++ .../com/goormy/hackathon/entity/Follow.java | 5 +- .../com/goormy/hackathon/entity/User.java | 2 +- .../hackathon/handler/FollowHandler.java | 7 +++ .../hackathon/lambda/FollowFunction.java | 44 ++++++++++++++++++ .../repository/FollowRepository.java | 9 ++++ .../repository/HashtagRepository.java | 9 ++++ .../hackathon/repository/UserRepository.java | 7 +++ .../hackathon/service/FollowService.java | 2 +- .../com/goormy/hackathon/service/dummy.txt | 0 13 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 .DS_Store mode change 100644 => 100755 gradlew create mode 100644 src/main/java/com/goormy/hackathon/controller/FollowController.java create mode 100644 src/main/java/com/goormy/hackathon/handler/FollowHandler.java create mode 100644 src/main/java/com/goormy/hackathon/lambda/FollowFunction.java create mode 100644 src/main/java/com/goormy/hackathon/repository/FollowRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/HashtagRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/UserRepository.java delete mode 100644 src/main/java/com/goormy/hackathon/service/dummy.txt diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c2e53a36000090b40947fe53175df0cb9ac4cb5d GIT binary patch literal 6148 zcmeHKPjAyO6n}2JHC;jUut~chS=zOf7SN_?mr%L`2QCYO14AWQq7jkBQ<9QHRVnB3 z9ry}d`6PT7PVk=XX->OwWYgqVJ^vj0{ru;b*scM9jc4Hqpa%dBI$>)AlWUCX$ycnQ zONhs08{z9joCJvoR$^^|Rlq86_Y|PDy9NQwAch3Y^-EjAOZ34XX>#aBWKibkdZqsi z&XYJVhQnX1(QK`)x1F}rbv}BZMd=lOG0Vq(_JN+>3Xuetc|Uj;N9DA)`AVdPAE!|! z32_)<$npC)4MjN?voy>l*HaZv$LUOa+w=L8(SDzgcJ~&2KHq;f?DH4TcNdF}v$gZ| z;Ar|KIZMTb95XQ7o1{I|cnRMyW6bEQm!*kFPqCC353W>!0h~exK7^=IWbARI(GPS} zqxG9(+2f_ywiyd$y=6w@Gh6P~qj6LLj;UB;{a#{q;0O-!O-|qq;sDN;-*SUyZ1(dA za)_Y7UkoYsng4VC^o@KszL6%zXK+#7JRsp)lDyw$EiaFjt{XtpZkox&lr0*rW6R@aFq}on)V^0#<>0r2uP9yvZ1+q|ers y$yp1jm>o{c)U5%AOEJ3q>1f&c$u?qZG1^xm;sI?3L literal 0 HcmV?d00001 diff --git a/build.gradle b/build.gradle index 79cea4c..e4d3ca8 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,11 @@ dependencies { implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.1") implementation 'io.awspring.cloud:spring-cloud-aws-starter-sqs' + implementation 'redis.clients:jedis:4.0.1' + implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' + implementation 'com.amazonaws:aws-lambda-java-events:3.11.0' + implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws:3.2.7' + compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' @@ -41,3 +46,26 @@ dependencies { tasks.named('test') { useJUnitPlatform() } +jar { + manifest { + attributes( + 'Manifest-Version': '1.0', + 'Main-Class': 'com.goormy.hackathon.HackathonApplication' + ) + } +} + +task buildZip(type: Zip) { + from compileJava + from processResources + into('lib') { + from configurations.runtimeClasspath + } + into('lib') { + from jar.archiveFile + } + archiveFileName = 'lambda-function.zip' + destinationDirectory = file("$buildDir/distributions") +} + +build.dependsOn buildZip diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/com/goormy/hackathon/controller/FollowController.java b/src/main/java/com/goormy/hackathon/controller/FollowController.java new file mode 100644 index 0000000..053dea7 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/controller/FollowController.java @@ -0,0 +1,22 @@ +package com.goormy.hackathon.controller; + +import com.goormy.hackathon.service.FollowService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/goormy") +public class FollowController { + + @Autowired + private FollowService followService; + + @PostMapping("/follow") + public ResponseEntity follow(@RequestHeader long userId, @RequestParam long hashtagId) { + followService.sendFollowRequest(userId,hashtagId); + return ResponseEntity.noContent().build(); + } + + +} diff --git a/src/main/java/com/goormy/hackathon/entity/Follow.java b/src/main/java/com/goormy/hackathon/entity/Follow.java index aab67cc..bf1348e 100644 --- a/src/main/java/com/goormy/hackathon/entity/Follow.java +++ b/src/main/java/com/goormy/hackathon/entity/Follow.java @@ -1,15 +1,16 @@ package com.goormy.hackathon.entity; -import com.goormy.hackathon.common.entity.BaseTimeEntity; import jakarta.persistence.*; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; @Entity @NoArgsConstructor @Getter -public class Follow extends BaseTimeEntity { +@Setter +public class Follow { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/com/goormy/hackathon/entity/User.java b/src/main/java/com/goormy/hackathon/entity/User.java index 55182a8..de36e63 100644 --- a/src/main/java/com/goormy/hackathon/entity/User.java +++ b/src/main/java/com/goormy/hackathon/entity/User.java @@ -13,7 +13,7 @@ @NoArgsConstructor @Getter @Table(name="users") -public class User extends BaseTimeEntity { +public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "user_id") diff --git a/src/main/java/com/goormy/hackathon/handler/FollowHandler.java b/src/main/java/com/goormy/hackathon/handler/FollowHandler.java new file mode 100644 index 0000000..30b9cc7 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/handler/FollowHandler.java @@ -0,0 +1,7 @@ +package com.goormy.hackathon.handler; + +import org.springframework.cloud.function.adapter.aws.FunctionInvoker; + +public class FollowHandler extends FunctionInvoker { + +} diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java new file mode 100644 index 0000000..d13937c --- /dev/null +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -0,0 +1,44 @@ +package com.goormy.hackathon.lambda; + +import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.repository.FollowRepository; +import com.goormy.hackathon.repository.HashtagRepository; +import com.goormy.hackathon.repository.UserRepository; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Map; +import java.util.function.Consumer; + +@Configuration +public class FollowFunction{ + + @Bean + public Consumer> processFollow(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository) { + return messageBody -> { + try { + // userId와 hashtagId를 Number로 파싱하고 long으로 변환 + long userId = ((Number) messageBody.get("userId")).longValue(); + long hashtagId = ((Number) messageBody.get("hashtagId")).longValue(); + + User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); + Hashtag hashtag = hashtagRepository.findById(hashtagId).orElseThrow(() -> new RuntimeException("존재하지 않는 해시태그입니다. hashtagId: " + hashtagId)); + + // Follow 객체 생성 및 설정 + Follow follow = new Follow(); + follow.setUser(user); + follow.setHashtag(hashtag); + + // MySQL에 데이터 저장 + followRepository.save(follow); + + System.out.println("Processed message: " + messageBody); + } catch (Exception e) { + System.err.println("Failed to process message: " + messageBody); + e.printStackTrace(); + } + }; + } +} diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowRepository.java new file mode 100644 index 0000000..fb8ee2f --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/FollowRepository.java @@ -0,0 +1,9 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.Follow; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface FollowRepository extends JpaRepository { +} diff --git a/src/main/java/com/goormy/hackathon/repository/HashtagRepository.java b/src/main/java/com/goormy/hackathon/repository/HashtagRepository.java new file mode 100644 index 0000000..f13623c --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/HashtagRepository.java @@ -0,0 +1,9 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.Hashtag; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface HashtagRepository extends JpaRepository { +} diff --git a/src/main/java/com/goormy/hackathon/repository/UserRepository.java b/src/main/java/com/goormy/hackathon/repository/UserRepository.java new file mode 100644 index 0000000..2e801fc --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/UserRepository.java @@ -0,0 +1,7 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository { +} diff --git a/src/main/java/com/goormy/hackathon/service/FollowService.java b/src/main/java/com/goormy/hackathon/service/FollowService.java index dac6db2..fd120d5 100644 --- a/src/main/java/com/goormy/hackathon/service/FollowService.java +++ b/src/main/java/com/goormy/hackathon/service/FollowService.java @@ -23,7 +23,7 @@ public class FollowService { @Value("${spring.cloud.aws.sqs.queue-url}") private String queueUrl; - public void sendFollowRequest(String userId, String hashtagId) { + public void sendFollowRequest(long userId, long hashtagId) { try{ ObjectMapper objectMapper = new ObjectMapper(); String messageBody = objectMapper.writeValueAsString(Map.of( diff --git a/src/main/java/com/goormy/hackathon/service/dummy.txt b/src/main/java/com/goormy/hackathon/service/dummy.txt deleted file mode 100644 index e69de29..0000000 From e2b42d1c8407e7259f2613c5edd7271090012a7c Mon Sep 17 00:00:00 2001 From: seonghooni Date: Tue, 30 Jul 2024 20:43:09 +0900 Subject: [PATCH 07/57] =?UTF-8?q?feat:=20LikeRedisRepository,=20LikeReposi?= =?UTF-8?q?tory=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/LikeRedisRepository.java | 28 ++++++++++++++++--- .../hackathon/repository/LikeRepository.java | 4 +++ src/main/resources/application-redis.yml | 5 ---- 3 files changed, 28 insertions(+), 9 deletions(-) delete mode 100644 src/main/resources/application-redis.yml diff --git a/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java index ab409fe..3b9fd8b 100644 --- a/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java @@ -11,8 +11,11 @@ @RequiredArgsConstructor public class LikeRedisRepository { - private final RedisTemplate redisTemplate; + private final RedisTemplate redisTemplate; + /** + * @description '좋아요' 정보를 업데이트 하는 함수 + * */ public void update(Long postId, Long userId, Integer value) { String key = "postlike:" + postId.toString(); String field = userId.toString(); @@ -20,7 +23,9 @@ public void update(Long postId, Long userId, Integer value) { redisTemplate.opsForHash().put(key, field, value); } - + /** + * @description '좋아요' 혹은 '좋아요 취소' 정보를 삭제하는 함수 + * */ public void delete(Long postId, Long userId){ String key = "postlike:" + postId.toString(); String field = userId.toString(); @@ -28,6 +33,9 @@ public void delete(Long postId, Long userId){ redisTemplate.opsForHash().delete(key, field); } + /** + * @description postId와 userId에 대한 value를 조회 + * */ public Integer findPostLikeFromCache(Long postId, Long userId) { String key = "postlike:" + postId.toString(); String field = userId.toString(); @@ -35,14 +43,26 @@ public Integer findPostLikeFromCache(Long postId, Long userId) { return (Integer) redisTemplate.opsForHash().get(key, field); } + /** + * @description Key에 대한 모든 field와 value를 조회 + * */ public Map findByKey(String key) { return redisTemplate.opsForHash().entries(key); } - public Set findKeys() { + /** + * @description Key에 대한 모든 field와 value를 삭제 + * */ + public void delete(String key) { + redisTemplate.delete(key); + } + + + + + public Set findAllKeys() { Set keys = redisTemplate.keys("postlike:*"); - System.out.println(keys); return keys; } diff --git a/src/main/java/com/goormy/hackathon/repository/LikeRepository.java b/src/main/java/com/goormy/hackathon/repository/LikeRepository.java index 6f9aa40..17a5f67 100644 --- a/src/main/java/com/goormy/hackathon/repository/LikeRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/LikeRepository.java @@ -1,6 +1,7 @@ package com.goormy.hackathon.repository; import com.goormy.hackathon.entity.Like; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -12,4 +13,7 @@ public interface LikeRepository extends JpaRepository { @Modifying @Query("delete from Like l where l.post.id = :postId and l.user.id = :userId") void deleteByPostIdAndUserId(@Param("postId") Long postId, @Param("userId")Long userId); + + @Query("select count(l)>0 from Like l where l.post.id = :postId and l.user.id = :userId") + boolean isExistByPostIdAndUserId(@Param("postId") Long postId, @Param("userId")Long userId); } diff --git a/src/main/resources/application-redis.yml b/src/main/resources/application-redis.yml deleted file mode 100644 index e231226..0000000 --- a/src/main/resources/application-redis.yml +++ /dev/null @@ -1,5 +0,0 @@ -spring: - data: - redis: - host: ${REDIS_HOST:localhost} - port: ${REDIS_PORT:6379} \ No newline at end of file From 666ca397ab2f74d091f653c3e699ccdd514c66c6 Mon Sep 17 00:00:00 2001 From: seonghooni Date: Tue, 30 Jul 2024 20:43:54 +0900 Subject: [PATCH 08/57] =?UTF-8?q?feat:=20like=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EA=B3=84=EC=B8=B5=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../goormy/hackathon/service/LikeService.java | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/service/LikeService.java diff --git a/src/main/java/com/goormy/hackathon/service/LikeService.java b/src/main/java/com/goormy/hackathon/service/LikeService.java new file mode 100644 index 0000000..d56cb91 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/LikeService.java @@ -0,0 +1,119 @@ +package com.goormy.hackathon.service; + +import com.goormy.hackathon.entity.Like; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.repository.LikeRedisRepository; +import com.goormy.hackathon.repository.LikeRepository; +import com.goormy.hackathon.repository.PostRepository; +import com.goormy.hackathon.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Map; +import java.util.Set; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class LikeService { + + private final LikeRedisRepository likeRedisRepository; + private final LikeRepository likeRepository; + private final UserRepository userRepository; + private final PostRepository postRepository; + + /** + * @description 좋아요 정보를 Redis 캐시에 업데이트 + * */ + @Transactional + public void addLike(Long postId, Long userId) { + // 캐시에서 좋아요에 대한 정보를 먼저 조회함 + Integer findPostLike = likeRedisRepository.findPostLikeFromCache(postId, userId); + + if (findPostLike == null) { + // 캐시에 좋아요에 대한 정보가 없다면, + // Key = postlike:{postId}, Field = {userId}, Value = 1 로 '좋아요' 정보 생성 + likeRedisRepository.update(postId, userId, 1); + }else if (findPostLike == -1) { + // '좋아요 취소' 정보가 있는 상태라면 + // '좋아요'를 다시 누른 것이기 때문에 '취소 정보'를 삭제 + likeRedisRepository.delete(postId,userId); + } + } + + /** + * @description 좋아요 취소 정보를 Redis 캐시에 업데이트 + * */ + @Transactional + public void cancelLike(Long postId, Long userId) { + // 캐시에서 좋아요 정보를 먼저 조회함 + Integer findPostLike = likeRedisRepository.findPostLikeFromCache(postId, userId); + + // 캐시에 좋아요에 대한 정보가 없다면, + // Key = postlike:{postId}, Field = {userId}, Value = -1 로 '좋아요 취소' 정보 생성 + if (findPostLike == null) { + likeRedisRepository.update(postId,userId,-1); + }else if (findPostLike == 1) { + // '좋아요'라는 정보가 있는 상태라면 + // '좋아요 취소'를 다시 누른 것이기 때문에 '좋아요' 정보를 삭젳 + likeRedisRepository.delete(postId,userId); + } + } + + /** + * @description 좋아요 정보가 있는지 조회 (1. Redis 조회 2. RDB 조회) + * */ + public boolean findLike(Long postId, Long userId) { + // 1. 캐시로부터 '좋아요'에 대한 정보를 조회함 + Integer value = likeRedisRepository.findPostLikeFromCache(postId, userId); + + if (value == null) { // 캐시에 정보가 없다면 DB에서 조회되는지 여부에 따라 true/false 리턴 + return likeRepository.isExistByPostIdAndUserId(postId, userId); + }else if (value == -1) { // 캐시에 '좋아요 삭제' 정보가 있다면 false 리턴 + return false; + }else{ // 캐시에 '좋아요 추가' 정보가 있다면 true 리턴 + return true; + } + } + + /** + * @description Redis에 있는 '좋아요' 정보들을 RDB에 반영하는 함수 + * */ + @Transactional + public void dumpToDB() { + // 1. "postlike:{postId} 형식의 모든 key 목록을 불러옴 + Set postLikeKeySet = likeRedisRepository.findAllKeys(); + + // 2. Key마다 postId, userId, value를 조회하는 과정 + for (String key: postLikeKeySet) { + + // 2-1. Key로 Hash 자료구조를 조회함. field = userId / value = 1 or -1 + Map result = likeRedisRepository.findByKey(key); + + // 2-2. key를 파싱하여 postId를 구함 + String[] split = key.split(":"); + Long postId = Long.valueOf(split[1]); + + for (Map.Entry entry : result.entrySet()) { + // 2-3. field를 형변환하여 userId를 구함 + Long userId = Long.valueOf(String.valueOf(entry.getKey())); + // 2-4. value를 형변환하여 1 또는 -1 값을 얻게 됨 + Integer value = Integer.valueOf(String.valueOf(entry.getValue())); + + // 3. value 값에 따라 DB에 어떻게 반영할지 결정하여 처리함 + if (value == 1) { // 3-1. 좋아요를 추가한 상태였다면 RDB에 insert 쿼리 발생 + User user = userRepository.getReferenceById(userId); + Post post = postRepository.getReferenceById(postId); + likeRepository.save(new Like(user, post)); + }else if (value == -1) { // 3-2. 좋아요를 취소한 상태였다면 RDB에 delete 쿼리 발생 + likeRepository.deleteByPostIdAndUserId(postId, userId); + } + } + + // 4. 해당 Key에 대해 RDB에 반영하는 과정을 마쳤으므로, + likeRedisRepository.delete(key); + } + } +} From 8056c0e2df8bf615b248735b45bad8008a54b7d3 Mon Sep 17 00:00:00 2001 From: seonghooni Date: Tue, 30 Jul 2024 20:44:18 +0900 Subject: [PATCH 09/57] =?UTF-8?q?test:=20like=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hackathon/config/RedisConfigTest.java | 27 ++++ .../repository/LikeRedisRepositoryTest.java | 25 +++ .../hackathon/service/LikeServiceTest.java | 145 ++++++++++++++++++ 3 files changed, 197 insertions(+) create mode 100644 src/test/java/com/goormy/hackathon/config/RedisConfigTest.java create mode 100644 src/test/java/com/goormy/hackathon/repository/LikeRedisRepositoryTest.java create mode 100644 src/test/java/com/goormy/hackathon/service/LikeServiceTest.java diff --git a/src/test/java/com/goormy/hackathon/config/RedisConfigTest.java b/src/test/java/com/goormy/hackathon/config/RedisConfigTest.java new file mode 100644 index 0000000..fc3a8ed --- /dev/null +++ b/src/test/java/com/goormy/hackathon/config/RedisConfigTest.java @@ -0,0 +1,27 @@ +package com.goormy.hackathon.config; + +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; + +@SpringBootTest +class RedisConfigTest { + + @Autowired + RedisTemplate redisTemplate; + + @Test + void redisConnectionTest() { + final String key = "a"; + final String data = "1"; + + final ValueOperations valueOperations = redisTemplate.opsForValue(); + valueOperations.set(key, data); + + final String s = valueOperations.get(key); + Assertions.assertThat(s).isEqualTo(data); + } +} \ No newline at end of file diff --git a/src/test/java/com/goormy/hackathon/repository/LikeRedisRepositoryTest.java b/src/test/java/com/goormy/hackathon/repository/LikeRedisRepositoryTest.java new file mode 100644 index 0000000..16bcb55 --- /dev/null +++ b/src/test/java/com/goormy/hackathon/repository/LikeRedisRepositoryTest.java @@ -0,0 +1,25 @@ +package com.goormy.hackathon.repository; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class LikeRedisRepositoryTest { + + @Autowired + LikeRedisRepository likeRedisRepository; + + @Test + void addLike() { + } + + @Test + void cancelLike() { + } + + @Test + void findByKey() { + likeRedisRepository.findAllKeys(); + } +} \ No newline at end of file diff --git a/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java b/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java new file mode 100644 index 0000000..2bb3dca --- /dev/null +++ b/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java @@ -0,0 +1,145 @@ +package com.goormy.hackathon.service; + +import com.goormy.hackathon.entity.Like; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.repository.LikeRedisRepository; +import com.goormy.hackathon.repository.LikeRepository; +import com.goormy.hackathon.repository.PostRepository; +import com.goormy.hackathon.repository.UserRepository; +import jakarta.persistence.PrePersist; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +class LikeServiceTest { + + @Autowired + UserRepository userRepository; + + @Autowired + PostRepository postRepository; + + @Autowired + LikeService likeService; + + @Autowired + LikeRepository likeRepository; + + @Autowired + LikeRedisRepository likeRedisRepository; + + @BeforeEach + void 데이터_주입() { + User user1 = User.builder() + .name("test") + .followerCount(0) + .followingCount(0) + .password("abc").build(); + User user2 = User.builder() + .name("test") + .followerCount(0) + .followingCount(0) + .password("abc").build(); + User user3 = User.builder() + .name("test") + .followerCount(0) + .followingCount(0) + .password("abc").build(); + + userRepository.saveAll(List.of(user1, user2, user3)); + + Post post1 = Post.builder() + .user(user1) + .likeCount(0) + .content("null") + .star(3) + .build(); + Post post2 = Post.builder() + .user(user2) + .likeCount(0) + .content("null2") + .star(3) + .build(); + Post post3 = Post.builder() + .user(user1) + .likeCount(0) + .content("null3") + .star(3) + .build(); + Post post4 = Post.builder() + .user(user2) + .likeCount(0) + .content("null4") + .star(3) + .build(); + Post post5 = Post.builder() + .user(user3) + .likeCount(0) + .content("null5") + .star(3) + .build(); + + postRepository.saveAll(List.of(post1, post2, post3, post4, post5)); + + Like like = Like.builder() + .user(user3) + .post(post4) + .build(); + + likeRepository.save(like); + } + @Test + void 좋아요_추가() { + // given + + // when + likeService.addLike(2L,1L); + + } + + @Test + void 좋아요_삭제() { + // given + + // when + likeService.cancelLike(2L,1L); + + } + + @Test + void 좋아요여부_조회() { + + // given + + // when + boolean exist = likeService.findLike(4L, 3L); + boolean noExist = likeService.findLike(2L, 3L); + + // then + Assertions.assertEquals(exist, true); + Assertions.assertEquals(noExist, false); + } + + @Test + void 캐시로부터_DB로_반영() { + + // given + likeRedisRepository.update(3L, 1L, 1); + likeRedisRepository.update(3L, 2L, 1); + likeRedisRepository.update(3L, 3L, 1); + likeRedisRepository.update(4L, 3L, -1); + + // when + likeService.dumpToDB(); + + // then + } +} \ No newline at end of file From 9a075ae5cbbb0cff4f18538ce3028302ba928a25 Mon Sep 17 00:00:00 2001 From: seonghooni Date: Tue, 30 Jul 2024 20:45:10 +0900 Subject: [PATCH 10/57] =?UTF-8?q?feat:=20like=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EA=B3=84=EC=B8=B5=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hackathon/controller/LikeController.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/controller/LikeController.java diff --git a/src/main/java/com/goormy/hackathon/controller/LikeController.java b/src/main/java/com/goormy/hackathon/controller/LikeController.java new file mode 100644 index 0000000..36b1a1e --- /dev/null +++ b/src/main/java/com/goormy/hackathon/controller/LikeController.java @@ -0,0 +1,41 @@ +package com.goormy.hackathon.controller; + +import com.goormy.hackathon.service.LikeService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("") +public class LikeController { + + private final LikeService likeService; + + @PostMapping("/likes") + public ResponseEntity addLike( + @RequestHeader(name = "userId") Long userId, + @RequestParam(name = "postId") Long postId) { + + likeService.addLike(postId, userId); + + return ResponseEntity.ok("success"); + } + + @DeleteMapping("/likes") + public ResponseEntity cancelLike( + @RequestHeader(name = "userId") Long userId, + @RequestParam(name = "postId") Long postId) { + + likeService.cancelLike(postId, userId); + + return ResponseEntity.ok("success"); + } + +} From 34d5a31d6e3bbcd46db872c97eaf6beb97756c57 Mon Sep 17 00:00:00 2001 From: seonghooni Date: Tue, 30 Jul 2024 20:46:02 +0900 Subject: [PATCH 11/57] =?UTF-8?q?feat:=20Post,=20Use=20=EB=A0=88=ED=8F=AC?= =?UTF-8?q?=EC=A7=80=ED=86=A0=EB=A6=AC=20=EA=B0=84=EB=8B=A8=ED=95=9C=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/goormy/hackathon/repository/PostRepository.java | 7 +++++++ .../com/goormy/hackathon/repository/UserRepository.java | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/repository/PostRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/UserRepository.java diff --git a/src/main/java/com/goormy/hackathon/repository/PostRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRepository.java new file mode 100644 index 0000000..2e2bda3 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/PostRepository.java @@ -0,0 +1,7 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.Post; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PostRepository extends JpaRepository { +} diff --git a/src/main/java/com/goormy/hackathon/repository/UserRepository.java b/src/main/java/com/goormy/hackathon/repository/UserRepository.java new file mode 100644 index 0000000..2e801fc --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/UserRepository.java @@ -0,0 +1,7 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository { +} From 1f6513a90313608c09382595d042a079dc32c4a0 Mon Sep 17 00:00:00 2001 From: Ga Dong Sik Date: Wed, 31 Jul 2024 01:51:02 +0900 Subject: [PATCH 12/57] =?UTF-8?q?feat:=20lambda=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EB=B0=B0=ED=8F=AC=20=EA=B9=83=20=EC=95=A1=EC=85=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy_lambda.yml | 61 +++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/deploy_lambda.yml diff --git a/.github/workflows/deploy_lambda.yml b/.github/workflows/deploy_lambda.yml new file mode 100644 index 0000000..49093f5 --- /dev/null +++ b/.github/workflows/deploy_lambda.yml @@ -0,0 +1,61 @@ +name: deploy_lambda + +on: + push: + branches: [ feat/like_service ] + workflow_dispatch: + inputs: + logLevel: + description: 'Log level' + required: true + default: 'warning' + tags: + description: 'Test Deploy' +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: JDK 세팅 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle without test + run: ./gradlew build -x test + + - name: Create deployment package + run: | + mkdir -p deployment + cp build/libs/*.jar deployment/ + if [ -d "lib" ]; then + cp -R lib/* deployment/ + fi + cd deployment + zip -r ../function.zip . + + - name: AWS 계정 세팅 + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: S3에 패키지 업로드 + run: | + aws s3 cp function.zip s3://gureumi-s3/deploy/function.zip + + - name: 람다 배포 + run: | + aws lambda update-function-code \ + --function-name ${{ secrets.LAMBDA_FUNCTION_NAME }} \ + --s3-bucket gureumi-s3 \ + --s3-key deploy/function.zip \ No newline at end of file From 79627a7483cfe81ca5fd749f82ee2d955b48698c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:00:11 +0900 Subject: [PATCH 13/57] =?UTF-8?q?feat:=20FollowRedisRepository=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/FollowRedisRepository.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java new file mode 100644 index 0000000..38f0df7 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java @@ -0,0 +1,26 @@ +package com.goormy.hackathon.repository; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Repository; + +@Repository +public class FollowRedisRepository { + + @Autowired + RedisTemplate redisTemplate; + + public void insertFollow(Long hashtagId, Long userId) { + String key = "hashtagId: " + hashtagId.toString(); + redisTemplate.opsForList().rightPush(key, userId.toString()); + } + + public void removeFollow(Long hashtagId, Long userId) { + String key = "hashtagId:" + hashtagId.toString(); + redisTemplate.opsForList().remove(key, 0, userId.toString()); + } + + public void removeAllFollows(Long hashtagId) { + String key = "hashtagId:" + hashtagId.toString(); + redisTemplate.delete(key); + }} From 42087421df66eaff61830975b38f4d94cb172c05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:01:03 +0900 Subject: [PATCH 14/57] =?UTF-8?q?feat:=20unfollow=20api=20=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FollowController.java | 6 +++++ .../hackathon/lambda/FollowFunction.java | 26 ++++++++++++------- .../repository/FollowRepository.java | 7 +++++ .../hackathon/service/FollowService.java | 17 +++++++++--- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/controller/FollowController.java b/src/main/java/com/goormy/hackathon/controller/FollowController.java index 053dea7..4c68275 100644 --- a/src/main/java/com/goormy/hackathon/controller/FollowController.java +++ b/src/main/java/com/goormy/hackathon/controller/FollowController.java @@ -18,5 +18,11 @@ public ResponseEntity follow(@RequestHeader long userId, @RequestParam l return ResponseEntity.noContent().build(); } + @PostMapping("/unfollow") + public ResponseEntity unfollow(@RequestHeader long userId, @RequestParam long hashtagId) { + followService.sendUnfollowRequest(userId,hashtagId); + return ResponseEntity.noContent().build(); + } + } diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index d13937c..721156e 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -22,21 +22,27 @@ public Consumer> processFollow(FollowRepository followReposi // userId와 hashtagId를 Number로 파싱하고 long으로 변환 long userId = ((Number) messageBody.get("userId")).longValue(); long hashtagId = ((Number) messageBody.get("hashtagId")).longValue(); + String action = (String) messageBody.get("action"); User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); Hashtag hashtag = hashtagRepository.findById(hashtagId).orElseThrow(() -> new RuntimeException("존재하지 않는 해시태그입니다. hashtagId: " + hashtagId)); - // Follow 객체 생성 및 설정 - Follow follow = new Follow(); - follow.setUser(user); - follow.setHashtag(hashtag); - - // MySQL에 데이터 저장 - followRepository.save(follow); - - System.out.println("Processed message: " + messageBody); + if ("follow".equals(action)) { + Follow follow = new Follow(); + follow.setUser(user); + follow.setHashtag(hashtag); + followRepository.save(follow); + System.out.println("팔로우 성공: " + messageBody); + } else if ("unfollow".equals(action)) { + Follow follow = followRepository.findByUserIdAndHashTagId(userId, hashtagId) + .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); + followRepository.delete(follow); + System.out.println("팔로우 취소 성공: " + messageBody); + } else { + System.out.println("존재하지 않는 action입니다 : " + action); + } } catch (Exception e) { - System.err.println("Failed to process message: " + messageBody); + System.err.println("메시지 전송 실패: " + messageBody); e.printStackTrace(); } }; diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowRepository.java index fb8ee2f..47cf486 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowRepository.java @@ -2,8 +2,15 @@ import com.goormy.hackathon.entity.Follow; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface FollowRepository extends JpaRepository { + + @Query("SELECT f FROM Follow f WHERE f.user.id = :userId AND f.hashtag.id = :hashtagId") + Optional findByUserIdAndHashTagId(@Param("userId") Long userId, @Param("hashtagId") Long hashtagId); } diff --git a/src/main/java/com/goormy/hackathon/service/FollowService.java b/src/main/java/com/goormy/hackathon/service/FollowService.java index fd120d5..8314a40 100644 --- a/src/main/java/com/goormy/hackathon/service/FollowService.java +++ b/src/main/java/com/goormy/hackathon/service/FollowService.java @@ -24,22 +24,31 @@ public class FollowService { private String queueUrl; public void sendFollowRequest(long userId, long hashtagId) { + sendRequest(userId, hashtagId, "follow"); + } + + public void sendUnfollowRequest(long userId, long hashtagId) { + sendRequest(userId, hashtagId, "unfollow"); + } + + public void sendRequest(long userId, long hashtagId, String action) { try{ ObjectMapper objectMapper = new ObjectMapper(); String messageBody = objectMapper.writeValueAsString(Map.of( "userId", userId, - "hashtagId", hashtagId + "hashtagId", hashtagId, + "action",action )); SendMessageRequest sendMsgRequest = SendMessageRequest.builder() .queueUrl(queueUrl) .messageBody(messageBody) .build(); - logger.info("Received follow request - userId: {}, hashtagId: {}", userId, hashtagId); + logger.info("메시지 송신 - action: {}, userId: {}, hashtagId: {}", action, userId, hashtagId); SendMessageResponse sendMsgResponse = sqsClient.sendMessage(sendMsgRequest); - logger.info("Message sent to SQS: {}, Message ID: {}, HTTP Status: {}", + logger.info("메시지가 전달되었습니다: {}, Message ID: {}, HTTP Status: {}", messageBody, sendMsgResponse.messageId(), sendMsgResponse.sdkHttpResponse().statusCode()); } catch (Exception e) { - logger.error("Failed to send message to SQS", e); + logger.error("메시지 전송 실패", e); } } } From 2e5087874bdd698900cbbe9d7d624bfe28d396ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:52:20 +0900 Subject: [PATCH 15/57] =?UTF-8?q?fix:=20setter=20=EC=A0=9C=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/goormy/hackathon/entity/Follow.java | 1 - src/main/java/com/goormy/hackathon/lambda/FollowFunction.java | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/entity/Follow.java b/src/main/java/com/goormy/hackathon/entity/Follow.java index bf1348e..c369754 100644 --- a/src/main/java/com/goormy/hackathon/entity/Follow.java +++ b/src/main/java/com/goormy/hackathon/entity/Follow.java @@ -9,7 +9,6 @@ @Entity @NoArgsConstructor @Getter -@Setter public class Follow { @Id diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index 721156e..7234e83 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -28,9 +28,7 @@ public Consumer> processFollow(FollowRepository followReposi Hashtag hashtag = hashtagRepository.findById(hashtagId).orElseThrow(() -> new RuntimeException("존재하지 않는 해시태그입니다. hashtagId: " + hashtagId)); if ("follow".equals(action)) { - Follow follow = new Follow(); - follow.setUser(user); - follow.setHashtag(hashtag); + Follow follow = new Follow(user,hashtag); followRepository.save(follow); System.out.println("팔로우 성공: " + messageBody); } else if ("unfollow".equals(action)) { From 90310d383856e136a538cadba9db5ac6cbc7fdaa Mon Sep 17 00:00:00 2001 From: seonghooni Date: Wed, 31 Jul 2024 17:43:06 +0900 Subject: [PATCH 16/57] =?UTF-8?q?fix:=20Like=20=EC=97=94=ED=8B=B0=ED=8B=B0?= =?UTF-8?q?=EC=9D=98=20=EC=83=9D=EC=84=B1=EC=9D=BC=EC=9E=90=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/goormy/hackathon/entity/Like.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/goormy/hackathon/entity/Like.java b/src/main/java/com/goormy/hackathon/entity/Like.java index 250228a..672942c 100644 --- a/src/main/java/com/goormy/hackathon/entity/Like.java +++ b/src/main/java/com/goormy/hackathon/entity/Like.java @@ -10,7 +10,7 @@ @NoArgsConstructor @Getter @Table(name = "likes") -public class Like extends BaseTimeEntity { +public class Like { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) From c08a64326fde00367c6d5c6704ad4908187acc80 Mon Sep 17 00:00:00 2001 From: seonghooni Date: Wed, 31 Jul 2024 17:43:20 +0900 Subject: [PATCH 17/57] =?UTF-8?q?chore:=20application.yml,=20.gitignore=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - src/main/resources/application.yml | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/application.yml diff --git a/.gitignore b/.gitignore index f208e71..c2065bc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ build/ !gradle/wrapper/gradle-wrapper.jar !**/src/main/**/build/ !**/src/test/**/build/ -/src/main/resources/application.yml ### STS ### .apt_generated diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..d3542c0 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,21 @@ +spring: + datasource: + url: ${MYSQL_URL:jdbc:mysql://localhost}:${MYSQL_PORT:3306}/${MYSQL_SCHEMA:dev} + driver-class-name: com.mysql.cj.jdbc.Driver + username: ${MYSQL_USERNAME:root} + password: ${MYSQL_PASSWORD:1234} + jpa: + hibernate: + ddl-auto: update + show-sql: true + properties: + hibernate: + format_sql: true + use_sql_comments: true +logging: + level: + org: + hibernate: + type: + descriptor: + sql: trace \ No newline at end of file From a75a6ea48837c8b2b286b0e5ef4437b0b45f7a66 Mon Sep 17 00:00:00 2001 From: Ga Dong Sik Date: Wed, 31 Jul 2024 18:42:29 +0900 Subject: [PATCH 18/57] =?UTF-8?q?feat:=20=ED=94=BC=EB=93=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/goormy/hackathon/config/dummy.txt | 0 .../controller/GetFeedController.java | 62 +++++++ .../com/goormy/hackathon/controller/dummy.txt | 0 .../converter/LocalDateTimeConverter.java | 25 +++ .../hackathon/dto/request/AddFeedUser.java | 26 +++ .../dto/response/GetFeedResponseDto.java | 35 ++++ .../hackathon/entity/BaseTimeEntity.java | 25 +++ .../com/goormy/hackathon/entity/Hashtag.java | 2 +- .../com/goormy/hackathon/entity/Post.java | 4 + .../goormy/hackathon/entity/PostHashtag.java | 2 +- .../com/goormy/hackathon/entity/User.java | 3 +- .../hackathon/redis/config/RedisConfig.java | 66 ++++++- .../redis/entity/PopularPostRedis.java | 15 ++ .../hackathon/redis/entity/PostRedis.java | 64 +++++++ .../redis/entity/PostSimpleInfo.java | 38 ++++ .../redis/entity/RecentUpdateRedis.java | 27 +++ .../hackathon/redis/entity/UserRedis.java | 59 ++++++ .../FeedHashtagRedisRepository.java | 32 ++++ .../repository/FeedUserRedisRepository.java | 36 ++++ .../FeedUserSortRedisRepository.java | 5 + .../repository/LikeRedisRepository.java | 80 ++++++++ .../PopularPostRedisRepository.java | 5 + .../repository/PostRedisRepository.java | 41 +++++ .../hackathon/repository/PostRepository.java | 9 + .../RecentUpdateRedisRepository.java | 37 ++++ .../repository/UserRedisRepository.java | 33 ++++ .../hackathon/repository/UserRespository.java | 8 + .../com/goormy/hackathon/repository/dummy.txt | 0 .../hackathon/service/GetFeedService.java | 171 ++++++++++++++++++ .../com/goormy/hackathon/service/dummy.txt | 0 30 files changed, 905 insertions(+), 5 deletions(-) delete mode 100644 src/main/java/com/goormy/hackathon/config/dummy.txt create mode 100644 src/main/java/com/goormy/hackathon/controller/GetFeedController.java delete mode 100644 src/main/java/com/goormy/hackathon/controller/dummy.txt create mode 100644 src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java create mode 100644 src/main/java/com/goormy/hackathon/dto/request/AddFeedUser.java create mode 100644 src/main/java/com/goormy/hackathon/dto/response/GetFeedResponseDto.java create mode 100644 src/main/java/com/goormy/hackathon/entity/BaseTimeEntity.java create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis.java create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/PostRedis.java create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis.java create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/UserRedis.java create mode 100644 src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/PostRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/UserRespository.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/dummy.txt create mode 100644 src/main/java/com/goormy/hackathon/service/GetFeedService.java delete mode 100644 src/main/java/com/goormy/hackathon/service/dummy.txt diff --git a/src/main/java/com/goormy/hackathon/config/dummy.txt b/src/main/java/com/goormy/hackathon/config/dummy.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java new file mode 100644 index 0000000..d714629 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java @@ -0,0 +1,62 @@ +package com.goormy.hackathon.controller; + +import com.goormy.hackathon.dto.request.AddFeedUser; +import com.goormy.hackathon.dto.response.GetFeedResponseDto; +import com.goormy.hackathon.redis.entity.PostSimpleInfo; +import com.goormy.hackathon.repository.FeedHashtagRedisRepository; +import com.goormy.hackathon.repository.FeedUserRedisRepository; +import com.goormy.hackathon.service.GetFeedService; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("") +public class GetFeedController { + + private final GetFeedService getFeedService; + + private final FeedUserRedisRepository feedUserRedisRepository; + private final FeedHashtagRedisRepository feedHashtagRedisRepository; + + /** + * [GET] 사용자 맞춤형 피드 조회 기능 + * + * @param userId : 사용자 Id + * @param size : Pagenation size + * @return : size만큼의 게시글을 반환 + */ + @GetMapping("/feed") + public ResponseEntity> getFeedList( + @RequestHeader Long userId, + @RequestParam int size + ) { + // 피드 리스트 반환 + return ResponseEntity.ok(getFeedService.getFeedList(userId, size)); + } + + @PostMapping("/userfeed") + public ResponseEntity addFeedUserData( + @RequestHeader Long userId, + @RequestBody AddFeedUser requestDto + ) { + requestDto.getInfoList().forEach( + info -> + feedHashtagRedisRepository.add(userId, + PostSimpleInfo.toEntity(info.getPostId(), info.getCreatedAt())) + ); + + // 피드 리스트 반환 + return ResponseEntity.ok("ok"); + } + +} + diff --git a/src/main/java/com/goormy/hackathon/controller/dummy.txt b/src/main/java/com/goormy/hackathon/controller/dummy.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java b/src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java new file mode 100644 index 0000000..25f9139 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java @@ -0,0 +1,25 @@ +package com.goormy.hackathon.converter; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import org.springframework.stereotype.Component; + +@Component +public class LocalDateTimeConverter { + + private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + public LocalDateTime convertToLocalDateTime(String source) { + try { + return LocalDateTime.parse(source, formatter); + } catch (DateTimeParseException e) { + throw new IllegalArgumentException( + "Invalid date time format. Please use this pattern: yyyy-MM-dd HH:mm:ss"); + } + } + + public String convertToString(LocalDateTime source) { + return source.format(formatter); + } +} \ No newline at end of file diff --git a/src/main/java/com/goormy/hackathon/dto/request/AddFeedUser.java b/src/main/java/com/goormy/hackathon/dto/request/AddFeedUser.java new file mode 100644 index 0000000..faaa1fa --- /dev/null +++ b/src/main/java/com/goormy/hackathon/dto/request/AddFeedUser.java @@ -0,0 +1,26 @@ +package com.goormy.hackathon.dto.request; + +import com.fasterxml.jackson.annotation.JsonFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.format.annotation.DateTimeFormat; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class AddFeedUser { + private List infoList; + + @Getter + public static class Info{ + private Long postId; + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") + private LocalDateTime createdAt; + } +} + + diff --git a/src/main/java/com/goormy/hackathon/dto/response/GetFeedResponseDto.java b/src/main/java/com/goormy/hackathon/dto/response/GetFeedResponseDto.java new file mode 100644 index 0000000..8b375cb --- /dev/null +++ b/src/main/java/com/goormy/hackathon/dto/response/GetFeedResponseDto.java @@ -0,0 +1,35 @@ +package com.goormy.hackathon.dto.response; + +import com.goormy.hackathon.redis.entity.PostRedis; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class GetFeedResponseDto { + + private Long id; + private String content; + private String imgUrl; + private Integer star; + private Integer likeCount; + private Long userId; + private List postHashtags; + + public static GetFeedResponseDto toDto(PostRedis postRedis) { + return GetFeedResponseDto.builder() + .id(postRedis.getId()) + .content(postRedis.getContent()) + .imgUrl(postRedis.getImgUrl()) + .star(postRedis.getStar()) + .likeCount(postRedis.getLikeCount()) + .userId(postRedis.getUserId()) + .postHashtags(postRedis.getPostHashtags()) + .build(); + } +} diff --git a/src/main/java/com/goormy/hackathon/entity/BaseTimeEntity.java b/src/main/java/com/goormy/hackathon/entity/BaseTimeEntity.java new file mode 100644 index 0000000..c6a1c42 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/entity/BaseTimeEntity.java @@ -0,0 +1,25 @@ +package com.goormy.hackathon.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; +import lombok.Getter; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@Getter +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public class BaseTimeEntity { + + @CreatedDate + private LocalDateTime createdAt; + + @LastModifiedDate + private LocalDateTime updatedAt; +} \ No newline at end of file diff --git a/src/main/java/com/goormy/hackathon/entity/Hashtag.java b/src/main/java/com/goormy/hackathon/entity/Hashtag.java index fde4a7e..747b559 100644 --- a/src/main/java/com/goormy/hackathon/entity/Hashtag.java +++ b/src/main/java/com/goormy/hackathon/entity/Hashtag.java @@ -11,7 +11,7 @@ @Entity @NoArgsConstructor @Getter -public class Hashtag { +public class Hashtag extends BaseTimeEntity{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/com/goormy/hackathon/entity/Post.java b/src/main/java/com/goormy/hackathon/entity/Post.java index 169705a..4472b55 100644 --- a/src/main/java/com/goormy/hackathon/entity/Post.java +++ b/src/main/java/com/goormy/hackathon/entity/Post.java @@ -2,12 +2,15 @@ import com.goormy.hackathon.common.entity.BaseTimeEntity; import jakarta.persistence.*; +import java.time.LocalDateTime; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.List; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; @Entity @NoArgsConstructor @@ -36,6 +39,7 @@ public class Post extends BaseTimeEntity { @OneToMany(mappedBy = "post", cascade = CascadeType.ALL) private List likes = new ArrayList<>(); + @Builder public Post(User user, String content, String imageUrl, Integer star, Integer likeCount) { this.user = user; diff --git a/src/main/java/com/goormy/hackathon/entity/PostHashtag.java b/src/main/java/com/goormy/hackathon/entity/PostHashtag.java index f56e1f2..cb73f79 100644 --- a/src/main/java/com/goormy/hackathon/entity/PostHashtag.java +++ b/src/main/java/com/goormy/hackathon/entity/PostHashtag.java @@ -8,7 +8,7 @@ @Entity @NoArgsConstructor @Getter -public class PostHashtag { +public class PostHashtag extends BaseTimeEntity{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/com/goormy/hackathon/entity/User.java b/src/main/java/com/goormy/hackathon/entity/User.java index 55182a8..b641c44 100644 --- a/src/main/java/com/goormy/hackathon/entity/User.java +++ b/src/main/java/com/goormy/hackathon/entity/User.java @@ -15,7 +15,8 @@ @Table(name="users") public class User extends BaseTimeEntity { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "user_id") private Long id; diff --git a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java index a6fe5c7..b9a91c5 100644 --- a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java +++ b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java @@ -1,5 +1,10 @@ package com.goormy.hackathon.redis.config; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.goormy.hackathon.redis.entity.PostRedis; +import com.goormy.hackathon.redis.entity.PostSimpleInfo; +import com.goormy.hackathon.redis.entity.UserRedis; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; @@ -7,10 +12,14 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; + @Configuration +@EnableRedisRepositories @EnableCaching public class RedisConfig { @@ -25,15 +34,68 @@ public RedisConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory(host, port); } + @Autowired + private ObjectMapper objectMapper; + @Bean public RedisTemplate redisTemplate() { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory()); redisTemplate.setKeySerializer(new StringRedisSerializer()); - redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( + Object.class); + redisTemplate.setValueSerializer(serializer); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(serializer); + return redisTemplate; + } + + @Bean + public RedisTemplate userRedisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( + UserRedis.class); + redisTemplate.setValueSerializer(serializer); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(serializer); + return redisTemplate; + } + + @Bean + public RedisTemplate postSimpleInfoRedisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( + PostSimpleInfo.class); + redisTemplate.setValueSerializer(serializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); - redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); + redisTemplate.setHashValueSerializer(serializer); return redisTemplate; } + @Bean + public RedisTemplate postRedisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( + PostRedis.class); + redisTemplate.setValueSerializer(serializer); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(serializer); + return redisTemplate; + } + + @Bean + public StringRedisTemplate stringRedisTemplate() { + final StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); + stringRedisTemplate.setKeySerializer(new StringRedisSerializer()); + stringRedisTemplate.setValueSerializer(new StringRedisSerializer()); + stringRedisTemplate.setConnectionFactory(redisConnectionFactory()); + return stringRedisTemplate; + } + } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis.java b/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis.java new file mode 100644 index 0000000..bbef442 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis.java @@ -0,0 +1,15 @@ +package com.goormy.hackathon.redis.entity; + +import jakarta.persistence.Id; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.data.redis.core.RedisHash; + +@Getter +@RedisHash("popular_post") +@AllArgsConstructor +public class PopularPostRedis { + + private List postIdList; // 최대 256개의 아티클 저장 -> 1KB +} diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PostRedis.java b/src/main/java/com/goormy/hackathon/redis/entity/PostRedis.java new file mode 100644 index 0000000..6dcbc45 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/PostRedis.java @@ -0,0 +1,64 @@ +package com.goormy.hackathon.redis.entity; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.Id; +import java.time.LocalDateTime; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import org.springframework.data.redis.core.RedisHash; + +@Getter +@RedisHash("post") +@AllArgsConstructor +@Builder +public class PostRedis { + + @Id + private Long id; + + private String content; + private String imgUrl; + private Integer star; + private Integer likeCount; + private Long userId; + private List postHashtags; + private String createdAt; + + + @JsonCreator + public PostRedis( + @JsonProperty("id") Long id, + @JsonProperty("content") String content, + @JsonProperty("imgUrl") String imgUrl, + @JsonProperty("star") int star, + @JsonProperty("likeCount") int likeCount, + @JsonProperty("userId") Long userId, + @JsonProperty("postHashtags") List postHashtags, + @JsonProperty("createdAt") String createdAt) { + this.id = id; + this.content = content; + this.imgUrl = imgUrl; + this.star = star; + this.likeCount = likeCount; + this.userId = userId; + this.postHashtags = postHashtags; + this.createdAt = createdAt; + } + + public static PostRedis toEntity(Long id, String content, String imgUrl, Integer star, + Integer likeCount, Long userId, List postHashtags, LocalDateTime createdAt) { + return PostRedis.builder() + .id(id) + .content(content) + .imgUrl(imgUrl) + .star(star) + .likeCount(likeCount) + .userId(userId) + .postHashtags(postHashtags) + .createdAt(createdAt.toString()) + .build(); + } +} diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java b/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java new file mode 100644 index 0000000..b93b191 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java @@ -0,0 +1,38 @@ +package com.goormy.hackathon.redis.entity; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import java.time.LocalDate; +import java.time.LocalDateTime; +import lombok.Builder; +import lombok.Getter; +import org.hibernate.annotations.CreationTimestamp; + +@Getter +@Builder +public class PostSimpleInfo { + + private Long postId; + private String createdAt; + + @JsonCreator + public PostSimpleInfo( + @JsonProperty("postId") Long postId, + @JsonProperty("createdAt") String createdAt) { + this.postId = postId; + this.createdAt = createdAt; + } + + public static PostSimpleInfo toEntity(Long postId, LocalDateTime createdAt) { + return PostSimpleInfo.builder() + .postId(postId) + .createdAt(createdAt.toString()) + .build(); + } + + +} diff --git a/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis.java b/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis.java new file mode 100644 index 0000000..04d94f8 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis.java @@ -0,0 +1,27 @@ +package com.goormy.hackathon.redis.entity; + +import jakarta.persistence.Id; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import org.springframework.data.redis.core.RedisHash; + +@AllArgsConstructor +@RedisHash("recent_update") +@Getter +@Builder +public class RecentUpdateRedis { + + @Id + private Long id; + private LocalDateTime recentUpdateTime; + + + public static RecentUpdateRedis toEntity(Long id, LocalDateTime recentUpdateTime) { + return RecentUpdateRedis.builder() + .id(id) + .recentUpdateTime(recentUpdateTime) + .build(); + } +} diff --git a/src/main/java/com/goormy/hackathon/redis/entity/UserRedis.java b/src/main/java/com/goormy/hackathon/redis/entity/UserRedis.java new file mode 100644 index 0000000..4d71d50 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/UserRedis.java @@ -0,0 +1,59 @@ +package com.goormy.hackathon.redis.entity; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.Id; +import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.springframework.data.redis.core.RedisHash; + +@Getter +@Setter +@Builder +public class UserRedis implements Serializable { + + private Long id; + + private String name; + + private String password; + + private Integer followerCount; + + private Integer followingCount; + + private List followerIdList; + + @JsonCreator + public UserRedis( + @JsonProperty("id") Long id, + @JsonProperty("name") String name, + @JsonProperty("password") String password, + @JsonProperty("followerCount") Integer followerCount, + @JsonProperty("followingCount") Integer followingCount, + @JsonProperty("followerIdList") List followerIdList) { + this.id = id; + this.name = name; + this.password = password; + this.followerCount = followerCount; + this.followingCount = followingCount; + this.followerIdList = followerIdList; + } + + + public static UserRedis toEntity(Long id, String name, String password, Integer followerCount, + Integer followingCount, List followerIdList) { + return UserRedis.builder() + .id(id) + .name(name) + .password(password) + .followerCount(followerCount) + .followingCount(followingCount) + .followerIdList(followerIdList) + .build(); + } +} diff --git a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java new file mode 100644 index 0000000..d8741e9 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java @@ -0,0 +1,32 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.redis.entity.PostSimpleInfo; +import jakarta.annotation.PostConstruct; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.ListOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class FeedHashtagRedisRepository { + + private final RedisTemplate redisTemplate; + private static final String FEED_HASHTAG_KEY = "feed_hashtag:"; + + private ListOperations listOperations; + + @PostConstruct + private void init() { + listOperations = redisTemplate.opsForList(); + } + + public void add(Long hashtagId, PostSimpleInfo value) { + listOperations.leftPush(FEED_HASHTAG_KEY + hashtagId, value); + } + + public List getAll(Long hashtagId) { + return listOperations.range(FEED_HASHTAG_KEY + hashtagId, 0, -1); + } +} diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java new file mode 100644 index 0000000..d26f98c --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java @@ -0,0 +1,36 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.redis.entity.PostSimpleInfo; +import jakarta.annotation.PostConstruct; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.ListOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class FeedUserRedisRepository { + + private final RedisTemplate redisTemplate; + private static final String FEED_USER_KEY = "feed_user:"; + + private ListOperations listOperations; + + @PostConstruct + private void init() { + listOperations = redisTemplate.opsForList(); + } + + public void add(Long userId, PostSimpleInfo value) { + listOperations.leftPush(FEED_USER_KEY + userId, value); + } + + public PostSimpleInfo get(Long userId) { + return listOperations.rightPop(FEED_USER_KEY + userId); + } + + public List getAll(Long userId) { + return listOperations.rightPop(FEED_USER_KEY + userId, Long.MAX_VALUE); + } +} diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java new file mode 100644 index 0000000..19e651b --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java @@ -0,0 +1,5 @@ +package com.goormy.hackathon.repository; + +public class FeedUserSortRedisRepository { + +} diff --git a/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java new file mode 100644 index 0000000..3b9fd8b --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java @@ -0,0 +1,80 @@ +package com.goormy.hackathon.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.*; +import org.springframework.stereotype.Repository; + +import java.util.Map; +import java.util.Set; + +@Repository +@RequiredArgsConstructor +public class LikeRedisRepository { + + private final RedisTemplate redisTemplate; + + /** + * @description '좋아요' 정보를 업데이트 하는 함수 + * */ + public void update(Long postId, Long userId, Integer value) { + String key = "postlike:" + postId.toString(); + String field = userId.toString(); + + redisTemplate.opsForHash().put(key, field, value); + } + + /** + * @description '좋아요' 혹은 '좋아요 취소' 정보를 삭제하는 함수 + * */ + public void delete(Long postId, Long userId){ + String key = "postlike:" + postId.toString(); + String field = userId.toString(); + + redisTemplate.opsForHash().delete(key, field); + } + + /** + * @description postId와 userId에 대한 value를 조회 + * */ + public Integer findPostLikeFromCache(Long postId, Long userId) { + String key = "postlike:" + postId.toString(); + String field = userId.toString(); + + return (Integer) redisTemplate.opsForHash().get(key, field); + } + + /** + * @description Key에 대한 모든 field와 value를 조회 + * */ + public Map findByKey(String key) { + return redisTemplate.opsForHash().entries(key); + } + + /** + * @description Key에 대한 모든 field와 value를 삭제 + * */ + public void delete(String key) { + redisTemplate.delete(key); + } + + + + + public Set findAllKeys() { + Set keys = redisTemplate.keys("postlike:*"); + + return keys; + } + + // # PostId로 조회하는 함수 +// public Map findByPostId(Long postId) { +// String key = "postlike:" + postId.toString(); +// Map entries = redisTemplate.opsForHash().entries(key); +// +// return entries.entrySet().stream() +// .collect(Collectors.toMap( +// entry -> Long.valueOf((String) entry.getKey()), +// entry -> (Integer) entry.getValue() +// )); +// } +} diff --git a/src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository.java new file mode 100644 index 0000000..fa15cb4 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository.java @@ -0,0 +1,5 @@ +package com.goormy.hackathon.repository; + +public class PopularPostRedisRepository { + +} diff --git a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java new file mode 100644 index 0000000..ffc2542 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java @@ -0,0 +1,41 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.redis.entity.PostRedis; +import jakarta.annotation.PostConstruct; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class PostRedisRepository { + + private final RedisTemplate redisTemplate; + private static final String POST_KEY = "post:"; + + private ValueOperations valueOperations; + + @PostConstruct + private void init() { + valueOperations = redisTemplate.opsForValue(); + } + + public void set(Long postId, PostRedis value) { + valueOperations.set(POST_KEY + postId, value); + } + + public Optional get(Long postId) { + PostRedis post = valueOperations.get(POST_KEY + postId); + return Optional.ofNullable(post); + } + + public List getAll(List postIdList) { + return postIdList.stream() + .map(postId -> valueOperations.get(POST_KEY + postId)) + .toList(); + } +} diff --git a/src/main/java/com/goormy/hackathon/repository/PostRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRepository.java new file mode 100644 index 0000000..065ae69 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/PostRepository.java @@ -0,0 +1,9 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.Post; +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PostRepository extends JpaRepository { + List findAllByIdIn(List ids); +} diff --git a/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java new file mode 100644 index 0000000..f598546 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java @@ -0,0 +1,37 @@ +package com.goormy.hackathon.repository; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Optional; + +@Component +@RequiredArgsConstructor +public class RecentUpdateRedisRepository { + + private final StringRedisTemplate stringRedisTemplate; + private static final String RECENT_UPDATE_KEY = "recent_update:"; + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; + + private ValueOperations valueOperations; + + @PostConstruct + private void init() { + valueOperations = stringRedisTemplate.opsForValue(); + } + + public void set(Long userId, LocalDateTime value) { + String formattedValue = value.format(FORMATTER); + valueOperations.set(RECENT_UPDATE_KEY + userId, formattedValue); + } + + public Optional get(Long userId) { + String value = valueOperations.get(RECENT_UPDATE_KEY + userId); + return Optional.ofNullable(value).map(v -> LocalDateTime.parse(v, FORMATTER)); + } +} diff --git a/src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java new file mode 100644 index 0000000..1328805 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java @@ -0,0 +1,33 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.redis.entity.UserRedis; +import jakarta.annotation.PostConstruct; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class UserRedisRepository { + + private final RedisTemplate redisTemplate; + private static final String USER_KEY = "user:"; + + private ValueOperations valueOperations; + + @PostConstruct + private void init() { + valueOperations = redisTemplate.opsForValue(); + } + + public void set(Long userId, UserRedis value) { + valueOperations.set(USER_KEY + userId, value); + } + + public Optional get(Long userId) { + UserRedis user = valueOperations.get(USER_KEY + userId); + return Optional.ofNullable(user); + } +} diff --git a/src/main/java/com/goormy/hackathon/repository/UserRespository.java b/src/main/java/com/goormy/hackathon/repository/UserRespository.java new file mode 100644 index 0000000..ec5b75f --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/UserRespository.java @@ -0,0 +1,8 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRespository extends JpaRepository { + +} diff --git a/src/main/java/com/goormy/hackathon/repository/dummy.txt b/src/main/java/com/goormy/hackathon/repository/dummy.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/goormy/hackathon/service/GetFeedService.java b/src/main/java/com/goormy/hackathon/service/GetFeedService.java new file mode 100644 index 0000000..6e16690 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/GetFeedService.java @@ -0,0 +1,171 @@ +package com.goormy.hackathon.service; + +import com.goormy.hackathon.converter.LocalDateTimeConverter; +import com.goormy.hackathon.dto.response.GetFeedResponseDto; +import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.redis.entity.PostRedis; +import com.goormy.hackathon.redis.entity.PostSimpleInfo; +import com.goormy.hackathon.redis.entity.UserRedis; +import com.goormy.hackathon.repository.FeedHashtagRedisRepository; +import com.goormy.hackathon.repository.FeedUserRedisRepository; +import com.goormy.hackathon.repository.PostRedisRepository; +import com.goormy.hackathon.repository.PostRepository; +import com.goormy.hackathon.repository.RecentUpdateRedisRepository; +import com.goormy.hackathon.repository.UserRedisRepository; +import com.goormy.hackathon.repository.UserRespository; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class GetFeedService { + + private final UserRespository userRespository; + private final PostRepository postRepository; + + private final LocalDateTimeConverter localDateTimeConverter; + + private final UserRedisRepository userRedisRepository; + private final PostRedisRepository postRedisRepository; + private final RecentUpdateRedisRepository recentUpdateRedisRepository; + private final FeedUserRedisRepository feedUserRedisRepository; + private final FeedHashtagRedisRepository feedHashtagRedisRepository; + + // 1. 사용자 정보를 가져옴 + private UserRedis getUser(Long userId) { + // 캐시 우선 검색 + Optional userCacheOptional = userRedisRepository.get(userId); + // 캐시에 없으면 RDB에서 검색 + return userCacheOptional.orElseGet(() -> { + User user = userRespository.findById(userId) + .orElseThrow(() -> new RuntimeException("User not found")); // 적절한 예외로 변경 필요 + List followIdList = user.getFollows().stream() + .map(Follow::getId) + .toList(); + // RDB에서 검색하고, UserCache에 추가 + userRedisRepository.set(userId, + UserRedis.toEntity(user.getId(), user.getName(), user.getPassword(), + user.getFollowerCount(), user.getFollowingCount(), followIdList)); + return UserRedis.toEntity(user.getId(), user.getName(), user.getPassword(), + user.getFollowerCount(), user.getFollowingCount(), followIdList); + }); + } + + // 2, 3. Push & Pull 방식으로 피드를 가져옴 + private List getPushPullFeed(UserRedis userRedis) { + // 날짜 세팅 + // recentUpdatedTime - 가장 마지막으로 업데이트한 시간이랑 3일 중 현재와 가장 가까운 시간을 기준으로 잡음 + LocalDateTime now = LocalDateTime.now(); + + LocalDateTime recentUpdatedTime = recentUpdateRedisRepository.get( + userRedis.getId()).orElse(now.minusDays(3)); + + // *** 2. Push 방식 *** + // Push 방식으로 저장되어있는 포스트 가져오기 -> Created At 정보도 같이 저장해야함 + // (이유) 한개의 Key에 있는 각 값마다 TTL 설정이 불가능하기 때문 + // feedUser 접근 + List feedUserCache = feedUserRedisRepository.getAll(userRedis.getId()); + // push 캐시 가져오고 비우기 & 3일 전 포스트까지만 가져오기 + List postSimpleInfoList = new ArrayList<>(feedUserCache.stream() + .filter(simpleInfo -> localDateTimeConverter.convertToLocalDateTime( + simpleInfo.getCreatedAt()).isAfter(recentUpdatedTime)) + .toList()); + + // *** 3. Pull 방식 *** + // Pull 방식으로 저장되어있는 인플루언서 포스트 가져오기 -> 사용자가 최근에 업데이트한 시간 이후부터 진행 + // (이유) 한개의 Key에 있는 각 값마다 TTL 설정이 불가능하기 때문 + // user의 follow 리스트를 순회하면서 가져와야함 + // 5000명이 넘는지를 판단해야함 -> popular 캐시에 있으면 되는 것 + // 기본적인 우선순위 정보는 가지고 있어도 좋을듯 -> 꼭 필요한 Post 정보만 가지고올 수 있도록 + // 3일 전 포스트까지만 가져오기 + userRedis.getFollowerIdList().forEach( + followId -> { + List info = feedHashtagRedisRepository.getAll(followId); + postSimpleInfoList.addAll(info.stream() + //.filter(simpleInfo -> simpleInfo.getCreatedAt().isAfter(recentUpdatedTime)) + .toList() + ); + } + ); + + // 최신 업데이트 시간 반영 + recentUpdateRedisRepository.set(userRedis.getId(), now); + + return postSimpleInfoList; + } + + // 5. size개의 post를 구분 + private List splitPostSimpleInfoList(List postSimpleInfoList, + int size) { + // 초기 반환을 위한 Id 리스트 + // TODO: 만약 size가 작으면 인기 게시물에서 가져와야함 + + // TODO: 나머지 정렬한 값을 Redis에 저장 + List postSimpleInfoListForRedis = postSimpleInfoList.stream() + .skip(size) + .toList(); + + // 사용자에게 반환할 게시글 리스트 + return postSimpleInfoList.stream() + .limit(size) + .map(PostSimpleInfo::getPostId) + .toList(); + } + + // 5. PostList를 가져옴 + private List getPostList(List postIdList) { + List postRedisList = new ArrayList<>(postRedisRepository.getAll(postIdList)); + List postCacheIdList = postRedisList.stream().map(PostRedis::getId).toList(); + + // cache에 없는 post id 리스트를 찾음 + List postIdListNotInCache = postIdList.stream() + .filter(id -> !postCacheIdList.contains(id)).toList(); + // RDS에서 가져온 이후 Cache에 업데이트 + List postList = postRepository.findAllByIdIn(postIdListNotInCache); + postList.forEach(post -> { + PostRedis postRedis = PostRedis.toEntity( + post.getId(), post.getContent(), post.getImageUrl(), post.getStar(), + post.getLikeCount(), post.getUser().getId(), + post.getPostHashtags().stream().map(hashtag -> hashtag.getHashtag().getName()) + .toList(), post.getCreatedAt() + ); + postRedisRepository.set(postRedis.getId(), postRedis); + postRedisList.add(postRedis); + }); + + // TODO: postId별로 like여부 받아오는 코드 추가 + + return postRedisList; + } + + // TODO: 각 포스트의 가중치를 생각해서 정렬하기 -> 일단은 날짜 기준으로 정렬되어있어서 패스 + public List getFeedList(Long userId, int size) { + // 1. 사용자 정보 가져오기 (Redis -> RDS) - 완료 + UserRedis userRedis = getUser(userId); + + // TODO: 2.0 진행 예정 + + // 2, 3. Push, Pull로 Feed List 가져오기 & 필터링 + // id, createdAt을 함께 가진 PostSimpleInfo 데이터 리스트 + // 나중에 (1)여기 먼저 조회 & 있으면 반환, 없으면 (2)push/pull 확인 후 부족하면 (3)인기 게시글 반환 + List pushPullFeedList = getPushPullFeed(userRedis); + + // 4. 최신순으로 정렬 + List sortedPushPullFeedList = pushPullFeedList.stream() + .sorted(Comparator.comparing(PostSimpleInfo::getCreatedAt)) + .toList(); + + // 5. 반환할 데이터와, Redis에 저장할 데이터를 구분하고, Redis에 저장 + List postIdListForReturn = splitPostSimpleInfoList(sortedPushPullFeedList, size); + // 5. post를 조회해서 반환 + return getPostList(postIdListForReturn).stream().map(GetFeedResponseDto::toDto).toList(); + + } +} diff --git a/src/main/java/com/goormy/hackathon/service/dummy.txt b/src/main/java/com/goormy/hackathon/service/dummy.txt deleted file mode 100644 index e69de29..0000000 From 4a8f4a9c6cdf90d719be4138ba517066179839b4 Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Wed, 31 Jul 2024 18:51:10 +0900 Subject: [PATCH 19/57] =?UTF-8?q?feat:=20=ED=95=B4=EC=8B=9C=ED=83=9C?= =?UTF-8?q?=EA=B7=B8=EA=B0=80=20=EC=9E=88=EC=9C=BC=EB=A9=B4=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A5=BC=20=EC=9E=AC=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EA=B3=A0=20=ED=95=B4=EC=8B=9C=ED=83=9C=EA=B7=B8=EA=B0=80=20?= =?UTF-8?q?=EC=97=86=EC=9C=BC=EB=A9=B4=20=EC=83=88=EB=A1=AD=EA=B2=8C=20?= =?UTF-8?q?=EA=B0=9D=EC=B2=B4=EB=A5=BC=20=EC=83=9D=EC=84=B1=ED=95=9C=20?= =?UTF-8?q?=ED=9B=84=20DB=EC=99=80=20Redis=EC=97=90=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../redis/entity/FollowCountCache.java | 29 +++++++++++++ .../FollowCountRedisRepository.java | 24 +++++++++++ .../repository/HashtagRepository.java | 10 +++++ .../hackathon/service/HashtagService.java | 43 +++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java create mode 100644 src/main/java/com/goormy/hackathon/redis/repository/FollowCountRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/HashtagRepository.java create mode 100644 src/main/java/com/goormy/hackathon/service/HashtagService.java diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java b/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java new file mode 100644 index 0000000..b904521 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java @@ -0,0 +1,29 @@ +package com.goormy.hackathon.redis.entity; + +import com.goormy.hackathon.entity.Hashtag; +import lombok.Getter; +import org.springframework.data.annotation.Id; + +import java.io.Serializable; + +@Getter +public class FollowCountCache implements Serializable { + + @Id + private Long hashtagId; + private Integer followCount; + + public FollowCountCache(Hashtag hashtag) { + this.hashtagId = hashtag.getId(); + this.followCount = 0; + } + + public String getKey() { + return "FollowCount:" + hashtagId; + } + + public String getField() { + return String.valueOf(hashtagId); + } + +} diff --git a/src/main/java/com/goormy/hackathon/redis/repository/FollowCountRedisRepository.java b/src/main/java/com/goormy/hackathon/redis/repository/FollowCountRedisRepository.java new file mode 100644 index 0000000..b7f110e --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/repository/FollowCountRedisRepository.java @@ -0,0 +1,24 @@ +package com.goormy.hackathon.redis.repository; + +import com.goormy.hackathon.redis.entity.FollowCountCache; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class FollowCountRedisRepository { + + private final RedisTemplate redisTemplate; + + public void save(FollowCountCache followCountCache) { + redisTemplate.opsForHash().put(followCountCache.getKey(), followCountCache.getField(), followCountCache.getFollowCount()); + } + + public Integer findFollowCount(Long hashtagId) { + String key = "FollowCount:" + hashtagId; + String field = String.valueOf(hashtagId); + return (Integer) redisTemplate.opsForHash().get(key, field); + } + +} diff --git a/src/main/java/com/goormy/hackathon/repository/HashtagRepository.java b/src/main/java/com/goormy/hackathon/repository/HashtagRepository.java new file mode 100644 index 0000000..ad7d655 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/HashtagRepository.java @@ -0,0 +1,10 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.Hashtag; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface HashtagRepository extends JpaRepository { + Optional findByName(String name); +} diff --git a/src/main/java/com/goormy/hackathon/service/HashtagService.java b/src/main/java/com/goormy/hackathon/service/HashtagService.java new file mode 100644 index 0000000..b1815f0 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/HashtagService.java @@ -0,0 +1,43 @@ +package com.goormy.hackathon.service; + +import com.goormy.hackathon.dto.hashtag.PostHashtagRequestDto; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.redis.entity.FollowCountCache; +import com.goormy.hackathon.redis.repository.FollowCountRedisRepository; +import com.goormy.hackathon.repository.HashtagRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class HashtagService { + + private final HashtagRepository hashtagRepository; + private final FollowCountRedisRepository followCountRedisRepository; + + @Transactional + public List getOrCreateHashtags(List hashtagRequestDtos) { + List hashtags = new ArrayList<>(); + for (var hashtagRequestDto : hashtagRequestDtos) { + // 이미 존재하는 해시태그인 경우 + var hashtag = hashtagRepository.findByName(hashtagRequestDto.name()) + .orElseGet(() -> { + // 새로운 해시태그인 경우 + var newHashtag = new Hashtag(hashtagRequestDto.name(), hashtagRequestDto.type()); + hashtagRepository.save(newHashtag); + + var followCountCache = new FollowCountCache(newHashtag); + followCountRedisRepository.save(followCountCache); + + return newHashtag; + }); + hashtags.add(hashtag); + } + return hashtags; + } + +} From 1702dbacbb6f95c25caa2622c6d845e7a89fbd52 Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Wed, 31 Jul 2024 18:52:01 +0900 Subject: [PATCH 20/57] =?UTF-8?q?feat:=20post=EB=A5=BC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=ED=95=98=EC=97=AC=20DB=EC=97=90=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hackathon/controller/PostController.java | 24 +++++++++ .../dto/hashtag/PostHashtagRequestDto.java | 10 ++++ .../dto/hashtag/PostHashtagResponseDto.java | 10 ++++ .../hackathon/dto/post/PostRequestDto.java | 14 ++++++ .../hackathon/dto/post/PostResponseDto.java | 36 +++++++++++++ .../com/goormy/hackathon/entity/Post.java | 13 +++++ .../redis/entity/FeedHashtagCache.java | 16 ++++++ .../hackathon/repository/PostRepository.java | 8 +++ .../hackathon/repository/UserRepository.java | 8 +++ .../goormy/hackathon/service/PostService.java | 50 +++++++++++++++++++ 10 files changed, 189 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/controller/PostController.java create mode 100644 src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagRequestDto.java create mode 100644 src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagResponseDto.java create mode 100644 src/main/java/com/goormy/hackathon/dto/post/PostRequestDto.java create mode 100644 src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache.java create mode 100644 src/main/java/com/goormy/hackathon/repository/PostRepository.java create mode 100644 src/main/java/com/goormy/hackathon/repository/UserRepository.java create mode 100644 src/main/java/com/goormy/hackathon/service/PostService.java diff --git a/src/main/java/com/goormy/hackathon/controller/PostController.java b/src/main/java/com/goormy/hackathon/controller/PostController.java new file mode 100644 index 0000000..0c18205 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/controller/PostController.java @@ -0,0 +1,24 @@ +package com.goormy.hackathon.controller; + + +import com.goormy.hackathon.dto.post.PostRequestDto; +import com.goormy.hackathon.dto.post.PostResponseDto; +import com.goormy.hackathon.service.PostService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/posts") +@RequiredArgsConstructor +public class PostController { + + private final PostService postService; + + @PostMapping + public PostResponseDto create( + @RequestHeader("userId") Long userId, + @RequestBody PostRequestDto postRequestDto) { + return postService.createPost(userId, postRequestDto); + } + +} diff --git a/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagRequestDto.java b/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagRequestDto.java new file mode 100644 index 0000000..dcb1210 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagRequestDto.java @@ -0,0 +1,10 @@ +package com.goormy.hackathon.dto.hashtag; + +import com.goormy.hackathon.entity.Hashtag; + +public record PostHashtagRequestDto( + String name, + Hashtag.Type type +) { + +} diff --git a/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagResponseDto.java b/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagResponseDto.java new file mode 100644 index 0000000..7f70681 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagResponseDto.java @@ -0,0 +1,10 @@ +package com.goormy.hackathon.dto.hashtag; + +import com.goormy.hackathon.entity.Hashtag; + +public record PostHashtagResponseDto( + String name, + Hashtag.Type type +) { + +} diff --git a/src/main/java/com/goormy/hackathon/dto/post/PostRequestDto.java b/src/main/java/com/goormy/hackathon/dto/post/PostRequestDto.java new file mode 100644 index 0000000..07e5274 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/dto/post/PostRequestDto.java @@ -0,0 +1,14 @@ +package com.goormy.hackathon.dto.post; + +import com.goormy.hackathon.dto.hashtag.PostHashtagRequestDto; + +import java.util.List; + +public record PostRequestDto( + String content, + String imageUrl, + Integer star, + List postHashtags +) { + +} diff --git a/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java b/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java new file mode 100644 index 0000000..ec6b69f --- /dev/null +++ b/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java @@ -0,0 +1,36 @@ +package com.goormy.hackathon.dto.post; + +import com.goormy.hackathon.dto.hashtag.PostHashtagResponseDto; +import com.goormy.hackathon.entity.Post; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +public record PostResponseDto( + Long id, + String content, + String imageUrl, + Integer star, + List postHashtags, + LocalDateTime createdAt + +) implements Serializable { + + public PostResponseDto(Post post) { + this( + post.getId(), + post.getContent(), + post.getImageUrl(), + post.getStar(), + mapHashtagsToDto(post), + post.getCreatedAt() + ); + } + + private static List mapHashtagsToDto(Post post) { + return post.getPostHashtags().stream() + .map(hashtag -> new PostHashtagResponseDto(hashtag.getName(), hashtag.getType())) + .toList(); + } +} diff --git a/src/main/java/com/goormy/hackathon/entity/Post.java b/src/main/java/com/goormy/hackathon/entity/Post.java index 169705a..5ec8bc0 100644 --- a/src/main/java/com/goormy/hackathon/entity/Post.java +++ b/src/main/java/com/goormy/hackathon/entity/Post.java @@ -44,4 +44,17 @@ public Post(User user, String content, String imageUrl, Integer star, Integer li this.star = star; this.likeCount = likeCount; } + + public List getPostHashtags() { + return postHashtags.stream() + .map(PostHashtag::getHashtag) + .toList(); + } + + public void setPostHashtags(List hashtags) { + this.postHashtags = hashtags.stream() + .map(hashtag -> new PostHashtag(this, hashtag)) + .toList(); + } + } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache.java b/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache.java new file mode 100644 index 0000000..7026166 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache.java @@ -0,0 +1,16 @@ +package com.goormy.hackathon.redis.entity; + +import lombok.Getter; +import org.springframework.data.annotation.Id; + +import java.io.Serializable; +import java.util.List; + +@Getter +public class FeedHashtagCache implements Serializable { + + @Id + Long hashtagId; + private List postList; + +} diff --git a/src/main/java/com/goormy/hackathon/repository/PostRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRepository.java new file mode 100644 index 0000000..0fbe34c --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/PostRepository.java @@ -0,0 +1,8 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.Post; +import org.springframework.data.repository.CrudRepository; + +public interface PostRepository extends CrudRepository { + +} diff --git a/src/main/java/com/goormy/hackathon/repository/UserRepository.java b/src/main/java/com/goormy/hackathon/repository/UserRepository.java new file mode 100644 index 0000000..44fc012 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/UserRepository.java @@ -0,0 +1,8 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository { + +} diff --git a/src/main/java/com/goormy/hackathon/service/PostService.java b/src/main/java/com/goormy/hackathon/service/PostService.java new file mode 100644 index 0000000..e305ae6 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/PostService.java @@ -0,0 +1,50 @@ +package com.goormy.hackathon.service; + +import com.goormy.hackathon.dto.post.PostRequestDto; +import com.goormy.hackathon.dto.post.PostResponseDto; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.redis.entity.PostCache; +import com.goormy.hackathon.repository.PostRepository; +import com.goormy.hackathon.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class PostService { + + private final UserRepository userRepository; + private final PostRepository postRepository; + private final HashtagService hashtagService; + private final PostCacheService postCacheService; + + @Transactional + public PostResponseDto createPost(Long userId, PostRequestDto postRequestDto) { + // 사용자 찾기 + var user = userRepository.findById(userId).orElseThrow( + () -> new IllegalArgumentException("User not found")); // TODO: Custom exception + + // post 생성 + var post = Post.builder() + .user(user) + .content(postRequestDto.content()) + .imageUrl(postRequestDto.imageUrl()) + .star(postRequestDto.star()) + .likeCount(0) + .build(); + + // hashtag 생성 + var postHashtags = hashtagService.getOrCreateHashtags(postRequestDto.postHashtags()); + post.setPostHashtags(postHashtags); + + // DB 저장 + postRepository.save(post); + + // redis 저장 + postCacheService.cache(post); + + return new PostResponseDto(post); + } + +} From 5f3765297e8f171df0ed476b0e4151718de3b712 Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Wed, 31 Jul 2024 18:53:34 +0900 Subject: [PATCH 21/57] =?UTF-8?q?feat:=20=EC=83=9D=EC=84=B1=ED=95=9C=20pos?= =?UTF-8?q?t=EB=A5=BC=20push=20=EB=AA=A8=EB=8D=B8=EA=B3=BC=20pull=20?= =?UTF-8?q?=EB=AA=A8=EB=8D=B8=EC=9D=84=20=ED=99=9C=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=EC=BA=90=EC=8B=9C=EC=97=90=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../redis/entity/FeedSimpleInfo.java | 22 ++++++++ .../hackathon/redis/entity/FeedUserCache.java | 21 ++++++++ .../redis/entity/FollowListCache.java | 16 ++++++ .../hackathon/redis/entity/PostCache.java | 43 ++++++++++++++++ .../FeedHashtagRedisRepository.java | 21 ++++++++ .../repository/FeedUserRedisRepository.java | 21 ++++++++ .../repository/FollowListRedisRepository.java | 21 ++++++++ .../redis/repository/PostRedisRepository.java | 18 +++++++ .../hackathon/service/PostCacheService.java | 50 +++++++++++++++++++ 9 files changed, 233 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/FeedSimpleInfo.java create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache.java create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/PostCache.java create mode 100644 src/main/java/com/goormy/hackathon/redis/repository/FeedHashtagRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/redis/repository/FeedUserRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/redis/repository/FollowListRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/redis/repository/PostRedisRepository.java create mode 100644 src/main/java/com/goormy/hackathon/service/PostCacheService.java diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FeedSimpleInfo.java b/src/main/java/com/goormy/hackathon/redis/entity/FeedSimpleInfo.java new file mode 100644 index 0000000..816e1db --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/FeedSimpleInfo.java @@ -0,0 +1,22 @@ +package com.goormy.hackathon.redis.entity; + +import com.goormy.hackathon.common.util.LocalDateTimeConverter; +import com.goormy.hackathon.entity.Post; +import lombok.Getter; +import org.springframework.data.annotation.Id; + +import java.io.Serializable; + +@Getter +public class FeedSimpleInfo implements Serializable { + + @Id + private Long id; + private String createdAt; + + public FeedSimpleInfo(Post post) { + this.id = post.getId(); + this.createdAt = LocalDateTimeConverter.convert(post.getCreatedAt()); + } + +} diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache.java b/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache.java new file mode 100644 index 0000000..d4dd0e9 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache.java @@ -0,0 +1,21 @@ +package com.goormy.hackathon.redis.entity; + +import com.goormy.hackathon.entity.Post; +import lombok.Getter; +import org.springframework.data.annotation.Id; + +import java.io.Serializable; +import java.util.List; + +@Getter +public class FeedUserCache implements Serializable { + + @Id + Long userId; + private List postList; + + public FeedUserCache(Post post) { + this.userId = post.getUser().getId(); + } + +} diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java b/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java new file mode 100644 index 0000000..3f2a1ea --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java @@ -0,0 +1,16 @@ +package com.goormy.hackathon.redis.entity; + +import lombok.Getter; +import org.springframework.data.annotation.Id; + +import java.io.Serializable; +import java.util.List; + +@Getter +public class FollowListCache implements Serializable { + + @Id + private String hashtagId; + private List userIdList; + +} diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PostCache.java b/src/main/java/com/goormy/hackathon/redis/entity/PostCache.java new file mode 100644 index 0000000..06c93f7 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/PostCache.java @@ -0,0 +1,43 @@ +package com.goormy.hackathon.redis.entity; + + +import com.goormy.hackathon.common.util.LocalDateTimeConverter; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.Post; +import lombok.Getter; +import org.springframework.data.annotation.Id; + +import java.io.Serializable; +import java.util.List; + +@Getter +public class PostCache implements Serializable { + + @Id + private Long postId; + private String content; + private String imageUrl; + private Integer star; + private Integer likeCount; + private Long userId; + private List postHashtags; + private String createdAt; + + public PostCache(Post post) { + this.postId = post.getId(); + this.content = post.getContent(); + this.imageUrl = post.getImageUrl(); + this.star = post.getStar(); + this.likeCount = 0; + this.userId = post.getUser().getId(); + this.postHashtags = post.getPostHashtags().stream() + .map(Hashtag::getName) + .toList(); + this.createdAt = LocalDateTimeConverter.convert(post.getCreatedAt()); + } + + public String getKey() { + return "Post:" + postId; + } + +} diff --git a/src/main/java/com/goormy/hackathon/redis/repository/FeedHashtagRedisRepository.java b/src/main/java/com/goormy/hackathon/redis/repository/FeedHashtagRedisRepository.java new file mode 100644 index 0000000..050c9a9 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/repository/FeedHashtagRedisRepository.java @@ -0,0 +1,21 @@ +package com.goormy.hackathon.redis.repository; + +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.redis.entity.FeedSimpleInfo; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class FeedHashtagRedisRepository { + + private final RedisTemplate redisTemplate; + + public void save(Long hashtagId, Post post) { + String key = "FeedHashtag:" + hashtagId; + Object value = new FeedSimpleInfo(post); + redisTemplate.opsForList().leftPush(key, value); + } + +} diff --git a/src/main/java/com/goormy/hackathon/redis/repository/FeedUserRedisRepository.java b/src/main/java/com/goormy/hackathon/redis/repository/FeedUserRedisRepository.java new file mode 100644 index 0000000..c4b1d47 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/repository/FeedUserRedisRepository.java @@ -0,0 +1,21 @@ +package com.goormy.hackathon.redis.repository; + +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.redis.entity.FeedSimpleInfo; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class FeedUserRedisRepository { + + private final RedisTemplate redisTemplate; + + public void save(Long userId, Post post) { + String key = "PostUser:" + userId; + Object value = new FeedSimpleInfo(post); + redisTemplate.opsForList().leftPush(key, value); + } + +} diff --git a/src/main/java/com/goormy/hackathon/redis/repository/FollowListRedisRepository.java b/src/main/java/com/goormy/hackathon/redis/repository/FollowListRedisRepository.java new file mode 100644 index 0000000..4c7335b --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/repository/FollowListRedisRepository.java @@ -0,0 +1,21 @@ +package com.goormy.hackathon.redis.repository; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class FollowListRedisRepository { + + private final RedisTemplate redisTemplate; + + // TODO: 수정 필요 - save 하는 쪽이 어떤 식으로 저장하느냐에 따라 호출 구현이 다를 듯 + public List findUserIdList(Long hashtagId) { + String key = "FollowList:" + hashtagId; + return (List) redisTemplate.opsForValue().get(key); + } + +} diff --git a/src/main/java/com/goormy/hackathon/redis/repository/PostRedisRepository.java b/src/main/java/com/goormy/hackathon/redis/repository/PostRedisRepository.java new file mode 100644 index 0000000..286f785 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/repository/PostRedisRepository.java @@ -0,0 +1,18 @@ +package com.goormy.hackathon.redis.repository; + +import com.goormy.hackathon.redis.entity.PostCache; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class PostRedisRepository { + + private final RedisTemplate redisTemplate; + + public void save(PostCache postCache) { + redisTemplate.opsForList().leftPush(postCache.getKey(), postCache); + } + +} diff --git a/src/main/java/com/goormy/hackathon/service/PostCacheService.java b/src/main/java/com/goormy/hackathon/service/PostCacheService.java new file mode 100644 index 0000000..7537bd7 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/PostCacheService.java @@ -0,0 +1,50 @@ +package com.goormy.hackathon.service; + +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.redis.entity.PostCache; +import com.goormy.hackathon.redis.repository.*; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class PostCacheService { + + private final PostRedisRepository postRedisRepository; + private final FollowCountRedisRepository followCountRedisRepository; + private final FollowListRedisRepository followListRedisRepository; + private final FeedUserRedisRepository feedUserRedisRepository; + private final FeedHashtagRedisRepository feedHashtagRedisRepository; + + // TODO: 이벤트로 발행한 후 이벤트를 받아 Redis에 비동기로 저장 + public void cache(Post post) { + postRedisRepository.save(new PostCache(post)); + for (var hashtag : post.getPostHashtags()) { + if (isPopular(hashtag)) { + pullModel(hashtag, post); + } else { + pushModel(hashtag, post); + } + } + } + + private boolean isPopular(Hashtag hashtag) { + var followCount = followCountRedisRepository.findFollowCount(hashtag.getId()); + if (followCount != null ) { + return followCount >= 5000; + } + return false; + } + + private void pushModel(Hashtag hashtag, Post post) { + var userIdList = followListRedisRepository.findUserIdList(hashtag.getId()); + userIdList.forEach(userId -> { + feedUserRedisRepository.save(Long.valueOf(userId), post); + }); + } + + private void pullModel(Hashtag hashtag, Post post) { + feedHashtagRedisRepository.save(hashtag.getId(), post); + } +} From 5455222b4e976009f9df682ce238030220f52f72 Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Wed, 31 Jul 2024 18:53:48 +0900 Subject: [PATCH 22/57] =?UTF-8?q?feat:=20LocalDateTime=EC=9D=84=20String?= =?UTF-8?q?=20=ED=98=95=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80=ED=99=98?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/LocalDateTimeConverter.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java diff --git a/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java b/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java new file mode 100644 index 0000000..be2ee4d --- /dev/null +++ b/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java @@ -0,0 +1,15 @@ +package com.goormy.hackathon.common.util; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public final class LocalDateTimeConverter { + + private LocalDateTimeConverter() { + } + + public static String convert(LocalDateTime value) { + return value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); + } + +} \ No newline at end of file From e9edec2fa041607ef79b032733dec83dfd64d71c Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Wed, 31 Jul 2024 18:57:34 +0900 Subject: [PATCH 23/57] =?UTF-8?q?refactor:=20/redis/repository=20=EC=97=90?= =?UTF-8?q?=20=EC=9E=88=EB=8A=94=20=ED=8C=8C=EC=9D=BC=EB=93=A4=EC=9D=84=20?= =?UTF-8?q?/repository=20=EB=A1=9C=20=EC=9D=B4=EB=8F=99=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{redis => }/repository/FeedHashtagRedisRepository.java | 2 +- .../{redis => }/repository/FeedUserRedisRepository.java | 2 +- .../{redis => }/repository/FollowCountRedisRepository.java | 2 +- .../{redis => }/repository/FollowListRedisRepository.java | 2 +- .../hackathon/{redis => }/repository/PostRedisRepository.java | 2 +- src/main/java/com/goormy/hackathon/service/HashtagService.java | 2 +- .../java/com/goormy/hackathon/service/PostCacheService.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) rename src/main/java/com/goormy/hackathon/{redis => }/repository/FeedHashtagRedisRepository.java (92%) rename src/main/java/com/goormy/hackathon/{redis => }/repository/FeedUserRedisRepository.java (92%) rename src/main/java/com/goormy/hackathon/{redis => }/repository/FollowCountRedisRepository.java (94%) rename src/main/java/com/goormy/hackathon/{redis => }/repository/FollowListRedisRepository.java (92%) rename src/main/java/com/goormy/hackathon/{redis => }/repository/PostRedisRepository.java (90%) diff --git a/src/main/java/com/goormy/hackathon/redis/repository/FeedHashtagRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java similarity index 92% rename from src/main/java/com/goormy/hackathon/redis/repository/FeedHashtagRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java index 050c9a9..1be24e0 100644 --- a/src/main/java/com/goormy/hackathon/redis/repository/FeedHashtagRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.redis.repository; +package com.goormy.hackathon.repository; import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.redis.entity.FeedSimpleInfo; diff --git a/src/main/java/com/goormy/hackathon/redis/repository/FeedUserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java similarity index 92% rename from src/main/java/com/goormy/hackathon/redis/repository/FeedUserRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java index c4b1d47..4e6b48e 100644 --- a/src/main/java/com/goormy/hackathon/redis/repository/FeedUserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.redis.repository; +package com.goormy.hackathon.repository; import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.redis.entity.FeedSimpleInfo; diff --git a/src/main/java/com/goormy/hackathon/redis/repository/FollowCountRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java similarity index 94% rename from src/main/java/com/goormy/hackathon/redis/repository/FollowCountRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java index b7f110e..8c62662 100644 --- a/src/main/java/com/goormy/hackathon/redis/repository/FollowCountRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.redis.repository; +package com.goormy.hackathon.repository; import com.goormy.hackathon.redis.entity.FollowCountCache; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/goormy/hackathon/redis/repository/FollowListRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java similarity index 92% rename from src/main/java/com/goormy/hackathon/redis/repository/FollowListRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java index 4c7335b..e263b41 100644 --- a/src/main/java/com/goormy/hackathon/redis/repository/FollowListRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.redis.repository; +package com.goormy.hackathon.repository; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; diff --git a/src/main/java/com/goormy/hackathon/redis/repository/PostRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java similarity index 90% rename from src/main/java/com/goormy/hackathon/redis/repository/PostRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java index 286f785..95a6e67 100644 --- a/src/main/java/com/goormy/hackathon/redis/repository/PostRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.redis.repository; +package com.goormy.hackathon.repository; import com.goormy.hackathon.redis.entity.PostCache; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/goormy/hackathon/service/HashtagService.java b/src/main/java/com/goormy/hackathon/service/HashtagService.java index b1815f0..3c01b7e 100644 --- a/src/main/java/com/goormy/hackathon/service/HashtagService.java +++ b/src/main/java/com/goormy/hackathon/service/HashtagService.java @@ -3,7 +3,7 @@ import com.goormy.hackathon.dto.hashtag.PostHashtagRequestDto; import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.redis.entity.FollowCountCache; -import com.goormy.hackathon.redis.repository.FollowCountRedisRepository; +import com.goormy.hackathon.repository.FollowCountRedisRepository; import com.goormy.hackathon.repository.HashtagRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; diff --git a/src/main/java/com/goormy/hackathon/service/PostCacheService.java b/src/main/java/com/goormy/hackathon/service/PostCacheService.java index 7537bd7..0c5a5ae 100644 --- a/src/main/java/com/goormy/hackathon/service/PostCacheService.java +++ b/src/main/java/com/goormy/hackathon/service/PostCacheService.java @@ -3,7 +3,7 @@ import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.redis.entity.PostCache; -import com.goormy.hackathon.redis.repository.*; +import com.goormy.hackathon.repository.*; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; From edc6d1035c31b95f8752bb7cf59edc0ea6015957 Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Wed, 31 Jul 2024 19:11:45 +0900 Subject: [PATCH 24/57] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=83=81=EC=86=8D=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/goormy/hackathon/dto/post/PostResponseDto.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java b/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java index ec6b69f..2343b8b 100644 --- a/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java +++ b/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java @@ -15,7 +15,7 @@ public record PostResponseDto( List postHashtags, LocalDateTime createdAt -) implements Serializable { +) { public PostResponseDto(Post post) { this( From 8ac82bdaf26a16f95ede2f81794f9e183766fdf8 Mon Sep 17 00:00:00 2001 From: seonghooni Date: Wed, 31 Jul 2024 19:04:03 +0900 Subject: [PATCH 25/57] =?UTF-8?q?chore:=20application-redis.yml=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-redis.yml | 5 +++++ src/main/resources/application.yml | 10 +++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/application-redis.yml diff --git a/src/main/resources/application-redis.yml b/src/main/resources/application-redis.yml new file mode 100644 index 0000000..e231226 --- /dev/null +++ b/src/main/resources/application-redis.yml @@ -0,0 +1,5 @@ +spring: + data: + redis: + host: ${REDIS_HOST:localhost} + port: ${REDIS_PORT:6379} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index d3542c0..98edb09 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,4 +1,8 @@ spring: + data: + redis: + host: localhost + port: 6379 datasource: url: ${MYSQL_URL:jdbc:mysql://localhost}:${MYSQL_PORT:3306}/${MYSQL_SCHEMA:dev} driver-class-name: com.mysql.cj.jdbc.Driver @@ -12,10 +16,14 @@ spring: hibernate: format_sql: true use_sql_comments: true + profiles: + include: + - redis + - swagger logging: level: org: hibernate: type: descriptor: - sql: trace \ No newline at end of file + sql: trace From 566e98447c46c4027e598a4b9e4c9880842ea38b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Wed, 31 Jul 2024 19:36:07 +0900 Subject: [PATCH 26/57] =?UTF-8?q?feat:=20redis=20->=20DB=20=EB=A7=88?= =?UTF-8?q?=EC=9D=B4=EA=B7=B8=EB=A0=88=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hackathon/HackathonApplication.java | 2 + .../hackathon/lambda/FollowFunction.java | 36 ++++++++++++++- .../repository/FollowRedisRepository.java | 46 ++++++++++++++++--- 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/HackathonApplication.java b/src/main/java/com/goormy/hackathon/HackathonApplication.java index be8645a..80c6918 100644 --- a/src/main/java/com/goormy/hackathon/HackathonApplication.java +++ b/src/main/java/com/goormy/hackathon/HackathonApplication.java @@ -2,8 +2,10 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication +@EnableScheduling public class HackathonApplication { public static void main(String[] args) { diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index 7234e83..da56ff9 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -3,20 +3,35 @@ import com.goormy.hackathon.entity.Follow; import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.repository.FollowRedisRepository; import com.goormy.hackathon.repository.FollowRepository; import com.goormy.hackathon.repository.HashtagRepository; import com.goormy.hackathon.repository.UserRepository; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.Scheduled; +import java.util.List; import java.util.Map; import java.util.function.Consumer; @Configuration public class FollowFunction{ + private final FollowRepository followRepository; + private final UserRepository userRepository; + private final HashtagRepository hashtagRepository; + private final FollowRedisRepository followRedisRepository; + + public FollowFunction(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository, FollowRedisRepository followRedisRepository) { + this.followRepository = followRepository; + this.userRepository = userRepository; + this.hashtagRepository = hashtagRepository; + this.followRedisRepository = followRedisRepository; + } + @Bean - public Consumer> processFollow(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository) { + public Consumer> processFollow() { return messageBody -> { try { // userId와 hashtagId를 Number로 파싱하고 long으로 변환 @@ -30,11 +45,13 @@ public Consumer> processFollow(FollowRepository followReposi if ("follow".equals(action)) { Follow follow = new Follow(user,hashtag); followRepository.save(follow); + followRedisRepository.insertFollow(hashtagId, userId); System.out.println("팔로우 성공: " + messageBody); } else if ("unfollow".equals(action)) { Follow follow = followRepository.findByUserIdAndHashTagId(userId, hashtagId) .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); followRepository.delete(follow); + followRedisRepository.removeFollow(hashtagId, userId); System.out.println("팔로우 취소 성공: " + messageBody); } else { System.out.println("존재하지 않는 action입니다 : " + action); @@ -45,4 +62,21 @@ public Consumer> processFollow(FollowRepository followReposi } }; } + + // Redis 데이터를 RDBMS에 저장하고 Redis 비우기 + @Scheduled(cron = "0 0 0 * * *") // 매일 자정에 실행 + public void migrateData() { + // Redis에서 모든 팔로우 데이터 가져오기 + List follows = followRedisRepository.getAllFollows(); + + // RDBMS에 배치 저장 + followRepository.deleteAll(); + followRepository.saveAll(follows); + + // Redis 비우기 + + System.out.println("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); + } + + } diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java index 38f0df7..b1c7a1a 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java @@ -1,26 +1,60 @@ package com.goormy.hackathon.repository; +import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + @Repository public class FollowRedisRepository { @Autowired RedisTemplate redisTemplate; + @Autowired + FollowRepository followRepository; + public void insertFollow(Long hashtagId, Long userId) { String key = "hashtagId: " + hashtagId.toString(); - redisTemplate.opsForList().rightPush(key, userId.toString()); + redisTemplate.opsForList().rightPush(key, userId); } public void removeFollow(Long hashtagId, Long userId) { String key = "hashtagId:" + hashtagId.toString(); - redisTemplate.opsForList().remove(key, 0, userId.toString()); + redisTemplate.opsForList().remove(key, 0, userId); } - public void removeAllFollows(Long hashtagId) { - String key = "hashtagId:" + hashtagId.toString(); - redisTemplate.delete(key); - }} + public List getAllFollows() { + // Redis에서 데이터를 가져와 RDBMS로 마이그레이션 + List follows = new ArrayList<>(); + + // 모든 키 가져오기 + Set keys = redisTemplate.keys("hashtagId:*"); + + if (keys != null) { + for (String key : keys) { + List userIds = (List) (List) redisTemplate.opsForList().range(key, 0, -1); + if (userIds != null) { + for (Long userId : userIds) { + Long hashtagId = Long.parseLong(key.split(":")[1]); + Follow follow = followRepository.findByUserIdAndHashTagId(userId,hashtagId) + .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); + follows.add(follow); + } + } + } + } + + return follows; + } + + + + +} From e8c9bb87874c988e17018a5836ad61f69189d073 Mon Sep 17 00:00:00 2001 From: Ga Dong Sik Date: Wed, 31 Jul 2024 21:24:30 +0900 Subject: [PATCH 27/57] =?UTF-8?q?fix:=20null=EB=A1=9C=20=EC=9D=B8=ED=95=B4?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=ED=95=98=EB=8A=94=20stream=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=82=AC=ED=95=AD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/GetFeedController.java | 17 ++++++++++- .../converter/LocalDateTimeConverter.java | 2 +- .../hackathon/service/GetFeedService.java | 30 ++++++++++++++----- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java index d714629..d2b38c3 100644 --- a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java +++ b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java @@ -43,6 +43,21 @@ public ResponseEntity> getFeedList( return ResponseEntity.ok(getFeedService.getFeedList(userId, size)); } + @PostMapping("/hashfeed") + public ResponseEntity addFeedHashtagData( + @RequestHeader Long userId, + @RequestBody AddFeedUser requestDto + ) { + requestDto.getInfoList().forEach( + info -> + feedHashtagRedisRepository.add(userId, + PostSimpleInfo.toEntity(info.getPostId(), info.getCreatedAt())) + ); + + // 피드 리스트 반환 + return ResponseEntity.ok("ok"); + } + @PostMapping("/userfeed") public ResponseEntity addFeedUserData( @RequestHeader Long userId, @@ -50,7 +65,7 @@ public ResponseEntity addFeedUserData( ) { requestDto.getInfoList().forEach( info -> - feedHashtagRedisRepository.add(userId, + feedUserRedisRepository.add(userId, PostSimpleInfo.toEntity(info.getPostId(), info.getCreatedAt())) ); diff --git a/src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java b/src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java index 25f9139..17c884a 100644 --- a/src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java +++ b/src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java @@ -8,7 +8,7 @@ @Component public class LocalDateTimeConverter { - private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); public LocalDateTime convertToLocalDateTime(String source) { try { diff --git a/src/main/java/com/goormy/hackathon/service/GetFeedService.java b/src/main/java/com/goormy/hackathon/service/GetFeedService.java index 6e16690..26b0ff6 100644 --- a/src/main/java/com/goormy/hackathon/service/GetFeedService.java +++ b/src/main/java/com/goormy/hackathon/service/GetFeedService.java @@ -15,10 +15,12 @@ import com.goormy.hackathon.repository.RecentUpdateRedisRepository; import com.goormy.hackathon.repository.UserRedisRepository; import com.goormy.hackathon.repository.UserRespository; +import jakarta.transaction.Transactional; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Objects; import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -45,7 +47,7 @@ private UserRedis getUser(Long userId) { // 캐시에 없으면 RDB에서 검색 return userCacheOptional.orElseGet(() -> { User user = userRespository.findById(userId) - .orElseThrow(() -> new RuntimeException("User not found")); // 적절한 예외로 변경 필요 + .orElseThrow(() -> new RuntimeException("유저 정보가 없습니다.")); // 적절한 예외로 변경 필요 List followIdList = user.getFollows().stream() .map(Follow::getId) .toList(); @@ -64,8 +66,8 @@ private List getPushPullFeed(UserRedis userRedis) { // recentUpdatedTime - 가장 마지막으로 업데이트한 시간이랑 3일 중 현재와 가장 가까운 시간을 기준으로 잡음 LocalDateTime now = LocalDateTime.now(); - LocalDateTime recentUpdatedTime = recentUpdateRedisRepository.get( - userRedis.getId()).orElse(now.minusDays(3)); + LocalDateTime recentUpdatedTime = now.minusDays(3);// recentUpdateRedisRepository.get( + //userRedis.getId()).orElse(now.minusDays(3)); // *** 2. Push 방식 *** // Push 방식으로 저장되어있는 포스트 가져오기 -> Created At 정보도 같이 저장해야함 @@ -89,7 +91,8 @@ private List getPushPullFeed(UserRedis userRedis) { followId -> { List info = feedHashtagRedisRepository.getAll(followId); postSimpleInfoList.addAll(info.stream() - //.filter(simpleInfo -> simpleInfo.getCreatedAt().isAfter(recentUpdatedTime)) + .filter(simpleInfo -> localDateTimeConverter.convertToLocalDateTime( + simpleInfo.getCreatedAt()).isAfter(recentUpdatedTime)) .toList() ); } @@ -122,7 +125,13 @@ private List splitPostSimpleInfoList(List postSimpleInfoLi // 5. PostList를 가져옴 private List getPostList(List postIdList) { List postRedisList = new ArrayList<>(postRedisRepository.getAll(postIdList)); - List postCacheIdList = postRedisList.stream().map(PostRedis::getId).toList(); + if (postRedisList.isEmpty()) { + return new ArrayList<>(); + } + List postCacheIdList = postRedisList.stream() + .filter(Objects::nonNull) // Filter out nulls + .map(PostRedis::getId) + .toList(); // cache에 없는 post id 리스트를 찾음 List postIdListNotInCache = postIdList.stream() @@ -142,10 +151,11 @@ private List getPostList(List postIdList) { // TODO: postId별로 like여부 받아오는 코드 추가 - return postRedisList; + return postRedisList.stream().filter(Objects::nonNull).toList(); } // TODO: 각 포스트의 가중치를 생각해서 정렬하기 -> 일단은 날짜 기준으로 정렬되어있어서 패스 + @Transactional public List getFeedList(Long userId, int size) { // 1. 사용자 정보 가져오기 (Redis -> RDS) - 완료 UserRedis userRedis = getUser(userId); @@ -155,7 +165,8 @@ public List getFeedList(Long userId, int size) { // 2, 3. Push, Pull로 Feed List 가져오기 & 필터링 // id, createdAt을 함께 가진 PostSimpleInfo 데이터 리스트 // 나중에 (1)여기 먼저 조회 & 있으면 반환, 없으면 (2)push/pull 확인 후 부족하면 (3)인기 게시글 반환 - List pushPullFeedList = getPushPullFeed(userRedis); + List pushPullFeedList = getPushPullFeed(userRedis).stream() + .filter(Objects::nonNull).toList(); // 4. 최신순으로 정렬 List sortedPushPullFeedList = pushPullFeedList.stream() @@ -165,7 +176,10 @@ public List getFeedList(Long userId, int size) { // 5. 반환할 데이터와, Redis에 저장할 데이터를 구분하고, Redis에 저장 List postIdListForReturn = splitPostSimpleInfoList(sortedPushPullFeedList, size); // 5. post를 조회해서 반환 - return getPostList(postIdListForReturn).stream().map(GetFeedResponseDto::toDto).toList(); + + List data = getPostList(postIdListForReturn); + List returnDto = data.stream().map(GetFeedResponseDto::toDto).toList(); + return returnDto; } } From 6cbeecffd972788e4a3facb1cca0e53686c54d29 Mon Sep 17 00:00:00 2001 From: Ga Dong Sik Date: Wed, 31 Jul 2024 21:39:52 +0900 Subject: [PATCH 28/57] =?UTF-8?q?feat:=20FeedUserSortRedisRepository=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20&=20RecentUpdateRedis=20TTL=203=EC=9D=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FeedUserSortRedisRepository.java | 30 +++++++++++++++++++ .../RecentUpdateRedisRepository.java | 8 +++-- .../hackathon/service/GetFeedService.java | 21 ++++++------- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java index 19e651b..05a1ded 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java @@ -1,5 +1,35 @@ package com.goormy.hackathon.repository; +import com.goormy.hackathon.redis.entity.PostSimpleInfo; +import jakarta.annotation.PostConstruct; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.ListOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor public class FeedUserSortRedisRepository { + private final RedisTemplate redisTemplate; + private static final String FEED_USER_SORTED_KEY = "feed_user_sort:"; + + private ListOperations listOperations; + + @PostConstruct + private void init() { + listOperations = redisTemplate.opsForList(); + } + + public void add(Long userId, PostSimpleInfo value) { + listOperations.leftPush(FEED_USER_SORTED_KEY + userId, value); + } + + public List getSome(Long userId, int size) { + return listOperations.rightPop(FEED_USER_SORTED_KEY + userId, size); + } + public List getAll(Long userId) { + return listOperations.rightPop(FEED_USER_SORTED_KEY + userId, Long.MAX_VALUE); + } } diff --git a/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java index f598546..57c9c59 100644 --- a/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java @@ -1,11 +1,11 @@ package com.goormy.hackathon.repository; import jakarta.annotation.PostConstruct; +import java.time.Duration; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; - import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.Optional; @@ -15,9 +15,11 @@ public class RecentUpdateRedisRepository { private final StringRedisTemplate stringRedisTemplate; - private static final String RECENT_UPDATE_KEY = "recent_update:"; private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; + private static final String RECENT_UPDATE_KEY = "recent_update:"; + private static final Duration TTL = Duration.ofDays(3); + private ValueOperations valueOperations; @PostConstruct @@ -27,7 +29,7 @@ private void init() { public void set(Long userId, LocalDateTime value) { String formattedValue = value.format(FORMATTER); - valueOperations.set(RECENT_UPDATE_KEY + userId, formattedValue); + valueOperations.set(RECENT_UPDATE_KEY + userId, formattedValue, TTL); } public Optional get(Long userId) { diff --git a/src/main/java/com/goormy/hackathon/service/GetFeedService.java b/src/main/java/com/goormy/hackathon/service/GetFeedService.java index 26b0ff6..9c1288a 100644 --- a/src/main/java/com/goormy/hackathon/service/GetFeedService.java +++ b/src/main/java/com/goormy/hackathon/service/GetFeedService.java @@ -10,6 +10,7 @@ import com.goormy.hackathon.redis.entity.UserRedis; import com.goormy.hackathon.repository.FeedHashtagRedisRepository; import com.goormy.hackathon.repository.FeedUserRedisRepository; +import com.goormy.hackathon.repository.FeedUserSortRedisRepository; import com.goormy.hackathon.repository.PostRedisRepository; import com.goormy.hackathon.repository.PostRepository; import com.goormy.hackathon.repository.RecentUpdateRedisRepository; @@ -34,11 +35,12 @@ public class GetFeedService { private final LocalDateTimeConverter localDateTimeConverter; - private final UserRedisRepository userRedisRepository; + private final FeedHashtagRedisRepository feedHashtagRedisRepository; + private final FeedUserRedisRepository feedUserRedisRepository; + private final FeedUserSortRedisRepository feedUserSortRedisRepository; private final PostRedisRepository postRedisRepository; private final RecentUpdateRedisRepository recentUpdateRedisRepository; - private final FeedUserRedisRepository feedUserRedisRepository; - private final FeedHashtagRedisRepository feedHashtagRedisRepository; + private final UserRedisRepository userRedisRepository; // 1. 사용자 정보를 가져옴 private UserRedis getUser(Long userId) { @@ -65,7 +67,6 @@ private List getPushPullFeed(UserRedis userRedis) { // 날짜 세팅 // recentUpdatedTime - 가장 마지막으로 업데이트한 시간이랑 3일 중 현재와 가장 가까운 시간을 기준으로 잡음 LocalDateTime now = LocalDateTime.now(); - LocalDateTime recentUpdatedTime = now.minusDays(3);// recentUpdateRedisRepository.get( //userRedis.getId()).orElse(now.minusDays(3)); @@ -112,8 +113,8 @@ private List splitPostSimpleInfoList(List postSimpleInfoLi // TODO: 나머지 정렬한 값을 Redis에 저장 List postSimpleInfoListForRedis = postSimpleInfoList.stream() - .skip(size) - .toList(); + .skip(size).toList(); + // 사용자에게 반환할 게시글 리스트 return postSimpleInfoList.stream() @@ -154,19 +155,19 @@ private List getPostList(List postIdList) { return postRedisList.stream().filter(Objects::nonNull).toList(); } - // TODO: 각 포스트의 가중치를 생각해서 정렬하기 -> 일단은 날짜 기준으로 정렬되어있어서 패스 + // 날짜 기준으로 정렬하는 것으로 우선순위 선정 @Transactional public List getFeedList(Long userId, int size) { - // 1. 사용자 정보 가져오기 (Redis -> RDS) - 완료 + // 1. 사용자 정보 가져오기 (Redis -> RDS) + // TODO: 사용자 정보에 Follow ID List 가져오는 로직 추가 필요 UserRedis userRedis = getUser(userId); // TODO: 2.0 진행 예정 // 2, 3. Push, Pull로 Feed List 가져오기 & 필터링 - // id, createdAt을 함께 가진 PostSimpleInfo 데이터 리스트 // 나중에 (1)여기 먼저 조회 & 있으면 반환, 없으면 (2)push/pull 확인 후 부족하면 (3)인기 게시글 반환 List pushPullFeedList = getPushPullFeed(userRedis).stream() - .filter(Objects::nonNull).toList(); + .filter(Objects::nonNull).toList(); // 여기서 Null 체크, 이후 리스트에 들어가는 모든 post는 null이 있을 수 없음 // 4. 최신순으로 정렬 List sortedPushPullFeedList = pushPullFeedList.stream() From da6b0008b30d3b7a662a2fff2ac1d53eefb584d7 Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Wed, 31 Jul 2024 22:45:57 +0900 Subject: [PATCH 29/57] =?UTF-8?q?refactor:=20FollowListCache=EC=97=90?= =?UTF-8?q?=EC=84=9C=20userIdList=20=ED=95=84=EB=93=9C=EC=9D=98=20?= =?UTF-8?q?=EC=9E=90=EB=A3=8C=ED=98=95=EC=9D=84=20List=20->=20Lis?= =?UTF-8?q?t=20=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/goormy/hackathon/redis/entity/FollowListCache.java | 2 +- .../hackathon/repository/FollowListRedisRepository.java | 4 ++-- .../java/com/goormy/hackathon/service/PostCacheService.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java b/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java index 3f2a1ea..6557b8e 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java @@ -11,6 +11,6 @@ public class FollowListCache implements Serializable { @Id private String hashtagId; - private List userIdList; + private List userIdList; } diff --git a/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java index e263b41..fa1c748 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java @@ -13,9 +13,9 @@ public class FollowListRedisRepository { private final RedisTemplate redisTemplate; // TODO: 수정 필요 - save 하는 쪽이 어떤 식으로 저장하느냐에 따라 호출 구현이 다를 듯 - public List findUserIdList(Long hashtagId) { + public List findUserIdList(Long hashtagId) { String key = "FollowList:" + hashtagId; - return (List) redisTemplate.opsForValue().get(key); + return (List) redisTemplate.opsForValue().get(key); } } diff --git a/src/main/java/com/goormy/hackathon/service/PostCacheService.java b/src/main/java/com/goormy/hackathon/service/PostCacheService.java index 0c5a5ae..d37235e 100644 --- a/src/main/java/com/goormy/hackathon/service/PostCacheService.java +++ b/src/main/java/com/goormy/hackathon/service/PostCacheService.java @@ -40,7 +40,7 @@ private boolean isPopular(Hashtag hashtag) { private void pushModel(Hashtag hashtag, Post post) { var userIdList = followListRedisRepository.findUserIdList(hashtag.getId()); userIdList.forEach(userId -> { - feedUserRedisRepository.save(Long.valueOf(userId), post); + feedUserRedisRepository.save(userId, post); }); } From 218f6ab7048472516c2ec9ce4cce85074f094a1f Mon Sep 17 00:00:00 2001 From: seonghooni Date: Wed, 31 Jul 2024 22:51:46 +0900 Subject: [PATCH 30/57] =?UTF-8?q?chore:=20AWSConfig.java=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../goormy/hackathon/config/AwsConfig.java | 32 +++++++++++++++++++ .../com/goormy/hackathon/controller/dummy.txt | 0 2 files changed, 32 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/config/AwsConfig.java delete mode 100644 src/main/java/com/goormy/hackathon/controller/dummy.txt diff --git a/src/main/java/com/goormy/hackathon/config/AwsConfig.java b/src/main/java/com/goormy/hackathon/config/AwsConfig.java new file mode 100644 index 0000000..811fab9 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/config/AwsConfig.java @@ -0,0 +1,32 @@ +package com.goormy.hackathon.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.sqs.SqsClient; + +@Configuration +public class AwsConfig { + + + @Value("${spring.cloud.aws.credentials.access-key}") + private String accessKey; + + @Value("${spring.cloud.aws.credentials.secret-key}") + private String secretKey; + + @Value("${spring.cloud.aws.region.static}") + private String region; + + @Bean + public SqsClient sqsClient() { + return SqsClient.builder() + .region(Region.of(region)) + .credentialsProvider(StaticCredentialsProvider.create( + AwsBasicCredentials.create(accessKey, secretKey))) + .build(); + } +} diff --git a/src/main/java/com/goormy/hackathon/controller/dummy.txt b/src/main/java/com/goormy/hackathon/controller/dummy.txt deleted file mode 100644 index e69de29..0000000 From 165d549628d1fe25b38560cb18bc8d7f932aa8d6 Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Wed, 31 Jul 2024 22:53:04 +0900 Subject: [PATCH 31/57] =?UTF-8?q?refactor:=20FeedUserCache=20=ED=82=A4=20?= =?UTF-8?q?=EA=B0=92=20=EB=B3=80=EA=B2=BD=20PostUser=20->=20FeedUser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../goormy/hackathon/repository/FeedUserRedisRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java index 4e6b48e..8256f96 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java @@ -13,7 +13,7 @@ public class FeedUserRedisRepository { private final RedisTemplate redisTemplate; public void save(Long userId, Post post) { - String key = "PostUser:" + userId; + String key = "FeedUser:" + userId; Object value = new FeedSimpleInfo(post); redisTemplate.opsForList().leftPush(key, value); } From fac9813f5aa26c4d5aaff35a796530e1adbcf28b Mon Sep 17 00:00:00 2001 From: Ga Dong Sik Date: Wed, 31 Jul 2024 23:36:43 +0900 Subject: [PATCH 32/57] =?UTF-8?q?refac:=20=EC=82=AC=EC=86=8C=ED=95=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util}/LocalDateTimeConverter.java | 4 +- .../controller/GetFeedController.java | 8 +- .../hackathon/redis/config/RedisConfig.java | 13 ++- .../redis/entity/PostSimpleInfo.java | 14 ++-- .../FeedHashtagRedisRepository.java | 2 +- .../repository/FeedUserRedisRepository.java | 2 +- .../FeedUserSortRedisRepository.java | 16 ++-- .../repository/FollowRepository.java | 8 ++ .../repository/LikeRedisRepository.java | 80 ------------------- .../repository/PostRedisRepository.java | 3 +- .../RecentUpdateRedisRepository.java | 2 +- .../repository/UserRedisRepository.java | 2 +- .../hackathon/service/GetFeedService.java | 60 +++++++------- 13 files changed, 78 insertions(+), 136 deletions(-) rename src/main/java/com/goormy/hackathon/{converter => common/util}/LocalDateTimeConverter.java (90%) create mode 100644 src/main/java/com/goormy/hackathon/repository/FollowRepository.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java diff --git a/src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java b/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java similarity index 90% rename from src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java rename to src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java index 17c884a..93a8456 100644 --- a/src/main/java/com/goormy/hackathon/converter/LocalDateTimeConverter.java +++ b/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.converter; +package com.goormy.hackathon.common.util; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -8,7 +8,7 @@ @Component public class LocalDateTimeConverter { - private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public LocalDateTime convertToLocalDateTime(String source) { try { diff --git a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java index d2b38c3..617999c 100644 --- a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java +++ b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java @@ -1,5 +1,6 @@ package com.goormy.hackathon.controller; +import com.goormy.hackathon.common.util.LocalDateTimeConverter; import com.goormy.hackathon.dto.request.AddFeedUser; import com.goormy.hackathon.dto.response.GetFeedResponseDto; import com.goormy.hackathon.redis.entity.PostSimpleInfo; @@ -23,6 +24,7 @@ public class GetFeedController { private final GetFeedService getFeedService; + private final LocalDateTimeConverter localDateTimeConverter; private final FeedUserRedisRepository feedUserRedisRepository; private final FeedHashtagRedisRepository feedHashtagRedisRepository; @@ -51,7 +53,8 @@ public ResponseEntity addFeedHashtagData( requestDto.getInfoList().forEach( info -> feedHashtagRedisRepository.add(userId, - PostSimpleInfo.toEntity(info.getPostId(), info.getCreatedAt())) + PostSimpleInfo.toEntity(info.getPostId(), + localDateTimeConverter.convertToString(info.getCreatedAt()))) ); // 피드 리스트 반환 @@ -66,7 +69,8 @@ public ResponseEntity addFeedUserData( requestDto.getInfoList().forEach( info -> feedUserRedisRepository.add(userId, - PostSimpleInfo.toEntity(info.getPostId(), info.getCreatedAt())) + PostSimpleInfo.toEntity(info.getPostId(), + localDateTimeConverter.convertToString(info.getCreatedAt()))) ); // 피드 리스트 반환 diff --git a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java index b9a91c5..50aaa07 100644 --- a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java +++ b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java @@ -14,6 +14,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; +import org.springframework.data.redis.serializer.GenericToStringSerializer; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @@ -34,9 +35,6 @@ public RedisConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory(host, port); } - @Autowired - private ObjectMapper objectMapper; - @Bean public RedisTemplate redisTemplate() { RedisTemplate redisTemplate = new RedisTemplate<>(); @@ -98,4 +96,13 @@ public StringRedisTemplate stringRedisTemplate() { return stringRedisTemplate; } + @Bean + public RedisTemplate longRedisTemplate(RedisConnectionFactory redisConnectionFactory) { + final RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new GenericToStringSerializer<>(Long.class)); + redisTemplate.setConnectionFactory(redisConnectionFactory); + return redisTemplate; + } + } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java b/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java index b93b191..277bb80 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java @@ -6,31 +6,33 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.goormy.hackathon.common.util.LocalDateTimeConverter; import java.time.LocalDate; import java.time.LocalDateTime; import lombok.Builder; import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.hibernate.annotations.CreationTimestamp; @Getter @Builder public class PostSimpleInfo { - private Long postId; + private Long id; private String createdAt; @JsonCreator public PostSimpleInfo( - @JsonProperty("postId") Long postId, + @JsonProperty("id") Long postId, @JsonProperty("createdAt") String createdAt) { - this.postId = postId; + this.id = postId; this.createdAt = createdAt; } - public static PostSimpleInfo toEntity(Long postId, LocalDateTime createdAt) { + public static PostSimpleInfo toEntity(Long postId, String createdAt) { return PostSimpleInfo.builder() - .postId(postId) - .createdAt(createdAt.toString()) + .id(postId) + .createdAt(createdAt) .build(); } diff --git a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java index d8741e9..7463f02 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java @@ -13,7 +13,7 @@ public class FeedHashtagRedisRepository { private final RedisTemplate redisTemplate; - private static final String FEED_HASHTAG_KEY = "feed_hashtag:"; + private static final String FEED_HASHTAG_KEY = "FeedHashtag:"; private ListOperations listOperations; diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java index d26f98c..578e476 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java @@ -13,7 +13,7 @@ public class FeedUserRedisRepository { private final RedisTemplate redisTemplate; - private static final String FEED_USER_KEY = "feed_user:"; + private static final String FEED_USER_KEY = "FeedUser:"; private ListOperations listOperations; diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java index 05a1ded..19eb45d 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java @@ -1,6 +1,5 @@ package com.goormy.hackathon.repository; -import com.goormy.hackathon.redis.entity.PostSimpleInfo; import jakarta.annotation.PostConstruct; import java.util.List; import lombok.RequiredArgsConstructor; @@ -11,25 +10,26 @@ @Component @RequiredArgsConstructor public class FeedUserSortRedisRepository { - private final RedisTemplate redisTemplate; - private static final String FEED_USER_SORTED_KEY = "feed_user_sort:"; - private ListOperations listOperations; + private final RedisTemplate redisTemplate; + private static final String FEED_USER_SORTED_KEY = "FeedUserSort:"; + + private ListOperations listOperations; @PostConstruct private void init() { listOperations = redisTemplate.opsForList(); } - public void add(Long userId, PostSimpleInfo value) { - listOperations.leftPush(FEED_USER_SORTED_KEY + userId, value); + public void add(Long userId, Long postId) { + listOperations.leftPush(FEED_USER_SORTED_KEY + userId, postId); } - public List getSome(Long userId, int size) { + public List getSome(Long userId, int size) { return listOperations.rightPop(FEED_USER_SORTED_KEY + userId, size); } - public List getAll(Long userId) { + public List getAll(Long userId) { return listOperations.rightPop(FEED_USER_SORTED_KEY + userId, Long.MAX_VALUE); } } diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowRepository.java new file mode 100644 index 0000000..3c55fa6 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/FollowRepository.java @@ -0,0 +1,8 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.Follow; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface FollowRepository extends JpaRepository { + +} diff --git a/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java deleted file mode 100644 index 3b9fd8b..0000000 --- a/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.goormy.hackathon.repository; - -import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.*; -import org.springframework.stereotype.Repository; - -import java.util.Map; -import java.util.Set; - -@Repository -@RequiredArgsConstructor -public class LikeRedisRepository { - - private final RedisTemplate redisTemplate; - - /** - * @description '좋아요' 정보를 업데이트 하는 함수 - * */ - public void update(Long postId, Long userId, Integer value) { - String key = "postlike:" + postId.toString(); - String field = userId.toString(); - - redisTemplate.opsForHash().put(key, field, value); - } - - /** - * @description '좋아요' 혹은 '좋아요 취소' 정보를 삭제하는 함수 - * */ - public void delete(Long postId, Long userId){ - String key = "postlike:" + postId.toString(); - String field = userId.toString(); - - redisTemplate.opsForHash().delete(key, field); - } - - /** - * @description postId와 userId에 대한 value를 조회 - * */ - public Integer findPostLikeFromCache(Long postId, Long userId) { - String key = "postlike:" + postId.toString(); - String field = userId.toString(); - - return (Integer) redisTemplate.opsForHash().get(key, field); - } - - /** - * @description Key에 대한 모든 field와 value를 조회 - * */ - public Map findByKey(String key) { - return redisTemplate.opsForHash().entries(key); - } - - /** - * @description Key에 대한 모든 field와 value를 삭제 - * */ - public void delete(String key) { - redisTemplate.delete(key); - } - - - - - public Set findAllKeys() { - Set keys = redisTemplate.keys("postlike:*"); - - return keys; - } - - // # PostId로 조회하는 함수 -// public Map findByPostId(Long postId) { -// String key = "postlike:" + postId.toString(); -// Map entries = redisTemplate.opsForHash().entries(key); -// -// return entries.entrySet().stream() -// .collect(Collectors.toMap( -// entry -> Long.valueOf((String) entry.getKey()), -// entry -> (Integer) entry.getValue() -// )); -// } -} diff --git a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java index ffc2542..0e6dfd6 100644 --- a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java @@ -3,7 +3,6 @@ import com.goormy.hackathon.redis.entity.PostRedis; import jakarta.annotation.PostConstruct; import java.util.List; -import java.util.Objects; import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; @@ -15,7 +14,7 @@ public class PostRedisRepository { private final RedisTemplate redisTemplate; - private static final String POST_KEY = "post:"; + private static final String POST_KEY = "Post:"; private ValueOperations valueOperations; diff --git a/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java index 57c9c59..c1ea7b0 100644 --- a/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java @@ -17,7 +17,7 @@ public class RecentUpdateRedisRepository { private final StringRedisTemplate stringRedisTemplate; private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; - private static final String RECENT_UPDATE_KEY = "recent_update:"; + private static final String RECENT_UPDATE_KEY = "RecentUpdate:"; private static final Duration TTL = Duration.ofDays(3); private ValueOperations valueOperations; diff --git a/src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java index 1328805..6f70d7b 100644 --- a/src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java @@ -13,7 +13,7 @@ public class UserRedisRepository { private final RedisTemplate redisTemplate; - private static final String USER_KEY = "user:"; + private static final String USER_KEY = "User:"; private ValueOperations valueOperations; diff --git a/src/main/java/com/goormy/hackathon/service/GetFeedService.java b/src/main/java/com/goormy/hackathon/service/GetFeedService.java index 9c1288a..72b90e4 100644 --- a/src/main/java/com/goormy/hackathon/service/GetFeedService.java +++ b/src/main/java/com/goormy/hackathon/service/GetFeedService.java @@ -1,6 +1,6 @@ package com.goormy.hackathon.service; -import com.goormy.hackathon.converter.LocalDateTimeConverter; +import com.goormy.hackathon.common.util.LocalDateTimeConverter; import com.goormy.hackathon.dto.response.GetFeedResponseDto; import com.goormy.hackathon.entity.Follow; import com.goormy.hackathon.entity.Post; @@ -67,8 +67,8 @@ private List getPushPullFeed(UserRedis userRedis) { // 날짜 세팅 // recentUpdatedTime - 가장 마지막으로 업데이트한 시간이랑 3일 중 현재와 가장 가까운 시간을 기준으로 잡음 LocalDateTime now = LocalDateTime.now(); - LocalDateTime recentUpdatedTime = now.minusDays(3);// recentUpdateRedisRepository.get( - //userRedis.getId()).orElse(now.minusDays(3)); + LocalDateTime recentUpdatedTime = recentUpdateRedisRepository.get(userRedis.getId()) + .orElse(now.minusDays(3)); // *** 2. Push 방식 *** // Push 방식으로 저장되어있는 포스트 가져오기 -> Created At 정보도 같이 저장해야함 @@ -84,14 +84,12 @@ private List getPushPullFeed(UserRedis userRedis) { // *** 3. Pull 방식 *** // Pull 방식으로 저장되어있는 인플루언서 포스트 가져오기 -> 사용자가 최근에 업데이트한 시간 이후부터 진행 // (이유) 한개의 Key에 있는 각 값마다 TTL 설정이 불가능하기 때문 - // user의 follow 리스트를 순회하면서 가져와야함 - // 5000명이 넘는지를 판단해야함 -> popular 캐시에 있으면 되는 것 - // 기본적인 우선순위 정보는 가지고 있어도 좋을듯 -> 꼭 필요한 Post 정보만 가지고올 수 있도록 - // 3일 전 포스트까지만 가져오기 + // user의 follow 리스트를 순회하면서 가져와야함 & 3일 전 포스트까지만 가져오기 userRedis.getFollowerIdList().forEach( followId -> { List info = feedHashtagRedisRepository.getAll(followId); postSimpleInfoList.addAll(info.stream() + .filter(Objects::nonNull) .filter(simpleInfo -> localDateTimeConverter.convertToLocalDateTime( simpleInfo.getCreatedAt()).isAfter(recentUpdatedTime)) .toList() @@ -102,35 +100,34 @@ private List getPushPullFeed(UserRedis userRedis) { // 최신 업데이트 시간 반영 recentUpdateRedisRepository.set(userRedis.getId(), now); - return postSimpleInfoList; + return postSimpleInfoList.stream().filter(Objects::nonNull).toList(); } // 5. size개의 post를 구분 - private List splitPostSimpleInfoList(List postSimpleInfoList, - int size) { + private List splitPostSimpleInfoList(UserRedis userRedis, + List postIdList, int size) { // 초기 반환을 위한 Id 리스트 - // TODO: 만약 size가 작으면 인기 게시물에서 가져와야함 - // TODO: 나머지 정렬한 값을 Redis에 저장 - List postSimpleInfoListForRedis = postSimpleInfoList.stream() + // 나머지 정렬한 값을 Redis에 저장 + List postIdListForRedis = postIdList.stream() .skip(size).toList(); - + postIdListForRedis.forEach( + postId -> feedUserSortRedisRepository.add(userRedis.getId(), postId)); // 사용자에게 반환할 게시글 리스트 - return postSimpleInfoList.stream() - .limit(size) - .map(PostSimpleInfo::getPostId) - .toList(); + return postIdList.stream().limit(size).toList(); } // 5. PostList를 가져옴 private List getPostList(List postIdList) { List postRedisList = new ArrayList<>(postRedisRepository.getAll(postIdList)); + if (postRedisList.isEmpty()) { return new ArrayList<>(); } + List postCacheIdList = postRedisList.stream() - .filter(Objects::nonNull) // Filter out nulls + .filter(Objects::nonNull) .map(PostRedis::getId) .toList(); @@ -159,28 +156,33 @@ private List getPostList(List postIdList) { @Transactional public List getFeedList(Long userId, int size) { // 1. 사용자 정보 가져오기 (Redis -> RDS) - // TODO: 사용자 정보에 Follow ID List 가져오는 로직 추가 필요 UserRedis userRedis = getUser(userId); - // TODO: 2.0 진행 예정 + // 2.0 이미 정리해둔 post가 있으면 가져오기 + List postIdList = feedUserSortRedisRepository.getSome(userId, size); + if (postIdList.size() == size) { + return getPostList(postIdList).stream().map(GetFeedResponseDto::toDto) + .toList(); + } else { + size -= postIdList.size(); + } // 2, 3. Push, Pull로 Feed List 가져오기 & 필터링 // 나중에 (1)여기 먼저 조회 & 있으면 반환, 없으면 (2)push/pull 확인 후 부족하면 (3)인기 게시글 반환 - List pushPullFeedList = getPushPullFeed(userRedis).stream() - .filter(Objects::nonNull).toList(); // 여기서 Null 체크, 이후 리스트에 들어가는 모든 post는 null이 있을 수 없음 + List pushPullFeedList = getPushPullFeed(userRedis); + // 여기서 Null 체크, 이후 리스트에 들어가는 모든 post는 null이 있을 수 없음 // 4. 최신순으로 정렬 - List sortedPushPullFeedList = pushPullFeedList.stream() + List sortedPushPullFeedList = pushPullFeedList.stream() .sorted(Comparator.comparing(PostSimpleInfo::getCreatedAt)) + .map(PostSimpleInfo::getId) .toList(); // 5. 반환할 데이터와, Redis에 저장할 데이터를 구분하고, Redis에 저장 - List postIdListForReturn = splitPostSimpleInfoList(sortedPushPullFeedList, size); + List postIdListForReturn = splitPostSimpleInfoList(userRedis, sortedPushPullFeedList, + size); // 5. post를 조회해서 반환 - - List data = getPostList(postIdListForReturn); - List returnDto = data.stream().map(GetFeedResponseDto::toDto).toList(); - return returnDto; + return getPostList(postIdListForReturn).stream().map(GetFeedResponseDto::toDto).toList(); } } From ec84b0ed7f74981b720fa66ac399d730ee048760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Thu, 1 Aug 2024 09:35:16 +0900 Subject: [PATCH 33/57] =?UTF-8?q?fix=20:=20=EB=A1=9C=EC=A7=81=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/goormy/hackathon/lambda/FollowFunction.java | 2 -- .../com/goormy/hackathon/repository/FollowRedisRepository.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index da56ff9..899d5d4 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -44,13 +44,11 @@ public Consumer> processFollow() { if ("follow".equals(action)) { Follow follow = new Follow(user,hashtag); - followRepository.save(follow); followRedisRepository.insertFollow(hashtagId, userId); System.out.println("팔로우 성공: " + messageBody); } else if ("unfollow".equals(action)) { Follow follow = followRepository.findByUserIdAndHashTagId(userId, hashtagId) .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); - followRepository.delete(follow); followRedisRepository.removeFollow(hashtagId, userId); System.out.println("팔로우 취소 성공: " + messageBody); } else { diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java index b1c7a1a..68628a0 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java @@ -1,8 +1,6 @@ package com.goormy.hackathon.repository; import com.goormy.hackathon.entity.Follow; -import com.goormy.hackathon.entity.Hashtag; -import com.goormy.hackathon.entity.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; From b186ad4fc99b1dd4ee72f789cdf8146eed3a5846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Thu, 1 Aug 2024 14:24:52 +0900 Subject: [PATCH 34/57] =?UTF-8?q?feat:=20scheduleHandler=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hackathon/handler/ScheduledHandler.java | 24 +++++++++++++++++++ .../hackathon/lambda/FollowFunction.java | 3 --- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java diff --git a/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java b/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java new file mode 100644 index 0000000..b420cfe --- /dev/null +++ b/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java @@ -0,0 +1,24 @@ +package com.goormy.hackathon.handler; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.ScheduledEvent; +import com.goormy.hackathon.lambda.FollowFunction; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +public class ScheduledHandler implements RequestHandler { + + private static final ApplicationContext context = new AnnotationConfigApplicationContext(FollowFunction.class); + private final FollowFunction followFunction; + + public ScheduledHandler() { + followFunction = context.getBean(FollowFunction.class); + } + + @Override + public String handleRequest(ScheduledEvent event, Context context) { + followFunction.migrateData(); + return "Data migration completed"; + } +} diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index 899d5d4..836f3e5 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -9,7 +9,6 @@ import com.goormy.hackathon.repository.UserRepository; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.Scheduled; import java.util.List; import java.util.Map; @@ -62,7 +61,6 @@ public Consumer> processFollow() { } // Redis 데이터를 RDBMS에 저장하고 Redis 비우기 - @Scheduled(cron = "0 0 0 * * *") // 매일 자정에 실행 public void migrateData() { // Redis에서 모든 팔로우 데이터 가져오기 List follows = followRedisRepository.getAllFollows(); @@ -72,7 +70,6 @@ public void migrateData() { followRepository.saveAll(follows); // Redis 비우기 - System.out.println("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); } From 147519fd72ffbb4c3c723228ec7e860cd507598a Mon Sep 17 00:00:00 2001 From: seonghooni Date: Wed, 31 Jul 2024 22:52:13 +0900 Subject: [PATCH 35/57] =?UTF-8?q?feat:=20AWS=20SQS=20=EB=B0=8F=20lambda=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit chore: Main-Class 경로 입력 fix: SQS 및 Lambda관련 설정 --- .github/workflows/deploy_lambda.yml | 2 +- build.gradle | 30 ++++ .../hackathon/controller/LikeController.java | 8 +- .../goormy/hackathon/handler/LikeHandler.java | 7 + .../goormy/hackathon/lambda/LikeFunction.java | 150 ++++++++++++++++++ .../goormy/hackathon/service/LikeService.java | 140 +++++----------- src/main/resources/application.yml | 15 +- 7 files changed, 242 insertions(+), 110 deletions(-) create mode 100644 src/main/java/com/goormy/hackathon/handler/LikeHandler.java create mode 100644 src/main/java/com/goormy/hackathon/lambda/LikeFunction.java diff --git a/.github/workflows/deploy_lambda.yml b/.github/workflows/deploy_lambda.yml index 49093f5..4e4ed75 100644 --- a/.github/workflows/deploy_lambda.yml +++ b/.github/workflows/deploy_lambda.yml @@ -30,7 +30,7 @@ jobs: run: chmod +x gradlew - name: Build with Gradle without test - run: ./gradlew build -x test + run: ./gradlew clean build -x test buildZip - name: Create deployment package run: | diff --git a/build.gradle b/build.gradle index 9ea1e0a..7a7a24a 100644 --- a/build.gradle +++ b/build.gradle @@ -23,10 +23,27 @@ repositories { mavenCentral() } +jar { + manifest { + attributes( + 'Manifest-Version': '1.0', + 'Main-Class': 'com.goormy.hackathon.HackathonApplication' + ) + } +} + dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-web' + + implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.1") + implementation 'io.awspring.cloud:spring-cloud-aws-starter-sqs' + implementation 'redis.clients:jedis:4.0.1' + implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' + implementation 'com.amazonaws:aws-lambda-java-events:3.11.0' + implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws:3.2.7' + compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' annotationProcessor 'org.projectlombok:lombok' @@ -38,3 +55,16 @@ dependencies { tasks.named('test') { useJUnitPlatform() } + +task buildZip(type: Zip) { + from compileJava + from processResources + into('lib') { + from configurations.runtimeClasspath + } + into('lib') { + from jar.archiveFile + } + archiveFileName = 'lambda-function.zip' + destinationDirectory = file("$buildDir/distributions") +} \ No newline at end of file diff --git a/src/main/java/com/goormy/hackathon/controller/LikeController.java b/src/main/java/com/goormy/hackathon/controller/LikeController.java index 36b1a1e..4d89a2b 100644 --- a/src/main/java/com/goormy/hackathon/controller/LikeController.java +++ b/src/main/java/com/goormy/hackathon/controller/LikeController.java @@ -23,9 +23,9 @@ public ResponseEntity addLike( @RequestHeader(name = "userId") Long userId, @RequestParam(name = "postId") Long postId) { - likeService.addLike(postId, userId); + likeService.sendLikeRequest(userId,postId); - return ResponseEntity.ok("success"); + return ResponseEntity.noContent().build(); } @DeleteMapping("/likes") @@ -33,9 +33,9 @@ public ResponseEntity cancelLike( @RequestHeader(name = "userId") Long userId, @RequestParam(name = "postId") Long postId) { - likeService.cancelLike(postId, userId); + likeService.sendCancelLikeRequest(userId,postId); - return ResponseEntity.ok("success"); + return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/goormy/hackathon/handler/LikeHandler.java b/src/main/java/com/goormy/hackathon/handler/LikeHandler.java new file mode 100644 index 0000000..e0aafc2 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/handler/LikeHandler.java @@ -0,0 +1,7 @@ +package com.goormy.hackathon.handler; + +import org.springframework.cloud.function.adapter.aws.FunctionInvoker; + +public class LikeHandler extends FunctionInvoker{ + +} diff --git a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java new file mode 100644 index 0000000..57b0f82 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java @@ -0,0 +1,150 @@ +package com.goormy.hackathon.lambda; + +import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.Like; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.repository.LikeRedisRepository; +import com.goormy.hackathon.repository.LikeRepository; +import com.goormy.hackathon.repository.PostRepository; +import com.goormy.hackathon.repository.UserRepository; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.Transactional; + +@Configuration +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class LikeFunction { + + private final LikeRedisRepository likeRedisRepository; + private final LikeRepository likeRepository; + private final UserRepository userRepository; + private final PostRepository postRepository; + + @Bean + public Consumer> processLike() { + return messageBody -> { + try { + // userId와 postId를 Long으로 변환 + Long userId = ((Long) messageBody.get("userId")); + Long postId = ((Long) messageBody.get("postId")); + String action = (String) messageBody.get("action"); + + User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); + Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("존재하지 않는 포스트 입니다. postId: " + postId)); + + if ("follow".equals(action)) { + addLike(postId,userId); + System.out.println("좋아요 성공: " + messageBody); + } else if ("unfollow".equals(action)) { + cancelLike(postId,userId); + System.out.println("좋아요 취소 성공: " + messageBody); + } else { + System.out.println("존재하지 않는 action입니다 : " + action); + } + } catch (Exception e) { + System.err.println("메시지 전송 실패: " + messageBody); + e.printStackTrace(); + } + }; + } + + /** + * @description 좋아요 정보를 Redis 캐시에 업데이트 + * */ + @Transactional + public void addLike(Long postId, Long userId) { + // 캐시에서 좋아요에 대한 정보를 먼저 조회함 + Integer findPostLike = likeRedisRepository.findPostLikeFromCache(postId, userId); + + if (findPostLike == null) { + // 캐시에 좋아요에 대한 정보가 없다면, + // Key = postlike:{postId}, Field = {userId}, Value = 1 로 '좋아요' 정보 생성 + likeRedisRepository.update(postId, userId, 1); + }else if (findPostLike == -1) { + // '좋아요 취소' 정보가 있는 상태라면 + // '좋아요'를 다시 누른 것이기 때문에 '취소 정보'를 삭제 + likeRedisRepository.delete(postId,userId); + } + } + + /** + * @description 좋아요 취소 정보를 Redis 캐시에 업데이트 + * */ + @Transactional + public void cancelLike(Long postId, Long userId) { + // 캐시에서 좋아요 정보를 먼저 조회함 + Integer findPostLike = likeRedisRepository.findPostLikeFromCache(postId, userId); + + // 캐시에 좋아요에 대한 정보가 없다면, + // Key = postlike:{postId}, Field = {userId}, Value = -1 로 '좋아요 취소' 정보 생성 + if (findPostLike == null) { + likeRedisRepository.update(postId,userId,-1); + }else if (findPostLike == 1) { + // '좋아요'라는 정보가 있는 상태라면 + // '좋아요 취소'를 다시 누른 것이기 때문에 '좋아요' 정보를 삭젳 + likeRedisRepository.delete(postId,userId); + } + } + + /** + * @description 좋아요 정보가 있는지 조회 (1. Redis 조회 2. RDB 조회) + * */ + public boolean findLike(Long postId, Long userId) { + // 1. 캐시로부터 '좋아요'에 대한 정보를 조회함 + Integer value = likeRedisRepository.findPostLikeFromCache(postId, userId); + + if (value == null) { // 캐시에 정보가 없다면 DB에서 조회되는지 여부에 따라 true/false 리턴 + return likeRepository.isExistByPostIdAndUserId(postId, userId); + }else if (value == -1) { // 캐시에 '좋아요 삭제' 정보가 있다면 false 리턴 + return false; + }else{ // 캐시에 '좋아요 추가' 정보가 있다면 true 리턴 + return true; + } + } + + /** + * @description Redis에 있는 '좋아요' 정보들을 RDB에 반영하는 함수 + * */ + @Transactional + public void dumpToDB() { + // 1. "postlike:{postId} 형식의 모든 key 목록을 불러옴 + Set postLikeKeySet = likeRedisRepository.findAllKeys(); + + // 2. Key마다 postId, userId, value를 조회하는 과정 + for (String key: postLikeKeySet) { + + // 2-1. Key로 Hash 자료구조를 조회함. field = userId / value = 1 or -1 + Map result = likeRedisRepository.findByKey(key); + + // 2-2. key를 파싱하여 postId를 구함 + String[] split = key.split(":"); + Long postId = Long.valueOf(split[1]); + + for (Map.Entry entry : result.entrySet()) { + // 2-3. field를 형변환하여 userId를 구함 + Long userId = Long.valueOf(String.valueOf(entry.getKey())); + // 2-4. value를 형변환하여 1 또는 -1 값을 얻게 됨 + Integer value = Integer.valueOf(String.valueOf(entry.getValue())); + + // 3. value 값에 따라 DB에 어떻게 반영할지 결정하여 처리함 + if (value == 1) { // 3-1. 좋아요를 추가한 상태였다면 RDB에 insert 쿼리 발생 + User user = userRepository.getReferenceById(userId); + Post post = postRepository.getReferenceById(postId); + likeRepository.save(new Like(user, post)); + }else if (value == -1) { // 3-2. 좋아요를 취소한 상태였다면 RDB에 delete 쿼리 발생 + likeRepository.deleteByPostIdAndUserId(postId, userId); + } + } + + // 4. 해당 Key에 대해 RDB에 반영하는 과정을 마쳤으므로, + likeRedisRepository.delete(key); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/goormy/hackathon/service/LikeService.java b/src/main/java/com/goormy/hackathon/service/LikeService.java index d56cb91..e1b1c41 100644 --- a/src/main/java/com/goormy/hackathon/service/LikeService.java +++ b/src/main/java/com/goormy/hackathon/service/LikeService.java @@ -1,119 +1,55 @@ package com.goormy.hackathon.service; -import com.goormy.hackathon.entity.Like; -import com.goormy.hackathon.entity.Post; -import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.LikeRedisRepository; -import com.goormy.hackathon.repository.LikeRepository; -import com.goormy.hackathon.repository.PostRepository; -import com.goormy.hackathon.repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - +import com.fasterxml.jackson.databind.ObjectMapper; +import com.goormy.hackathon.lambda.LikeFunction; import java.util.Map; -import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.SendMessageRequest; +import software.amazon.awssdk.services.sqs.model.SendMessageResponse; @Service -@Transactional(readOnly = true) -@RequiredArgsConstructor public class LikeService { - private final LikeRedisRepository likeRedisRepository; - private final LikeRepository likeRepository; - private final UserRepository userRepository; - private final PostRepository postRepository; - - /** - * @description 좋아요 정보를 Redis 캐시에 업데이트 - * */ - @Transactional - public void addLike(Long postId, Long userId) { - // 캐시에서 좋아요에 대한 정보를 먼저 조회함 - Integer findPostLike = likeRedisRepository.findPostLikeFromCache(postId, userId); + private static final Logger logger = LoggerFactory.getLogger(LikeFunction.class); - if (findPostLike == null) { - // 캐시에 좋아요에 대한 정보가 없다면, - // Key = postlike:{postId}, Field = {userId}, Value = 1 로 '좋아요' 정보 생성 - likeRedisRepository.update(postId, userId, 1); - }else if (findPostLike == -1) { - // '좋아요 취소' 정보가 있는 상태라면 - // '좋아요'를 다시 누른 것이기 때문에 '취소 정보'를 삭제 - likeRedisRepository.delete(postId,userId); - } - } + @Autowired + private SqsClient sqsClient; - /** - * @description 좋아요 취소 정보를 Redis 캐시에 업데이트 - * */ - @Transactional - public void cancelLike(Long postId, Long userId) { - // 캐시에서 좋아요 정보를 먼저 조회함 - Integer findPostLike = likeRedisRepository.findPostLikeFromCache(postId, userId); + @Value("${spring.cloud.aws.sqs.queue-url}") + private String queueUrl; - // 캐시에 좋아요에 대한 정보가 없다면, - // Key = postlike:{postId}, Field = {userId}, Value = -1 로 '좋아요 취소' 정보 생성 - if (findPostLike == null) { - likeRedisRepository.update(postId,userId,-1); - }else if (findPostLike == 1) { - // '좋아요'라는 정보가 있는 상태라면 - // '좋아요 취소'를 다시 누른 것이기 때문에 '좋아요' 정보를 삭젳 - likeRedisRepository.delete(postId,userId); - } + public void sendLikeRequest(Long userId, Long postId) { + sendRequest(userId, postId, "like"); } - /** - * @description 좋아요 정보가 있는지 조회 (1. Redis 조회 2. RDB 조회) - * */ - public boolean findLike(Long postId, Long userId) { - // 1. 캐시로부터 '좋아요'에 대한 정보를 조회함 - Integer value = likeRedisRepository.findPostLikeFromCache(postId, userId); - - if (value == null) { // 캐시에 정보가 없다면 DB에서 조회되는지 여부에 따라 true/false 리턴 - return likeRepository.isExistByPostIdAndUserId(postId, userId); - }else if (value == -1) { // 캐시에 '좋아요 삭제' 정보가 있다면 false 리턴 - return false; - }else{ // 캐시에 '좋아요 추가' 정보가 있다면 true 리턴 - return true; - } + public void sendCancelLikeRequest(Long userId, Long postId) { + sendRequest(userId, postId, "unlike"); } - /** - * @description Redis에 있는 '좋아요' 정보들을 RDB에 반영하는 함수 - * */ - @Transactional - public void dumpToDB() { - // 1. "postlike:{postId} 형식의 모든 key 목록을 불러옴 - Set postLikeKeySet = likeRedisRepository.findAllKeys(); - - // 2. Key마다 postId, userId, value를 조회하는 과정 - for (String key: postLikeKeySet) { - - // 2-1. Key로 Hash 자료구조를 조회함. field = userId / value = 1 or -1 - Map result = likeRedisRepository.findByKey(key); - - // 2-2. key를 파싱하여 postId를 구함 - String[] split = key.split(":"); - Long postId = Long.valueOf(split[1]); - - for (Map.Entry entry : result.entrySet()) { - // 2-3. field를 형변환하여 userId를 구함 - Long userId = Long.valueOf(String.valueOf(entry.getKey())); - // 2-4. value를 형변환하여 1 또는 -1 값을 얻게 됨 - Integer value = Integer.valueOf(String.valueOf(entry.getValue())); - - // 3. value 값에 따라 DB에 어떻게 반영할지 결정하여 처리함 - if (value == 1) { // 3-1. 좋아요를 추가한 상태였다면 RDB에 insert 쿼리 발생 - User user = userRepository.getReferenceById(userId); - Post post = postRepository.getReferenceById(postId); - likeRepository.save(new Like(user, post)); - }else if (value == -1) { // 3-2. 좋아요를 취소한 상태였다면 RDB에 delete 쿼리 발생 - likeRepository.deleteByPostIdAndUserId(postId, userId); - } - } - - // 4. 해당 Key에 대해 RDB에 반영하는 과정을 마쳤으므로, - likeRedisRepository.delete(key); + public void sendRequest(Long userId, Long postId, String action) { + try{ + ObjectMapper objectMapper = new ObjectMapper(); + String messageBody = objectMapper.writeValueAsString(Map.of( + "userId", userId, + "postId", postId, + "action", action + )); + SendMessageRequest sendMsgRequest = SendMessageRequest.builder() + .queueUrl(queueUrl) + .messageBody(messageBody) + .build(); + + logger.info("메시지 송신 - action: {}, user Id: {}, postId: {}", action, userId, postId); + SendMessageResponse sendMsgResponse = sqsClient.sendMessage(sendMsgRequest); + logger.info("메시지가 전달되었습니다: {}, Message ID: {}, HTTP Status: {}", + messageBody, sendMsgResponse.messageId(), sendMsgResponse.sdkHttpResponse().statusCode()); + } catch (Exception e) { + logger.error("메시지 전송 실패", e); } } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 98edb09..bff310f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,10 +4,10 @@ spring: host: localhost port: 6379 datasource: - url: ${MYSQL_URL:jdbc:mysql://localhost}:${MYSQL_PORT:3306}/${MYSQL_SCHEMA:dev} + url: ${MYSQL_URL:jdbc:mysql://localhost}:${MYSQL_PORT:3306}/${MYSQL_SCHEMA:gureumi-rds} driver-class-name: com.mysql.cj.jdbc.Driver - username: ${MYSQL_USERNAME:root} - password: ${MYSQL_PASSWORD:1234} + username: ${MYSQL_USERNAME:admin} + password: ${MYSQL_PASSWORD:rnfmalelql3} jpa: hibernate: ddl-auto: update @@ -20,6 +20,15 @@ spring: include: - redis - swagger + cloud: + aws: + region: + static: ${{ secrets.AWS_REGION }} + credentials: + access-key: ${{ secrets.AWS_ACCESS_KEY_ID }} + secret-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + sqs: + queue-url: https://sqs.ap-northeast-2.amazonaws.com/008971650206/GoormySQSForLike logging: level: org: From f7baf6f4f6fc8776949e70ccb71c17dcd52ff00c Mon Sep 17 00:00:00 2001 From: seonghooni Date: Thu, 1 Aug 2024 14:48:56 +0900 Subject: [PATCH 36/57] =?UTF-8?q?fix:=20=EC=9E=90=EB=8F=99=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=20=ED=8C=8C=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/deploy_lambda.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_lambda.yml b/.github/workflows/deploy_lambda.yml index 4e4ed75..311e319 100644 --- a/.github/workflows/deploy_lambda.yml +++ b/.github/workflows/deploy_lambda.yml @@ -35,7 +35,7 @@ jobs: - name: Create deployment package run: | mkdir -p deployment - cp build/libs/*.jar deployment/ + cp build/distributions/lambda-function.zip deployment/ if [ -d "lib" ]; then cp -R lib/* deployment/ fi From da5459d5f88e5b5b7bf694fe5d4b0f80e381fe9e Mon Sep 17 00:00:00 2001 From: seonghooni Date: Thu, 1 Aug 2024 17:54:21 +0900 Subject: [PATCH 37/57] =?UTF-8?q?fix:=20Like=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EB=9E=8C=EB=8B=A4=EC=97=90=EC=84=9C=20=EC=8B=A4=ED=96=89?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 6 ++++-- .../goormy/hackathon/lambda/LikeFunction.java | 18 ++++++++++++------ .../hackathon/service/LikeServiceTest.java | 16 +++++++--------- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/build.gradle b/build.gradle index 7a7a24a..58147ef 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ dependencies { implementation 'redis.clients:jedis:4.0.1' implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' implementation 'com.amazonaws:aws-lambda-java-events:3.11.0' - implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws:3.2.7' + implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws:4.0.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' @@ -67,4 +67,6 @@ task buildZip(type: Zip) { } archiveFileName = 'lambda-function.zip' destinationDirectory = file("$buildDir/distributions") -} \ No newline at end of file +} + +build.dependsOn buildZip \ No newline at end of file diff --git a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java index 57b0f82..8e3de1d 100644 --- a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java @@ -1,5 +1,6 @@ package com.goormy.hackathon.lambda; +import com.fasterxml.jackson.databind.ObjectMapper; import com.goormy.hackathon.entity.Follow; import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.Like; @@ -9,6 +10,7 @@ import com.goormy.hackathon.repository.LikeRepository; import com.goormy.hackathon.repository.PostRepository; import com.goormy.hackathon.repository.UserRepository; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; @@ -26,23 +28,27 @@ public class LikeFunction { private final LikeRepository likeRepository; private final UserRepository userRepository; private final PostRepository postRepository; + private final ObjectMapper objectMapper; @Bean public Consumer> processLike() { return messageBody -> { try { - // userId와 postId를 Long으로 변환 - Long userId = ((Long) messageBody.get("userId")); - Long postId = ((Long) messageBody.get("postId")); - String action = (String) messageBody.get("action"); + List> records = (List>) messageBody.get("Records"); + String bodyString = (String) records.get(0).get("body"); + Map body = objectMapper.readValue(bodyString, Map.class); + + long userId = ((Number) body.get("userId")).longValue(); + long postId = ((Number) body.get("postId")).longValue(); + String action = (String) body.get("action"); User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("존재하지 않는 포스트 입니다. postId: " + postId)); - if ("follow".equals(action)) { + if ("like".equals(action)) { addLike(postId,userId); System.out.println("좋아요 성공: " + messageBody); - } else if ("unfollow".equals(action)) { + } else if ("unlike".equals(action)) { cancelLike(postId,userId); System.out.println("좋아요 취소 성공: " + messageBody); } else { diff --git a/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java b/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java index 2bb3dca..67b1723 100644 --- a/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java +++ b/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java @@ -3,11 +3,11 @@ import com.goormy.hackathon.entity.Like; import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.lambda.LikeFunction; import com.goormy.hackathon.repository.LikeRedisRepository; import com.goormy.hackathon.repository.LikeRepository; import com.goormy.hackathon.repository.PostRepository; import com.goormy.hackathon.repository.UserRepository; -import jakarta.persistence.PrePersist; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -16,8 +16,6 @@ import java.util.List; -import static org.junit.jupiter.api.Assertions.*; - @SpringBootTest class LikeServiceTest { @@ -28,7 +26,7 @@ class LikeServiceTest { PostRepository postRepository; @Autowired - LikeService likeService; + LikeFunction likeFunction; @Autowired LikeRepository likeRepository; @@ -101,7 +99,7 @@ class LikeServiceTest { // given // when - likeService.addLike(2L,1L); + likeFunction.addLike(2L,1L); } @@ -110,7 +108,7 @@ class LikeServiceTest { // given // when - likeService.cancelLike(2L,1L); + likeFunction.cancelLike(2L,1L); } @@ -120,8 +118,8 @@ class LikeServiceTest { // given // when - boolean exist = likeService.findLike(4L, 3L); - boolean noExist = likeService.findLike(2L, 3L); + boolean exist = likeFunction.findLike(4L, 3L); + boolean noExist = likeFunction.findLike(2L, 3L); // then Assertions.assertEquals(exist, true); @@ -138,7 +136,7 @@ class LikeServiceTest { likeRedisRepository.update(4L, 3L, -1); // when - likeService.dumpToDB(); + likeFunction.dumpToDB(); // then } From a9903ebd600ab9f2b1b36ea050aa6514de7163e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:33:25 +0900 Subject: [PATCH 38/57] =?UTF-8?q?refactor:=20=EB=A9=94=EC=86=8C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows.follow_deploy.yml | 59 +++++++++++++++++++ .../controller/FollowController.java | 1 - .../hackathon/lambda/FollowFunction.java | 26 ++++++-- .../repository/FollowRedisRepository.java | 4 +- 4 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 .github/workflows.follow_deploy.yml diff --git a/.github/workflows.follow_deploy.yml b/.github/workflows.follow_deploy.yml new file mode 100644 index 0000000..334a289 --- /dev/null +++ b/.github/workflows.follow_deploy.yml @@ -0,0 +1,59 @@ +name: deploy_lambda + +on: + push: + branches: [ feat/follow_service#6 ] + workflow_dispatch: + inputs: + logLevel: + description: 'Log level' + required: true + default: 'warning' + tags: + description: 'Test Deploy' +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: JDK 세팅 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle without test + run: ./gradlew clean build buildZip + + - name: Create deployment package + run: | + mkdir -p deployment + cp build/libs/*.jar deployment/ + if [ -d "lib" ]; then + cp -R lib/* deployment/ + fi + cd deployment + zip -r ../follow_service.zip . + - name: AWS 계정 세팅 + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: S3에 패키지 업로드 + run: | + aws s3 cp follow_service.zip s3://gureumi-s3/lambda-function.zip + - name: 람다 배포 + run: | + aws lambda update-function-code \ + --function-name ${{ secrets.LAMBDA_FOLLOW_FUNCTION_NAME }} \ + --s3-bucket gureumi-s3 \ + --s3-key lambda-function.zip \ No newline at end of file diff --git a/src/main/java/com/goormy/hackathon/controller/FollowController.java b/src/main/java/com/goormy/hackathon/controller/FollowController.java index 4c68275..ae1bab6 100644 --- a/src/main/java/com/goormy/hackathon/controller/FollowController.java +++ b/src/main/java/com/goormy/hackathon/controller/FollowController.java @@ -6,7 +6,6 @@ import org.springframework.web.bind.annotation.*; @RestController -@RequestMapping("/goormy") public class FollowController { @Autowired diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index 836f3e5..259dc96 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -1,5 +1,6 @@ package com.goormy.hackathon.lambda; +import com.fasterxml.jackson.databind.ObjectMapper; import com.goormy.hackathon.entity.Follow; import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.User; @@ -7,6 +8,8 @@ import com.goormy.hackathon.repository.FollowRepository; import com.goormy.hackathon.repository.HashtagRepository; import com.goormy.hackathon.repository.UserRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -21,34 +24,45 @@ public class FollowFunction{ private final UserRepository userRepository; private final HashtagRepository hashtagRepository; private final FollowRedisRepository followRedisRepository; + private final ObjectMapper objectMapper; + private static final Logger logger = LoggerFactory.getLogger(FollowFunction.class); - public FollowFunction(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository, FollowRedisRepository followRedisRepository) { + + public FollowFunction(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository, FollowRedisRepository followRedisRepository + , ObjectMapper objectMapper) { this.followRepository = followRepository; this.userRepository = userRepository; this.hashtagRepository = hashtagRepository; this.followRedisRepository = followRedisRepository; + this.objectMapper = objectMapper; } @Bean public Consumer> processFollow() { return messageBody -> { try { + + List> records = (List>) messageBody.get("Records"); + String bodyString = (String) records.get(0).get("body"); + Map body = objectMapper.readValue(bodyString, Map.class); + // userId와 hashtagId를 Number로 파싱하고 long으로 변환 - long userId = ((Number) messageBody.get("userId")).longValue(); - long hashtagId = ((Number) messageBody.get("hashtagId")).longValue(); - String action = (String) messageBody.get("action"); + long userId = ((Number) body.get("userId")).longValue(); + long hashtagId = ((Number) body.get("hashtagId")).longValue(); + String action = (String) body.get("action"); + logger.info("userId: {}, hashtagId: {}, action: {}", userId, hashtagId, action); User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); Hashtag hashtag = hashtagRepository.findById(hashtagId).orElseThrow(() -> new RuntimeException("존재하지 않는 해시태그입니다. hashtagId: " + hashtagId)); if ("follow".equals(action)) { Follow follow = new Follow(user,hashtag); - followRedisRepository.insertFollow(hashtagId, userId); + followRedisRepository.set(hashtagId, userId); System.out.println("팔로우 성공: " + messageBody); } else if ("unfollow".equals(action)) { Follow follow = followRepository.findByUserIdAndHashTagId(userId, hashtagId) .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); - followRedisRepository.removeFollow(hashtagId, userId); + followRedisRepository.delete(hashtagId, userId); System.out.println("팔로우 취소 성공: " + messageBody); } else { System.out.println("존재하지 않는 action입니다 : " + action); diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java index 68628a0..799d533 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java @@ -18,12 +18,12 @@ public class FollowRedisRepository { @Autowired FollowRepository followRepository; - public void insertFollow(Long hashtagId, Long userId) { + public void set(Long hashtagId, Long userId) { String key = "hashtagId: " + hashtagId.toString(); redisTemplate.opsForList().rightPush(key, userId); } - public void removeFollow(Long hashtagId, Long userId) { + public void delete(Long hashtagId, Long userId) { String key = "hashtagId:" + hashtagId.toString(); redisTemplate.opsForList().remove(key, 0, userId); } From 6125dd82a6a7cf62b64dec4e4db4f04a31700f15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Thu, 1 Aug 2024 20:34:14 +0900 Subject: [PATCH 39/57] =?UTF-8?q?Chore:=20function=20=EB=B2=84=EC=A0=84=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index e4d3ca8..2f70143 100644 --- a/build.gradle +++ b/build.gradle @@ -28,12 +28,13 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.1") implementation 'io.awspring.cloud:spring-cloud-aws-starter-sqs' - implementation 'redis.clients:jedis:4.0.1' implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' implementation 'com.amazonaws:aws-lambda-java-events:3.11.0' - implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws:3.2.7' + implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws:4.0.0' + implementation 'com.fasterxml.jackson.core:jackson-databind' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' From 2afac935a6e4ec181c1c689cc7b46a17b71c958c Mon Sep 17 00:00:00 2001 From: seonghooni Date: Thu, 1 Aug 2024 20:39:34 +0900 Subject: [PATCH 40/57] =?UTF-8?q?fix:=20RedisRepository=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EB=AA=85=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/goormy/hackathon/lambda/LikeFunction.java | 14 ++++++-------- .../hackathon/repository/LikeRedisRepository.java | 6 +++--- .../goormy/hackathon/service/LikeServiceTest.java | 8 ++++---- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java index 8e3de1d..0f51ccc 100644 --- a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java @@ -1,8 +1,6 @@ package com.goormy.hackathon.lambda; import com.fasterxml.jackson.databind.ObjectMapper; -import com.goormy.hackathon.entity.Follow; -import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.Like; import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.entity.User; @@ -67,12 +65,12 @@ public Consumer> processLike() { @Transactional public void addLike(Long postId, Long userId) { // 캐시에서 좋아요에 대한 정보를 먼저 조회함 - Integer findPostLike = likeRedisRepository.findPostLikeFromCache(postId, userId); + Integer findPostLike = likeRedisRepository.findPostLikeByPostIdAndUserId(postId, userId); if (findPostLike == null) { // 캐시에 좋아요에 대한 정보가 없다면, // Key = postlike:{postId}, Field = {userId}, Value = 1 로 '좋아요' 정보 생성 - likeRedisRepository.update(postId, userId, 1); + likeRedisRepository.set(postId, userId, 1); }else if (findPostLike == -1) { // '좋아요 취소' 정보가 있는 상태라면 // '좋아요'를 다시 누른 것이기 때문에 '취소 정보'를 삭제 @@ -86,12 +84,12 @@ public void addLike(Long postId, Long userId) { @Transactional public void cancelLike(Long postId, Long userId) { // 캐시에서 좋아요 정보를 먼저 조회함 - Integer findPostLike = likeRedisRepository.findPostLikeFromCache(postId, userId); + Integer findPostLike = likeRedisRepository.findPostLikeByPostIdAndUserId(postId, userId); // 캐시에 좋아요에 대한 정보가 없다면, // Key = postlike:{postId}, Field = {userId}, Value = -1 로 '좋아요 취소' 정보 생성 if (findPostLike == null) { - likeRedisRepository.update(postId,userId,-1); + likeRedisRepository.set(postId,userId,-1); }else if (findPostLike == 1) { // '좋아요'라는 정보가 있는 상태라면 // '좋아요 취소'를 다시 누른 것이기 때문에 '좋아요' 정보를 삭젳 @@ -104,7 +102,7 @@ public void cancelLike(Long postId, Long userId) { * */ public boolean findLike(Long postId, Long userId) { // 1. 캐시로부터 '좋아요'에 대한 정보를 조회함 - Integer value = likeRedisRepository.findPostLikeFromCache(postId, userId); + Integer value = likeRedisRepository.findPostLikeByPostIdAndUserId(postId, userId); if (value == null) { // 캐시에 정보가 없다면 DB에서 조회되는지 여부에 따라 true/false 리턴 return likeRepository.isExistByPostIdAndUserId(postId, userId); @@ -127,7 +125,7 @@ public void dumpToDB() { for (String key: postLikeKeySet) { // 2-1. Key로 Hash 자료구조를 조회함. field = userId / value = 1 or -1 - Map result = likeRedisRepository.findByKey(key); + Map result = likeRedisRepository.findPostLikeByKey(key); // 2-2. key를 파싱하여 postId를 구함 String[] split = key.split(":"); diff --git a/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java index 3b9fd8b..c066477 100644 --- a/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java @@ -16,7 +16,7 @@ public class LikeRedisRepository { /** * @description '좋아요' 정보를 업데이트 하는 함수 * */ - public void update(Long postId, Long userId, Integer value) { + public void set(Long postId, Long userId, Integer value) { String key = "postlike:" + postId.toString(); String field = userId.toString(); @@ -36,7 +36,7 @@ public void delete(Long postId, Long userId){ /** * @description postId와 userId에 대한 value를 조회 * */ - public Integer findPostLikeFromCache(Long postId, Long userId) { + public Integer findPostLikeByPostIdAndUserId(Long postId, Long userId) { String key = "postlike:" + postId.toString(); String field = userId.toString(); @@ -46,7 +46,7 @@ public Integer findPostLikeFromCache(Long postId, Long userId) { /** * @description Key에 대한 모든 field와 value를 조회 * */ - public Map findByKey(String key) { + public Map findPostLikeByKey(String key) { return redisTemplate.opsForHash().entries(key); } diff --git a/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java b/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java index 67b1723..0d2073f 100644 --- a/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java +++ b/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java @@ -130,10 +130,10 @@ class LikeServiceTest { void 캐시로부터_DB로_반영() { // given - likeRedisRepository.update(3L, 1L, 1); - likeRedisRepository.update(3L, 2L, 1); - likeRedisRepository.update(3L, 3L, 1); - likeRedisRepository.update(4L, 3L, -1); + likeRedisRepository.set(3L, 1L, 1); + likeRedisRepository.set(3L, 2L, 1); + likeRedisRepository.set(3L, 3L, 1); + likeRedisRepository.set(4L, 3L, -1); // when likeFunction.dumpToDB(); From 05bb55dda085270f666cbab680aa09482fc2ad62 Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Thu, 1 Aug 2024 21:02:55 +0900 Subject: [PATCH 41/57] =?UTF-8?q?refactor:=20RedisRepository=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/FeedHashtagRedisRepository.java | 2 +- .../hackathon/repository/FeedUserRedisRepository.java | 2 +- .../repository/FollowCountRedisRepository.java | 4 ++-- .../repository/FollowListRedisRepository.java | 2 +- .../hackathon/repository/PostRedisRepository.java | 2 +- .../com/goormy/hackathon/service/HashtagService.java | 2 +- .../com/goormy/hackathon/service/PostCacheService.java | 10 +++++----- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java index 1be24e0..40662be 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java @@ -12,7 +12,7 @@ public class FeedHashtagRedisRepository { private final RedisTemplate redisTemplate; - public void save(Long hashtagId, Post post) { + public void set(Long hashtagId, Post post) { String key = "FeedHashtag:" + hashtagId; Object value = new FeedSimpleInfo(post); redisTemplate.opsForList().leftPush(key, value); diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java index 8256f96..0f7d863 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java @@ -12,7 +12,7 @@ public class FeedUserRedisRepository { private final RedisTemplate redisTemplate; - public void save(Long userId, Post post) { + public void set(Long userId, Post post) { String key = "FeedUser:" + userId; Object value = new FeedSimpleInfo(post); redisTemplate.opsForList().leftPush(key, value); diff --git a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java index 8c62662..64cdfd1 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java @@ -11,11 +11,11 @@ public class FollowCountRedisRepository { private final RedisTemplate redisTemplate; - public void save(FollowCountCache followCountCache) { + public void set(FollowCountCache followCountCache) { redisTemplate.opsForHash().put(followCountCache.getKey(), followCountCache.getField(), followCountCache.getFollowCount()); } - public Integer findFollowCount(Long hashtagId) { + public Integer findFollowCountByHashtagId(Long hashtagId) { String key = "FollowCount:" + hashtagId; String field = String.valueOf(hashtagId); return (Integer) redisTemplate.opsForHash().get(key, field); diff --git a/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java index fa1c748..3956530 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java @@ -13,7 +13,7 @@ public class FollowListRedisRepository { private final RedisTemplate redisTemplate; // TODO: 수정 필요 - save 하는 쪽이 어떤 식으로 저장하느냐에 따라 호출 구현이 다를 듯 - public List findUserIdList(Long hashtagId) { + public List findUserIdListByHashtagId(Long hashtagId) { String key = "FollowList:" + hashtagId; return (List) redisTemplate.opsForValue().get(key); } diff --git a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java index 95a6e67..f0c5699 100644 --- a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java @@ -11,7 +11,7 @@ public class PostRedisRepository { private final RedisTemplate redisTemplate; - public void save(PostCache postCache) { + public void set(PostCache postCache) { redisTemplate.opsForList().leftPush(postCache.getKey(), postCache); } diff --git a/src/main/java/com/goormy/hackathon/service/HashtagService.java b/src/main/java/com/goormy/hackathon/service/HashtagService.java index 3c01b7e..f89e44e 100644 --- a/src/main/java/com/goormy/hackathon/service/HashtagService.java +++ b/src/main/java/com/goormy/hackathon/service/HashtagService.java @@ -31,7 +31,7 @@ public List getOrCreateHashtags(List hashtagRequ hashtagRepository.save(newHashtag); var followCountCache = new FollowCountCache(newHashtag); - followCountRedisRepository.save(followCountCache); + followCountRedisRepository.set(followCountCache); return newHashtag; }); diff --git a/src/main/java/com/goormy/hackathon/service/PostCacheService.java b/src/main/java/com/goormy/hackathon/service/PostCacheService.java index d37235e..2737ab0 100644 --- a/src/main/java/com/goormy/hackathon/service/PostCacheService.java +++ b/src/main/java/com/goormy/hackathon/service/PostCacheService.java @@ -19,7 +19,7 @@ public class PostCacheService { // TODO: 이벤트로 발행한 후 이벤트를 받아 Redis에 비동기로 저장 public void cache(Post post) { - postRedisRepository.save(new PostCache(post)); + postRedisRepository.set(new PostCache(post)); for (var hashtag : post.getPostHashtags()) { if (isPopular(hashtag)) { pullModel(hashtag, post); @@ -30,7 +30,7 @@ public void cache(Post post) { } private boolean isPopular(Hashtag hashtag) { - var followCount = followCountRedisRepository.findFollowCount(hashtag.getId()); + var followCount = followCountRedisRepository.findFollowCountByHashtagId(hashtag.getId()); if (followCount != null ) { return followCount >= 5000; } @@ -38,13 +38,13 @@ private boolean isPopular(Hashtag hashtag) { } private void pushModel(Hashtag hashtag, Post post) { - var userIdList = followListRedisRepository.findUserIdList(hashtag.getId()); + var userIdList = followListRedisRepository.findUserIdListByHashtagId(hashtag.getId()); userIdList.forEach(userId -> { - feedUserRedisRepository.save(userId, post); + feedUserRedisRepository.set(userId, post); }); } private void pullModel(Hashtag hashtag, Post post) { - feedHashtagRedisRepository.save(hashtag.getId(), post); + feedHashtagRedisRepository.set(hashtag.getId(), post); } } From e54cda08290f56a21eefeacfe4a9056291fc14ec Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Thu, 1 Aug 2024 21:11:46 +0900 Subject: [PATCH 42/57] =?UTF-8?q?refactor:=20=EC=BA=90=EC=8B=9C=20?= =?UTF-8?q?=ED=82=A4=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/goormy/hackathon/redis/entity/FollowCountCache.java | 2 +- src/main/java/com/goormy/hackathon/redis/entity/PostCache.java | 2 +- .../goormy/hackathon/repository/FeedHashtagRedisRepository.java | 2 +- .../goormy/hackathon/repository/FeedUserRedisRepository.java | 2 +- .../goormy/hackathon/repository/FollowCountRedisRepository.java | 2 +- .../goormy/hackathon/repository/FollowListRedisRepository.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java b/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java index b904521..bc37040 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java @@ -19,7 +19,7 @@ public FollowCountCache(Hashtag hashtag) { } public String getKey() { - return "FollowCount:" + hashtagId; + return "followcount:" + hashtagId; } public String getField() { diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PostCache.java b/src/main/java/com/goormy/hackathon/redis/entity/PostCache.java index 06c93f7..5386ba9 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/PostCache.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/PostCache.java @@ -37,7 +37,7 @@ public PostCache(Post post) { } public String getKey() { - return "Post:" + postId; + return "post:" + postId; } } diff --git a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java index 40662be..272cc62 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java @@ -13,7 +13,7 @@ public class FeedHashtagRedisRepository { private final RedisTemplate redisTemplate; public void set(Long hashtagId, Post post) { - String key = "FeedHashtag:" + hashtagId; + String key = "feedhashtag:" + hashtagId; Object value = new FeedSimpleInfo(post); redisTemplate.opsForList().leftPush(key, value); } diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java index 0f7d863..983c6f8 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java @@ -13,7 +13,7 @@ public class FeedUserRedisRepository { private final RedisTemplate redisTemplate; public void set(Long userId, Post post) { - String key = "FeedUser:" + userId; + String key = "feeduser:" + userId; Object value = new FeedSimpleInfo(post); redisTemplate.opsForList().leftPush(key, value); } diff --git a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java index 64cdfd1..85c7500 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java @@ -16,7 +16,7 @@ public void set(FollowCountCache followCountCache) { } public Integer findFollowCountByHashtagId(Long hashtagId) { - String key = "FollowCount:" + hashtagId; + String key = "followcount:" + hashtagId; String field = String.valueOf(hashtagId); return (Integer) redisTemplate.opsForHash().get(key, field); } diff --git a/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java index 3956530..2e081c5 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java @@ -14,7 +14,7 @@ public class FollowListRedisRepository { // TODO: 수정 필요 - save 하는 쪽이 어떤 식으로 저장하느냐에 따라 호출 구현이 다를 듯 public List findUserIdListByHashtagId(Long hashtagId) { - String key = "FollowList:" + hashtagId; + String key = "followlist:" + hashtagId; return (List) redisTemplate.opsForValue().get(key); } From dd56d6bccdf0971835b252c751898a36aeb31d42 Mon Sep 17 00:00:00 2001 From: Ga Dong Sik Date: Thu, 1 Aug 2024 21:22:19 +0900 Subject: [PATCH 43/57] =?UTF-8?q?fix:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=9D=B4=EB=A6=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...er.java => LocalDateTimeConverter_DS.java} | 2 +- .../controller/GetFeedController.java | 19 ++-- .../dto/response/GetFeedResponseDto.java | 18 ++-- .../hackathon/entity/BaseTimeEntity.java | 25 ----- .../com/goormy/hackathon/entity/Hashtag.java | 3 +- .../goormy/hackathon/entity/PostHashtag.java | 2 +- .../hackathon/redis/config/RedisConfig.java | 32 +++---- ...ostRedis.java => PopularPostRedis_DS.java} | 3 +- .../{PostRedis.java => PostRedis_DS.java} | 8 +- .../redis/entity/PostSimpleInfo.java | 40 -------- .../redis/entity/PostSimpleInfo_DS.java | 31 +++++++ ...teRedis.java => RecentUpdateRedis_DS.java} | 6 +- .../{UserRedis.java => UserRedis_DS.java} | 11 +-- ...ava => FeedHashtagRedisRepository_DS.java} | 14 +-- ...y.java => FeedUserRedisRepository_DS.java} | 16 ++-- ...va => FeedUserSortRedisRepository_DS.java} | 4 +- ...ava => PopularPostRedisRepository_DS.java} | 2 +- ...itory.java => PostRedisRepository_DS.java} | 18 ++-- ...va => RecentUpdateRedisRepository_DS.java} | 4 +- ...itory.java => UserRedisRepository_DS.java} | 16 ++-- .../hackathon/service/GetFeedService.java | 93 ++++++++++--------- 21 files changed, 165 insertions(+), 202 deletions(-) rename src/main/java/com/goormy/hackathon/common/util/{LocalDateTimeConverter.java => LocalDateTimeConverter_DS.java} (94%) delete mode 100644 src/main/java/com/goormy/hackathon/entity/BaseTimeEntity.java rename src/main/java/com/goormy/hackathon/redis/entity/{PopularPostRedis.java => PopularPostRedis_DS.java} (83%) rename src/main/java/com/goormy/hackathon/redis/entity/{PostRedis.java => PostRedis_DS.java} (90%) delete mode 100644 src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java create mode 100644 src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo_DS.java rename src/main/java/com/goormy/hackathon/redis/entity/{RecentUpdateRedis.java => RecentUpdateRedis_DS.java} (73%) rename src/main/java/com/goormy/hackathon/redis/entity/{UserRedis.java => UserRedis_DS.java} (80%) rename src/main/java/com/goormy/hackathon/repository/{FeedHashtagRedisRepository.java => FeedHashtagRedisRepository_DS.java} (58%) rename src/main/java/com/goormy/hackathon/repository/{FeedUserRedisRepository.java => FeedUserRedisRepository_DS.java} (59%) rename src/main/java/com/goormy/hackathon/repository/{FeedUserSortRedisRepository.java => FeedUserSortRedisRepository_DS.java} (89%) rename src/main/java/com/goormy/hackathon/repository/{PopularPostRedisRepository.java => PopularPostRedisRepository_DS.java} (50%) rename src/main/java/com/goormy/hackathon/repository/{PostRedisRepository.java => PostRedisRepository_DS.java} (58%) rename src/main/java/com/goormy/hackathon/repository/{RecentUpdateRedisRepository.java => RecentUpdateRedisRepository_DS.java} (92%) rename src/main/java/com/goormy/hackathon/repository/{UserRedisRepository.java => UserRedisRepository_DS.java} (55%) diff --git a/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java b/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter_DS.java similarity index 94% rename from src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java rename to src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter_DS.java index 93a8456..5802268 100644 --- a/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java +++ b/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter_DS.java @@ -6,7 +6,7 @@ import org.springframework.stereotype.Component; @Component -public class LocalDateTimeConverter { +public class LocalDateTimeConverter_DS { private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); diff --git a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java index 617999c..9bf62de 100644 --- a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java +++ b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java @@ -1,11 +1,12 @@ package com.goormy.hackathon.controller; -import com.goormy.hackathon.common.util.LocalDateTimeConverter; +import com.goormy.hackathon.common.util.LocalDateTimeConverter_DS; +import com.goormy.hackathon.common.util.LocalDateTimeConverter_DS; import com.goormy.hackathon.dto.request.AddFeedUser; import com.goormy.hackathon.dto.response.GetFeedResponseDto; -import com.goormy.hackathon.redis.entity.PostSimpleInfo; -import com.goormy.hackathon.repository.FeedHashtagRedisRepository; -import com.goormy.hackathon.repository.FeedUserRedisRepository; +import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; +import com.goormy.hackathon.repository.FeedHashtagRedisRepository_DS; +import com.goormy.hackathon.repository.FeedUserRedisRepository_DS; import com.goormy.hackathon.service.GetFeedService; import java.util.List; import lombok.RequiredArgsConstructor; @@ -24,10 +25,10 @@ public class GetFeedController { private final GetFeedService getFeedService; - private final LocalDateTimeConverter localDateTimeConverter; + private final LocalDateTimeConverter_DS localDateTimeConverter; - private final FeedUserRedisRepository feedUserRedisRepository; - private final FeedHashtagRedisRepository feedHashtagRedisRepository; + private final FeedUserRedisRepository_DS feedUserRedisRepository; + private final FeedHashtagRedisRepository_DS feedHashtagRedisRepository; /** * [GET] 사용자 맞춤형 피드 조회 기능 @@ -53,7 +54,7 @@ public ResponseEntity addFeedHashtagData( requestDto.getInfoList().forEach( info -> feedHashtagRedisRepository.add(userId, - PostSimpleInfo.toEntity(info.getPostId(), + PostSimpleInfo_DS.toEntity(info.getPostId(), localDateTimeConverter.convertToString(info.getCreatedAt()))) ); @@ -69,7 +70,7 @@ public ResponseEntity addFeedUserData( requestDto.getInfoList().forEach( info -> feedUserRedisRepository.add(userId, - PostSimpleInfo.toEntity(info.getPostId(), + PostSimpleInfo_DS.toEntity(info.getPostId(), localDateTimeConverter.convertToString(info.getCreatedAt()))) ); diff --git a/src/main/java/com/goormy/hackathon/dto/response/GetFeedResponseDto.java b/src/main/java/com/goormy/hackathon/dto/response/GetFeedResponseDto.java index 8b375cb..fd5d7d6 100644 --- a/src/main/java/com/goormy/hackathon/dto/response/GetFeedResponseDto.java +++ b/src/main/java/com/goormy/hackathon/dto/response/GetFeedResponseDto.java @@ -1,6 +1,6 @@ package com.goormy.hackathon.dto.response; -import com.goormy.hackathon.redis.entity.PostRedis; +import com.goormy.hackathon.redis.entity.PostRedis_DS; import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; @@ -21,15 +21,15 @@ public class GetFeedResponseDto { private Long userId; private List postHashtags; - public static GetFeedResponseDto toDto(PostRedis postRedis) { + public static GetFeedResponseDto toDto(PostRedis_DS postRedisDS) { return GetFeedResponseDto.builder() - .id(postRedis.getId()) - .content(postRedis.getContent()) - .imgUrl(postRedis.getImgUrl()) - .star(postRedis.getStar()) - .likeCount(postRedis.getLikeCount()) - .userId(postRedis.getUserId()) - .postHashtags(postRedis.getPostHashtags()) + .id(postRedisDS.getId()) + .content(postRedisDS.getContent()) + .imgUrl(postRedisDS.getImgUrl()) + .star(postRedisDS.getStar()) + .likeCount(postRedisDS.getLikeCount()) + .userId(postRedisDS.getUserId()) + .postHashtags(postRedisDS.getPostHashtags()) .build(); } } diff --git a/src/main/java/com/goormy/hackathon/entity/BaseTimeEntity.java b/src/main/java/com/goormy/hackathon/entity/BaseTimeEntity.java deleted file mode 100644 index c6a1c42..0000000 --- a/src/main/java/com/goormy/hackathon/entity/BaseTimeEntity.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.goormy.hackathon.entity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EntityListeners; -import jakarta.persistence.MappedSuperclass; -import java.time.LocalDateTime; -import lombok.Getter; -import org.hibernate.annotations.CreationTimestamp; -import org.hibernate.annotations.UpdateTimestamp; -import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.annotation.LastModifiedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; - -@Getter -@MappedSuperclass -@EntityListeners(AuditingEntityListener.class) -public class BaseTimeEntity { - - @CreatedDate - private LocalDateTime createdAt; - - @LastModifiedDate - private LocalDateTime updatedAt; -} \ No newline at end of file diff --git a/src/main/java/com/goormy/hackathon/entity/Hashtag.java b/src/main/java/com/goormy/hackathon/entity/Hashtag.java index 747b559..a1e5f9f 100644 --- a/src/main/java/com/goormy/hackathon/entity/Hashtag.java +++ b/src/main/java/com/goormy/hackathon/entity/Hashtag.java @@ -1,5 +1,6 @@ package com.goormy.hackathon.entity; +import com.goormy.hackathon.common.entity.BaseTimeEntity; import jakarta.persistence.*; import lombok.Builder; import lombok.Getter; @@ -11,7 +12,7 @@ @Entity @NoArgsConstructor @Getter -public class Hashtag extends BaseTimeEntity{ +public class Hashtag extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/com/goormy/hackathon/entity/PostHashtag.java b/src/main/java/com/goormy/hackathon/entity/PostHashtag.java index cb73f79..86b8912 100644 --- a/src/main/java/com/goormy/hackathon/entity/PostHashtag.java +++ b/src/main/java/com/goormy/hackathon/entity/PostHashtag.java @@ -8,7 +8,7 @@ @Entity @NoArgsConstructor @Getter -public class PostHashtag extends BaseTimeEntity{ +public class PostHashtag{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java index 50aaa07..3ee16da 100644 --- a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java +++ b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java @@ -1,10 +1,8 @@ package com.goormy.hackathon.redis.config; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.goormy.hackathon.redis.entity.PostRedis; -import com.goormy.hackathon.redis.entity.PostSimpleInfo; -import com.goormy.hackathon.redis.entity.UserRedis; -import org.springframework.beans.factory.annotation.Autowired; +import com.goormy.hackathon.redis.entity.PostRedis_DS; +import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; +import com.goormy.hackathon.redis.entity.UserRedis_DS; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; @@ -49,12 +47,12 @@ public RedisTemplate redisTemplate() { } @Bean - public RedisTemplate userRedisTemplate() { - RedisTemplate redisTemplate = new RedisTemplate<>(); + public RedisTemplate userRedisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory()); redisTemplate.setKeySerializer(new StringRedisSerializer()); - Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( - UserRedis.class); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( + UserRedis_DS.class); redisTemplate.setValueSerializer(serializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(serializer); @@ -62,12 +60,12 @@ public RedisTemplate userRedisTemplate() { } @Bean - public RedisTemplate postSimpleInfoRedisTemplate() { - RedisTemplate redisTemplate = new RedisTemplate<>(); + public RedisTemplate postSimpleInfoRedisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory()); redisTemplate.setKeySerializer(new StringRedisSerializer()); - Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( - PostSimpleInfo.class); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( + PostSimpleInfo_DS.class); redisTemplate.setValueSerializer(serializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(serializer); @@ -75,12 +73,12 @@ public RedisTemplate postSimpleInfoRedisTemplate() { } @Bean - public RedisTemplate postRedisTemplate() { - RedisTemplate redisTemplate = new RedisTemplate<>(); + public RedisTemplate postRedisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory()); redisTemplate.setKeySerializer(new StringRedisSerializer()); - Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( - PostRedis.class); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( + PostRedis_DS.class); redisTemplate.setValueSerializer(serializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(serializer); diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis.java b/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis_DS.java similarity index 83% rename from src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis.java rename to src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis_DS.java index bbef442..db78245 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis_DS.java @@ -1,6 +1,5 @@ package com.goormy.hackathon.redis.entity; -import jakarta.persistence.Id; import java.util.List; import lombok.AllArgsConstructor; import lombok.Getter; @@ -9,7 +8,7 @@ @Getter @RedisHash("popular_post") @AllArgsConstructor -public class PopularPostRedis { +public class PopularPostRedis_DS { private List postIdList; // 최대 256개의 아티클 저장 -> 1KB } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PostRedis.java b/src/main/java/com/goormy/hackathon/redis/entity/PostRedis_DS.java similarity index 90% rename from src/main/java/com/goormy/hackathon/redis/entity/PostRedis.java rename to src/main/java/com/goormy/hackathon/redis/entity/PostRedis_DS.java index 6dcbc45..3c07647 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/PostRedis.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/PostRedis_DS.java @@ -14,7 +14,7 @@ @RedisHash("post") @AllArgsConstructor @Builder -public class PostRedis { +public class PostRedis_DS { @Id private Long id; @@ -29,7 +29,7 @@ public class PostRedis { @JsonCreator - public PostRedis( + public PostRedis_DS( @JsonProperty("id") Long id, @JsonProperty("content") String content, @JsonProperty("imgUrl") String imgUrl, @@ -48,9 +48,9 @@ public PostRedis( this.createdAt = createdAt; } - public static PostRedis toEntity(Long id, String content, String imgUrl, Integer star, + public static PostRedis_DS toEntity(Long id, String content, String imgUrl, Integer star, Integer likeCount, Long userId, List postHashtags, LocalDateTime createdAt) { - return PostRedis.builder() + return PostRedis_DS.builder() .id(id) .content(content) .imgUrl(imgUrl) diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java b/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java deleted file mode 100644 index 277bb80..0000000 --- a/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.goormy.hackathon.redis.entity; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; -import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; -import com.goormy.hackathon.common.util.LocalDateTimeConverter; -import java.time.LocalDate; -import java.time.LocalDateTime; -import lombok.Builder; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.hibernate.annotations.CreationTimestamp; - -@Getter -@Builder -public class PostSimpleInfo { - - private Long id; - private String createdAt; - - @JsonCreator - public PostSimpleInfo( - @JsonProperty("id") Long postId, - @JsonProperty("createdAt") String createdAt) { - this.id = postId; - this.createdAt = createdAt; - } - - public static PostSimpleInfo toEntity(Long postId, String createdAt) { - return PostSimpleInfo.builder() - .id(postId) - .createdAt(createdAt) - .build(); - } - - -} diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo_DS.java b/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo_DS.java new file mode 100644 index 0000000..c6bfd56 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo_DS.java @@ -0,0 +1,31 @@ +package com.goormy.hackathon.redis.entity; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class PostSimpleInfo_DS { + + private Long id; + private String createdAt; + + @JsonCreator + public PostSimpleInfo_DS( + @JsonProperty("id") Long postId, + @JsonProperty("createdAt") String createdAt) { + this.id = postId; + this.createdAt = createdAt; + } + + public static PostSimpleInfo_DS toEntity(Long postId, String createdAt) { + return PostSimpleInfo_DS.builder() + .id(postId) + .createdAt(createdAt) + .build(); + } + + +} diff --git a/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis.java b/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis_DS.java similarity index 73% rename from src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis.java rename to src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis_DS.java index 04d94f8..9fc023a 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis_DS.java @@ -11,15 +11,15 @@ @RedisHash("recent_update") @Getter @Builder -public class RecentUpdateRedis { +public class RecentUpdateRedis_DS { @Id private Long id; private LocalDateTime recentUpdateTime; - public static RecentUpdateRedis toEntity(Long id, LocalDateTime recentUpdateTime) { - return RecentUpdateRedis.builder() + public static RecentUpdateRedis_DS toEntity(Long id, LocalDateTime recentUpdateTime) { + return RecentUpdateRedis_DS.builder() .id(id) .recentUpdateTime(recentUpdateTime) .build(); diff --git a/src/main/java/com/goormy/hackathon/redis/entity/UserRedis.java b/src/main/java/com/goormy/hackathon/redis/entity/UserRedis_DS.java similarity index 80% rename from src/main/java/com/goormy/hackathon/redis/entity/UserRedis.java rename to src/main/java/com/goormy/hackathon/redis/entity/UserRedis_DS.java index 4d71d50..7ec2c31 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/UserRedis.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/UserRedis_DS.java @@ -2,19 +2,16 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.persistence.Id; import java.io.Serializable; import java.util.List; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import org.springframework.data.redis.core.RedisHash; @Getter @Setter @Builder -public class UserRedis implements Serializable { +public class UserRedis_DS implements Serializable { private Long id; @@ -29,7 +26,7 @@ public class UserRedis implements Serializable { private List followerIdList; @JsonCreator - public UserRedis( + public UserRedis_DS( @JsonProperty("id") Long id, @JsonProperty("name") String name, @JsonProperty("password") String password, @@ -45,9 +42,9 @@ public UserRedis( } - public static UserRedis toEntity(Long id, String name, String password, Integer followerCount, + public static UserRedis_DS toEntity(Long id, String name, String password, Integer followerCount, Integer followingCount, List followerIdList) { - return UserRedis.builder() + return UserRedis_DS.builder() .id(id) .name(name) .password(password) diff --git a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_DS.java similarity index 58% rename from src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_DS.java index 7463f02..de93e1c 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_DS.java @@ -1,6 +1,6 @@ package com.goormy.hackathon.repository; -import com.goormy.hackathon.redis.entity.PostSimpleInfo; +import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; import jakarta.annotation.PostConstruct; import java.util.List; import lombok.RequiredArgsConstructor; @@ -10,23 +10,23 @@ @Component @RequiredArgsConstructor -public class FeedHashtagRedisRepository { +public class FeedHashtagRedisRepository_DS { - private final RedisTemplate redisTemplate; - private static final String FEED_HASHTAG_KEY = "FeedHashtag:"; + private final RedisTemplate redisTemplate; + private static final String FEED_HASHTAG_KEY = "feedhashtag:"; - private ListOperations listOperations; + private ListOperations listOperations; @PostConstruct private void init() { listOperations = redisTemplate.opsForList(); } - public void add(Long hashtagId, PostSimpleInfo value) { + public void add(Long hashtagId, PostSimpleInfo_DS value) { listOperations.leftPush(FEED_HASHTAG_KEY + hashtagId, value); } - public List getAll(Long hashtagId) { + public List getAll(Long hashtagId) { return listOperations.range(FEED_HASHTAG_KEY + hashtagId, 0, -1); } } diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_DS.java similarity index 59% rename from src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_DS.java index 578e476..0adc009 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_DS.java @@ -1,6 +1,6 @@ package com.goormy.hackathon.repository; -import com.goormy.hackathon.redis.entity.PostSimpleInfo; +import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; import jakarta.annotation.PostConstruct; import java.util.List; import lombok.RequiredArgsConstructor; @@ -10,27 +10,27 @@ @Component @RequiredArgsConstructor -public class FeedUserRedisRepository { +public class FeedUserRedisRepository_DS { - private final RedisTemplate redisTemplate; - private static final String FEED_USER_KEY = "FeedUser:"; + private final RedisTemplate redisTemplate; + private static final String FEED_USER_KEY = "feeduser:"; - private ListOperations listOperations; + private ListOperations listOperations; @PostConstruct private void init() { listOperations = redisTemplate.opsForList(); } - public void add(Long userId, PostSimpleInfo value) { + public void add(Long userId, PostSimpleInfo_DS value) { listOperations.leftPush(FEED_USER_KEY + userId, value); } - public PostSimpleInfo get(Long userId) { + public PostSimpleInfo_DS get(Long userId) { return listOperations.rightPop(FEED_USER_KEY + userId); } - public List getAll(Long userId) { + public List getAll(Long userId) { return listOperations.rightPop(FEED_USER_KEY + userId, Long.MAX_VALUE); } } diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository_DS.java similarity index 89% rename from src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository_DS.java index 19eb45d..91fe101 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository_DS.java @@ -9,10 +9,10 @@ @Component @RequiredArgsConstructor -public class FeedUserSortRedisRepository { +public class FeedUserSortRedisRepository_DS { private final RedisTemplate redisTemplate; - private static final String FEED_USER_SORTED_KEY = "FeedUserSort:"; + private static final String FEED_USER_SORTED_KEY = "feedusersort:"; private ListOperations listOperations; diff --git a/src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository_DS.java similarity index 50% rename from src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository_DS.java index fa15cb4..b68791c 100644 --- a/src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository_DS.java @@ -1,5 +1,5 @@ package com.goormy.hackathon.repository; -public class PopularPostRedisRepository { +public class PopularPostRedisRepository_DS { } diff --git a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository_DS.java similarity index 58% rename from src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/PostRedisRepository_DS.java index 0e6dfd6..2d4e3b7 100644 --- a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository_DS.java @@ -1,6 +1,6 @@ package com.goormy.hackathon.repository; -import com.goormy.hackathon.redis.entity.PostRedis; +import com.goormy.hackathon.redis.entity.PostRedis_DS; import jakarta.annotation.PostConstruct; import java.util.List; import java.util.Optional; @@ -11,28 +11,28 @@ @Component @RequiredArgsConstructor -public class PostRedisRepository { +public class PostRedisRepository_DS { - private final RedisTemplate redisTemplate; - private static final String POST_KEY = "Post:"; + private final RedisTemplate redisTemplate; + private static final String POST_KEY = "post:"; - private ValueOperations valueOperations; + private ValueOperations valueOperations; @PostConstruct private void init() { valueOperations = redisTemplate.opsForValue(); } - public void set(Long postId, PostRedis value) { + public void set(Long postId, PostRedis_DS value) { valueOperations.set(POST_KEY + postId, value); } - public Optional get(Long postId) { - PostRedis post = valueOperations.get(POST_KEY + postId); + public Optional get(Long postId) { + PostRedis_DS post = valueOperations.get(POST_KEY + postId); return Optional.ofNullable(post); } - public List getAll(List postIdList) { + public List getAll(List postIdList) { return postIdList.stream() .map(postId -> valueOperations.get(POST_KEY + postId)) .toList(); diff --git a/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository_DS.java similarity index 92% rename from src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository_DS.java index c1ea7b0..c1555ea 100644 --- a/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository_DS.java @@ -12,12 +12,12 @@ @Component @RequiredArgsConstructor -public class RecentUpdateRedisRepository { +public class RecentUpdateRedisRepository_DS { private final StringRedisTemplate stringRedisTemplate; private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; - private static final String RECENT_UPDATE_KEY = "RecentUpdate:"; + private static final String RECENT_UPDATE_KEY = "recentupdate:"; private static final Duration TTL = Duration.ofDays(3); private ValueOperations valueOperations; diff --git a/src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/UserRedisRepository_DS.java similarity index 55% rename from src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/UserRedisRepository_DS.java index 6f70d7b..2a5a41e 100644 --- a/src/main/java/com/goormy/hackathon/repository/UserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/UserRedisRepository_DS.java @@ -1,6 +1,6 @@ package com.goormy.hackathon.repository; -import com.goormy.hackathon.redis.entity.UserRedis; +import com.goormy.hackathon.redis.entity.UserRedis_DS; import jakarta.annotation.PostConstruct; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -10,24 +10,24 @@ @Component @RequiredArgsConstructor -public class UserRedisRepository { +public class UserRedisRepository_DS { - private final RedisTemplate redisTemplate; - private static final String USER_KEY = "User:"; + private final RedisTemplate redisTemplate; + private static final String USER_KEY = "user:"; - private ValueOperations valueOperations; + private ValueOperations valueOperations; @PostConstruct private void init() { valueOperations = redisTemplate.opsForValue(); } - public void set(Long userId, UserRedis value) { + public void set(Long userId, UserRedis_DS value) { valueOperations.set(USER_KEY + userId, value); } - public Optional get(Long userId) { - UserRedis user = valueOperations.get(USER_KEY + userId); + public Optional get(Long userId) { + UserRedis_DS user = valueOperations.get(USER_KEY + userId); return Optional.ofNullable(user); } } diff --git a/src/main/java/com/goormy/hackathon/service/GetFeedService.java b/src/main/java/com/goormy/hackathon/service/GetFeedService.java index 72b90e4..6e0aeac 100644 --- a/src/main/java/com/goormy/hackathon/service/GetFeedService.java +++ b/src/main/java/com/goormy/hackathon/service/GetFeedService.java @@ -1,20 +1,21 @@ package com.goormy.hackathon.service; -import com.goormy.hackathon.common.util.LocalDateTimeConverter; +import com.goormy.hackathon.common.util.LocalDateTimeConverter_DS; import com.goormy.hackathon.dto.response.GetFeedResponseDto; import com.goormy.hackathon.entity.Follow; import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.redis.entity.PostRedis; -import com.goormy.hackathon.redis.entity.PostSimpleInfo; -import com.goormy.hackathon.redis.entity.UserRedis; -import com.goormy.hackathon.repository.FeedHashtagRedisRepository; -import com.goormy.hackathon.repository.FeedUserRedisRepository; -import com.goormy.hackathon.repository.FeedUserSortRedisRepository; -import com.goormy.hackathon.repository.PostRedisRepository; +import com.goormy.hackathon.redis.entity.PostRedis_DS; +import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; +import com.goormy.hackathon.redis.entity.UserRedis_DS; +import com.goormy.hackathon.repository.FeedHashtagRedisRepository_DS; +import com.goormy.hackathon.repository.FeedUserRedisRepository_DS; +import com.goormy.hackathon.repository.FeedUserSortRedisRepository_DS; +import com.goormy.hackathon.repository.PostRedisRepository_DS; import com.goormy.hackathon.repository.PostRepository; -import com.goormy.hackathon.repository.RecentUpdateRedisRepository; -import com.goormy.hackathon.repository.UserRedisRepository; +import com.goormy.hackathon.repository.RecentUpdateRedisRepository_DS; +import com.goormy.hackathon.repository.RecentUpdateRedisRepository_DS; +import com.goormy.hackathon.repository.UserRedisRepository_DS; import com.goormy.hackathon.repository.UserRespository; import jakarta.transaction.Transactional; import java.time.LocalDateTime; @@ -33,19 +34,19 @@ public class GetFeedService { private final UserRespository userRespository; private final PostRepository postRepository; - private final LocalDateTimeConverter localDateTimeConverter; + private final LocalDateTimeConverter_DS localDateTimeConverter; - private final FeedHashtagRedisRepository feedHashtagRedisRepository; - private final FeedUserRedisRepository feedUserRedisRepository; - private final FeedUserSortRedisRepository feedUserSortRedisRepository; - private final PostRedisRepository postRedisRepository; - private final RecentUpdateRedisRepository recentUpdateRedisRepository; - private final UserRedisRepository userRedisRepository; + private final FeedHashtagRedisRepository_DS feedHashtagRedisRepository; + private final FeedUserRedisRepository_DS feedUserRedisRepository; + private final FeedUserSortRedisRepository_DS feedUserSortRedisRepository; + private final PostRedisRepository_DS postRedisRepository; + private final RecentUpdateRedisRepository_DS recentUpdateRedisRepository; + private final UserRedisRepository_DS userRedisRepository; // 1. 사용자 정보를 가져옴 - private UserRedis getUser(Long userId) { + private UserRedis_DS getUser(Long userId) { // 캐시 우선 검색 - Optional userCacheOptional = userRedisRepository.get(userId); + Optional userCacheOptional = userRedisRepository.get(userId); // 캐시에 없으면 RDB에서 검색 return userCacheOptional.orElseGet(() -> { User user = userRespository.findById(userId) @@ -55,28 +56,28 @@ private UserRedis getUser(Long userId) { .toList(); // RDB에서 검색하고, UserCache에 추가 userRedisRepository.set(userId, - UserRedis.toEntity(user.getId(), user.getName(), user.getPassword(), + UserRedis_DS.toEntity(user.getId(), user.getName(), user.getPassword(), user.getFollowerCount(), user.getFollowingCount(), followIdList)); - return UserRedis.toEntity(user.getId(), user.getName(), user.getPassword(), + return UserRedis_DS.toEntity(user.getId(), user.getName(), user.getPassword(), user.getFollowerCount(), user.getFollowingCount(), followIdList); }); } // 2, 3. Push & Pull 방식으로 피드를 가져옴 - private List getPushPullFeed(UserRedis userRedis) { + private List getPushPullFeed(UserRedis_DS userRedisDS) { // 날짜 세팅 // recentUpdatedTime - 가장 마지막으로 업데이트한 시간이랑 3일 중 현재와 가장 가까운 시간을 기준으로 잡음 LocalDateTime now = LocalDateTime.now(); - LocalDateTime recentUpdatedTime = recentUpdateRedisRepository.get(userRedis.getId()) + LocalDateTime recentUpdatedTime = recentUpdateRedisRepository.get(userRedisDS.getId()) .orElse(now.minusDays(3)); // *** 2. Push 방식 *** // Push 방식으로 저장되어있는 포스트 가져오기 -> Created At 정보도 같이 저장해야함 // (이유) 한개의 Key에 있는 각 값마다 TTL 설정이 불가능하기 때문 // feedUser 접근 - List feedUserCache = feedUserRedisRepository.getAll(userRedis.getId()); + List feedUserCache = feedUserRedisRepository.getAll(userRedisDS.getId()); // push 캐시 가져오고 비우기 & 3일 전 포스트까지만 가져오기 - List postSimpleInfoList = new ArrayList<>(feedUserCache.stream() + List postSimpleInfoDSList = new ArrayList<>(feedUserCache.stream() .filter(simpleInfo -> localDateTimeConverter.convertToLocalDateTime( simpleInfo.getCreatedAt()).isAfter(recentUpdatedTime)) .toList()); @@ -85,10 +86,10 @@ private List getPushPullFeed(UserRedis userRedis) { // Pull 방식으로 저장되어있는 인플루언서 포스트 가져오기 -> 사용자가 최근에 업데이트한 시간 이후부터 진행 // (이유) 한개의 Key에 있는 각 값마다 TTL 설정이 불가능하기 때문 // user의 follow 리스트를 순회하면서 가져와야함 & 3일 전 포스트까지만 가져오기 - userRedis.getFollowerIdList().forEach( + userRedisDS.getFollowerIdList().forEach( followId -> { - List info = feedHashtagRedisRepository.getAll(followId); - postSimpleInfoList.addAll(info.stream() + List info = feedHashtagRedisRepository.getAll(followId); + postSimpleInfoDSList.addAll(info.stream() .filter(Objects::nonNull) .filter(simpleInfo -> localDateTimeConverter.convertToLocalDateTime( simpleInfo.getCreatedAt()).isAfter(recentUpdatedTime)) @@ -98,13 +99,13 @@ private List getPushPullFeed(UserRedis userRedis) { ); // 최신 업데이트 시간 반영 - recentUpdateRedisRepository.set(userRedis.getId(), now); + recentUpdateRedisRepository.set(userRedisDS.getId(), now); - return postSimpleInfoList.stream().filter(Objects::nonNull).toList(); + return postSimpleInfoDSList.stream().filter(Objects::nonNull).toList(); } // 5. size개의 post를 구분 - private List splitPostSimpleInfoList(UserRedis userRedis, + private List splitPostSimpleInfoList(UserRedis_DS userRedisDS, List postIdList, int size) { // 초기 반환을 위한 Id 리스트 @@ -112,23 +113,23 @@ private List splitPostSimpleInfoList(UserRedis userRedis, List postIdListForRedis = postIdList.stream() .skip(size).toList(); postIdListForRedis.forEach( - postId -> feedUserSortRedisRepository.add(userRedis.getId(), postId)); + postId -> feedUserSortRedisRepository.add(userRedisDS.getId(), postId)); // 사용자에게 반환할 게시글 리스트 return postIdList.stream().limit(size).toList(); } // 5. PostList를 가져옴 - private List getPostList(List postIdList) { - List postRedisList = new ArrayList<>(postRedisRepository.getAll(postIdList)); + private List getPostList(List postIdList) { + List postRedisDSList = new ArrayList<>(postRedisRepository.getAll(postIdList)); - if (postRedisList.isEmpty()) { + if (postRedisDSList.isEmpty()) { return new ArrayList<>(); } - List postCacheIdList = postRedisList.stream() + List postCacheIdList = postRedisDSList.stream() .filter(Objects::nonNull) - .map(PostRedis::getId) + .map(PostRedis_DS::getId) .toList(); // cache에 없는 post id 리스트를 찾음 @@ -137,26 +138,26 @@ private List getPostList(List postIdList) { // RDS에서 가져온 이후 Cache에 업데이트 List postList = postRepository.findAllByIdIn(postIdListNotInCache); postList.forEach(post -> { - PostRedis postRedis = PostRedis.toEntity( + PostRedis_DS postRedisDS = PostRedis_DS.toEntity( post.getId(), post.getContent(), post.getImageUrl(), post.getStar(), post.getLikeCount(), post.getUser().getId(), post.getPostHashtags().stream().map(hashtag -> hashtag.getHashtag().getName()) .toList(), post.getCreatedAt() ); - postRedisRepository.set(postRedis.getId(), postRedis); - postRedisList.add(postRedis); + postRedisRepository.set(postRedisDS.getId(), postRedisDS); + postRedisDSList.add(postRedisDS); }); // TODO: postId별로 like여부 받아오는 코드 추가 - return postRedisList.stream().filter(Objects::nonNull).toList(); + return postRedisDSList.stream().filter(Objects::nonNull).toList(); } // 날짜 기준으로 정렬하는 것으로 우선순위 선정 @Transactional public List getFeedList(Long userId, int size) { // 1. 사용자 정보 가져오기 (Redis -> RDS) - UserRedis userRedis = getUser(userId); + UserRedis_DS userRedisDS = getUser(userId); // 2.0 이미 정리해둔 post가 있으면 가져오기 List postIdList = feedUserSortRedisRepository.getSome(userId, size); @@ -169,17 +170,17 @@ public List getFeedList(Long userId, int size) { // 2, 3. Push, Pull로 Feed List 가져오기 & 필터링 // 나중에 (1)여기 먼저 조회 & 있으면 반환, 없으면 (2)push/pull 확인 후 부족하면 (3)인기 게시글 반환 - List pushPullFeedList = getPushPullFeed(userRedis); + List pushPullFeedList = getPushPullFeed(userRedisDS); // 여기서 Null 체크, 이후 리스트에 들어가는 모든 post는 null이 있을 수 없음 // 4. 최신순으로 정렬 List sortedPushPullFeedList = pushPullFeedList.stream() - .sorted(Comparator.comparing(PostSimpleInfo::getCreatedAt)) - .map(PostSimpleInfo::getId) + .sorted(Comparator.comparing(PostSimpleInfo_DS::getCreatedAt)) + .map(PostSimpleInfo_DS::getId) .toList(); // 5. 반환할 데이터와, Redis에 저장할 데이터를 구분하고, Redis에 저장 - List postIdListForReturn = splitPostSimpleInfoList(userRedis, sortedPushPullFeedList, + List postIdListForReturn = splitPostSimpleInfoList(userRedisDS, sortedPushPullFeedList, size); // 5. post를 조회해서 반환 return getPostList(postIdListForReturn).stream().map(GetFeedResponseDto::toDto).toList(); From c6afe5cddf534897744e88b64ac23045bb34cba0 Mon Sep 17 00:00:00 2001 From: seplease Date: Thu, 1 Aug 2024 21:22:54 +0900 Subject: [PATCH 44/57] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=20=ED=8C=94?= =?UTF-8?q?=EB=A1=9C=EC=9E=89=20=ED=95=B4=EC=8B=9C=ED=83=9C=EA=B7=B8=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C,=20=ED=8C=94=EB=A1=9C?= =?UTF-8?q?=EC=9A=B0=20=EC=96=B8=ED=8C=94=EB=A1=9C=EC=9A=B0=20=EC=88=98=20?= =?UTF-8?q?=EC=BA=90=EC=8B=9C,=20=ED=95=B4=EC=8B=9C=ED=83=9C=EA=B7=B8=20?= =?UTF-8?q?=EA=B2=80=EC=83=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FollowController_sieun.java | 36 ++++++++++++++++ .../controller/PostController_sieun.java | 28 ++++++++++++ .../hackathon/dto/HashtagDto_sieun.java | 18 ++++++++ .../FollowCountRedisRepository_sieun.java | 38 ++++++++++++++++ .../repository/FollowRepository_sieun.java | 17 ++++++++ .../repository/PostRepository_sieun.java | 15 +++++++ .../repository/UserRepository_sieun.java | 10 +++++ .../service/FollowService_sieun.java | 43 +++++++++++++++++++ .../hackathon/service/PostService_sieun.java | 34 +++++++++++++++ .../hackathon/service/UserService_sieun.java | 17 ++++++++ 10 files changed, 256 insertions(+) create mode 100644 src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/controller/PostController_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/dto/HashtagDto_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/repository/FollowRepository_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/repository/PostRepository_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/repository/UserRepository_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/service/FollowService_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/service/PostService_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/service/UserService_sieun.java diff --git a/src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java b/src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java new file mode 100644 index 0000000..f152249 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java @@ -0,0 +1,36 @@ +package com.goormy.hackathon.controller; + +import com.goormy.hackathon.dto.HashtagDto_sieun; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.service.FollowService_sieun; +import com.goormy.hackathon.service.UserService_sieun; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("/followings") +public class FollowController_sieun { + + @Autowired + private FollowService_sieun followServiceSieun; + @Autowired + private UserService_sieun userServiceSieun; + + @GetMapping + public List getFollowedHashtags(@RequestHeader("userId") Long userId) { + User user = userServiceSieun.findById(userId); + + List hashtags = followServiceSieun.getFollowedHashtags(user); + + return hashtags.stream() + .map(hashtag -> new HashtagDto_sieun(hashtag.getId(), hashtag.getName(), hashtag.getType().toString())) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/goormy/hackathon/controller/PostController_sieun.java b/src/main/java/com/goormy/hackathon/controller/PostController_sieun.java new file mode 100644 index 0000000..9fe818a --- /dev/null +++ b/src/main/java/com/goormy/hackathon/controller/PostController_sieun.java @@ -0,0 +1,28 @@ +package com.goormy.hackathon.controller; + +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.service.PostService_sieun; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.web.bind.annotation.*; + +@RestController +public class PostController_sieun { + private final PostService_sieun postServiceSieun; + + @Autowired + public PostController_sieun(PostService_sieun postServiceSieun) { + this.postServiceSieun = postServiceSieun; + } + + @GetMapping("/posts/by-hashtag") + public Page getPostsByHashtag( + @RequestParam(name = "hashtag") String hashtag, + @RequestParam(name = "page") int page, + @RequestParam(name = "size") int size) { + System.out.println("Received request to fetch posts by hashtag: " + hashtag); + Page postsPage = postServiceSieun.getPostsByHashtag(hashtag, page, size); + System.out.println("Returning page " + postsPage.getNumber() + " of " + postsPage.getTotalPages() + " for hashtag: " + hashtag); + return postsPage; + } +} diff --git a/src/main/java/com/goormy/hackathon/dto/HashtagDto_sieun.java b/src/main/java/com/goormy/hackathon/dto/HashtagDto_sieun.java new file mode 100644 index 0000000..1cba285 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/dto/HashtagDto_sieun.java @@ -0,0 +1,18 @@ +package com.goormy.hackathon.dto; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class HashtagDto_sieun { + private Long id; + private String name; + private String type; + + public HashtagDto_sieun(Long id, String name, String type) { + this.id = id; + this.name = name; + this.type = type; + } +} diff --git a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_sieun.java b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_sieun.java new file mode 100644 index 0000000..2db1789 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_sieun.java @@ -0,0 +1,38 @@ + +package com.goormy.hackathon.repository; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +@Service +public class FollowCountRedisRepository_sieun { + + private final RedisTemplate integerRedisTemplate; + private static final String FOLLOWING_COUNT_KEY = "follow_count:"; + + @Autowired + public FollowCountRedisRepository_sieun(RedisTemplate integerRedisTemplate) { + this.integerRedisTemplate = integerRedisTemplate; + } + + public Integer getFollowCount(Long hashtagId) { + String key = FOLLOWING_COUNT_KEY + hashtagId; + return integerRedisTemplate.opsForValue().get(key); + } + + public void setFollowCount(Long hashtagId, int followCount) { + String key = FOLLOWING_COUNT_KEY + hashtagId; + integerRedisTemplate.opsForValue().set(key, followCount); + } + + public void incrementFollowCount(Long hashtagId) { + String key = FOLLOWING_COUNT_KEY + hashtagId; + integerRedisTemplate.opsForValue().increment(key, 1); + } + + public void decrementFollowCount(Long hashtagId) { + String key = FOLLOWING_COUNT_KEY + hashtagId; + integerRedisTemplate.opsForValue().decrement(key, 1); + } +} diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRepository_sieun.java b/src/main/java/com/goormy/hackathon/repository/FollowRepository_sieun.java new file mode 100644 index 0000000..635c8ec --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/FollowRepository_sieun.java @@ -0,0 +1,17 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface FollowRepository_sieun extends JpaRepository { + @Query("SELECT f.hashtag FROM Follow f WHERE f.user = :user") + List findHashtagsByUser(@Param("user") User user); +} diff --git a/src/main/java/com/goormy/hackathon/repository/PostRepository_sieun.java b/src/main/java/com/goormy/hackathon/repository/PostRepository_sieun.java new file mode 100644 index 0000000..4bbb7ba --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/PostRepository_sieun.java @@ -0,0 +1,15 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.Post; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +@Repository +public interface PostRepository_sieun extends JpaRepository { + @Query("SELECT p FROM Post p JOIN p.postHashtags ph JOIN ph.hashtag h WHERE h.name = :hashtagName") + Page findPostsByHashtagName(@Param("hashtagName") String hashtagName, Pageable pageable); +} diff --git a/src/main/java/com/goormy/hackathon/repository/UserRepository_sieun.java b/src/main/java/com/goormy/hackathon/repository/UserRepository_sieun.java new file mode 100644 index 0000000..de03c01 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/UserRepository_sieun.java @@ -0,0 +1,10 @@ +package com.goormy.hackathon.repository; + +import com.goormy.hackathon.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository_sieun extends JpaRepository { + User findByName(String name); +} diff --git a/src/main/java/com/goormy/hackathon/service/FollowService_sieun.java b/src/main/java/com/goormy/hackathon/service/FollowService_sieun.java new file mode 100644 index 0000000..6a4217b --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/FollowService_sieun.java @@ -0,0 +1,43 @@ +package com.goormy.hackathon.service; + +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.repository.FollowCountRedisRepository_sieun; +import com.goormy.hackathon.repository.FollowRepository_sieun; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class FollowService_sieun { + + private final FollowRepository_sieun followRepositorySieun; + private final FollowCountRedisRepository_sieun followCountRedisRepositorySieun; + + // 유저가 팔로우하고 있는 해시태그 목록 조회 + public List getFollowedHashtags(User user) { + return followRepositorySieun.findHashtagsByUser(user); + } + + // 팔로우, 언팔로우 캐시 부분 + @Transactional + public void followHashtag(Long hashtagId) { + Integer currentCount = followCountRedisRepositorySieun.getFollowCount(hashtagId); + if (currentCount == null) { + followCountRedisRepositorySieun.setFollowCount(hashtagId, 1); // 처음 팔로우인 경우 초기화 + } else { + followCountRedisRepositorySieun.incrementFollowCount(hashtagId); // 기존 팔로우 수 증가 + } + } + + @Transactional + public void unfollowHashtag(Long hashtagId) { + Integer currentCount = followCountRedisRepositorySieun.getFollowCount(hashtagId); + if (currentCount != null && currentCount > 0) { + followCountRedisRepositorySieun.decrementFollowCount(hashtagId); // 팔로우 수 감소 + } + } +} diff --git a/src/main/java/com/goormy/hackathon/service/PostService_sieun.java b/src/main/java/com/goormy/hackathon/service/PostService_sieun.java new file mode 100644 index 0000000..068796b --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/PostService_sieun.java @@ -0,0 +1,34 @@ +package com.goormy.hackathon.service; + +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.repository.PostRepository_sieun; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; + +@Service +public class PostService_sieun { + + private final PostRepository_sieun postRepositorySieun; + + @Autowired + public PostService_sieun(PostRepository_sieun postRepositorySieun) { + this.postRepositorySieun = postRepositorySieun; + } + + public Page getPostsByHashtag(String hashtagName, int page, int size) { + System.out.println("Fetching posts with hashtag: " + hashtagName + ", page: " + page + ", size: " + size); + Page postsPage = postRepositorySieun.findPostsByHashtagName(hashtagName, PageRequest.of(page, size)); + + if (postsPage == null) { + throw new RuntimeException("No posts found for the given hashtag."); + } + + System.out.println("Total elements: " + postsPage.getTotalElements()); + System.out.println("Total pages: " + postsPage.getTotalPages()); + System.out.println("Current page: " + postsPage.getNumber()); + System.out.println("Number of posts on this page: " + postsPage.getNumberOfElements()); + return postsPage; + } +} diff --git a/src/main/java/com/goormy/hackathon/service/UserService_sieun.java b/src/main/java/com/goormy/hackathon/service/UserService_sieun.java new file mode 100644 index 0000000..97f9b12 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/UserService_sieun.java @@ -0,0 +1,17 @@ +package com.goormy.hackathon.service; + +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.repository.UserRepository_sieun; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class UserService_sieun { + + @Autowired + private UserRepository_sieun userRepositorySieun; + + public User findById(Long id) { + return userRepositorySieun.findById(id).orElse(null); + } +} From 90dc9b9b7b0309bb6e04b28ee6f3710e97c50d83 Mon Sep 17 00:00:00 2001 From: siyeonSon Date: Thu, 1 Aug 2024 21:30:23 +0900 Subject: [PATCH 45/57] =?UTF-8?q?refactor:=20=EB=AA=A8=EB=93=A0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=ED=8C=8C=EC=9D=BC=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=98=EC=97=AC=20=5FSY=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...r.java => LocalDateTimeConverter__SY.java} | 4 +- .../hackathon/controller/PostController.java | 24 --------- .../controller/PostController_SY.java | 24 +++++++++ ...Dto.java => PostHashtagRequestDto_SY.java} | 2 +- ...to.java => PostHashtagResponseDto_SY.java} | 2 +- .../hackathon/dto/post/PostRequestDto.java | 14 ------ .../hackathon/dto/post/PostRequestDto_SY.java | 14 ++++++ ...sponseDto.java => PostResponseDto_SY.java} | 13 +++-- ...tagCache.java => FeedHashtagCache_SY.java} | 4 +- ...SimpleInfo.java => FeedSimpleInfo_SY.java} | 8 +-- ...edUserCache.java => FeedUserCache_SY.java} | 6 +-- ...untCache.java => FollowCountCache_SY.java} | 4 +- ...ListCache.java => FollowListCache_SY.java} | 2 +- .../{PostCache.java => PostCache_SY.java} | 8 +-- ...ava => FeedHashtagRedisRepository_SY.java} | 6 +-- ...y.java => FeedUserRedisRepository_SY.java} | 6 +-- ...ava => FollowCountRedisRepository_SY.java} | 8 +-- ...java => FollowListRedisRepository_SY.java} | 6 +-- ...ository.java => HashtagRepository_SY.java} | 2 +- ...itory.java => PostRedisRepository_SY.java} | 8 +-- ...Repository.java => PostRepository_SY.java} | 2 +- ...Repository.java => UserRepository_SY.java} | 2 +- ...tagService.java => HashtagService_SY.java} | 24 ++++----- ...eService.java => PostCacheService_SY.java} | 26 +++++----- .../goormy/hackathon/service/PostService.java | 50 ------------------- .../hackathon/service/PostService_SY.java | 49 ++++++++++++++++++ 26 files changed, 159 insertions(+), 159 deletions(-) rename src/main/java/com/goormy/hackathon/common/util/{LocalDateTimeConverter.java => LocalDateTimeConverter__SY.java} (74%) delete mode 100644 src/main/java/com/goormy/hackathon/controller/PostController.java create mode 100644 src/main/java/com/goormy/hackathon/controller/PostController_SY.java rename src/main/java/com/goormy/hackathon/dto/hashtag/{PostHashtagRequestDto.java => PostHashtagRequestDto_SY.java} (78%) rename src/main/java/com/goormy/hackathon/dto/hashtag/{PostHashtagResponseDto.java => PostHashtagResponseDto_SY.java} (77%) delete mode 100644 src/main/java/com/goormy/hackathon/dto/post/PostRequestDto.java create mode 100644 src/main/java/com/goormy/hackathon/dto/post/PostRequestDto_SY.java rename src/main/java/com/goormy/hackathon/dto/post/{PostResponseDto.java => PostResponseDto_SY.java} (60%) rename src/main/java/com/goormy/hackathon/redis/entity/{FeedHashtagCache.java => FeedHashtagCache_SY.java} (66%) rename src/main/java/com/goormy/hackathon/redis/entity/{FeedSimpleInfo.java => FeedSimpleInfo_SY.java} (54%) rename src/main/java/com/goormy/hackathon/redis/entity/{FeedUserCache.java => FeedUserCache_SY.java} (67%) rename src/main/java/com/goormy/hackathon/redis/entity/{FollowCountCache.java => FollowCountCache_SY.java} (82%) rename src/main/java/com/goormy/hackathon/redis/entity/{FollowListCache.java => FollowListCache_SY.java} (81%) rename src/main/java/com/goormy/hackathon/redis/entity/{PostCache.java => PostCache_SY.java} (79%) rename src/main/java/com/goormy/hackathon/repository/{FeedHashtagRedisRepository.java => FeedHashtagRedisRepository_SY.java} (75%) rename src/main/java/com/goormy/hackathon/repository/{FeedUserRedisRepository.java => FeedUserRedisRepository_SY.java} (76%) rename src/main/java/com/goormy/hackathon/repository/{FollowCountRedisRepository.java => FollowCountRedisRepository_SY.java} (63%) rename src/main/java/com/goormy/hackathon/repository/{FollowListRedisRepository.java => FollowListRedisRepository_SY.java} (72%) rename src/main/java/com/goormy/hackathon/repository/{HashtagRepository.java => HashtagRepository_SY.java} (74%) rename src/main/java/com/goormy/hackathon/repository/{PostRedisRepository.java => PostRedisRepository_SY.java} (57%) rename src/main/java/com/goormy/hackathon/repository/{PostRepository.java => PostRepository_SY.java} (66%) rename src/main/java/com/goormy/hackathon/repository/{UserRepository.java => UserRepository_SY.java} (67%) rename src/main/java/com/goormy/hackathon/service/{HashtagService.java => HashtagService_SY.java} (62%) rename src/main/java/com/goormy/hackathon/service/{PostCacheService.java => PostCacheService_SY.java} (52%) delete mode 100644 src/main/java/com/goormy/hackathon/service/PostService.java create mode 100644 src/main/java/com/goormy/hackathon/service/PostService_SY.java diff --git a/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java b/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter__SY.java similarity index 74% rename from src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java rename to src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter__SY.java index be2ee4d..2ac5df3 100644 --- a/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter.java +++ b/src/main/java/com/goormy/hackathon/common/util/LocalDateTimeConverter__SY.java @@ -3,9 +3,9 @@ import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -public final class LocalDateTimeConverter { +public final class LocalDateTimeConverter__SY { - private LocalDateTimeConverter() { + private LocalDateTimeConverter__SY() { } public static String convert(LocalDateTime value) { diff --git a/src/main/java/com/goormy/hackathon/controller/PostController.java b/src/main/java/com/goormy/hackathon/controller/PostController.java deleted file mode 100644 index 0c18205..0000000 --- a/src/main/java/com/goormy/hackathon/controller/PostController.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.goormy.hackathon.controller; - - -import com.goormy.hackathon.dto.post.PostRequestDto; -import com.goormy.hackathon.dto.post.PostResponseDto; -import com.goormy.hackathon.service.PostService; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/posts") -@RequiredArgsConstructor -public class PostController { - - private final PostService postService; - - @PostMapping - public PostResponseDto create( - @RequestHeader("userId") Long userId, - @RequestBody PostRequestDto postRequestDto) { - return postService.createPost(userId, postRequestDto); - } - -} diff --git a/src/main/java/com/goormy/hackathon/controller/PostController_SY.java b/src/main/java/com/goormy/hackathon/controller/PostController_SY.java new file mode 100644 index 0000000..a798bb9 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/controller/PostController_SY.java @@ -0,0 +1,24 @@ +package com.goormy.hackathon.controller; + + +import com.goormy.hackathon.dto.post.PostRequestDto_SY; +import com.goormy.hackathon.dto.post.PostResponseDto_SY; +import com.goormy.hackathon.service.PostService_SY; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/posts") +@RequiredArgsConstructor +public class PostController_SY { + + private final PostService_SY postServiceSY; + + @PostMapping + public PostResponseDto_SY create( + @RequestHeader("userId") Long userId, + @RequestBody PostRequestDto_SY postRequestDtoSY) { + return postServiceSY.createPost(userId, postRequestDtoSY); + } + +} diff --git a/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagRequestDto.java b/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagRequestDto_SY.java similarity index 78% rename from src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagRequestDto.java rename to src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagRequestDto_SY.java index dcb1210..40250de 100644 --- a/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagRequestDto.java +++ b/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagRequestDto_SY.java @@ -2,7 +2,7 @@ import com.goormy.hackathon.entity.Hashtag; -public record PostHashtagRequestDto( +public record PostHashtagRequestDto_SY( String name, Hashtag.Type type ) { diff --git a/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagResponseDto.java b/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagResponseDto_SY.java similarity index 77% rename from src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagResponseDto.java rename to src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagResponseDto_SY.java index 7f70681..ef7046b 100644 --- a/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagResponseDto.java +++ b/src/main/java/com/goormy/hackathon/dto/hashtag/PostHashtagResponseDto_SY.java @@ -2,7 +2,7 @@ import com.goormy.hackathon.entity.Hashtag; -public record PostHashtagResponseDto( +public record PostHashtagResponseDto_SY( String name, Hashtag.Type type ) { diff --git a/src/main/java/com/goormy/hackathon/dto/post/PostRequestDto.java b/src/main/java/com/goormy/hackathon/dto/post/PostRequestDto.java deleted file mode 100644 index 07e5274..0000000 --- a/src/main/java/com/goormy/hackathon/dto/post/PostRequestDto.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.goormy.hackathon.dto.post; - -import com.goormy.hackathon.dto.hashtag.PostHashtagRequestDto; - -import java.util.List; - -public record PostRequestDto( - String content, - String imageUrl, - Integer star, - List postHashtags -) { - -} diff --git a/src/main/java/com/goormy/hackathon/dto/post/PostRequestDto_SY.java b/src/main/java/com/goormy/hackathon/dto/post/PostRequestDto_SY.java new file mode 100644 index 0000000..6b7dae3 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/dto/post/PostRequestDto_SY.java @@ -0,0 +1,14 @@ +package com.goormy.hackathon.dto.post; + +import com.goormy.hackathon.dto.hashtag.PostHashtagRequestDto_SY; + +import java.util.List; + +public record PostRequestDto_SY( + String content, + String imageUrl, + Integer star, + List postHashtags +) { + +} diff --git a/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java b/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto_SY.java similarity index 60% rename from src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java rename to src/main/java/com/goormy/hackathon/dto/post/PostResponseDto_SY.java index 2343b8b..4cc17b6 100644 --- a/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto.java +++ b/src/main/java/com/goormy/hackathon/dto/post/PostResponseDto_SY.java @@ -1,23 +1,22 @@ package com.goormy.hackathon.dto.post; -import com.goormy.hackathon.dto.hashtag.PostHashtagResponseDto; +import com.goormy.hackathon.dto.hashtag.PostHashtagResponseDto_SY; import com.goormy.hackathon.entity.Post; -import java.io.Serializable; import java.time.LocalDateTime; import java.util.List; -public record PostResponseDto( +public record PostResponseDto_SY( Long id, String content, String imageUrl, Integer star, - List postHashtags, + List postHashtags, LocalDateTime createdAt ) { - public PostResponseDto(Post post) { + public PostResponseDto_SY(Post post) { this( post.getId(), post.getContent(), @@ -28,9 +27,9 @@ public PostResponseDto(Post post) { ); } - private static List mapHashtagsToDto(Post post) { + private static List mapHashtagsToDto(Post post) { return post.getPostHashtags().stream() - .map(hashtag -> new PostHashtagResponseDto(hashtag.getName(), hashtag.getType())) + .map(hashtag -> new PostHashtagResponseDto_SY(hashtag.getName(), hashtag.getType())) .toList(); } } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache.java b/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache_SY.java similarity index 66% rename from src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache.java rename to src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache_SY.java index 7026166..6f92897 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache_SY.java @@ -7,10 +7,10 @@ import java.util.List; @Getter -public class FeedHashtagCache implements Serializable { +public class FeedHashtagCache_SY implements Serializable { @Id Long hashtagId; - private List postList; + private List postList; } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FeedSimpleInfo.java b/src/main/java/com/goormy/hackathon/redis/entity/FeedSimpleInfo_SY.java similarity index 54% rename from src/main/java/com/goormy/hackathon/redis/entity/FeedSimpleInfo.java rename to src/main/java/com/goormy/hackathon/redis/entity/FeedSimpleInfo_SY.java index 816e1db..edc9768 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FeedSimpleInfo.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FeedSimpleInfo_SY.java @@ -1,6 +1,6 @@ package com.goormy.hackathon.redis.entity; -import com.goormy.hackathon.common.util.LocalDateTimeConverter; +import com.goormy.hackathon.common.util.LocalDateTimeConverter__SY; import com.goormy.hackathon.entity.Post; import lombok.Getter; import org.springframework.data.annotation.Id; @@ -8,15 +8,15 @@ import java.io.Serializable; @Getter -public class FeedSimpleInfo implements Serializable { +public class FeedSimpleInfo_SY implements Serializable { @Id private Long id; private String createdAt; - public FeedSimpleInfo(Post post) { + public FeedSimpleInfo_SY(Post post) { this.id = post.getId(); - this.createdAt = LocalDateTimeConverter.convert(post.getCreatedAt()); + this.createdAt = LocalDateTimeConverter__SY.convert(post.getCreatedAt()); } } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache.java b/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache_SY.java similarity index 67% rename from src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache.java rename to src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache_SY.java index d4dd0e9..82c10a8 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache_SY.java @@ -8,13 +8,13 @@ import java.util.List; @Getter -public class FeedUserCache implements Serializable { +public class FeedUserCache_SY implements Serializable { @Id Long userId; - private List postList; + private List postList; - public FeedUserCache(Post post) { + public FeedUserCache_SY(Post post) { this.userId = post.getUser().getId(); } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java b/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache_SY.java similarity index 82% rename from src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java rename to src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache_SY.java index bc37040..34c97dc 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache_SY.java @@ -7,13 +7,13 @@ import java.io.Serializable; @Getter -public class FollowCountCache implements Serializable { +public class FollowCountCache_SY implements Serializable { @Id private Long hashtagId; private Integer followCount; - public FollowCountCache(Hashtag hashtag) { + public FollowCountCache_SY(Hashtag hashtag) { this.hashtagId = hashtag.getId(); this.followCount = 0; } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java b/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache_SY.java similarity index 81% rename from src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java rename to src/main/java/com/goormy/hackathon/redis/entity/FollowListCache_SY.java index 6557b8e..27f3f0d 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache_SY.java @@ -7,7 +7,7 @@ import java.util.List; @Getter -public class FollowListCache implements Serializable { +public class FollowListCache_SY implements Serializable { @Id private String hashtagId; diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PostCache.java b/src/main/java/com/goormy/hackathon/redis/entity/PostCache_SY.java similarity index 79% rename from src/main/java/com/goormy/hackathon/redis/entity/PostCache.java rename to src/main/java/com/goormy/hackathon/redis/entity/PostCache_SY.java index 5386ba9..61bcfee 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/PostCache.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/PostCache_SY.java @@ -1,7 +1,7 @@ package com.goormy.hackathon.redis.entity; -import com.goormy.hackathon.common.util.LocalDateTimeConverter; +import com.goormy.hackathon.common.util.LocalDateTimeConverter__SY; import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.Post; import lombok.Getter; @@ -11,7 +11,7 @@ import java.util.List; @Getter -public class PostCache implements Serializable { +public class PostCache_SY implements Serializable { @Id private Long postId; @@ -23,7 +23,7 @@ public class PostCache implements Serializable { private List postHashtags; private String createdAt; - public PostCache(Post post) { + public PostCache_SY(Post post) { this.postId = post.getId(); this.content = post.getContent(); this.imageUrl = post.getImageUrl(); @@ -33,7 +33,7 @@ public PostCache(Post post) { this.postHashtags = post.getPostHashtags().stream() .map(Hashtag::getName) .toList(); - this.createdAt = LocalDateTimeConverter.convert(post.getCreatedAt()); + this.createdAt = LocalDateTimeConverter__SY.convert(post.getCreatedAt()); } public String getKey() { diff --git a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_SY.java similarity index 75% rename from src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_SY.java index 272cc62..8792017 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_SY.java @@ -1,20 +1,20 @@ package com.goormy.hackathon.repository; import com.goormy.hackathon.entity.Post; -import com.goormy.hackathon.redis.entity.FeedSimpleInfo; +import com.goormy.hackathon.redis.entity.FeedSimpleInfo_SY; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; @Repository @RequiredArgsConstructor -public class FeedHashtagRedisRepository { +public class FeedHashtagRedisRepository_SY { private final RedisTemplate redisTemplate; public void set(Long hashtagId, Post post) { String key = "feedhashtag:" + hashtagId; - Object value = new FeedSimpleInfo(post); + Object value = new FeedSimpleInfo_SY(post); redisTemplate.opsForList().leftPush(key, value); } diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_SY.java similarity index 76% rename from src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_SY.java index 983c6f8..a650efa 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_SY.java @@ -1,20 +1,20 @@ package com.goormy.hackathon.repository; import com.goormy.hackathon.entity.Post; -import com.goormy.hackathon.redis.entity.FeedSimpleInfo; +import com.goormy.hackathon.redis.entity.FeedSimpleInfo_SY; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; @Repository @RequiredArgsConstructor -public class FeedUserRedisRepository { +public class FeedUserRedisRepository_SY { private final RedisTemplate redisTemplate; public void set(Long userId, Post post) { String key = "feeduser:" + userId; - Object value = new FeedSimpleInfo(post); + Object value = new FeedSimpleInfo_SY(post); redisTemplate.opsForList().leftPush(key, value); } diff --git a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_SY.java similarity index 63% rename from src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_SY.java index 85c7500..33d11c3 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_SY.java @@ -1,18 +1,18 @@ package com.goormy.hackathon.repository; -import com.goormy.hackathon.redis.entity.FollowCountCache; +import com.goormy.hackathon.redis.entity.FollowCountCache_SY; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; @Repository @RequiredArgsConstructor -public class FollowCountRedisRepository { +public class FollowCountRedisRepository_SY { private final RedisTemplate redisTemplate; - public void set(FollowCountCache followCountCache) { - redisTemplate.opsForHash().put(followCountCache.getKey(), followCountCache.getField(), followCountCache.getFollowCount()); + public void set(FollowCountCache_SY followCountCacheSY) { + redisTemplate.opsForHash().put(followCountCacheSY.getKey(), followCountCacheSY.getField(), followCountCacheSY.getFollowCount()); } public Integer findFollowCountByHashtagId(Long hashtagId) { diff --git a/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository_SY.java similarity index 72% rename from src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository_SY.java index 2e081c5..c44e5eb 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository_SY.java @@ -8,14 +8,14 @@ @Repository @RequiredArgsConstructor -public class FollowListRedisRepository { +public class FollowListRedisRepository_SY { private final RedisTemplate redisTemplate; // TODO: 수정 필요 - save 하는 쪽이 어떤 식으로 저장하느냐에 따라 호출 구현이 다를 듯 - public List findUserIdListByHashtagId(Long hashtagId) { + public List findUserIdListByHashtagId(Long hashtagId) { String key = "followlist:" + hashtagId; - return (List) redisTemplate.opsForValue().get(key); + return (List) redisTemplate.opsForValue().get(key); } } diff --git a/src/main/java/com/goormy/hackathon/repository/HashtagRepository.java b/src/main/java/com/goormy/hackathon/repository/HashtagRepository_SY.java similarity index 74% rename from src/main/java/com/goormy/hackathon/repository/HashtagRepository.java rename to src/main/java/com/goormy/hackathon/repository/HashtagRepository_SY.java index ad7d655..d7fe08c 100644 --- a/src/main/java/com/goormy/hackathon/repository/HashtagRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/HashtagRepository_SY.java @@ -5,6 +5,6 @@ import java.util.Optional; -public interface HashtagRepository extends JpaRepository { +public interface HashtagRepository_SY extends JpaRepository { Optional findByName(String name); } diff --git a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository_SY.java similarity index 57% rename from src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/PostRedisRepository_SY.java index f0c5699..5b9f217 100644 --- a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository_SY.java @@ -1,18 +1,18 @@ package com.goormy.hackathon.repository; -import com.goormy.hackathon.redis.entity.PostCache; +import com.goormy.hackathon.redis.entity.PostCache_SY; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; @Repository @RequiredArgsConstructor -public class PostRedisRepository { +public class PostRedisRepository_SY { private final RedisTemplate redisTemplate; - public void set(PostCache postCache) { - redisTemplate.opsForList().leftPush(postCache.getKey(), postCache); + public void set(PostCache_SY postCacheSY) { + redisTemplate.opsForList().leftPush(postCacheSY.getKey(), postCacheSY); } } diff --git a/src/main/java/com/goormy/hackathon/repository/PostRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java similarity index 66% rename from src/main/java/com/goormy/hackathon/repository/PostRepository.java rename to src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java index 0fbe34c..9da0ed6 100644 --- a/src/main/java/com/goormy/hackathon/repository/PostRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java @@ -3,6 +3,6 @@ import com.goormy.hackathon.entity.Post; import org.springframework.data.repository.CrudRepository; -public interface PostRepository extends CrudRepository { +public interface PostRepository_SY extends CrudRepository { } diff --git a/src/main/java/com/goormy/hackathon/repository/UserRepository.java b/src/main/java/com/goormy/hackathon/repository/UserRepository_SY.java similarity index 67% rename from src/main/java/com/goormy/hackathon/repository/UserRepository.java rename to src/main/java/com/goormy/hackathon/repository/UserRepository_SY.java index 44fc012..a56539e 100644 --- a/src/main/java/com/goormy/hackathon/repository/UserRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/UserRepository_SY.java @@ -3,6 +3,6 @@ import com.goormy.hackathon.entity.User; import org.springframework.data.jpa.repository.JpaRepository; -public interface UserRepository extends JpaRepository { +public interface UserRepository_SY extends JpaRepository { } diff --git a/src/main/java/com/goormy/hackathon/service/HashtagService.java b/src/main/java/com/goormy/hackathon/service/HashtagService_SY.java similarity index 62% rename from src/main/java/com/goormy/hackathon/service/HashtagService.java rename to src/main/java/com/goormy/hackathon/service/HashtagService_SY.java index f89e44e..2e98950 100644 --- a/src/main/java/com/goormy/hackathon/service/HashtagService.java +++ b/src/main/java/com/goormy/hackathon/service/HashtagService_SY.java @@ -1,10 +1,10 @@ package com.goormy.hackathon.service; -import com.goormy.hackathon.dto.hashtag.PostHashtagRequestDto; +import com.goormy.hackathon.dto.hashtag.PostHashtagRequestDto_SY; import com.goormy.hackathon.entity.Hashtag; -import com.goormy.hackathon.redis.entity.FollowCountCache; -import com.goormy.hackathon.repository.FollowCountRedisRepository; -import com.goormy.hackathon.repository.HashtagRepository; +import com.goormy.hackathon.redis.entity.FollowCountCache_SY; +import com.goormy.hackathon.repository.FollowCountRedisRepository_SY; +import com.goormy.hackathon.repository.HashtagRepository_SY; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -14,24 +14,24 @@ @Service @RequiredArgsConstructor -public class HashtagService { +public class HashtagService_SY { - private final HashtagRepository hashtagRepository; - private final FollowCountRedisRepository followCountRedisRepository; + private final HashtagRepository_SY hashtagRepositorySY; + private final FollowCountRedisRepository_SY followCountRedisRepositorySY; @Transactional - public List getOrCreateHashtags(List hashtagRequestDtos) { + public List getOrCreateHashtags(List hashtagRequestDtos) { List hashtags = new ArrayList<>(); for (var hashtagRequestDto : hashtagRequestDtos) { // 이미 존재하는 해시태그인 경우 - var hashtag = hashtagRepository.findByName(hashtagRequestDto.name()) + var hashtag = hashtagRepositorySY.findByName(hashtagRequestDto.name()) .orElseGet(() -> { // 새로운 해시태그인 경우 var newHashtag = new Hashtag(hashtagRequestDto.name(), hashtagRequestDto.type()); - hashtagRepository.save(newHashtag); + hashtagRepositorySY.save(newHashtag); - var followCountCache = new FollowCountCache(newHashtag); - followCountRedisRepository.set(followCountCache); + var followCountCache = new FollowCountCache_SY(newHashtag); + followCountRedisRepositorySY.set(followCountCache); return newHashtag; }); diff --git a/src/main/java/com/goormy/hackathon/service/PostCacheService.java b/src/main/java/com/goormy/hackathon/service/PostCacheService_SY.java similarity index 52% rename from src/main/java/com/goormy/hackathon/service/PostCacheService.java rename to src/main/java/com/goormy/hackathon/service/PostCacheService_SY.java index 2737ab0..d1aa2b4 100644 --- a/src/main/java/com/goormy/hackathon/service/PostCacheService.java +++ b/src/main/java/com/goormy/hackathon/service/PostCacheService_SY.java @@ -2,24 +2,26 @@ import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.Post; -import com.goormy.hackathon.redis.entity.PostCache; +import com.goormy.hackathon.redis.entity.PostCache_SY; import com.goormy.hackathon.repository.*; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.List; + @Service @RequiredArgsConstructor -public class PostCacheService { +public class PostCacheService_SY { - private final PostRedisRepository postRedisRepository; - private final FollowCountRedisRepository followCountRedisRepository; - private final FollowListRedisRepository followListRedisRepository; - private final FeedUserRedisRepository feedUserRedisRepository; - private final FeedHashtagRedisRepository feedHashtagRedisRepository; + private final PostRedisRepository_SY postRedisRepositorySY; + private final FollowCountRedisRepository_SY followCountRedisRepositorySY; + private final FollowListRedisRepository_SY followListRedisRepositorySY; + private final FeedUserRedisRepository_SY feedUserRedisRepositorySY; + private final FeedHashtagRedisRepository_SY feedHashtagRedisRepositorySY; // TODO: 이벤트로 발행한 후 이벤트를 받아 Redis에 비동기로 저장 public void cache(Post post) { - postRedisRepository.set(new PostCache(post)); + postRedisRepositorySY.set(new PostCache_SY(post)); for (var hashtag : post.getPostHashtags()) { if (isPopular(hashtag)) { pullModel(hashtag, post); @@ -30,7 +32,7 @@ public void cache(Post post) { } private boolean isPopular(Hashtag hashtag) { - var followCount = followCountRedisRepository.findFollowCountByHashtagId(hashtag.getId()); + var followCount = followCountRedisRepositorySY.findFollowCountByHashtagId(hashtag.getId()); if (followCount != null ) { return followCount >= 5000; } @@ -38,13 +40,13 @@ private boolean isPopular(Hashtag hashtag) { } private void pushModel(Hashtag hashtag, Post post) { - var userIdList = followListRedisRepository.findUserIdListByHashtagId(hashtag.getId()); + var userIdList = followListRedisRepositorySY.findUserIdListByHashtagId(hashtag.getId()); userIdList.forEach(userId -> { - feedUserRedisRepository.set(userId, post); + feedUserRedisRepositorySY.set(Long.valueOf(userId), post); }); } private void pullModel(Hashtag hashtag, Post post) { - feedHashtagRedisRepository.set(hashtag.getId(), post); + feedHashtagRedisRepositorySY.set(hashtag.getId(), post); } } diff --git a/src/main/java/com/goormy/hackathon/service/PostService.java b/src/main/java/com/goormy/hackathon/service/PostService.java deleted file mode 100644 index e305ae6..0000000 --- a/src/main/java/com/goormy/hackathon/service/PostService.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.goormy.hackathon.service; - -import com.goormy.hackathon.dto.post.PostRequestDto; -import com.goormy.hackathon.dto.post.PostResponseDto; -import com.goormy.hackathon.entity.Post; -import com.goormy.hackathon.redis.entity.PostCache; -import com.goormy.hackathon.repository.PostRepository; -import com.goormy.hackathon.repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -public class PostService { - - private final UserRepository userRepository; - private final PostRepository postRepository; - private final HashtagService hashtagService; - private final PostCacheService postCacheService; - - @Transactional - public PostResponseDto createPost(Long userId, PostRequestDto postRequestDto) { - // 사용자 찾기 - var user = userRepository.findById(userId).orElseThrow( - () -> new IllegalArgumentException("User not found")); // TODO: Custom exception - - // post 생성 - var post = Post.builder() - .user(user) - .content(postRequestDto.content()) - .imageUrl(postRequestDto.imageUrl()) - .star(postRequestDto.star()) - .likeCount(0) - .build(); - - // hashtag 생성 - var postHashtags = hashtagService.getOrCreateHashtags(postRequestDto.postHashtags()); - post.setPostHashtags(postHashtags); - - // DB 저장 - postRepository.save(post); - - // redis 저장 - postCacheService.cache(post); - - return new PostResponseDto(post); - } - -} diff --git a/src/main/java/com/goormy/hackathon/service/PostService_SY.java b/src/main/java/com/goormy/hackathon/service/PostService_SY.java new file mode 100644 index 0000000..bc94cd1 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/PostService_SY.java @@ -0,0 +1,49 @@ +package com.goormy.hackathon.service; + +import com.goormy.hackathon.dto.post.PostRequestDto_SY; +import com.goormy.hackathon.dto.post.PostResponseDto_SY; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.repository.PostRepository_SY; +import com.goormy.hackathon.repository.UserRepository_SY; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class PostService_SY { + + private final UserRepository_SY userRepositorySY; + private final PostRepository_SY postRepositorySY; + private final HashtagService_SY hashtagServiceSY; + private final PostCacheService_SY postCacheServiceSY; + + @Transactional + public PostResponseDto_SY createPost(Long userId, PostRequestDto_SY postRequestDtoSY) { + // 사용자 찾기 + var user = userRepositorySY.findById(userId).orElseThrow( + () -> new IllegalArgumentException("User not found")); // TODO: Custom exception + + // post 생성 + var post = Post.builder() + .user(user) + .content(postRequestDtoSY.content()) + .imageUrl(postRequestDtoSY.imageUrl()) + .star(postRequestDtoSY.star()) + .likeCount(0) + .build(); + + // hashtag 생성 + var postHashtags = hashtagServiceSY.getOrCreateHashtags(postRequestDtoSY.postHashtags()); + post.setPostHashtags(postHashtags); + + // DB 저장 + postRepositorySY.save(post); + + // redis 저장 + postCacheServiceSY.cache(post); + + return new PostResponseDto_SY(post); + } + +} From b3122c4240534e69202903d935934bd5979d6e3c Mon Sep 17 00:00:00 2001 From: Ga Dong Sik Date: Thu, 1 Aug 2024 21:38:21 +0900 Subject: [PATCH 46/57] =?UTF-8?q?fix:=20Hashtag=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/goormy/hackathon/service/GetFeedService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/service/GetFeedService.java b/src/main/java/com/goormy/hackathon/service/GetFeedService.java index 6e0aeac..ee6c6c0 100644 --- a/src/main/java/com/goormy/hackathon/service/GetFeedService.java +++ b/src/main/java/com/goormy/hackathon/service/GetFeedService.java @@ -3,6 +3,7 @@ import com.goormy.hackathon.common.util.LocalDateTimeConverter_DS; import com.goormy.hackathon.dto.response.GetFeedResponseDto; import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.entity.User; import com.goormy.hackathon.redis.entity.PostRedis_DS; @@ -14,7 +15,6 @@ import com.goormy.hackathon.repository.PostRedisRepository_DS; import com.goormy.hackathon.repository.PostRepository; import com.goormy.hackathon.repository.RecentUpdateRedisRepository_DS; -import com.goormy.hackathon.repository.RecentUpdateRedisRepository_DS; import com.goormy.hackathon.repository.UserRedisRepository_DS; import com.goormy.hackathon.repository.UserRespository; import jakarta.transaction.Transactional; @@ -141,7 +141,7 @@ private List getPostList(List postIdList) { PostRedis_DS postRedisDS = PostRedis_DS.toEntity( post.getId(), post.getContent(), post.getImageUrl(), post.getStar(), post.getLikeCount(), post.getUser().getId(), - post.getPostHashtags().stream().map(hashtag -> hashtag.getHashtag().getName()) + post.getPostHashtags().stream().map(Hashtag::getName) .toList(), post.getCreatedAt() ); postRedisRepository.set(postRedisDS.getId(), postRedisDS); From b789538787ecf293837e07275f8d091a114f030c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:47:28 +0900 Subject: [PATCH 47/57] merge --- .../controller/FollowController_sieun.java | 4 ++-- .../hackathon/lambda/FollowFunction.java | 23 +++++++++++++++---- ...n.java => FollowCountRedisRepository.java} | 4 ++-- .../repository/FollowRepository.java | 6 +++++ .../repository/FollowRepository_sieun.java | 17 -------------- .../repository/UserRepository_sieun.java | 10 -------- .../hackathon/service/FollowService.java | 1 + .../service/FollowService_sieun.java | 13 ++++------- ...serService_sieun.java => UserService.java} | 8 +++---- src/main/resources/application.yml | 2 +- 10 files changed, 39 insertions(+), 49 deletions(-) rename src/main/java/com/goormy/hackathon/repository/{FollowCountRedisRepository_sieun.java => FollowCountRedisRepository.java} (88%) delete mode 100644 src/main/java/com/goormy/hackathon/repository/FollowRepository_sieun.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/UserRepository_sieun.java rename src/main/java/com/goormy/hackathon/service/{UserService_sieun.java => UserService.java} (55%) diff --git a/src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java b/src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java index f152249..0a5f77f 100644 --- a/src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java +++ b/src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java @@ -4,7 +4,7 @@ import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.User; import com.goormy.hackathon.service.FollowService_sieun; -import com.goormy.hackathon.service.UserService_sieun; +import com.goormy.hackathon.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestHeader; @@ -21,7 +21,7 @@ public class FollowController_sieun { @Autowired private FollowService_sieun followServiceSieun; @Autowired - private UserService_sieun userServiceSieun; + private UserService userServiceSieun; @GetMapping public List getFollowedHashtags(@RequestHeader("userId") Long userId) { diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index 259dc96..2fd9d6c 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -4,10 +4,7 @@ import com.goormy.hackathon.entity.Follow; import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.FollowRedisRepository; -import com.goormy.hackathon.repository.FollowRepository; -import com.goormy.hackathon.repository.HashtagRepository; -import com.goormy.hackathon.repository.UserRepository; +import com.goormy.hackathon.repository.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; @@ -24,17 +21,19 @@ public class FollowFunction{ private final UserRepository userRepository; private final HashtagRepository hashtagRepository; private final FollowRedisRepository followRedisRepository; + private final FollowCountRedisRepository followCountRedisRepository; private final ObjectMapper objectMapper; private static final Logger logger = LoggerFactory.getLogger(FollowFunction.class); public FollowFunction(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository, FollowRedisRepository followRedisRepository - , ObjectMapper objectMapper) { + , ObjectMapper objectMapper, FollowCountRedisRepository followCountRedisRepositorySieun) { this.followRepository = followRepository; this.userRepository = userRepository; this.hashtagRepository = hashtagRepository; this.followRedisRepository = followRedisRepository; this.objectMapper = objectMapper; + this.followCountRedisRepository = followCountRedisRepositorySieun; } @Bean @@ -57,12 +56,26 @@ public Consumer> processFollow() { if ("follow".equals(action)) { Follow follow = new Follow(user,hashtag); + // follow_list:{hashtagId} 저장 followRedisRepository.set(hashtagId, userId); + // follow_count:{hashtagId} 저장 + Integer currentCount = followCountRedisRepository.getFollowCount(hashtagId); + if (currentCount == null) { + followCountRedisRepository.setFollowCount(hashtagId, 1); // 처음 팔로우인 경우 초기화 + } else { + followCountRedisRepository.incrementFollowCount(hashtagId); // 기존 팔로우 수 증가 + } System.out.println("팔로우 성공: " + messageBody); } else if ("unfollow".equals(action)) { + // follow_list:{hashtagId} 삭제 Follow follow = followRepository.findByUserIdAndHashTagId(userId, hashtagId) .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); followRedisRepository.delete(hashtagId, userId); + // follow_count:{hashtagId} 삭제 + Integer currentCount = followCountRedisRepository.getFollowCount(hashtagId); + if (currentCount != null && currentCount > 0) { + followCountRedisRepository.decrementFollowCount(hashtagId); // 팔로우 수 감소 + } System.out.println("팔로우 취소 성공: " + messageBody); } else { System.out.println("존재하지 않는 action입니다 : " + action); diff --git a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_sieun.java b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java similarity index 88% rename from src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_sieun.java rename to src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java index 2db1789..998d47e 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_sieun.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java @@ -6,13 +6,13 @@ import org.springframework.stereotype.Service; @Service -public class FollowCountRedisRepository_sieun { +public class FollowCountRedisRepository { private final RedisTemplate integerRedisTemplate; private static final String FOLLOWING_COUNT_KEY = "follow_count:"; @Autowired - public FollowCountRedisRepository_sieun(RedisTemplate integerRedisTemplate) { + public FollowCountRedisRepository(RedisTemplate integerRedisTemplate) { this.integerRedisTemplate = integerRedisTemplate; } diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRepository.java b/src/main/java/com/goormy/hackathon/repository/FollowRepository.java index 47cf486..d6ae201 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/FollowRepository.java @@ -1,11 +1,14 @@ package com.goormy.hackathon.repository; import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; @Repository @@ -13,4 +16,7 @@ public interface FollowRepository extends JpaRepository { @Query("SELECT f FROM Follow f WHERE f.user.id = :userId AND f.hashtag.id = :hashtagId") Optional findByUserIdAndHashTagId(@Param("userId") Long userId, @Param("hashtagId") Long hashtagId); + + @Query("SELECT f.hashtag FROM Follow f WHERE f.user = :user") + List findHashtagsByUser(@Param("user") User user); } diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRepository_sieun.java b/src/main/java/com/goormy/hackathon/repository/FollowRepository_sieun.java deleted file mode 100644 index 635c8ec..0000000 --- a/src/main/java/com/goormy/hackathon/repository/FollowRepository_sieun.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.entity.Follow; -import com.goormy.hackathon.entity.Hashtag; -import com.goormy.hackathon.entity.User; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -public interface FollowRepository_sieun extends JpaRepository { - @Query("SELECT f.hashtag FROM Follow f WHERE f.user = :user") - List findHashtagsByUser(@Param("user") User user); -} diff --git a/src/main/java/com/goormy/hackathon/repository/UserRepository_sieun.java b/src/main/java/com/goormy/hackathon/repository/UserRepository_sieun.java deleted file mode 100644 index de03c01..0000000 --- a/src/main/java/com/goormy/hackathon/repository/UserRepository_sieun.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.entity.User; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface UserRepository_sieun extends JpaRepository { - User findByName(String name); -} diff --git a/src/main/java/com/goormy/hackathon/service/FollowService.java b/src/main/java/com/goormy/hackathon/service/FollowService.java index 8314a40..5a680ab 100644 --- a/src/main/java/com/goormy/hackathon/service/FollowService.java +++ b/src/main/java/com/goormy/hackathon/service/FollowService.java @@ -24,6 +24,7 @@ public class FollowService { private String queueUrl; public void sendFollowRequest(long userId, long hashtagId) { + sendRequest(userId, hashtagId, "follow"); } diff --git a/src/main/java/com/goormy/hackathon/service/FollowService_sieun.java b/src/main/java/com/goormy/hackathon/service/FollowService_sieun.java index 6a4217b..7569418 100644 --- a/src/main/java/com/goormy/hackathon/service/FollowService_sieun.java +++ b/src/main/java/com/goormy/hackathon/service/FollowService_sieun.java @@ -2,9 +2,8 @@ import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.FollowCountRedisRepository_sieun; -import com.goormy.hackathon.repository.FollowRepository_sieun; -import jakarta.transaction.Transactional; +import com.goormy.hackathon.repository.FollowCountRedisRepository; +import com.goormy.hackathon.repository.FollowRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -14,16 +13,15 @@ @RequiredArgsConstructor public class FollowService_sieun { - private final FollowRepository_sieun followRepositorySieun; - private final FollowCountRedisRepository_sieun followCountRedisRepositorySieun; + private final FollowRepository followRepository; + private final FollowCountRedisRepository followCountRedisRepositorySieun; // 유저가 팔로우하고 있는 해시태그 목록 조회 public List getFollowedHashtags(User user) { - return followRepositorySieun.findHashtagsByUser(user); + return followRepository.findHashtagsByUser(user); } // 팔로우, 언팔로우 캐시 부분 - @Transactional public void followHashtag(Long hashtagId) { Integer currentCount = followCountRedisRepositorySieun.getFollowCount(hashtagId); if (currentCount == null) { @@ -33,7 +31,6 @@ public void followHashtag(Long hashtagId) { } } - @Transactional public void unfollowHashtag(Long hashtagId) { Integer currentCount = followCountRedisRepositorySieun.getFollowCount(hashtagId); if (currentCount != null && currentCount > 0) { diff --git a/src/main/java/com/goormy/hackathon/service/UserService_sieun.java b/src/main/java/com/goormy/hackathon/service/UserService.java similarity index 55% rename from src/main/java/com/goormy/hackathon/service/UserService_sieun.java rename to src/main/java/com/goormy/hackathon/service/UserService.java index 97f9b12..4ef741d 100644 --- a/src/main/java/com/goormy/hackathon/service/UserService_sieun.java +++ b/src/main/java/com/goormy/hackathon/service/UserService.java @@ -1,17 +1,17 @@ package com.goormy.hackathon.service; import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.UserRepository_sieun; +import com.goormy.hackathon.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service -public class UserService_sieun { +public class UserService { @Autowired - private UserRepository_sieun userRepositorySieun; + private UserRepository userRepository; public User findById(Long id) { - return userRepositorySieun.findById(id).orElse(null); + return userRepository.findById(id).orElse(null); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index bff310f..e40b72f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,7 +4,7 @@ spring: host: localhost port: 6379 datasource: - url: ${MYSQL_URL:jdbc:mysql://localhost}:${MYSQL_PORT:3306}/${MYSQL_SCHEMA:gureumi-rds} + url: ${MYSQL_URL:jdbc:mysql://gureumi-rds.cfgaqgkoy31u.ap-northeast-2.rds.amazonaws.com}:${MYSQL_PORT:3306}/${MYSQL_SCHEMA:gureumi-rds} driver-class-name: com.mysql.cj.jdbc.Driver username: ${MYSQL_USERNAME:admin} password: ${MYSQL_PASSWORD:rnfmalelql3} From ef8fd66797d779befff5eea6707e147753b4336b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Fri, 2 Aug 2024 14:07:59 +0900 Subject: [PATCH 48/57] merge --- .../goormy/hackathon/redis/config/RedisConfig.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java index 3ee16da..49085c2 100644 --- a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java +++ b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java @@ -103,4 +103,16 @@ public RedisTemplate longRedisTemplate(RedisConnectionFactory redi return redisTemplate; } + // Integer 형식으로 저장 (FollowCount에서 사용) + @Bean + public RedisTemplate integerRedisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Integer.class)); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Integer.class)); + return redisTemplate; + } + } From dbb6a3046b812724874f094b2d94c3b8d2087069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Fri, 2 Aug 2024 14:26:01 +0900 Subject: [PATCH 49/57] =?UTF-8?q?Service/Controller=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FollowController.java | 29 ++++++++- .../controller/FollowController_sieun.java | 36 ----------- .../hackathon/controller/LikeController.java | 5 +- .../hackathon/controller/PostController.java | 37 +++++++++++ .../controller/PostController_SY.java | 24 ------- .../controller/PostController_sieun.java | 28 --------- .../hackathon/lambda/FollowFunction.java | 19 ++---- .../repository/PostRepository_SY.java | 7 ++- .../hackathon/service/FollowSQSService.java | 55 ++++++++++++++++ .../hackathon/service/FollowService.java | 63 +++++++------------ .../service/FollowService_sieun.java | 40 ------------ ...tagService_SY.java => HashtagService.java} | 2 +- .../{LikeService.java => LikeSQSService.java} | 2 +- ...eService_SY.java => PostCacheService.java} | 4 +- .../{PostService_SY.java => PostService.java} | 23 ++++++- .../hackathon/service/PostService_sieun.java | 34 ---------- 16 files changed, 180 insertions(+), 228 deletions(-) delete mode 100644 src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/controller/PostController.java delete mode 100644 src/main/java/com/goormy/hackathon/controller/PostController_SY.java delete mode 100644 src/main/java/com/goormy/hackathon/controller/PostController_sieun.java create mode 100644 src/main/java/com/goormy/hackathon/service/FollowSQSService.java delete mode 100644 src/main/java/com/goormy/hackathon/service/FollowService_sieun.java rename src/main/java/com/goormy/hackathon/service/{HashtagService_SY.java => HashtagService.java} (98%) rename src/main/java/com/goormy/hackathon/service/{LikeService.java => LikeSQSService.java} (98%) rename src/main/java/com/goormy/hackathon/service/{PostCacheService_SY.java => PostCacheService.java} (96%) rename src/main/java/com/goormy/hackathon/service/{PostService_SY.java => PostService.java} (60%) delete mode 100644 src/main/java/com/goormy/hackathon/service/PostService_sieun.java diff --git a/src/main/java/com/goormy/hackathon/controller/FollowController.java b/src/main/java/com/goormy/hackathon/controller/FollowController.java index ae1bab6..9c81ade 100644 --- a/src/main/java/com/goormy/hackathon/controller/FollowController.java +++ b/src/main/java/com/goormy/hackathon/controller/FollowController.java @@ -1,27 +1,52 @@ package com.goormy.hackathon.controller; +import com.goormy.hackathon.dto.HashtagDto_sieun; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.service.FollowSQSService; import com.goormy.hackathon.service.FollowService; +import com.goormy.hackathon.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.List; +import java.util.stream.Collectors; + @RestController public class FollowController { + @Autowired + private FollowSQSService followSQSService; + @Autowired private FollowService followService; + @Autowired + private UserService userService; + @PostMapping("/follow") public ResponseEntity follow(@RequestHeader long userId, @RequestParam long hashtagId) { - followService.sendFollowRequest(userId,hashtagId); + followSQSService.sendFollowRequest(userId,hashtagId); return ResponseEntity.noContent().build(); } @PostMapping("/unfollow") public ResponseEntity unfollow(@RequestHeader long userId, @RequestParam long hashtagId) { - followService.sendUnfollowRequest(userId,hashtagId); + followSQSService.sendUnfollowRequest(userId,hashtagId); return ResponseEntity.noContent().build(); } + @GetMapping("/followings") + public List getFollowedHashtags(@RequestHeader("userId") Long userId) { + User user = userService.findById(userId); + + List hashtags = followService.getFollowedHashtags(user); + + return hashtags.stream() + .map(hashtag -> new HashtagDto_sieun(hashtag.getId(), hashtag.getName(), hashtag.getType().toString())) + .collect(Collectors.toList()); + } + } diff --git a/src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java b/src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java deleted file mode 100644 index 0a5f77f..0000000 --- a/src/main/java/com/goormy/hackathon/controller/FollowController_sieun.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.goormy.hackathon.controller; - -import com.goormy.hackathon.dto.HashtagDto_sieun; -import com.goormy.hackathon.entity.Hashtag; -import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.service.FollowService_sieun; -import com.goormy.hackathon.service.UserService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; -import java.util.stream.Collectors; - -@RestController -@RequestMapping("/followings") -public class FollowController_sieun { - - @Autowired - private FollowService_sieun followServiceSieun; - @Autowired - private UserService userServiceSieun; - - @GetMapping - public List getFollowedHashtags(@RequestHeader("userId") Long userId) { - User user = userServiceSieun.findById(userId); - - List hashtags = followServiceSieun.getFollowedHashtags(user); - - return hashtags.stream() - .map(hashtag -> new HashtagDto_sieun(hashtag.getId(), hashtag.getName(), hashtag.getType().toString())) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/com/goormy/hackathon/controller/LikeController.java b/src/main/java/com/goormy/hackathon/controller/LikeController.java index 4d89a2b..ae988a7 100644 --- a/src/main/java/com/goormy/hackathon/controller/LikeController.java +++ b/src/main/java/com/goormy/hackathon/controller/LikeController.java @@ -1,11 +1,10 @@ package com.goormy.hackathon.controller; -import com.goormy.hackathon.service.LikeService; +import com.goormy.hackathon.service.LikeSQSService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -16,7 +15,7 @@ @RequestMapping("") public class LikeController { - private final LikeService likeService; + private final LikeSQSService likeService; @PostMapping("/likes") public ResponseEntity addLike( diff --git a/src/main/java/com/goormy/hackathon/controller/PostController.java b/src/main/java/com/goormy/hackathon/controller/PostController.java new file mode 100644 index 0000000..33ba3b9 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/controller/PostController.java @@ -0,0 +1,37 @@ +package com.goormy.hackathon.controller; + + +import com.goormy.hackathon.dto.post.PostRequestDto_SY; +import com.goormy.hackathon.dto.post.PostResponseDto_SY; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.service.PostService; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/posts") +@RequiredArgsConstructor +public class PostController { + + private final PostService postService; + + @PostMapping + public PostResponseDto_SY create( + @RequestHeader("userId") Long userId, + @RequestBody PostRequestDto_SY postRequestDtoSY) { + return postService.createPost(userId, postRequestDtoSY); + } + + @GetMapping("/search") + public Page getPostsByHashtag( + @RequestParam(name = "hashtag") String hashtag, + @RequestParam(name = "page") int page, + @RequestParam(name = "size") int size) { + System.out.println("Received request to fetch posts by hashtag: " + hashtag); + Page postsPage = postService.getPostsByHashtag(hashtag, page, size); + System.out.println("Returning page " + postsPage.getNumber() + " of " + postsPage.getTotalPages() + " for hashtag: " + hashtag); + return postsPage; + } + +} diff --git a/src/main/java/com/goormy/hackathon/controller/PostController_SY.java b/src/main/java/com/goormy/hackathon/controller/PostController_SY.java deleted file mode 100644 index a798bb9..0000000 --- a/src/main/java/com/goormy/hackathon/controller/PostController_SY.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.goormy.hackathon.controller; - - -import com.goormy.hackathon.dto.post.PostRequestDto_SY; -import com.goormy.hackathon.dto.post.PostResponseDto_SY; -import com.goormy.hackathon.service.PostService_SY; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/posts") -@RequiredArgsConstructor -public class PostController_SY { - - private final PostService_SY postServiceSY; - - @PostMapping - public PostResponseDto_SY create( - @RequestHeader("userId") Long userId, - @RequestBody PostRequestDto_SY postRequestDtoSY) { - return postServiceSY.createPost(userId, postRequestDtoSY); - } - -} diff --git a/src/main/java/com/goormy/hackathon/controller/PostController_sieun.java b/src/main/java/com/goormy/hackathon/controller/PostController_sieun.java deleted file mode 100644 index 9fe818a..0000000 --- a/src/main/java/com/goormy/hackathon/controller/PostController_sieun.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.goormy.hackathon.controller; - -import com.goormy.hackathon.entity.Post; -import com.goormy.hackathon.service.PostService_sieun; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.web.bind.annotation.*; - -@RestController -public class PostController_sieun { - private final PostService_sieun postServiceSieun; - - @Autowired - public PostController_sieun(PostService_sieun postServiceSieun) { - this.postServiceSieun = postServiceSieun; - } - - @GetMapping("/posts/by-hashtag") - public Page getPostsByHashtag( - @RequestParam(name = "hashtag") String hashtag, - @RequestParam(name = "page") int page, - @RequestParam(name = "size") int size) { - System.out.println("Received request to fetch posts by hashtag: " + hashtag); - Page postsPage = postServiceSieun.getPostsByHashtag(hashtag, page, size); - System.out.println("Returning page " + postsPage.getNumber() + " of " + postsPage.getTotalPages() + " for hashtag: " + hashtag); - return postsPage; - } -} diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index 2fd9d6c..87d78d4 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -5,6 +5,7 @@ import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.User; import com.goormy.hackathon.repository.*; +import com.goormy.hackathon.service.FollowService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; @@ -21,19 +22,19 @@ public class FollowFunction{ private final UserRepository userRepository; private final HashtagRepository hashtagRepository; private final FollowRedisRepository followRedisRepository; - private final FollowCountRedisRepository followCountRedisRepository; + private final FollowService followServiceSieun; private final ObjectMapper objectMapper; private static final Logger logger = LoggerFactory.getLogger(FollowFunction.class); public FollowFunction(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository, FollowRedisRepository followRedisRepository - , ObjectMapper objectMapper, FollowCountRedisRepository followCountRedisRepositorySieun) { + , ObjectMapper objectMapper, FollowService followServiceSieun) { this.followRepository = followRepository; this.userRepository = userRepository; this.hashtagRepository = hashtagRepository; this.followRedisRepository = followRedisRepository; this.objectMapper = objectMapper; - this.followCountRedisRepository = followCountRedisRepositorySieun; + this.followServiceSieun = followServiceSieun; } @Bean @@ -59,12 +60,7 @@ public Consumer> processFollow() { // follow_list:{hashtagId} 저장 followRedisRepository.set(hashtagId, userId); // follow_count:{hashtagId} 저장 - Integer currentCount = followCountRedisRepository.getFollowCount(hashtagId); - if (currentCount == null) { - followCountRedisRepository.setFollowCount(hashtagId, 1); // 처음 팔로우인 경우 초기화 - } else { - followCountRedisRepository.incrementFollowCount(hashtagId); // 기존 팔로우 수 증가 - } + followServiceSieun.followHashtag(hashtagId); System.out.println("팔로우 성공: " + messageBody); } else if ("unfollow".equals(action)) { // follow_list:{hashtagId} 삭제 @@ -72,10 +68,7 @@ public Consumer> processFollow() { .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); followRedisRepository.delete(hashtagId, userId); // follow_count:{hashtagId} 삭제 - Integer currentCount = followCountRedisRepository.getFollowCount(hashtagId); - if (currentCount != null && currentCount > 0) { - followCountRedisRepository.decrementFollowCount(hashtagId); // 팔로우 수 감소 - } + followServiceSieun.unfollowHashtag(hashtagId); System.out.println("팔로우 취소 성공: " + messageBody); } else { System.out.println("존재하지 않는 action입니다 : " + action); diff --git a/src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java b/src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java index 9da0ed6..b3797b3 100644 --- a/src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java +++ b/src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java @@ -1,8 +1,13 @@ package com.goormy.hackathon.repository; import com.goormy.hackathon.entity.Post; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; public interface PostRepository_SY extends CrudRepository { - + @Query("SELECT p FROM Post p JOIN p.postHashtags ph JOIN ph.hashtag h WHERE h.name = :hashtagName") + Page findPostsByHashtagName(@Param("hashtagName") String hashtagName, Pageable pageable); } diff --git a/src/main/java/com/goormy/hackathon/service/FollowSQSService.java b/src/main/java/com/goormy/hackathon/service/FollowSQSService.java new file mode 100644 index 0000000..d63e4b4 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/service/FollowSQSService.java @@ -0,0 +1,55 @@ +package com.goormy.hackathon.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import software.amazon.awssdk.services.sqs.SqsClient; +import software.amazon.awssdk.services.sqs.model.SendMessageRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import software.amazon.awssdk.services.sqs.model.SendMessageResponse; + +import java.util.Map; + +@Service +public class FollowSQSService { + private static final Logger logger = LoggerFactory.getLogger(FollowSQSService.class); + + + @Autowired + private SqsClient sqsClient; + + @Value("${spring.cloud.aws.sqs.queue-url}") + private String queueUrl; + + public void sendFollowRequest(long userId, long hashtagId) { + + sendRequest(userId, hashtagId, "follow"); + } + + public void sendUnfollowRequest(long userId, long hashtagId) { + sendRequest(userId, hashtagId, "unfollow"); + } + + public void sendRequest(long userId, long hashtagId, String action) { + try{ + ObjectMapper objectMapper = new ObjectMapper(); + String messageBody = objectMapper.writeValueAsString(Map.of( + "userId", userId, + "hashtagId", hashtagId, + "action",action + )); + SendMessageRequest sendMsgRequest = SendMessageRequest.builder() + .queueUrl(queueUrl) + .messageBody(messageBody) + .build(); + logger.info("메시지 송신 - action: {}, userId: {}, hashtagId: {}", action, userId, hashtagId); + SendMessageResponse sendMsgResponse = sqsClient.sendMessage(sendMsgRequest); + logger.info("메시지가 전달되었습니다: {}, Message ID: {}, HTTP Status: {}", + messageBody, sendMsgResponse.messageId(), sendMsgResponse.sdkHttpResponse().statusCode()); + } catch (Exception e) { + logger.error("메시지 전송 실패", e); + } + } +} diff --git a/src/main/java/com/goormy/hackathon/service/FollowService.java b/src/main/java/com/goormy/hackathon/service/FollowService.java index 5a680ab..433bec8 100644 --- a/src/main/java/com/goormy/hackathon/service/FollowService.java +++ b/src/main/java/com/goormy/hackathon/service/FollowService.java @@ -1,55 +1,40 @@ package com.goormy.hackathon.service; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.repository.FollowCountRedisRepository; +import com.goormy.hackathon.repository.FollowRepository; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import software.amazon.awssdk.services.sqs.SqsClient; -import software.amazon.awssdk.services.sqs.model.SendMessageRequest; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import software.amazon.awssdk.services.sqs.model.SendMessageResponse; -import java.util.Map; +import java.util.List; @Service +@RequiredArgsConstructor public class FollowService { - private static final Logger logger = LoggerFactory.getLogger(FollowService.class); + private final FollowRepository followRepository; + private final FollowCountRedisRepository followCountRedisRepositorySieun; - @Autowired - private SqsClient sqsClient; - - @Value("${spring.cloud.aws.sqs.queue-url}") - private String queueUrl; - - public void sendFollowRequest(long userId, long hashtagId) { - - sendRequest(userId, hashtagId, "follow"); + // 유저가 팔로우하고 있는 해시태그 목록 조회 + public List getFollowedHashtags(User user) { + return followRepository.findHashtagsByUser(user); } - public void sendUnfollowRequest(long userId, long hashtagId) { - sendRequest(userId, hashtagId, "unfollow"); + // 팔로우, 언팔로우 캐시 부분 + public void followHashtag(Long hashtagId) { + Integer currentCount = followCountRedisRepositorySieun.getFollowCount(hashtagId); + if (currentCount == null) { + followCountRedisRepositorySieun.setFollowCount(hashtagId, 1); // 처음 팔로우인 경우 초기화 + } else { + followCountRedisRepositorySieun.incrementFollowCount(hashtagId); // 기존 팔로우 수 증가 + } } - public void sendRequest(long userId, long hashtagId, String action) { - try{ - ObjectMapper objectMapper = new ObjectMapper(); - String messageBody = objectMapper.writeValueAsString(Map.of( - "userId", userId, - "hashtagId", hashtagId, - "action",action - )); - SendMessageRequest sendMsgRequest = SendMessageRequest.builder() - .queueUrl(queueUrl) - .messageBody(messageBody) - .build(); - logger.info("메시지 송신 - action: {}, userId: {}, hashtagId: {}", action, userId, hashtagId); - SendMessageResponse sendMsgResponse = sqsClient.sendMessage(sendMsgRequest); - logger.info("메시지가 전달되었습니다: {}, Message ID: {}, HTTP Status: {}", - messageBody, sendMsgResponse.messageId(), sendMsgResponse.sdkHttpResponse().statusCode()); - } catch (Exception e) { - logger.error("메시지 전송 실패", e); + public void unfollowHashtag(Long hashtagId) { + Integer currentCount = followCountRedisRepositorySieun.getFollowCount(hashtagId); + if (currentCount != null && currentCount > 0) { + followCountRedisRepositorySieun.decrementFollowCount(hashtagId); // 팔로우 수 감소 } } } diff --git a/src/main/java/com/goormy/hackathon/service/FollowService_sieun.java b/src/main/java/com/goormy/hackathon/service/FollowService_sieun.java deleted file mode 100644 index 7569418..0000000 --- a/src/main/java/com/goormy/hackathon/service/FollowService_sieun.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.goormy.hackathon.service; - -import com.goormy.hackathon.entity.Hashtag; -import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.FollowCountRedisRepository; -import com.goormy.hackathon.repository.FollowRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import java.util.List; - -@Service -@RequiredArgsConstructor -public class FollowService_sieun { - - private final FollowRepository followRepository; - private final FollowCountRedisRepository followCountRedisRepositorySieun; - - // 유저가 팔로우하고 있는 해시태그 목록 조회 - public List getFollowedHashtags(User user) { - return followRepository.findHashtagsByUser(user); - } - - // 팔로우, 언팔로우 캐시 부분 - public void followHashtag(Long hashtagId) { - Integer currentCount = followCountRedisRepositorySieun.getFollowCount(hashtagId); - if (currentCount == null) { - followCountRedisRepositorySieun.setFollowCount(hashtagId, 1); // 처음 팔로우인 경우 초기화 - } else { - followCountRedisRepositorySieun.incrementFollowCount(hashtagId); // 기존 팔로우 수 증가 - } - } - - public void unfollowHashtag(Long hashtagId) { - Integer currentCount = followCountRedisRepositorySieun.getFollowCount(hashtagId); - if (currentCount != null && currentCount > 0) { - followCountRedisRepositorySieun.decrementFollowCount(hashtagId); // 팔로우 수 감소 - } - } -} diff --git a/src/main/java/com/goormy/hackathon/service/HashtagService_SY.java b/src/main/java/com/goormy/hackathon/service/HashtagService.java similarity index 98% rename from src/main/java/com/goormy/hackathon/service/HashtagService_SY.java rename to src/main/java/com/goormy/hackathon/service/HashtagService.java index 2e98950..2083d7c 100644 --- a/src/main/java/com/goormy/hackathon/service/HashtagService_SY.java +++ b/src/main/java/com/goormy/hackathon/service/HashtagService.java @@ -14,7 +14,7 @@ @Service @RequiredArgsConstructor -public class HashtagService_SY { +public class HashtagService { private final HashtagRepository_SY hashtagRepositorySY; private final FollowCountRedisRepository_SY followCountRedisRepositorySY; diff --git a/src/main/java/com/goormy/hackathon/service/LikeService.java b/src/main/java/com/goormy/hackathon/service/LikeSQSService.java similarity index 98% rename from src/main/java/com/goormy/hackathon/service/LikeService.java rename to src/main/java/com/goormy/hackathon/service/LikeSQSService.java index e1b1c41..22006a0 100644 --- a/src/main/java/com/goormy/hackathon/service/LikeService.java +++ b/src/main/java/com/goormy/hackathon/service/LikeSQSService.java @@ -13,7 +13,7 @@ import software.amazon.awssdk.services.sqs.model.SendMessageResponse; @Service -public class LikeService { +public class LikeSQSService { private static final Logger logger = LoggerFactory.getLogger(LikeFunction.class); diff --git a/src/main/java/com/goormy/hackathon/service/PostCacheService_SY.java b/src/main/java/com/goormy/hackathon/service/PostCacheService.java similarity index 96% rename from src/main/java/com/goormy/hackathon/service/PostCacheService_SY.java rename to src/main/java/com/goormy/hackathon/service/PostCacheService.java index d1aa2b4..fa84b08 100644 --- a/src/main/java/com/goormy/hackathon/service/PostCacheService_SY.java +++ b/src/main/java/com/goormy/hackathon/service/PostCacheService.java @@ -7,11 +7,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import java.util.List; - @Service @RequiredArgsConstructor -public class PostCacheService_SY { +public class PostCacheService { private final PostRedisRepository_SY postRedisRepositorySY; private final FollowCountRedisRepository_SY followCountRedisRepositorySY; diff --git a/src/main/java/com/goormy/hackathon/service/PostService_SY.java b/src/main/java/com/goormy/hackathon/service/PostService.java similarity index 60% rename from src/main/java/com/goormy/hackathon/service/PostService_SY.java rename to src/main/java/com/goormy/hackathon/service/PostService.java index bc94cd1..e60e542 100644 --- a/src/main/java/com/goormy/hackathon/service/PostService_SY.java +++ b/src/main/java/com/goormy/hackathon/service/PostService.java @@ -6,17 +6,19 @@ import com.goormy.hackathon.repository.PostRepository_SY; import com.goormy.hackathon.repository.UserRepository_SY; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor -public class PostService_SY { +public class PostService { private final UserRepository_SY userRepositorySY; private final PostRepository_SY postRepositorySY; - private final HashtagService_SY hashtagServiceSY; - private final PostCacheService_SY postCacheServiceSY; + private final HashtagService hashtagServiceSY; + private final PostCacheService postCacheServiceSY; @Transactional public PostResponseDto_SY createPost(Long userId, PostRequestDto_SY postRequestDtoSY) { @@ -46,4 +48,19 @@ public PostResponseDto_SY createPost(Long userId, PostRequestDto_SY postRequestD return new PostResponseDto_SY(post); } + public Page getPostsByHashtag(String hashtagName, int page, int size) { + System.out.println("Fetching posts with hashtag: " + hashtagName + ", page: " + page + ", size: " + size); + Page postsPage = postRepositorySY.findPostsByHashtagName(hashtagName, PageRequest.of(page, size)); + + if (postsPage == null) { + throw new RuntimeException("No posts found for the given hashtag."); + } + + System.out.println("Total elements: " + postsPage.getTotalElements()); + System.out.println("Total pages: " + postsPage.getTotalPages()); + System.out.println("Current page: " + postsPage.getNumber()); + System.out.println("Number of posts on this page: " + postsPage.getNumberOfElements()); + return postsPage; + } + } diff --git a/src/main/java/com/goormy/hackathon/service/PostService_sieun.java b/src/main/java/com/goormy/hackathon/service/PostService_sieun.java deleted file mode 100644 index 068796b..0000000 --- a/src/main/java/com/goormy/hackathon/service/PostService_sieun.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.goormy.hackathon.service; - -import com.goormy.hackathon.entity.Post; -import com.goormy.hackathon.repository.PostRepository_sieun; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.stereotype.Service; - -@Service -public class PostService_sieun { - - private final PostRepository_sieun postRepositorySieun; - - @Autowired - public PostService_sieun(PostRepository_sieun postRepositorySieun) { - this.postRepositorySieun = postRepositorySieun; - } - - public Page getPostsByHashtag(String hashtagName, int page, int size) { - System.out.println("Fetching posts with hashtag: " + hashtagName + ", page: " + page + ", size: " + size); - Page postsPage = postRepositorySieun.findPostsByHashtagName(hashtagName, PageRequest.of(page, size)); - - if (postsPage == null) { - throw new RuntimeException("No posts found for the given hashtag."); - } - - System.out.println("Total elements: " + postsPage.getTotalElements()); - System.out.println("Total pages: " + postsPage.getTotalPages()); - System.out.println("Current page: " + postsPage.getNumber()); - System.out.println("Number of posts on this page: " + postsPage.getNumberOfElements()); - return postsPage; - } -} From 8c63583daf4456e90ce22694b76bcd2613e43216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Fri, 2 Aug 2024 15:01:13 +0900 Subject: [PATCH 50/57] =?UTF-8?q?refactor:=20repository=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=20=EB=B0=8F=20=EB=B6=84=EB=A5=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/GetFeedController.java | 9 +++---- .../hackathon/lambda/FollowFunction.java | 17 +++++++------ .../goormy/hackathon/lambda/LikeFunction.java | 8 +++--- .../FeedHashtagRedisRepository_SY.java | 21 ---------------- .../FeedUserRedisRepository_SY.java | 21 ---------------- .../FollowCountRedisRepository_SY.java | 24 ------------------ .../FollowListRedisRepository_SY.java | 21 ---------------- .../repository/HashtagRepository_SY.java | 10 -------- .../{ => JPA}/FollowRepository.java | 2 +- .../{ => JPA}/HashtagRepository.java | 5 +++- .../repository/{ => JPA}/LikeRepository.java | 4 +-- .../PostRepository.java} | 11 +++++--- .../repository/{ => JPA}/UserRepository.java | 2 +- .../PopularPostRedisRepository_DS.java | 5 ---- .../repository/PostRedisRepository_SY.java | 18 ------------- .../hackathon/repository/PostRepository.java | 9 ------- .../repository/PostRepository_SY.java | 13 ---------- .../FeedHashtagRedisRepository.java} | 22 +++++++++++----- .../FeedUserRedisRepository.java} | 18 ++++++++++--- .../FeedUserSortRedisRepository.java} | 4 +-- .../FollowCountRedisRepository.java | 18 +++++++++++-- .../FollowListRedisRepository.java} | 11 ++++++-- .../{ => Redis}/LikeRedisRepository.java | 2 +- .../Redis/PopularPostRedisRepository.java | 5 ++++ .../PostRedisRepository.java} | 15 ++++++++--- .../RecentUpdateRedisRepository.java} | 4 +-- .../UserRedisRepository.java} | 4 +-- .../repository/UserRepository_SY.java | 8 ------ .../hackathon/repository/UserRespository.java | 8 ------ .../hackathon/service/FollowService.java | 4 +-- .../hackathon/service/GetFeedService.java | 25 ++++++++----------- .../hackathon/service/HashtagService.java | 12 ++++----- .../hackathon/service/PostCacheService.java | 22 ++++++++-------- .../goormy/hackathon/service/PostService.java | 22 ++++++++-------- .../goormy/hackathon/service/UserService.java | 2 +- .../repository/LikeRedisRepositoryTest.java | 1 + .../hackathon/service/LikeServiceTest.java | 8 +++--- 37 files changed, 156 insertions(+), 259 deletions(-) delete mode 100644 src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_SY.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_SY.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_SY.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository_SY.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/HashtagRepository_SY.java rename src/main/java/com/goormy/hackathon/repository/{ => JPA}/FollowRepository.java (94%) rename src/main/java/com/goormy/hackathon/repository/{ => JPA}/HashtagRepository.java (67%) rename src/main/java/com/goormy/hackathon/repository/{ => JPA}/LikeRepository.java (86%) rename src/main/java/com/goormy/hackathon/repository/{PostRepository_sieun.java => JPA/PostRepository.java} (73%) rename src/main/java/com/goormy/hackathon/repository/{ => JPA}/UserRepository.java (79%) delete mode 100644 src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository_DS.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/PostRedisRepository_SY.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/PostRepository.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java rename src/main/java/com/goormy/hackathon/repository/{FeedHashtagRedisRepository_DS.java => Redis/FeedHashtagRedisRepository.java} (56%) rename src/main/java/com/goormy/hackathon/repository/{FeedUserRedisRepository_DS.java => Redis/FeedUserRedisRepository.java} (65%) rename src/main/java/com/goormy/hackathon/repository/{FeedUserSortRedisRepository_DS.java => Redis/FeedUserSortRedisRepository.java} (91%) rename src/main/java/com/goormy/hackathon/repository/{ => Redis}/FollowCountRedisRepository.java (62%) rename src/main/java/com/goormy/hackathon/repository/{FollowRedisRepository.java => Redis/FollowListRedisRepository.java} (79%) rename src/main/java/com/goormy/hackathon/repository/{ => Redis}/LikeRedisRepository.java (97%) create mode 100644 src/main/java/com/goormy/hackathon/repository/Redis/PopularPostRedisRepository.java rename src/main/java/com/goormy/hackathon/repository/{PostRedisRepository_DS.java => Redis/PostRedisRepository.java} (72%) rename src/main/java/com/goormy/hackathon/repository/{RecentUpdateRedisRepository_DS.java => Redis/RecentUpdateRedisRepository.java} (93%) rename src/main/java/com/goormy/hackathon/repository/{UserRedisRepository_DS.java => Redis/UserRedisRepository.java} (92%) delete mode 100644 src/main/java/com/goormy/hackathon/repository/UserRepository_SY.java delete mode 100644 src/main/java/com/goormy/hackathon/repository/UserRespository.java diff --git a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java index 9bf62de..570bc7b 100644 --- a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java +++ b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java @@ -1,12 +1,11 @@ package com.goormy.hackathon.controller; -import com.goormy.hackathon.common.util.LocalDateTimeConverter_DS; import com.goormy.hackathon.common.util.LocalDateTimeConverter_DS; import com.goormy.hackathon.dto.request.AddFeedUser; import com.goormy.hackathon.dto.response.GetFeedResponseDto; import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; -import com.goormy.hackathon.repository.FeedHashtagRedisRepository_DS; -import com.goormy.hackathon.repository.FeedUserRedisRepository_DS; +import com.goormy.hackathon.repository.Redis.FeedHashtagRedisRepository; +import com.goormy.hackathon.repository.Redis.FeedUserRedisRepository; import com.goormy.hackathon.service.GetFeedService; import java.util.List; import lombok.RequiredArgsConstructor; @@ -27,8 +26,8 @@ public class GetFeedController { private final GetFeedService getFeedService; private final LocalDateTimeConverter_DS localDateTimeConverter; - private final FeedUserRedisRepository_DS feedUserRedisRepository; - private final FeedHashtagRedisRepository_DS feedHashtagRedisRepository; + private final FeedUserRedisRepository feedUserRedisRepository; + private final FeedHashtagRedisRepository feedHashtagRedisRepository; /** * [GET] 사용자 맞춤형 피드 조회 기능 diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index 87d78d4..392fa24 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -4,7 +4,10 @@ import com.goormy.hackathon.entity.Follow; import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.*; +import com.goormy.hackathon.repository.JPA.FollowRepository; +import com.goormy.hackathon.repository.JPA.HashtagRepository; +import com.goormy.hackathon.repository.JPA.UserRepository; +import com.goormy.hackathon.repository.Redis.FollowListRedisRepository; import com.goormy.hackathon.service.FollowService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,18 +24,18 @@ public class FollowFunction{ private final FollowRepository followRepository; private final UserRepository userRepository; private final HashtagRepository hashtagRepository; - private final FollowRedisRepository followRedisRepository; + private final FollowListRedisRepository followListRedisRepository; private final FollowService followServiceSieun; private final ObjectMapper objectMapper; private static final Logger logger = LoggerFactory.getLogger(FollowFunction.class); - public FollowFunction(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository, FollowRedisRepository followRedisRepository + public FollowFunction(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository, FollowListRedisRepository followListRedisRepository , ObjectMapper objectMapper, FollowService followServiceSieun) { this.followRepository = followRepository; this.userRepository = userRepository; this.hashtagRepository = hashtagRepository; - this.followRedisRepository = followRedisRepository; + this.followListRedisRepository = followListRedisRepository; this.objectMapper = objectMapper; this.followServiceSieun = followServiceSieun; } @@ -58,7 +61,7 @@ public Consumer> processFollow() { if ("follow".equals(action)) { Follow follow = new Follow(user,hashtag); // follow_list:{hashtagId} 저장 - followRedisRepository.set(hashtagId, userId); + followListRedisRepository.set(hashtagId, userId); // follow_count:{hashtagId} 저장 followServiceSieun.followHashtag(hashtagId); System.out.println("팔로우 성공: " + messageBody); @@ -66,7 +69,7 @@ public Consumer> processFollow() { // follow_list:{hashtagId} 삭제 Follow follow = followRepository.findByUserIdAndHashTagId(userId, hashtagId) .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); - followRedisRepository.delete(hashtagId, userId); + followListRedisRepository.delete(hashtagId, userId); // follow_count:{hashtagId} 삭제 followServiceSieun.unfollowHashtag(hashtagId); System.out.println("팔로우 취소 성공: " + messageBody); @@ -83,7 +86,7 @@ public Consumer> processFollow() { // Redis 데이터를 RDBMS에 저장하고 Redis 비우기 public void migrateData() { // Redis에서 모든 팔로우 데이터 가져오기 - List follows = followRedisRepository.getAllFollows(); + List follows = followListRedisRepository.getAllFollows(); // RDBMS에 배치 저장 followRepository.deleteAll(); diff --git a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java index 0f51ccc..f00c4d3 100644 --- a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java @@ -4,10 +4,10 @@ import com.goormy.hackathon.entity.Like; import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.LikeRedisRepository; -import com.goormy.hackathon.repository.LikeRepository; -import com.goormy.hackathon.repository.PostRepository; -import com.goormy.hackathon.repository.UserRepository; +import com.goormy.hackathon.repository.Redis.LikeRedisRepository; +import com.goormy.hackathon.repository.JPA.LikeRepository; +import com.goormy.hackathon.repository.JPA.PostRepository; +import com.goormy.hackathon.repository.JPA.UserRepository; import java.util.List; import java.util.Map; import java.util.Set; diff --git a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_SY.java b/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_SY.java deleted file mode 100644 index 8792017..0000000 --- a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_SY.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.entity.Post; -import com.goormy.hackathon.redis.entity.FeedSimpleInfo_SY; -import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Repository; - -@Repository -@RequiredArgsConstructor -public class FeedHashtagRedisRepository_SY { - - private final RedisTemplate redisTemplate; - - public void set(Long hashtagId, Post post) { - String key = "feedhashtag:" + hashtagId; - Object value = new FeedSimpleInfo_SY(post); - redisTemplate.opsForList().leftPush(key, value); - } - -} diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_SY.java b/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_SY.java deleted file mode 100644 index a650efa..0000000 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_SY.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.entity.Post; -import com.goormy.hackathon.redis.entity.FeedSimpleInfo_SY; -import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Repository; - -@Repository -@RequiredArgsConstructor -public class FeedUserRedisRepository_SY { - - private final RedisTemplate redisTemplate; - - public void set(Long userId, Post post) { - String key = "feeduser:" + userId; - Object value = new FeedSimpleInfo_SY(post); - redisTemplate.opsForList().leftPush(key, value); - } - -} diff --git a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_SY.java b/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_SY.java deleted file mode 100644 index 33d11c3..0000000 --- a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository_SY.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.redis.entity.FollowCountCache_SY; -import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Repository; - -@Repository -@RequiredArgsConstructor -public class FollowCountRedisRepository_SY { - - private final RedisTemplate redisTemplate; - - public void set(FollowCountCache_SY followCountCacheSY) { - redisTemplate.opsForHash().put(followCountCacheSY.getKey(), followCountCacheSY.getField(), followCountCacheSY.getFollowCount()); - } - - public Integer findFollowCountByHashtagId(Long hashtagId) { - String key = "followcount:" + hashtagId; - String field = String.valueOf(hashtagId); - return (Integer) redisTemplate.opsForHash().get(key, field); - } - -} diff --git a/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository_SY.java b/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository_SY.java deleted file mode 100644 index c44e5eb..0000000 --- a/src/main/java/com/goormy/hackathon/repository/FollowListRedisRepository_SY.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.goormy.hackathon.repository; - -import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Repository; - -import java.util.List; - -@Repository -@RequiredArgsConstructor -public class FollowListRedisRepository_SY { - - private final RedisTemplate redisTemplate; - - // TODO: 수정 필요 - save 하는 쪽이 어떤 식으로 저장하느냐에 따라 호출 구현이 다를 듯 - public List findUserIdListByHashtagId(Long hashtagId) { - String key = "followlist:" + hashtagId; - return (List) redisTemplate.opsForValue().get(key); - } - -} diff --git a/src/main/java/com/goormy/hackathon/repository/HashtagRepository_SY.java b/src/main/java/com/goormy/hackathon/repository/HashtagRepository_SY.java deleted file mode 100644 index d7fe08c..0000000 --- a/src/main/java/com/goormy/hackathon/repository/HashtagRepository_SY.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.entity.Hashtag; -import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.Optional; - -public interface HashtagRepository_SY extends JpaRepository { - Optional findByName(String name); -} diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRepository.java b/src/main/java/com/goormy/hackathon/repository/JPA/FollowRepository.java similarity index 94% rename from src/main/java/com/goormy/hackathon/repository/FollowRepository.java rename to src/main/java/com/goormy/hackathon/repository/JPA/FollowRepository.java index d6ae201..c4c81ae 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/JPA/FollowRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.JPA; import com.goormy.hackathon.entity.Follow; import com.goormy.hackathon.entity.Hashtag; diff --git a/src/main/java/com/goormy/hackathon/repository/HashtagRepository.java b/src/main/java/com/goormy/hackathon/repository/JPA/HashtagRepository.java similarity index 67% rename from src/main/java/com/goormy/hackathon/repository/HashtagRepository.java rename to src/main/java/com/goormy/hackathon/repository/JPA/HashtagRepository.java index f13623c..ccb114a 100644 --- a/src/main/java/com/goormy/hackathon/repository/HashtagRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/JPA/HashtagRepository.java @@ -1,9 +1,12 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.JPA; import com.goormy.hackathon.entity.Hashtag; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.Optional; + @Repository public interface HashtagRepository extends JpaRepository { + Optional findByName(String name); } diff --git a/src/main/java/com/goormy/hackathon/repository/LikeRepository.java b/src/main/java/com/goormy/hackathon/repository/JPA/LikeRepository.java similarity index 86% rename from src/main/java/com/goormy/hackathon/repository/LikeRepository.java rename to src/main/java/com/goormy/hackathon/repository/JPA/LikeRepository.java index 17a5f67..551da68 100644 --- a/src/main/java/com/goormy/hackathon/repository/LikeRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/JPA/LikeRepository.java @@ -1,12 +1,10 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.JPA; import com.goormy.hackathon.entity.Like; -import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; public interface LikeRepository extends JpaRepository { diff --git a/src/main/java/com/goormy/hackathon/repository/PostRepository_sieun.java b/src/main/java/com/goormy/hackathon/repository/JPA/PostRepository.java similarity index 73% rename from src/main/java/com/goormy/hackathon/repository/PostRepository_sieun.java rename to src/main/java/com/goormy/hackathon/repository/JPA/PostRepository.java index 4bbb7ba..22fd0dd 100644 --- a/src/main/java/com/goormy/hackathon/repository/PostRepository_sieun.java +++ b/src/main/java/com/goormy/hackathon/repository/JPA/PostRepository.java @@ -1,15 +1,18 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.JPA; import com.goormy.hackathon.entity.Post; +import java.util.List; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; -@Repository -public interface PostRepository_sieun extends JpaRepository { +public interface PostRepository extends JpaRepository { + List findAllByIdIn(List ids); + @Query("SELECT p FROM Post p JOIN p.postHashtags ph JOIN ph.hashtag h WHERE h.name = :hashtagName") Page findPostsByHashtagName(@Param("hashtagName") String hashtagName, Pageable pageable); + } diff --git a/src/main/java/com/goormy/hackathon/repository/UserRepository.java b/src/main/java/com/goormy/hackathon/repository/JPA/UserRepository.java similarity index 79% rename from src/main/java/com/goormy/hackathon/repository/UserRepository.java rename to src/main/java/com/goormy/hackathon/repository/JPA/UserRepository.java index 2e801fc..d22ed64 100644 --- a/src/main/java/com/goormy/hackathon/repository/UserRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/JPA/UserRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.JPA; import com.goormy.hackathon.entity.User; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository_DS.java b/src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository_DS.java deleted file mode 100644 index b68791c..0000000 --- a/src/main/java/com/goormy/hackathon/repository/PopularPostRedisRepository_DS.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.goormy.hackathon.repository; - -public class PopularPostRedisRepository_DS { - -} diff --git a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository_SY.java b/src/main/java/com/goormy/hackathon/repository/PostRedisRepository_SY.java deleted file mode 100644 index 5b9f217..0000000 --- a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository_SY.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.redis.entity.PostCache_SY; -import lombok.RequiredArgsConstructor; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Repository; - -@Repository -@RequiredArgsConstructor -public class PostRedisRepository_SY { - - private final RedisTemplate redisTemplate; - - public void set(PostCache_SY postCacheSY) { - redisTemplate.opsForList().leftPush(postCacheSY.getKey(), postCacheSY); - } - -} diff --git a/src/main/java/com/goormy/hackathon/repository/PostRepository.java b/src/main/java/com/goormy/hackathon/repository/PostRepository.java deleted file mode 100644 index 065ae69..0000000 --- a/src/main/java/com/goormy/hackathon/repository/PostRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.entity.Post; -import java.util.List; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface PostRepository extends JpaRepository { - List findAllByIdIn(List ids); -} diff --git a/src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java b/src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java deleted file mode 100644 index b3797b3..0000000 --- a/src/main/java/com/goormy/hackathon/repository/PostRepository_SY.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.entity.Post; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.query.Param; - -public interface PostRepository_SY extends CrudRepository { - @Query("SELECT p FROM Post p JOIN p.postHashtags ph JOIN ph.hashtag h WHERE h.name = :hashtagName") - Page findPostsByHashtagName(@Param("hashtagName") String hashtagName, Pageable pageable); -} diff --git a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_DS.java b/src/main/java/com/goormy/hackathon/repository/Redis/FeedHashtagRedisRepository.java similarity index 56% rename from src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_DS.java rename to src/main/java/com/goormy/hackathon/repository/Redis/FeedHashtagRedisRepository.java index de93e1c..2f9d76e 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedHashtagRedisRepository_DS.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/FeedHashtagRedisRepository.java @@ -1,25 +1,29 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.Redis; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.redis.entity.FeedSimpleInfo_SY; import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; import jakarta.annotation.PostConstruct; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.ListOperations; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; -@Component +@Repository @RequiredArgsConstructor -public class FeedHashtagRedisRepository_DS { +public class FeedHashtagRedisRepository { - private final RedisTemplate redisTemplate; + private final RedisTemplate redisTemplate_postSimple; private static final String FEED_HASHTAG_KEY = "feedhashtag:"; + private final RedisTemplate redisTemplate_postHashtag; + private ListOperations listOperations; @PostConstruct private void init() { - listOperations = redisTemplate.opsForList(); + listOperations = redisTemplate_postSimple.opsForList(); } public void add(Long hashtagId, PostSimpleInfo_DS value) { @@ -29,4 +33,10 @@ public void add(Long hashtagId, PostSimpleInfo_DS value) { public List getAll(Long hashtagId) { return listOperations.range(FEED_HASHTAG_KEY + hashtagId, 0, -1); } + + public void set(Long hashtagId, Post post) { + String key = "feedhashtag:" + hashtagId; + Object value = new FeedSimpleInfo_SY(post); + redisTemplate_postHashtag.opsForList().leftPush(key, value); + } } diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_DS.java b/src/main/java/com/goormy/hackathon/repository/Redis/FeedUserRedisRepository.java similarity index 65% rename from src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_DS.java rename to src/main/java/com/goormy/hackathon/repository/Redis/FeedUserRedisRepository.java index 0adc009..8717e7b 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserRedisRepository_DS.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/FeedUserRedisRepository.java @@ -1,19 +1,22 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.Redis; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.redis.entity.FeedSimpleInfo_SY; import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; import jakarta.annotation.PostConstruct; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.ListOperations; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; -@Component +@Repository @RequiredArgsConstructor -public class FeedUserRedisRepository_DS { +public class FeedUserRedisRepository { private final RedisTemplate redisTemplate; private static final String FEED_USER_KEY = "feeduser:"; + private final RedisTemplate redisTemplate_feedUser; private ListOperations listOperations; @@ -33,4 +36,11 @@ public PostSimpleInfo_DS get(Long userId) { public List getAll(Long userId) { return listOperations.rightPop(FEED_USER_KEY + userId, Long.MAX_VALUE); } + + + public void set(Long userId, Post post) { + String key = "feeduser:" + userId; + Object value = new FeedSimpleInfo_SY(post); + redisTemplate_feedUser.opsForList().leftPush(key, value); + } } diff --git a/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository_DS.java b/src/main/java/com/goormy/hackathon/repository/Redis/FeedUserSortRedisRepository.java similarity index 91% rename from src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository_DS.java rename to src/main/java/com/goormy/hackathon/repository/Redis/FeedUserSortRedisRepository.java index 91fe101..33e5472 100644 --- a/src/main/java/com/goormy/hackathon/repository/FeedUserSortRedisRepository_DS.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/FeedUserSortRedisRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.Redis; import jakarta.annotation.PostConstruct; import java.util.List; @@ -9,7 +9,7 @@ @Component @RequiredArgsConstructor -public class FeedUserSortRedisRepository_DS { +public class FeedUserSortRedisRepository { private final RedisTemplate redisTemplate; private static final String FEED_USER_SORTED_KEY = "feedusersort:"; diff --git a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/Redis/FollowCountRedisRepository.java similarity index 62% rename from src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/Redis/FollowCountRedisRepository.java index 998d47e..5f597de 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowCountRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/FollowCountRedisRepository.java @@ -1,6 +1,7 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.Redis; +import com.goormy.hackathon.redis.entity.FollowCountCache_SY; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @@ -10,10 +11,13 @@ public class FollowCountRedisRepository { private final RedisTemplate integerRedisTemplate; private static final String FOLLOWING_COUNT_KEY = "follow_count:"; + private final RedisTemplate redisTemplate; @Autowired - public FollowCountRedisRepository(RedisTemplate integerRedisTemplate) { + public FollowCountRedisRepository(RedisTemplate integerRedisTemplate + , RedisTemplate redisTemplate) { this.integerRedisTemplate = integerRedisTemplate; + this.redisTemplate = redisTemplate; } public Integer getFollowCount(Long hashtagId) { @@ -35,4 +39,14 @@ public void decrementFollowCount(Long hashtagId) { String key = FOLLOWING_COUNT_KEY + hashtagId; integerRedisTemplate.opsForValue().decrement(key, 1); } + + public void set(FollowCountCache_SY followCountCacheSY) { + redisTemplate.opsForHash().put(followCountCacheSY.getKey(), followCountCacheSY.getField(), followCountCacheSY.getFollowCount()); + } + + public Integer findFollowCountByHashtagId(Long hashtagId) { + String key = "followcount:" + hashtagId; + String field = String.valueOf(hashtagId); + return (Integer) redisTemplate.opsForHash().get(key, field); + } } diff --git a/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java similarity index 79% rename from src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java index 799d533..ad08a25 100644 --- a/src/main/java/com/goormy/hackathon/repository/FollowRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java @@ -1,6 +1,7 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.Redis; import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.repository.JPA.FollowRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; @@ -10,7 +11,7 @@ import java.util.Set; @Repository -public class FollowRedisRepository { +public class FollowListRedisRepository { @Autowired RedisTemplate redisTemplate; @@ -52,6 +53,12 @@ public List getAllFollows() { return follows; } + // TODO: 수정 필요 - save 하는 쪽이 어떤 식으로 저장하느냐에 따라 호출 구현이 다를 듯 + public List findUserIdListByHashtagId(Long hashtagId) { + String key = "followlist:" + hashtagId; + return (List) redisTemplate.opsForValue().get(key); + } + diff --git a/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/Redis/LikeRedisRepository.java similarity index 97% rename from src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java rename to src/main/java/com/goormy/hackathon/repository/Redis/LikeRedisRepository.java index c066477..a7dc175 100644 --- a/src/main/java/com/goormy/hackathon/repository/LikeRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/LikeRedisRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.Redis; import lombok.RequiredArgsConstructor; import org.springframework.data.redis.core.*; diff --git a/src/main/java/com/goormy/hackathon/repository/Redis/PopularPostRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/Redis/PopularPostRedisRepository.java new file mode 100644 index 0000000..18d1449 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/repository/Redis/PopularPostRedisRepository.java @@ -0,0 +1,5 @@ +package com.goormy.hackathon.repository.Redis; + +public class PopularPostRedisRepository { + +} diff --git a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository_DS.java b/src/main/java/com/goormy/hackathon/repository/Redis/PostRedisRepository.java similarity index 72% rename from src/main/java/com/goormy/hackathon/repository/PostRedisRepository_DS.java rename to src/main/java/com/goormy/hackathon/repository/Redis/PostRedisRepository.java index 2d4e3b7..7999a2e 100644 --- a/src/main/java/com/goormy/hackathon/repository/PostRedisRepository_DS.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/PostRedisRepository.java @@ -1,5 +1,6 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.Redis; +import com.goormy.hackathon.redis.entity.PostCache_SY; import com.goormy.hackathon.redis.entity.PostRedis_DS; import jakarta.annotation.PostConstruct; import java.util.List; @@ -11,16 +12,18 @@ @Component @RequiredArgsConstructor -public class PostRedisRepository_DS { +public class PostRedisRepository { + + private final RedisTemplate redisTemplate_postRedis; + private final RedisTemplate redisTemplate; - private final RedisTemplate redisTemplate; private static final String POST_KEY = "post:"; private ValueOperations valueOperations; @PostConstruct private void init() { - valueOperations = redisTemplate.opsForValue(); + valueOperations = redisTemplate_postRedis.opsForValue(); } public void set(Long postId, PostRedis_DS value) { @@ -37,4 +40,8 @@ public List getAll(List postIdList) { .map(postId -> valueOperations.get(POST_KEY + postId)) .toList(); } + + public void set(PostCache_SY postCacheSY) { + redisTemplate.opsForList().leftPush(postCacheSY.getKey(), postCacheSY); + } } diff --git a/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository_DS.java b/src/main/java/com/goormy/hackathon/repository/Redis/RecentUpdateRedisRepository.java similarity index 93% rename from src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository_DS.java rename to src/main/java/com/goormy/hackathon/repository/Redis/RecentUpdateRedisRepository.java index c1555ea..e4414a4 100644 --- a/src/main/java/com/goormy/hackathon/repository/RecentUpdateRedisRepository_DS.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/RecentUpdateRedisRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.Redis; import jakarta.annotation.PostConstruct; import java.time.Duration; @@ -12,7 +12,7 @@ @Component @RequiredArgsConstructor -public class RecentUpdateRedisRepository_DS { +public class RecentUpdateRedisRepository { private final StringRedisTemplate stringRedisTemplate; private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME; diff --git a/src/main/java/com/goormy/hackathon/repository/UserRedisRepository_DS.java b/src/main/java/com/goormy/hackathon/repository/Redis/UserRedisRepository.java similarity index 92% rename from src/main/java/com/goormy/hackathon/repository/UserRedisRepository_DS.java rename to src/main/java/com/goormy/hackathon/repository/Redis/UserRedisRepository.java index 2a5a41e..ed6cf31 100644 --- a/src/main/java/com/goormy/hackathon/repository/UserRedisRepository_DS.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/UserRedisRepository.java @@ -1,4 +1,4 @@ -package com.goormy.hackathon.repository; +package com.goormy.hackathon.repository.Redis; import com.goormy.hackathon.redis.entity.UserRedis_DS; import jakarta.annotation.PostConstruct; @@ -10,7 +10,7 @@ @Component @RequiredArgsConstructor -public class UserRedisRepository_DS { +public class UserRedisRepository { private final RedisTemplate redisTemplate; private static final String USER_KEY = "user:"; diff --git a/src/main/java/com/goormy/hackathon/repository/UserRepository_SY.java b/src/main/java/com/goormy/hackathon/repository/UserRepository_SY.java deleted file mode 100644 index a56539e..0000000 --- a/src/main/java/com/goormy/hackathon/repository/UserRepository_SY.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.entity.User; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface UserRepository_SY extends JpaRepository { - -} diff --git a/src/main/java/com/goormy/hackathon/repository/UserRespository.java b/src/main/java/com/goormy/hackathon/repository/UserRespository.java deleted file mode 100644 index ec5b75f..0000000 --- a/src/main/java/com/goormy/hackathon/repository/UserRespository.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.goormy.hackathon.repository; - -import com.goormy.hackathon.entity.User; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface UserRespository extends JpaRepository { - -} diff --git a/src/main/java/com/goormy/hackathon/service/FollowService.java b/src/main/java/com/goormy/hackathon/service/FollowService.java index 433bec8..cdfdf05 100644 --- a/src/main/java/com/goormy/hackathon/service/FollowService.java +++ b/src/main/java/com/goormy/hackathon/service/FollowService.java @@ -2,8 +2,8 @@ import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.FollowCountRedisRepository; -import com.goormy.hackathon.repository.FollowRepository; +import com.goormy.hackathon.repository.Redis.FollowCountRedisRepository; +import com.goormy.hackathon.repository.JPA.FollowRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; diff --git a/src/main/java/com/goormy/hackathon/service/GetFeedService.java b/src/main/java/com/goormy/hackathon/service/GetFeedService.java index ee6c6c0..122d9d3 100644 --- a/src/main/java/com/goormy/hackathon/service/GetFeedService.java +++ b/src/main/java/com/goormy/hackathon/service/GetFeedService.java @@ -9,14 +9,9 @@ import com.goormy.hackathon.redis.entity.PostRedis_DS; import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; import com.goormy.hackathon.redis.entity.UserRedis_DS; -import com.goormy.hackathon.repository.FeedHashtagRedisRepository_DS; -import com.goormy.hackathon.repository.FeedUserRedisRepository_DS; -import com.goormy.hackathon.repository.FeedUserSortRedisRepository_DS; -import com.goormy.hackathon.repository.PostRedisRepository_DS; -import com.goormy.hackathon.repository.PostRepository; -import com.goormy.hackathon.repository.RecentUpdateRedisRepository_DS; -import com.goormy.hackathon.repository.UserRedisRepository_DS; -import com.goormy.hackathon.repository.UserRespository; +import com.goormy.hackathon.repository.JPA.PostRepository; +import com.goormy.hackathon.repository.JPA.UserRepository; +import com.goormy.hackathon.repository.Redis.*; import jakarta.transaction.Transactional; import java.time.LocalDateTime; import java.util.ArrayList; @@ -31,17 +26,17 @@ @RequiredArgsConstructor public class GetFeedService { - private final UserRespository userRespository; + private final UserRepository userRespository; private final PostRepository postRepository; private final LocalDateTimeConverter_DS localDateTimeConverter; - private final FeedHashtagRedisRepository_DS feedHashtagRedisRepository; - private final FeedUserRedisRepository_DS feedUserRedisRepository; - private final FeedUserSortRedisRepository_DS feedUserSortRedisRepository; - private final PostRedisRepository_DS postRedisRepository; - private final RecentUpdateRedisRepository_DS recentUpdateRedisRepository; - private final UserRedisRepository_DS userRedisRepository; + private final FeedHashtagRedisRepository feedHashtagRedisRepository; + private final FeedUserRedisRepository feedUserRedisRepository; + private final FeedUserSortRedisRepository feedUserSortRedisRepository; + private final PostRedisRepository postRedisRepository; + private final RecentUpdateRedisRepository recentUpdateRedisRepository; + private final UserRedisRepository userRedisRepository; // 1. 사용자 정보를 가져옴 private UserRedis_DS getUser(Long userId) { diff --git a/src/main/java/com/goormy/hackathon/service/HashtagService.java b/src/main/java/com/goormy/hackathon/service/HashtagService.java index 2083d7c..ef0a38c 100644 --- a/src/main/java/com/goormy/hackathon/service/HashtagService.java +++ b/src/main/java/com/goormy/hackathon/service/HashtagService.java @@ -3,8 +3,8 @@ import com.goormy.hackathon.dto.hashtag.PostHashtagRequestDto_SY; import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.redis.entity.FollowCountCache_SY; -import com.goormy.hackathon.repository.FollowCountRedisRepository_SY; -import com.goormy.hackathon.repository.HashtagRepository_SY; +import com.goormy.hackathon.repository.Redis.FollowCountRedisRepository; +import com.goormy.hackathon.repository.JPA.HashtagRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,19 +16,19 @@ @RequiredArgsConstructor public class HashtagService { - private final HashtagRepository_SY hashtagRepositorySY; - private final FollowCountRedisRepository_SY followCountRedisRepositorySY; + private final HashtagRepository hashtagRepository; + private final FollowCountRedisRepository followCountRedisRepositorySY; @Transactional public List getOrCreateHashtags(List hashtagRequestDtos) { List hashtags = new ArrayList<>(); for (var hashtagRequestDto : hashtagRequestDtos) { // 이미 존재하는 해시태그인 경우 - var hashtag = hashtagRepositorySY.findByName(hashtagRequestDto.name()) + var hashtag = hashtagRepository.findByName(hashtagRequestDto.name()) .orElseGet(() -> { // 새로운 해시태그인 경우 var newHashtag = new Hashtag(hashtagRequestDto.name(), hashtagRequestDto.type()); - hashtagRepositorySY.save(newHashtag); + hashtagRepository.save(newHashtag); var followCountCache = new FollowCountCache_SY(newHashtag); followCountRedisRepositorySY.set(followCountCache); diff --git a/src/main/java/com/goormy/hackathon/service/PostCacheService.java b/src/main/java/com/goormy/hackathon/service/PostCacheService.java index fa84b08..c9ee64a 100644 --- a/src/main/java/com/goormy/hackathon/service/PostCacheService.java +++ b/src/main/java/com/goormy/hackathon/service/PostCacheService.java @@ -3,7 +3,7 @@ import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.redis.entity.PostCache_SY; -import com.goormy.hackathon.repository.*; +import com.goormy.hackathon.repository.Redis.*; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -11,15 +11,15 @@ @RequiredArgsConstructor public class PostCacheService { - private final PostRedisRepository_SY postRedisRepositorySY; - private final FollowCountRedisRepository_SY followCountRedisRepositorySY; - private final FollowListRedisRepository_SY followListRedisRepositorySY; - private final FeedUserRedisRepository_SY feedUserRedisRepositorySY; - private final FeedHashtagRedisRepository_SY feedHashtagRedisRepositorySY; + private final PostRedisRepository postRedisRepository; + private final FollowCountRedisRepository followCountRedisRepository; + private final FollowListRedisRepository followListRedisRepository; + private final FeedUserRedisRepository feedUserRedisRepository; + private final FeedHashtagRedisRepository feedHashtagRedisRepository; // TODO: 이벤트로 발행한 후 이벤트를 받아 Redis에 비동기로 저장 public void cache(Post post) { - postRedisRepositorySY.set(new PostCache_SY(post)); + postRedisRepository.set(new PostCache_SY(post)); for (var hashtag : post.getPostHashtags()) { if (isPopular(hashtag)) { pullModel(hashtag, post); @@ -30,7 +30,7 @@ public void cache(Post post) { } private boolean isPopular(Hashtag hashtag) { - var followCount = followCountRedisRepositorySY.findFollowCountByHashtagId(hashtag.getId()); + var followCount = followCountRedisRepository.findFollowCountByHashtagId(hashtag.getId()); if (followCount != null ) { return followCount >= 5000; } @@ -38,13 +38,13 @@ private boolean isPopular(Hashtag hashtag) { } private void pushModel(Hashtag hashtag, Post post) { - var userIdList = followListRedisRepositorySY.findUserIdListByHashtagId(hashtag.getId()); + var userIdList = followListRedisRepository.findUserIdListByHashtagId(hashtag.getId()); userIdList.forEach(userId -> { - feedUserRedisRepositorySY.set(Long.valueOf(userId), post); + feedUserRedisRepository.set(Long.valueOf(userId), post); }); } private void pullModel(Hashtag hashtag, Post post) { - feedHashtagRedisRepositorySY.set(hashtag.getId(), post); + feedHashtagRedisRepository.set(hashtag.getId(), post); } } diff --git a/src/main/java/com/goormy/hackathon/service/PostService.java b/src/main/java/com/goormy/hackathon/service/PostService.java index e60e542..8918deb 100644 --- a/src/main/java/com/goormy/hackathon/service/PostService.java +++ b/src/main/java/com/goormy/hackathon/service/PostService.java @@ -3,8 +3,8 @@ import com.goormy.hackathon.dto.post.PostRequestDto_SY; import com.goormy.hackathon.dto.post.PostResponseDto_SY; import com.goormy.hackathon.entity.Post; -import com.goormy.hackathon.repository.PostRepository_SY; -import com.goormy.hackathon.repository.UserRepository_SY; +import com.goormy.hackathon.repository.JPA.PostRepository; +import com.goormy.hackathon.repository.JPA.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -15,15 +15,15 @@ @RequiredArgsConstructor public class PostService { - private final UserRepository_SY userRepositorySY; - private final PostRepository_SY postRepositorySY; - private final HashtagService hashtagServiceSY; - private final PostCacheService postCacheServiceSY; + private final UserRepository userRepository; + private final PostRepository postRepository; + private final HashtagService hashtagService; + private final PostCacheService postCacheService; @Transactional public PostResponseDto_SY createPost(Long userId, PostRequestDto_SY postRequestDtoSY) { // 사용자 찾기 - var user = userRepositorySY.findById(userId).orElseThrow( + var user = userRepository.findById(userId).orElseThrow( () -> new IllegalArgumentException("User not found")); // TODO: Custom exception // post 생성 @@ -36,21 +36,21 @@ public PostResponseDto_SY createPost(Long userId, PostRequestDto_SY postRequestD .build(); // hashtag 생성 - var postHashtags = hashtagServiceSY.getOrCreateHashtags(postRequestDtoSY.postHashtags()); + var postHashtags = hashtagService.getOrCreateHashtags(postRequestDtoSY.postHashtags()); post.setPostHashtags(postHashtags); // DB 저장 - postRepositorySY.save(post); + postRepository.save(post); // redis 저장 - postCacheServiceSY.cache(post); + postCacheService.cache(post); return new PostResponseDto_SY(post); } public Page getPostsByHashtag(String hashtagName, int page, int size) { System.out.println("Fetching posts with hashtag: " + hashtagName + ", page: " + page + ", size: " + size); - Page postsPage = postRepositorySY.findPostsByHashtagName(hashtagName, PageRequest.of(page, size)); + Page postsPage = postRepository.findPostsByHashtagName(hashtagName, PageRequest.of(page, size)); if (postsPage == null) { throw new RuntimeException("No posts found for the given hashtag."); diff --git a/src/main/java/com/goormy/hackathon/service/UserService.java b/src/main/java/com/goormy/hackathon/service/UserService.java index 4ef741d..bd0772a 100644 --- a/src/main/java/com/goormy/hackathon/service/UserService.java +++ b/src/main/java/com/goormy/hackathon/service/UserService.java @@ -1,7 +1,7 @@ package com.goormy.hackathon.service; import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.UserRepository; +import com.goormy.hackathon.repository.JPA.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/src/test/java/com/goormy/hackathon/repository/LikeRedisRepositoryTest.java b/src/test/java/com/goormy/hackathon/repository/LikeRedisRepositoryTest.java index 16bcb55..107bcb0 100644 --- a/src/test/java/com/goormy/hackathon/repository/LikeRedisRepositoryTest.java +++ b/src/test/java/com/goormy/hackathon/repository/LikeRedisRepositoryTest.java @@ -1,5 +1,6 @@ package com.goormy.hackathon.repository; +import com.goormy.hackathon.repository.Redis.LikeRedisRepository; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; diff --git a/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java b/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java index 0d2073f..9516983 100644 --- a/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java +++ b/src/test/java/com/goormy/hackathon/service/LikeServiceTest.java @@ -4,10 +4,10 @@ import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.entity.User; import com.goormy.hackathon.lambda.LikeFunction; -import com.goormy.hackathon.repository.LikeRedisRepository; -import com.goormy.hackathon.repository.LikeRepository; -import com.goormy.hackathon.repository.PostRepository; -import com.goormy.hackathon.repository.UserRepository; +import com.goormy.hackathon.repository.Redis.LikeRedisRepository; +import com.goormy.hackathon.repository.JPA.LikeRepository; +import com.goormy.hackathon.repository.JPA.PostRepository; +import com.goormy.hackathon.repository.JPA.UserRepository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From 5ee232e66f063f922b7d884017919c6386d11fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Fri, 2 Aug 2024 15:15:04 +0900 Subject: [PATCH 51/57] =?UTF-8?q?refactor:=20Redis=20Entity=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/GetFeedController.java | 6 ++-- .../hackathon/redis/config/RedisConfig.java | 20 ++++++------ ...tagCache_SY.java => FeedHashtagCache.java} | 2 +- ...edUserCache_SY.java => FeedUserCache.java} | 4 +-- ...untCache_SY.java => FollowCountCache.java} | 4 +-- ...ListCache_SY.java => FollowListCache.java} | 2 +- ...ostRedis_DS.java => PopularPostRedis.java} | 2 +- ...SimpleInfo_DS.java => PostSimpleInfo.java} | 8 ++--- ...teRedis_DS.java => RecentUpdateRedis.java} | 6 ++-- .../{UserRedis_DS.java => UserRedis.java} | 10 +++--- .../Redis/FeedHashtagRedisRepository.java | 10 +++--- .../Redis/FeedUserRedisRepository.java | 12 +++---- .../Redis/FollowCountRedisRepository.java | 4 +-- .../repository/Redis/UserRedisRepository.java | 12 +++---- .../hackathon/service/GetFeedService.java | 32 +++++++++---------- .../hackathon/service/HashtagService.java | 4 +-- 16 files changed, 69 insertions(+), 69 deletions(-) rename src/main/java/com/goormy/hackathon/redis/entity/{FeedHashtagCache_SY.java => FeedHashtagCache.java} (81%) rename src/main/java/com/goormy/hackathon/redis/entity/{FeedUserCache_SY.java => FeedUserCache.java} (78%) rename src/main/java/com/goormy/hackathon/redis/entity/{FollowCountCache_SY.java => FollowCountCache.java} (82%) rename src/main/java/com/goormy/hackathon/redis/entity/{FollowListCache_SY.java => FollowListCache.java} (81%) rename src/main/java/com/goormy/hackathon/redis/entity/{PopularPostRedis_DS.java => PopularPostRedis.java} (90%) rename src/main/java/com/goormy/hackathon/redis/entity/{PostSimpleInfo_DS.java => PostSimpleInfo.java} (74%) rename src/main/java/com/goormy/hackathon/redis/entity/{RecentUpdateRedis_DS.java => RecentUpdateRedis.java} (73%) rename src/main/java/com/goormy/hackathon/redis/entity/{UserRedis_DS.java => UserRedis.java} (81%) diff --git a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java index 570bc7b..5005184 100644 --- a/src/main/java/com/goormy/hackathon/controller/GetFeedController.java +++ b/src/main/java/com/goormy/hackathon/controller/GetFeedController.java @@ -3,7 +3,7 @@ import com.goormy.hackathon.common.util.LocalDateTimeConverter_DS; import com.goormy.hackathon.dto.request.AddFeedUser; import com.goormy.hackathon.dto.response.GetFeedResponseDto; -import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; +import com.goormy.hackathon.redis.entity.PostSimpleInfo; import com.goormy.hackathon.repository.Redis.FeedHashtagRedisRepository; import com.goormy.hackathon.repository.Redis.FeedUserRedisRepository; import com.goormy.hackathon.service.GetFeedService; @@ -53,7 +53,7 @@ public ResponseEntity addFeedHashtagData( requestDto.getInfoList().forEach( info -> feedHashtagRedisRepository.add(userId, - PostSimpleInfo_DS.toEntity(info.getPostId(), + PostSimpleInfo.toEntity(info.getPostId(), localDateTimeConverter.convertToString(info.getCreatedAt()))) ); @@ -69,7 +69,7 @@ public ResponseEntity addFeedUserData( requestDto.getInfoList().forEach( info -> feedUserRedisRepository.add(userId, - PostSimpleInfo_DS.toEntity(info.getPostId(), + PostSimpleInfo.toEntity(info.getPostId(), localDateTimeConverter.convertToString(info.getCreatedAt()))) ); diff --git a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java index 49085c2..8d7479b 100644 --- a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java +++ b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java @@ -1,8 +1,8 @@ package com.goormy.hackathon.redis.config; import com.goormy.hackathon.redis.entity.PostRedis_DS; -import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; -import com.goormy.hackathon.redis.entity.UserRedis_DS; +import com.goormy.hackathon.redis.entity.PostSimpleInfo; +import com.goormy.hackathon.redis.entity.UserRedis; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; @@ -47,12 +47,12 @@ public RedisTemplate redisTemplate() { } @Bean - public RedisTemplate userRedisTemplate() { - RedisTemplate redisTemplate = new RedisTemplate<>(); + public RedisTemplate userRedisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory()); redisTemplate.setKeySerializer(new StringRedisSerializer()); - Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( - UserRedis_DS.class); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( + UserRedis.class); redisTemplate.setValueSerializer(serializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(serializer); @@ -60,12 +60,12 @@ public RedisTemplate userRedisTemplate() { } @Bean - public RedisTemplate postSimpleInfoRedisTemplate() { - RedisTemplate redisTemplate = new RedisTemplate<>(); + public RedisTemplate postSimpleInfoRedisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory()); redisTemplate.setKeySerializer(new StringRedisSerializer()); - Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( - PostSimpleInfo_DS.class); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>( + PostSimpleInfo.class); redisTemplate.setValueSerializer(serializer); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); redisTemplate.setHashValueSerializer(serializer); diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache_SY.java b/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache.java similarity index 81% rename from src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache_SY.java rename to src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache.java index 6f92897..efd294d 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache_SY.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FeedHashtagCache.java @@ -7,7 +7,7 @@ import java.util.List; @Getter -public class FeedHashtagCache_SY implements Serializable { +public class FeedHashtagCache implements Serializable { @Id Long hashtagId; diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache_SY.java b/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache.java similarity index 78% rename from src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache_SY.java rename to src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache.java index 82c10a8..b4342b8 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache_SY.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FeedUserCache.java @@ -8,13 +8,13 @@ import java.util.List; @Getter -public class FeedUserCache_SY implements Serializable { +public class FeedUserCache implements Serializable { @Id Long userId; private List postList; - public FeedUserCache_SY(Post post) { + public FeedUserCache(Post post) { this.userId = post.getUser().getId(); } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache_SY.java b/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java similarity index 82% rename from src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache_SY.java rename to src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java index 34c97dc..bc37040 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache_SY.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FollowCountCache.java @@ -7,13 +7,13 @@ import java.io.Serializable; @Getter -public class FollowCountCache_SY implements Serializable { +public class FollowCountCache implements Serializable { @Id private Long hashtagId; private Integer followCount; - public FollowCountCache_SY(Hashtag hashtag) { + public FollowCountCache(Hashtag hashtag) { this.hashtagId = hashtag.getId(); this.followCount = 0; } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache_SY.java b/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java similarity index 81% rename from src/main/java/com/goormy/hackathon/redis/entity/FollowListCache_SY.java rename to src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java index 27f3f0d..6557b8e 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache_SY.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/FollowListCache.java @@ -7,7 +7,7 @@ import java.util.List; @Getter -public class FollowListCache_SY implements Serializable { +public class FollowListCache implements Serializable { @Id private String hashtagId; diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis_DS.java b/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis.java similarity index 90% rename from src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis_DS.java rename to src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis.java index db78245..c58ec02 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis_DS.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/PopularPostRedis.java @@ -8,7 +8,7 @@ @Getter @RedisHash("popular_post") @AllArgsConstructor -public class PopularPostRedis_DS { +public class PopularPostRedis { private List postIdList; // 최대 256개의 아티클 저장 -> 1KB } diff --git a/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo_DS.java b/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java similarity index 74% rename from src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo_DS.java rename to src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java index c6bfd56..b8d2eba 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo_DS.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/PostSimpleInfo.java @@ -7,21 +7,21 @@ @Getter @Builder -public class PostSimpleInfo_DS { +public class PostSimpleInfo { private Long id; private String createdAt; @JsonCreator - public PostSimpleInfo_DS( + public PostSimpleInfo( @JsonProperty("id") Long postId, @JsonProperty("createdAt") String createdAt) { this.id = postId; this.createdAt = createdAt; } - public static PostSimpleInfo_DS toEntity(Long postId, String createdAt) { - return PostSimpleInfo_DS.builder() + public static PostSimpleInfo toEntity(Long postId, String createdAt) { + return PostSimpleInfo.builder() .id(postId) .createdAt(createdAt) .build(); diff --git a/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis_DS.java b/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis.java similarity index 73% rename from src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis_DS.java rename to src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis.java index 9fc023a..04d94f8 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis_DS.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/RecentUpdateRedis.java @@ -11,15 +11,15 @@ @RedisHash("recent_update") @Getter @Builder -public class RecentUpdateRedis_DS { +public class RecentUpdateRedis { @Id private Long id; private LocalDateTime recentUpdateTime; - public static RecentUpdateRedis_DS toEntity(Long id, LocalDateTime recentUpdateTime) { - return RecentUpdateRedis_DS.builder() + public static RecentUpdateRedis toEntity(Long id, LocalDateTime recentUpdateTime) { + return RecentUpdateRedis.builder() .id(id) .recentUpdateTime(recentUpdateTime) .build(); diff --git a/src/main/java/com/goormy/hackathon/redis/entity/UserRedis_DS.java b/src/main/java/com/goormy/hackathon/redis/entity/UserRedis.java similarity index 81% rename from src/main/java/com/goormy/hackathon/redis/entity/UserRedis_DS.java rename to src/main/java/com/goormy/hackathon/redis/entity/UserRedis.java index 7ec2c31..ba5a7d3 100644 --- a/src/main/java/com/goormy/hackathon/redis/entity/UserRedis_DS.java +++ b/src/main/java/com/goormy/hackathon/redis/entity/UserRedis.java @@ -11,7 +11,7 @@ @Getter @Setter @Builder -public class UserRedis_DS implements Serializable { +public class UserRedis implements Serializable { private Long id; @@ -26,7 +26,7 @@ public class UserRedis_DS implements Serializable { private List followerIdList; @JsonCreator - public UserRedis_DS( + public UserRedis( @JsonProperty("id") Long id, @JsonProperty("name") String name, @JsonProperty("password") String password, @@ -42,9 +42,9 @@ public UserRedis_DS( } - public static UserRedis_DS toEntity(Long id, String name, String password, Integer followerCount, - Integer followingCount, List followerIdList) { - return UserRedis_DS.builder() + public static UserRedis toEntity(Long id, String name, String password, Integer followerCount, + Integer followingCount, List followerIdList) { + return UserRedis.builder() .id(id) .name(name) .password(password) diff --git a/src/main/java/com/goormy/hackathon/repository/Redis/FeedHashtagRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/Redis/FeedHashtagRedisRepository.java index 2f9d76e..72120ac 100644 --- a/src/main/java/com/goormy/hackathon/repository/Redis/FeedHashtagRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/FeedHashtagRedisRepository.java @@ -2,7 +2,7 @@ import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.redis.entity.FeedSimpleInfo_SY; -import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; +import com.goormy.hackathon.redis.entity.PostSimpleInfo; import jakarta.annotation.PostConstruct; import java.util.List; import lombok.RequiredArgsConstructor; @@ -14,23 +14,23 @@ @RequiredArgsConstructor public class FeedHashtagRedisRepository { - private final RedisTemplate redisTemplate_postSimple; + private final RedisTemplate redisTemplate_postSimple; private static final String FEED_HASHTAG_KEY = "feedhashtag:"; private final RedisTemplate redisTemplate_postHashtag; - private ListOperations listOperations; + private ListOperations listOperations; @PostConstruct private void init() { listOperations = redisTemplate_postSimple.opsForList(); } - public void add(Long hashtagId, PostSimpleInfo_DS value) { + public void add(Long hashtagId, PostSimpleInfo value) { listOperations.leftPush(FEED_HASHTAG_KEY + hashtagId, value); } - public List getAll(Long hashtagId) { + public List getAll(Long hashtagId) { return listOperations.range(FEED_HASHTAG_KEY + hashtagId, 0, -1); } diff --git a/src/main/java/com/goormy/hackathon/repository/Redis/FeedUserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/Redis/FeedUserRedisRepository.java index 8717e7b..26a3b2a 100644 --- a/src/main/java/com/goormy/hackathon/repository/Redis/FeedUserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/FeedUserRedisRepository.java @@ -2,7 +2,7 @@ import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.redis.entity.FeedSimpleInfo_SY; -import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; +import com.goormy.hackathon.redis.entity.PostSimpleInfo; import jakarta.annotation.PostConstruct; import java.util.List; import lombok.RequiredArgsConstructor; @@ -14,26 +14,26 @@ @RequiredArgsConstructor public class FeedUserRedisRepository { - private final RedisTemplate redisTemplate; + private final RedisTemplate redisTemplate; private static final String FEED_USER_KEY = "feeduser:"; private final RedisTemplate redisTemplate_feedUser; - private ListOperations listOperations; + private ListOperations listOperations; @PostConstruct private void init() { listOperations = redisTemplate.opsForList(); } - public void add(Long userId, PostSimpleInfo_DS value) { + public void add(Long userId, PostSimpleInfo value) { listOperations.leftPush(FEED_USER_KEY + userId, value); } - public PostSimpleInfo_DS get(Long userId) { + public PostSimpleInfo get(Long userId) { return listOperations.rightPop(FEED_USER_KEY + userId); } - public List getAll(Long userId) { + public List getAll(Long userId) { return listOperations.rightPop(FEED_USER_KEY + userId, Long.MAX_VALUE); } diff --git a/src/main/java/com/goormy/hackathon/repository/Redis/FollowCountRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/Redis/FollowCountRedisRepository.java index 5f597de..6664407 100644 --- a/src/main/java/com/goormy/hackathon/repository/Redis/FollowCountRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/FollowCountRedisRepository.java @@ -1,7 +1,7 @@ package com.goormy.hackathon.repository.Redis; -import com.goormy.hackathon.redis.entity.FollowCountCache_SY; +import com.goormy.hackathon.redis.entity.FollowCountCache; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @@ -40,7 +40,7 @@ public void decrementFollowCount(Long hashtagId) { integerRedisTemplate.opsForValue().decrement(key, 1); } - public void set(FollowCountCache_SY followCountCacheSY) { + public void set(FollowCountCache followCountCacheSY) { redisTemplate.opsForHash().put(followCountCacheSY.getKey(), followCountCacheSY.getField(), followCountCacheSY.getFollowCount()); } diff --git a/src/main/java/com/goormy/hackathon/repository/Redis/UserRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/Redis/UserRedisRepository.java index ed6cf31..35e82b0 100644 --- a/src/main/java/com/goormy/hackathon/repository/Redis/UserRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/UserRedisRepository.java @@ -1,6 +1,6 @@ package com.goormy.hackathon.repository.Redis; -import com.goormy.hackathon.redis.entity.UserRedis_DS; +import com.goormy.hackathon.redis.entity.UserRedis; import jakarta.annotation.PostConstruct; import java.util.Optional; import lombok.RequiredArgsConstructor; @@ -12,22 +12,22 @@ @RequiredArgsConstructor public class UserRedisRepository { - private final RedisTemplate redisTemplate; + private final RedisTemplate redisTemplate; private static final String USER_KEY = "user:"; - private ValueOperations valueOperations; + private ValueOperations valueOperations; @PostConstruct private void init() { valueOperations = redisTemplate.opsForValue(); } - public void set(Long userId, UserRedis_DS value) { + public void set(Long userId, UserRedis value) { valueOperations.set(USER_KEY + userId, value); } - public Optional get(Long userId) { - UserRedis_DS user = valueOperations.get(USER_KEY + userId); + public Optional get(Long userId) { + UserRedis user = valueOperations.get(USER_KEY + userId); return Optional.ofNullable(user); } } diff --git a/src/main/java/com/goormy/hackathon/service/GetFeedService.java b/src/main/java/com/goormy/hackathon/service/GetFeedService.java index 122d9d3..2b03900 100644 --- a/src/main/java/com/goormy/hackathon/service/GetFeedService.java +++ b/src/main/java/com/goormy/hackathon/service/GetFeedService.java @@ -7,8 +7,8 @@ import com.goormy.hackathon.entity.Post; import com.goormy.hackathon.entity.User; import com.goormy.hackathon.redis.entity.PostRedis_DS; -import com.goormy.hackathon.redis.entity.PostSimpleInfo_DS; -import com.goormy.hackathon.redis.entity.UserRedis_DS; +import com.goormy.hackathon.redis.entity.PostSimpleInfo; +import com.goormy.hackathon.redis.entity.UserRedis; import com.goormy.hackathon.repository.JPA.PostRepository; import com.goormy.hackathon.repository.JPA.UserRepository; import com.goormy.hackathon.repository.Redis.*; @@ -39,9 +39,9 @@ public class GetFeedService { private final UserRedisRepository userRedisRepository; // 1. 사용자 정보를 가져옴 - private UserRedis_DS getUser(Long userId) { + private UserRedis getUser(Long userId) { // 캐시 우선 검색 - Optional userCacheOptional = userRedisRepository.get(userId); + Optional userCacheOptional = userRedisRepository.get(userId); // 캐시에 없으면 RDB에서 검색 return userCacheOptional.orElseGet(() -> { User user = userRespository.findById(userId) @@ -51,15 +51,15 @@ private UserRedis_DS getUser(Long userId) { .toList(); // RDB에서 검색하고, UserCache에 추가 userRedisRepository.set(userId, - UserRedis_DS.toEntity(user.getId(), user.getName(), user.getPassword(), + UserRedis.toEntity(user.getId(), user.getName(), user.getPassword(), user.getFollowerCount(), user.getFollowingCount(), followIdList)); - return UserRedis_DS.toEntity(user.getId(), user.getName(), user.getPassword(), + return UserRedis.toEntity(user.getId(), user.getName(), user.getPassword(), user.getFollowerCount(), user.getFollowingCount(), followIdList); }); } // 2, 3. Push & Pull 방식으로 피드를 가져옴 - private List getPushPullFeed(UserRedis_DS userRedisDS) { + private List getPushPullFeed(UserRedis userRedisDS) { // 날짜 세팅 // recentUpdatedTime - 가장 마지막으로 업데이트한 시간이랑 3일 중 현재와 가장 가까운 시간을 기준으로 잡음 LocalDateTime now = LocalDateTime.now(); @@ -70,9 +70,9 @@ private List getPushPullFeed(UserRedis_DS userRedisDS) { // Push 방식으로 저장되어있는 포스트 가져오기 -> Created At 정보도 같이 저장해야함 // (이유) 한개의 Key에 있는 각 값마다 TTL 설정이 불가능하기 때문 // feedUser 접근 - List feedUserCache = feedUserRedisRepository.getAll(userRedisDS.getId()); + List feedUserCache = feedUserRedisRepository.getAll(userRedisDS.getId()); // push 캐시 가져오고 비우기 & 3일 전 포스트까지만 가져오기 - List postSimpleInfoDSList = new ArrayList<>(feedUserCache.stream() + List postSimpleInfoDSList = new ArrayList<>(feedUserCache.stream() .filter(simpleInfo -> localDateTimeConverter.convertToLocalDateTime( simpleInfo.getCreatedAt()).isAfter(recentUpdatedTime)) .toList()); @@ -83,7 +83,7 @@ private List getPushPullFeed(UserRedis_DS userRedisDS) { // user의 follow 리스트를 순회하면서 가져와야함 & 3일 전 포스트까지만 가져오기 userRedisDS.getFollowerIdList().forEach( followId -> { - List info = feedHashtagRedisRepository.getAll(followId); + List info = feedHashtagRedisRepository.getAll(followId); postSimpleInfoDSList.addAll(info.stream() .filter(Objects::nonNull) .filter(simpleInfo -> localDateTimeConverter.convertToLocalDateTime( @@ -100,8 +100,8 @@ private List getPushPullFeed(UserRedis_DS userRedisDS) { } // 5. size개의 post를 구분 - private List splitPostSimpleInfoList(UserRedis_DS userRedisDS, - List postIdList, int size) { + private List splitPostSimpleInfoList(UserRedis userRedisDS, + List postIdList, int size) { // 초기 반환을 위한 Id 리스트 // 나머지 정렬한 값을 Redis에 저장 @@ -152,7 +152,7 @@ private List getPostList(List postIdList) { @Transactional public List getFeedList(Long userId, int size) { // 1. 사용자 정보 가져오기 (Redis -> RDS) - UserRedis_DS userRedisDS = getUser(userId); + UserRedis userRedisDS = getUser(userId); // 2.0 이미 정리해둔 post가 있으면 가져오기 List postIdList = feedUserSortRedisRepository.getSome(userId, size); @@ -165,13 +165,13 @@ public List getFeedList(Long userId, int size) { // 2, 3. Push, Pull로 Feed List 가져오기 & 필터링 // 나중에 (1)여기 먼저 조회 & 있으면 반환, 없으면 (2)push/pull 확인 후 부족하면 (3)인기 게시글 반환 - List pushPullFeedList = getPushPullFeed(userRedisDS); + List pushPullFeedList = getPushPullFeed(userRedisDS); // 여기서 Null 체크, 이후 리스트에 들어가는 모든 post는 null이 있을 수 없음 // 4. 최신순으로 정렬 List sortedPushPullFeedList = pushPullFeedList.stream() - .sorted(Comparator.comparing(PostSimpleInfo_DS::getCreatedAt)) - .map(PostSimpleInfo_DS::getId) + .sorted(Comparator.comparing(PostSimpleInfo::getCreatedAt)) + .map(PostSimpleInfo::getId) .toList(); // 5. 반환할 데이터와, Redis에 저장할 데이터를 구분하고, Redis에 저장 diff --git a/src/main/java/com/goormy/hackathon/service/HashtagService.java b/src/main/java/com/goormy/hackathon/service/HashtagService.java index ef0a38c..e1d89cb 100644 --- a/src/main/java/com/goormy/hackathon/service/HashtagService.java +++ b/src/main/java/com/goormy/hackathon/service/HashtagService.java @@ -2,7 +2,7 @@ import com.goormy.hackathon.dto.hashtag.PostHashtagRequestDto_SY; import com.goormy.hackathon.entity.Hashtag; -import com.goormy.hackathon.redis.entity.FollowCountCache_SY; +import com.goormy.hackathon.redis.entity.FollowCountCache; import com.goormy.hackathon.repository.Redis.FollowCountRedisRepository; import com.goormy.hackathon.repository.JPA.HashtagRepository; import lombok.RequiredArgsConstructor; @@ -30,7 +30,7 @@ public List getOrCreateHashtags(List hashtagR var newHashtag = new Hashtag(hashtagRequestDto.name(), hashtagRequestDto.type()); hashtagRepository.save(newHashtag); - var followCountCache = new FollowCountCache_SY(newHashtag); + var followCountCache = new FollowCountCache(newHashtag); followCountRedisRepositorySY.set(followCountCache); return newHashtag; From 39faec1d06dfd4e6294f77e6a4f168ab06274729 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Fri, 2 Aug 2024 17:34:58 +0900 Subject: [PATCH 52/57] =?UTF-8?q?feat:=20migrateFunction=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- .../hackathon/handler/FollowHandler.java | 4 + .../hackathon/handler/ScheduledHandler.java | 14 +- .../hackathon/lambda/FollowFunction.java | 122 ++++++++---------- .../goormy/hackathon/lambda/LikeFunction.java | 58 ++++----- .../hackathon/lambda/MigrateFunction.java | 36 ++++++ 6 files changed, 125 insertions(+), 111 deletions(-) create mode 100644 src/main/java/com/goormy/hackathon/lambda/MigrateFunction.java diff --git a/build.gradle b/build.gradle index 2b28269..e979347 100644 --- a/build.gradle +++ b/build.gradle @@ -43,13 +43,13 @@ dependencies { implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' implementation 'com.amazonaws:aws-lambda-java-events:3.11.0' implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws:4.0.0' + implementation 'org.springframework.cloud:spring-cloud-starter-function-web:4.0.0' implementation 'com.fasterxml.jackson.core:jackson-databind' implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.1") implementation 'io.awspring.cloud:spring-cloud-aws-starter-sqs' implementation 'redis.clients:jedis:4.0.1' implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' implementation 'com.amazonaws:aws-lambda-java-events:3.11.0' - implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws:4.0.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' diff --git a/src/main/java/com/goormy/hackathon/handler/FollowHandler.java b/src/main/java/com/goormy/hackathon/handler/FollowHandler.java index 30b9cc7..f244b36 100644 --- a/src/main/java/com/goormy/hackathon/handler/FollowHandler.java +++ b/src/main/java/com/goormy/hackathon/handler/FollowHandler.java @@ -3,5 +3,9 @@ import org.springframework.cloud.function.adapter.aws.FunctionInvoker; public class FollowHandler extends FunctionInvoker { + private static final String FOLLOW_FUNCTION = "followFunction"; + public FollowHandler() { + super(FOLLOW_FUNCTION); + } } diff --git a/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java b/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java index b420cfe..13a551b 100644 --- a/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java +++ b/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java @@ -4,21 +4,15 @@ import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.events.ScheduledEvent; import com.goormy.hackathon.lambda.FollowFunction; +import org.springframework.cloud.function.adapter.aws.FunctionInvoker; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -public class ScheduledHandler implements RequestHandler { - - private static final ApplicationContext context = new AnnotationConfigApplicationContext(FollowFunction.class); - private final FollowFunction followFunction; +public class ScheduledHandler extends FunctionInvoker { + private static final String MIGRATE = "migrationFunction"; public ScheduledHandler() { - followFunction = context.getBean(FollowFunction.class); + super(MIGRATE); } - @Override - public String handleRequest(ScheduledEvent event, Context context) { - followFunction.migrateData(); - return "Data migration completed"; - } } diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index 392fa24..674d3fe 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -9,92 +9,72 @@ import com.goormy.hackathon.repository.JPA.UserRepository; import com.goormy.hackathon.repository.Redis.FollowListRedisRepository; import com.goormy.hackathon.service.FollowService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Bean; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; import java.util.function.Consumer; +@RequiredArgsConstructor @Configuration -public class FollowFunction{ +@Slf4j +public class FollowFunction implements Consumer { private final FollowRepository followRepository; private final UserRepository userRepository; private final HashtagRepository hashtagRepository; private final FollowListRedisRepository followListRedisRepository; - private final FollowService followServiceSieun; + private final FollowService followService; private final ObjectMapper objectMapper; - private static final Logger logger = LoggerFactory.getLogger(FollowFunction.class); - - public FollowFunction(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository, FollowListRedisRepository followListRedisRepository - , ObjectMapper objectMapper, FollowService followServiceSieun) { - this.followRepository = followRepository; - this.userRepository = userRepository; - this.hashtagRepository = hashtagRepository; - this.followListRedisRepository = followListRedisRepository; - this.objectMapper = objectMapper; - this.followServiceSieun = followServiceSieun; - } - - @Bean - public Consumer> processFollow() { - return messageBody -> { - try { - - List> records = (List>) messageBody.get("Records"); - String bodyString = (String) records.get(0).get("body"); - Map body = objectMapper.readValue(bodyString, Map.class); - - // userId와 hashtagId를 Number로 파싱하고 long으로 변환 - long userId = ((Number) body.get("userId")).longValue(); - long hashtagId = ((Number) body.get("hashtagId")).longValue(); - String action = (String) body.get("action"); - logger.info("userId: {}, hashtagId: {}, action: {}", userId, hashtagId, action); - - User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); - Hashtag hashtag = hashtagRepository.findById(hashtagId).orElseThrow(() -> new RuntimeException("존재하지 않는 해시태그입니다. hashtagId: " + hashtagId)); - - if ("follow".equals(action)) { - Follow follow = new Follow(user,hashtag); - // follow_list:{hashtagId} 저장 - followListRedisRepository.set(hashtagId, userId); - // follow_count:{hashtagId} 저장 - followServiceSieun.followHashtag(hashtagId); - System.out.println("팔로우 성공: " + messageBody); - } else if ("unfollow".equals(action)) { - // follow_list:{hashtagId} 삭제 - Follow follow = followRepository.findByUserIdAndHashTagId(userId, hashtagId) - .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); - followListRedisRepository.delete(hashtagId, userId); - // follow_count:{hashtagId} 삭제 - followServiceSieun.unfollowHashtag(hashtagId); - System.out.println("팔로우 취소 성공: " + messageBody); - } else { - System.out.println("존재하지 않는 action입니다 : " + action); - } - } catch (Exception e) { - System.err.println("메시지 전송 실패: " + messageBody); - e.printStackTrace(); + @Override + public void accept(Object messageBody) { + try { + Map messageMap= (Map) messageBody; + List> records = (List>) messageMap.get("Records"); + String bodyString = (String) records.get(0).get("body"); + Map body = objectMapper.readValue(bodyString, Map.class); + + // userId와 hashtagId를 Number로 파싱하고 long으로 변환 + long userId = ((Number) body.get("userId")).longValue(); + long hashtagId = ((Number) body.get("hashtagId")).longValue(); + String action = (String) body.get("action"); + log.info("userId: {}, hashtagId: {}, action: {}", userId, hashtagId, action); + + User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); + Hashtag hashtag = hashtagRepository.findById(hashtagId).orElseThrow(() -> new RuntimeException("존재하지 않는 해시태그입니다. hashtagId: " + hashtagId)); + + if ("follow".equals(action)) { + Follow follow = new Follow(user,hashtag); + // follow_list:{hashtagId} 저장 + followListRedisRepository.set(hashtagId, userId); + // follow_count:{hashtagId} 저장 + followService.followHashtag(hashtagId); + log.info("팔로우 성공: " + messageBody); + } else if ("unfollow".equals(action)) { + // follow_list:{hashtagId} 삭제 + Follow follow = followRepository.findByUserIdAndHashTagId(userId, hashtagId) + .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); + followListRedisRepository.delete(hashtagId, userId); + // follow_count:{hashtagId} 삭제 + followService.unfollowHashtag(hashtagId); + log.info("팔로우 취소 성공: " + messageBody); + } else { + log.warn("존재하지 않는 action입니다 : " + action); } - }; - } - - // Redis 데이터를 RDBMS에 저장하고 Redis 비우기 - public void migrateData() { - // Redis에서 모든 팔로우 데이터 가져오기 - List follows = followListRedisRepository.getAllFollows(); - - // RDBMS에 배치 저장 - followRepository.deleteAll(); - followRepository.saveAll(follows); - - // Redis 비우기 - System.out.println("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); + } catch (Exception e) { + log.error("메시지 전송 실패: " + messageBody, e); + } } - +// // Redis 데이터를 RDBMS에 저장하고 Redis 비우기 +// public void migrateData() { +// List follows = followListRedisRepository.getAllFollows(); +// followRepository.deleteAll(); +// followRepository.saveAll(follows); +// log.info("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); +// } } diff --git a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java index f00c4d3..4470911 100644 --- a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java @@ -20,7 +20,7 @@ @Configuration @Transactional(readOnly = true) @RequiredArgsConstructor -public class LikeFunction { +public class LikeFunction implements Consumer{ private final LikeRedisRepository likeRedisRepository; private final LikeRepository likeRepository; @@ -28,35 +28,35 @@ public class LikeFunction { private final PostRepository postRepository; private final ObjectMapper objectMapper; - @Bean - public Consumer> processLike() { - return messageBody -> { - try { - List> records = (List>) messageBody.get("Records"); - String bodyString = (String) records.get(0).get("body"); - Map body = objectMapper.readValue(bodyString, Map.class); - - long userId = ((Number) body.get("userId")).longValue(); - long postId = ((Number) body.get("postId")).longValue(); - String action = (String) body.get("action"); - - User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); - Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("존재하지 않는 포스트 입니다. postId: " + postId)); - - if ("like".equals(action)) { - addLike(postId,userId); - System.out.println("좋아요 성공: " + messageBody); - } else if ("unlike".equals(action)) { - cancelLike(postId,userId); - System.out.println("좋아요 취소 성공: " + messageBody); - } else { - System.out.println("존재하지 않는 action입니다 : " + action); - } - } catch (Exception e) { - System.err.println("메시지 전송 실패: " + messageBody); - e.printStackTrace(); + @Override + public void accept(Object messageBody) { + try { + Map messageMap = (Map) messageBody; + List> records = (List>) messageMap.get("Records"); + String bodyString = (String) records.get(0).get("body"); + Map body = objectMapper.readValue(bodyString, Map.class); + + long userId = ((Number) body.get("userId")).longValue(); + long postId = ((Number) body.get("postId")).longValue(); + String action = (String) body.get("action"); + + User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); + Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("존재하지 않는 포스트 입니다. postId: " + postId)); + + if ("like".equals(action)) { + addLike(postId,userId); + System.out.println("좋아요 성공: " + messageBody); + } else if ("unlike".equals(action)) { + cancelLike(postId,userId); + System.out.println("좋아요 취소 성공: " + messageBody); + } else { + System.out.println("존재하지 않는 action입니다 : " + action); } - }; + + } catch (Exception e) { + System.err.println("메시지 전송 실패: " + messageBody); + e.printStackTrace(); + } } /** diff --git a/src/main/java/com/goormy/hackathon/lambda/MigrateFunction.java b/src/main/java/com/goormy/hackathon/lambda/MigrateFunction.java new file mode 100644 index 0000000..f5fc288 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/lambda/MigrateFunction.java @@ -0,0 +1,36 @@ +package com.goormy.hackathon.lambda; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.repository.JPA.FollowRepository; +import com.goormy.hackathon.repository.JPA.HashtagRepository; +import com.goormy.hackathon.repository.JPA.UserRepository; +import com.goormy.hackathon.repository.Redis.FollowListRedisRepository; +import com.goormy.hackathon.service.FollowService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; + +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +@RequiredArgsConstructor +@Configuration +@Slf4j +public class MigrateFunction implements Consumer { + + private final FollowRepository followRepository; + private final FollowListRedisRepository followListRedisRepository; + + @Override + public void accept(Object o) { + List follows = followListRedisRepository.getAllFollows(); + followRepository.deleteAll(); + followRepository.saveAll(follows); + log.info("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); + } + +} From be5e2094652317840e83ac799b96df03bf1189b7 Mon Sep 17 00:00:00 2001 From: seonghooni Date: Fri, 2 Aug 2024 17:49:44 +0900 Subject: [PATCH 53/57] =?UTF-8?q?fix:=20lambda=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + .../hackathon/handler/FollowHandler.java | 4 + .../goormy/hackathon/handler/LikeHandler.java | 4 + .../hackathon/handler/ScheduledHandler.java | 21 +--- .../hackathon/lambda/FollowFunction.java | 94 +++++++++--------- .../goormy/hackathon/lambda/LikeFunction.java | 62 ++++++------ .../hackathon/lambda/ScheduledFunction.java | 99 +++++++++++++++++++ .../hackathon/service/FollowSQSService.java | 2 +- .../hackathon/service/LikeSQSService.java | 2 +- src/main/resources/application.yml | 3 +- 10 files changed, 196 insertions(+), 96 deletions(-) create mode 100644 src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java diff --git a/build.gradle b/build.gradle index 2b28269..9caae23 100644 --- a/build.gradle +++ b/build.gradle @@ -50,6 +50,7 @@ dependencies { implementation 'com.amazonaws:aws-lambda-java-core:1.2.1' implementation 'com.amazonaws:aws-lambda-java-events:3.11.0' implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws:4.0.0' + implementation 'org.springframework.cloud:spring-cloud-starter-function-web:4.0.0' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' diff --git a/src/main/java/com/goormy/hackathon/handler/FollowHandler.java b/src/main/java/com/goormy/hackathon/handler/FollowHandler.java index 30b9cc7..087bd8c 100644 --- a/src/main/java/com/goormy/hackathon/handler/FollowHandler.java +++ b/src/main/java/com/goormy/hackathon/handler/FollowHandler.java @@ -3,5 +3,9 @@ import org.springframework.cloud.function.adapter.aws.FunctionInvoker; public class FollowHandler extends FunctionInvoker { + private static String FollowHandler = "followFunction"; + public FollowHandler() { + super(FollowHandler); + } } diff --git a/src/main/java/com/goormy/hackathon/handler/LikeHandler.java b/src/main/java/com/goormy/hackathon/handler/LikeHandler.java index e0aafc2..08f5e82 100644 --- a/src/main/java/com/goormy/hackathon/handler/LikeHandler.java +++ b/src/main/java/com/goormy/hackathon/handler/LikeHandler.java @@ -3,5 +3,9 @@ import org.springframework.cloud.function.adapter.aws.FunctionInvoker; public class LikeHandler extends FunctionInvoker{ + private static String LikeHandler = "likeFunction"; + public LikeHandler() { + super(LikeHandler); + } } diff --git a/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java b/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java index b420cfe..c5f60bd 100644 --- a/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java +++ b/src/main/java/com/goormy/hackathon/handler/ScheduledHandler.java @@ -1,24 +1,11 @@ package com.goormy.hackathon.handler; -import com.amazonaws.services.lambda.runtime.Context; -import com.amazonaws.services.lambda.runtime.RequestHandler; -import com.amazonaws.services.lambda.runtime.events.ScheduledEvent; -import com.goormy.hackathon.lambda.FollowFunction; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.cloud.function.adapter.aws.FunctionInvoker; -public class ScheduledHandler implements RequestHandler { - - private static final ApplicationContext context = new AnnotationConfigApplicationContext(FollowFunction.class); - private final FollowFunction followFunction; +public class ScheduledHandler extends FunctionInvoker { + private static String ScheduledHandler = "scheduledFunction"; public ScheduledHandler() { - followFunction = context.getBean(FollowFunction.class); - } - - @Override - public String handleRequest(ScheduledEvent event, Context context) { - followFunction.migrateData(); - return "Data migration completed"; + super(ScheduledHandler); } } diff --git a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java index 392fa24..bb5cc23 100644 --- a/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/FollowFunction.java @@ -11,79 +11,80 @@ import com.goormy.hackathon.service.FollowService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.function.Consumer; @Configuration -public class FollowFunction{ +public class FollowFunction implements Consumer{ private final FollowRepository followRepository; private final UserRepository userRepository; private final HashtagRepository hashtagRepository; private final FollowListRedisRepository followListRedisRepository; - private final FollowService followServiceSieun; + private final FollowService followService; private final ObjectMapper objectMapper; private static final Logger logger = LoggerFactory.getLogger(FollowFunction.class); public FollowFunction(FollowRepository followRepository, UserRepository userRepository, HashtagRepository hashtagRepository, FollowListRedisRepository followListRedisRepository - , ObjectMapper objectMapper, FollowService followServiceSieun) { + , ObjectMapper objectMapper, FollowService followService) { this.followRepository = followRepository; this.userRepository = userRepository; this.hashtagRepository = hashtagRepository; this.followListRedisRepository = followListRedisRepository; this.objectMapper = objectMapper; - this.followServiceSieun = followServiceSieun; + this.followService = followService; } - @Bean - public Consumer> processFollow() { - return messageBody -> { - try { - - List> records = (List>) messageBody.get("Records"); - String bodyString = (String) records.get(0).get("body"); - Map body = objectMapper.readValue(bodyString, Map.class); - - // userId와 hashtagId를 Number로 파싱하고 long으로 변환 - long userId = ((Number) body.get("userId")).longValue(); - long hashtagId = ((Number) body.get("hashtagId")).longValue(); - String action = (String) body.get("action"); - logger.info("userId: {}, hashtagId: {}, action: {}", userId, hashtagId, action); - - User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); - Hashtag hashtag = hashtagRepository.findById(hashtagId).orElseThrow(() -> new RuntimeException("존재하지 않는 해시태그입니다. hashtagId: " + hashtagId)); - - if ("follow".equals(action)) { - Follow follow = new Follow(user,hashtag); - // follow_list:{hashtagId} 저장 - followListRedisRepository.set(hashtagId, userId); - // follow_count:{hashtagId} 저장 - followServiceSieun.followHashtag(hashtagId); - System.out.println("팔로우 성공: " + messageBody); - } else if ("unfollow".equals(action)) { - // follow_list:{hashtagId} 삭제 - Follow follow = followRepository.findByUserIdAndHashTagId(userId, hashtagId) - .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); - followListRedisRepository.delete(hashtagId, userId); - // follow_count:{hashtagId} 삭제 - followServiceSieun.unfollowHashtag(hashtagId); - System.out.println("팔로우 취소 성공: " + messageBody); - } else { - System.out.println("존재하지 않는 action입니다 : " + action); - } - } catch (Exception e) { - System.err.println("메시지 전송 실패: " + messageBody); - e.printStackTrace(); + @Override + public void accept(Object messageBody) { + try { + String messageString = new String((byte[]) messageBody, StandardCharsets.UTF_8); + + Map messageMap = objectMapper.readValue(messageString, Map.class); + List> records = (List>) messageMap.get("Records"); + String bodyString = (String) records.get(0).get("body"); + Map body = objectMapper.readValue(bodyString, Map.class); + + + // userId와 hashtagId를 Number로 파싱하고 long으로 변환 + long userId = ((Number) body.get("userId")).longValue(); + long hashtagId = ((Number) body.get("hashtagId")).longValue(); + String action = (String) body.get("action"); + logger.info("userId: {}, hashtagId: {}, action: {}", userId, hashtagId, action); + + User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); + Hashtag hashtag = hashtagRepository.findById(hashtagId).orElseThrow(() -> new RuntimeException("존재하지 않는 해시태그입니다. hashtagId: " + hashtagId)); + + if ("follow".equals(action)) { + Follow follow = new Follow(user,hashtag); + // follow_list:{hashtagId} 저장 + followListRedisRepository.set(hashtagId, userId); + // follow_count:{hashtagId} 저장 + followService.followHashtag(hashtagId); + System.out.println("팔로우 성공: " + messageBody); + } else if ("unfollow".equals(action)) { + // follow_list:{hashtagId} 삭제 + Follow follow = followRepository.findByUserIdAndHashTagId(userId, hashtagId) + .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); + followListRedisRepository.delete(hashtagId, userId); + // follow_count:{hashtagId} 삭제 + followService.unfollowHashtag(hashtagId); + System.out.println("팔로우 취소 성공: " + messageBody); + } else { + System.out.println("존재하지 않는 action입니다 : " + action); } - }; + } catch (Exception e) { + System.err.println("메시지 전송 실패: " + messageBody); + e.printStackTrace(); + } } - // Redis 데이터를 RDBMS에 저장하고 Redis 비우기 + public void migrateData() { // Redis에서 모든 팔로우 데이터 가져오기 List follows = followListRedisRepository.getAllFollows(); @@ -96,5 +97,4 @@ public void migrateData() { System.out.println("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); } - } diff --git a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java index f00c4d3..01f9021 100644 --- a/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/LikeFunction.java @@ -8,6 +8,8 @@ import com.goormy.hackathon.repository.JPA.LikeRepository; import com.goormy.hackathon.repository.JPA.PostRepository; import com.goormy.hackathon.repository.JPA.UserRepository; + +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.Set; @@ -20,7 +22,7 @@ @Configuration @Transactional(readOnly = true) @RequiredArgsConstructor -public class LikeFunction { +public class LikeFunction implements Consumer{ private final LikeRedisRepository likeRedisRepository; private final LikeRepository likeRepository; @@ -28,35 +30,37 @@ public class LikeFunction { private final PostRepository postRepository; private final ObjectMapper objectMapper; - @Bean - public Consumer> processLike() { - return messageBody -> { - try { - List> records = (List>) messageBody.get("Records"); - String bodyString = (String) records.get(0).get("body"); - Map body = objectMapper.readValue(bodyString, Map.class); - - long userId = ((Number) body.get("userId")).longValue(); - long postId = ((Number) body.get("postId")).longValue(); - String action = (String) body.get("action"); - - User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); - Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("존재하지 않는 포스트 입니다. postId: " + postId)); - - if ("like".equals(action)) { - addLike(postId,userId); - System.out.println("좋아요 성공: " + messageBody); - } else if ("unlike".equals(action)) { - cancelLike(postId,userId); - System.out.println("좋아요 취소 성공: " + messageBody); - } else { - System.out.println("존재하지 않는 action입니다 : " + action); - } - } catch (Exception e) { - System.err.println("메시지 전송 실패: " + messageBody); - e.printStackTrace(); + @Override + public void accept(Object messageBody) { + try { + String messageString = new String((byte[]) messageBody, StandardCharsets.UTF_8); + + Map messageMap = objectMapper.readValue(messageString, Map.class); + List> records = (List>) messageMap.get("Records"); + String bodyString = (String) records.get(0).get("body"); + Map body = objectMapper.readValue(bodyString, Map.class); + + long userId = ((Number) body.get("userId")).longValue(); + long postId = ((Number) body.get("postId")).longValue(); + String action = (String) body.get("action"); + + User user = userRepository.findById(userId).orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다. userId: " + userId)); + Post post = postRepository.findById(postId).orElseThrow(() -> new RuntimeException("존재하지 않는 포스트 입니다. postId: " + postId)); + + if ("like".equals(action)) { + addLike(postId,userId); + System.out.println("좋아요 성공: " + messageBody); + } else if ("unlike".equals(action)) { + cancelLike(postId,userId); + System.out.println("좋아요 취소 성공: " + messageBody); + } else { + System.out.println("존재하지 않는 action입니다 : " + action); } - }; + + } catch (Exception e) { + System.err.println("메시지 전송 실패: " + messageBody); + e.printStackTrace(); + } } /** diff --git a/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java b/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java new file mode 100644 index 0000000..3506041 --- /dev/null +++ b/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java @@ -0,0 +1,99 @@ +package com.goormy.hackathon.lambda; + +import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.entity.Like; +import com.goormy.hackathon.entity.Post; +import com.goormy.hackathon.entity.User; +import com.goormy.hackathon.repository.JPA.FollowRepository; +import com.goormy.hackathon.repository.JPA.LikeRepository; +import com.goormy.hackathon.repository.JPA.PostRepository; +import com.goormy.hackathon.repository.JPA.UserRepository; +import com.goormy.hackathon.repository.Redis.FollowListRedisRepository; +import com.goormy.hackathon.repository.Redis.LikeRedisRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; + +@Component +@RequiredArgsConstructor +@Slf4j +public class ScheduledFunction implements Consumer{ + + private final LikeRedisRepository likeRedisRepository; + private final LikeRepository likeRepository; + private final UserRepository userRepository; + private final FollowListRedisRepository followRedisRepository; + private final FollowRepository followRepository; + private final PostRepository postRepository; + + @Override + public void accept(Object o) { + dumpToDB(); + migrateData(); + } + + /** + * @description Redis에 있는 '좋아요' 정보들을 RDB에 반영하는 함수 + * */ + @Transactional + public void dumpToDB() { + // 1. "postlike:{postId} 형식의 모든 key 목록을 불러옴 + Set postLikeKeySet = likeRedisRepository.findAllKeys(); + + // 2. Key마다 postId, userId, value를 조회하는 과정 + for (String key: postLikeKeySet) { + + // 2-1. Key로 Hash 자료구조를 조회함. field = userId / value = 1 or -1 + Map result = likeRedisRepository.findPostLikeByKey(key); + + // 2-2. key를 파싱하여 postId를 구함 + String[] split = key.split(":"); + Long postId = Long.valueOf(split[1]); + + for (Map.Entry entry : result.entrySet()) { + // 2-3. field를 형변환하여 userId를 구함 + Long userId = Long.valueOf(String.valueOf(entry.getKey())); + // 2-4. value를 형변환하여 1 또는 -1 값을 얻게 됨 + Integer value = Integer.valueOf(String.valueOf(entry.getValue())); + + // 3. value 값에 따라 DB에 어떻게 반영할지 결정하여 처리함 + if (value == 1) { // 3-1. 좋아요를 추가한 상태였다면 RDB에 insert 쿼리 발생 + User user = userRepository.getReferenceById(userId); + Post post = postRepository.getReferenceById(postId); + likeRepository.save(new Like(user, post)); + }else if (value == -1) { // 3-2. 좋아요를 취소한 상태였다면 RDB에 delete 쿼리 발생 + likeRepository.deleteByPostIdAndUserId(postId, userId); + } + } + + // 4. 해당 Key에 대해 RDB에 반영하는 과정을 마쳤으므로, + likeRedisRepository.delete(key); + } + } + + /** + * @description Redis에 있는 '팔로우' 정보들을 RDB에 반영하는 함수 + * */ + // Redis 데이터를 RDBMS에 저장하고 Redis 비우기 + public void migrateData() { + // Redis에서 모든 팔로우 데이터 가져오기 + List follows = followRedisRepository.getAllFollows(); + + // RDBMS에 배치 저장 + followRepository.deleteAll(); + followRepository.saveAll(follows); + + // Redis 비우기 + log.info("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); + } +} diff --git a/src/main/java/com/goormy/hackathon/service/FollowSQSService.java b/src/main/java/com/goormy/hackathon/service/FollowSQSService.java index d63e4b4..a85389e 100644 --- a/src/main/java/com/goormy/hackathon/service/FollowSQSService.java +++ b/src/main/java/com/goormy/hackathon/service/FollowSQSService.java @@ -20,7 +20,7 @@ public class FollowSQSService { @Autowired private SqsClient sqsClient; - @Value("${spring.cloud.aws.sqs.queue-url}") + @Value("${spring.cloud.aws.sqs.queue-url-follow}") private String queueUrl; public void sendFollowRequest(long userId, long hashtagId) { diff --git a/src/main/java/com/goormy/hackathon/service/LikeSQSService.java b/src/main/java/com/goormy/hackathon/service/LikeSQSService.java index 22006a0..d35080e 100644 --- a/src/main/java/com/goormy/hackathon/service/LikeSQSService.java +++ b/src/main/java/com/goormy/hackathon/service/LikeSQSService.java @@ -20,7 +20,7 @@ public class LikeSQSService { @Autowired private SqsClient sqsClient; - @Value("${spring.cloud.aws.sqs.queue-url}") + @Value("${spring.cloud.aws.sqs.queue-url-like}") private String queueUrl; public void sendLikeRequest(Long userId, Long postId) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e40b72f..8389b97 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -28,7 +28,8 @@ spring: access-key: ${{ secrets.AWS_ACCESS_KEY_ID }} secret-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} sqs: - queue-url: https://sqs.ap-northeast-2.amazonaws.com/008971650206/GoormySQSForLike + queue-url-like: https://sqs.ap-northeast-2.amazonaws.com/008971650206/GoormySQSForLike + queue-url-follow: https://sqs.ap-northeast-2.amazonaws.com/008971650206/GoormySQS logging: level: org: From d0b7d034462370675616796b664ec11d837fb498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Tue, 6 Aug 2024 17:01:01 +0900 Subject: [PATCH 54/57] =?UTF-8?q?fix:=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hackathon/lambda/MigrateFunction.java | 36 -------------- .../hackathon/lambda/ScheduledFunction.java | 20 +++----- .../Redis/FollowListRedisRepository.java | 47 ++++++++++++------- 3 files changed, 38 insertions(+), 65 deletions(-) delete mode 100644 src/main/java/com/goormy/hackathon/lambda/MigrateFunction.java diff --git a/src/main/java/com/goormy/hackathon/lambda/MigrateFunction.java b/src/main/java/com/goormy/hackathon/lambda/MigrateFunction.java deleted file mode 100644 index f5fc288..0000000 --- a/src/main/java/com/goormy/hackathon/lambda/MigrateFunction.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.goormy.hackathon.lambda; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.goormy.hackathon.entity.Follow; -import com.goormy.hackathon.entity.Hashtag; -import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.JPA.FollowRepository; -import com.goormy.hackathon.repository.JPA.HashtagRepository; -import com.goormy.hackathon.repository.JPA.UserRepository; -import com.goormy.hackathon.repository.Redis.FollowListRedisRepository; -import com.goormy.hackathon.service.FollowService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.context.annotation.Configuration; - -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; - -@RequiredArgsConstructor -@Configuration -@Slf4j -public class MigrateFunction implements Consumer { - - private final FollowRepository followRepository; - private final FollowListRedisRepository followListRedisRepository; - - @Override - public void accept(Object o) { - List follows = followListRedisRepository.getAllFollows(); - followRepository.deleteAll(); - followRepository.saveAll(follows); - log.info("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); - } - -} diff --git a/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java b/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java index 3506041..68b0c2e 100644 --- a/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java @@ -32,14 +32,14 @@ public class ScheduledFunction implements Consumer{ private final LikeRedisRepository likeRedisRepository; private final LikeRepository likeRepository; private final UserRepository userRepository; - private final FollowListRedisRepository followRedisRepository; + private final FollowListRedisRepository followListRedisRepository; private final FollowRepository followRepository; private final PostRepository postRepository; @Override public void accept(Object o) { dumpToDB(); - migrateData(); + migrateDB(); } /** @@ -81,19 +81,13 @@ public void dumpToDB() { } } - /** - * @description Redis에 있는 '팔로우' 정보들을 RDB에 반영하는 함수 - * */ - // Redis 데이터를 RDBMS에 저장하고 Redis 비우기 - public void migrateData() { - // Redis에서 모든 팔로우 데이터 가져오기 - List follows = followRedisRepository.getAllFollows(); - - // RDBMS에 배치 저장 + @Transactional + public void migrateDB() { + List follows = followListRedisRepository.getAllFollows(); followRepository.deleteAll(); followRepository.saveAll(follows); - - // Redis 비우기 log.info("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); } + + } diff --git a/src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java index ad08a25..2e1478f 100644 --- a/src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java @@ -1,27 +1,43 @@ package com.goormy.hackathon.repository.Redis; import com.goormy.hackathon.entity.Follow; +import com.goormy.hackathon.entity.Hashtag; +import com.goormy.hackathon.entity.User; import com.goormy.hackathon.repository.JPA.FollowRepository; +import com.goormy.hackathon.repository.JPA.HashtagRepository; +import com.goormy.hackathon.repository.JPA.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.ListOperations; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Repository; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; @Repository +@Slf4j +@RequiredArgsConstructor public class FollowListRedisRepository { - @Autowired - RedisTemplate redisTemplate; + private final RedisTemplate redisTemplate; - @Autowired - FollowRepository followRepository; + private ListOperations listOperations; + + private final FollowRepository followRepository; + + private final HashtagRepository hashtagRepository; + + private final UserRepository userRepository; public void set(Long hashtagId, Long userId) { - String key = "hashtagId: " + hashtagId.toString(); - redisTemplate.opsForList().rightPush(key, userId); + String key = "hashtagId:" + hashtagId.toString(); + String userid = userId.toString(); + redisTemplate.opsForList().rightPush(key, userid); } public void delete(Long hashtagId, Long userId) { @@ -30,26 +46,25 @@ public void delete(Long hashtagId, Long userId) { } public List getAllFollows() { - // Redis에서 데이터를 가져와 RDBMS로 마이그레이션 - List follows = new ArrayList<>(); - - // 모든 키 가져오기 Set keys = redisTemplate.keys("hashtagId:*"); - + List follows = new ArrayList<>(); if (keys != null) { for (String key : keys) { - List userIds = (List) (List) redisTemplate.opsForList().range(key, 0, -1); + + List userIds = redisTemplate.opsForList().range(key, 0, -1); if (userIds != null) { - for (Long userId : userIds) { + for (Object userId : userIds) { Long hashtagId = Long.parseLong(key.split(":")[1]); - Follow follow = followRepository.findByUserIdAndHashTagId(userId,hashtagId) - .orElseThrow(() -> new RuntimeException("존재하지 않는 팔로우입니다. userId: " + userId + " hashtagId: " + hashtagId)); + User user = userRepository.findById((Long)userId) + .orElseThrow(() -> new IllegalArgumentException("해당 사용자를 찾을 수 없습니다.")); + Hashtag hashtag = hashtagRepository.findById(hashtagId) + .orElseThrow(() -> new IllegalArgumentException("해당 해시태그 찾을 수 없습니다. ")); + Follow follow = new Follow(user, hashtag); follows.add(follow); } } } } - return follows; } From f33ca236df81b53b9dbd6cb097130ec6d8f98bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:10:52 +0900 Subject: [PATCH 55/57] =?UTF-8?q?fix:=20redis=20config=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RedisCommandExecutionException 오류 해결 --- .../com/goormy/hackathon/redis/config/RedisConfig.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java index 8d7479b..d2f8ed4 100644 --- a/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java +++ b/src/main/java/com/goormy/hackathon/redis/config/RedisConfig.java @@ -7,6 +7,7 @@ import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; @@ -30,7 +31,9 @@ public class RedisConfig { @Bean public RedisConnectionFactory redisConnectionFactory() { - return new LettuceConnectionFactory(host, port); + RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration() + .clusterNode(host, port); + return new LettuceConnectionFactory(clusterConfig); } @Bean @@ -115,4 +118,6 @@ public RedisTemplate integerRedisTemplate() { return redisTemplate; } + + } From e849dfda2871f5eec30be9644e39b74f6cc08fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:11:51 +0900 Subject: [PATCH 56/57] =?UTF-8?q?refactor=20:=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=EB=A1=9C=EA=B9=85=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../goormy/hackathon/lambda/ScheduledFunction.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java b/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java index 68b0c2e..efd4ff1 100644 --- a/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java @@ -83,9 +83,15 @@ public void dumpToDB() { @Transactional public void migrateDB() { - List follows = followListRedisRepository.getAllFollows(); - followRepository.deleteAll(); - followRepository.saveAll(follows); + log.info("데이터 이전을 시작합니다."); + try { + List follows = followListRedisRepository.getAllFollows(); + followRepository.deleteAll(); + followRepository.saveAll(follows); + } + catch (Exception e) { + log.error("데이터 이전에 실패했습니다.",e); + } log.info("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); } From e4fa85bff6f38cef491aba165614ce5bd35921a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=80=EC=97=B0?= <99721126+dlrkdus@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:47:52 +0900 Subject: [PATCH 57/57] =?UTF-8?q?fix:=20Redis=20=EC=BA=90=EC=8A=A4?= =?UTF-8?q?=ED=8C=85=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hackathon/lambda/ScheduledFunction.java | 4 ++-- .../Redis/FollowListRedisRepository.java | 16 ++++------------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java b/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java index efd4ff1..6ee9d96 100644 --- a/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java +++ b/src/main/java/com/goormy/hackathon/lambda/ScheduledFunction.java @@ -81,18 +81,18 @@ public void dumpToDB() { } } - @Transactional + @Transactional(rollbackFor = Exception.class) public void migrateDB() { log.info("데이터 이전을 시작합니다."); try { List follows = followListRedisRepository.getAllFollows(); followRepository.deleteAll(); followRepository.saveAll(follows); + log.info("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); } catch (Exception e) { log.error("데이터 이전에 실패했습니다.",e); } - log.info("Redis 데이터를 RDBMS로 옮기고 Redis를 초기화했습니다."); } diff --git a/src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java b/src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java index 2e1478f..81a448f 100644 --- a/src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java +++ b/src/main/java/com/goormy/hackathon/repository/Redis/FollowListRedisRepository.java @@ -3,21 +3,16 @@ import com.goormy.hackathon.entity.Follow; import com.goormy.hackathon.entity.Hashtag; import com.goormy.hackathon.entity.User; -import com.goormy.hackathon.repository.JPA.FollowRepository; import com.goormy.hackathon.repository.JPA.HashtagRepository; import com.goormy.hackathon.repository.JPA.UserRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.ListOperations; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Repository; import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; @Repository @Slf4j @@ -26,18 +21,13 @@ public class FollowListRedisRepository { private final RedisTemplate redisTemplate; - private ListOperations listOperations; - - private final FollowRepository followRepository; - private final HashtagRepository hashtagRepository; private final UserRepository userRepository; public void set(Long hashtagId, Long userId) { String key = "hashtagId:" + hashtagId.toString(); - String userid = userId.toString(); - redisTemplate.opsForList().rightPush(key, userid); + redisTemplate.opsForList().rightPush(key, userId); } public void delete(Long hashtagId, Long userId) { @@ -55,7 +45,9 @@ public List getAllFollows() { if (userIds != null) { for (Object userId : userIds) { Long hashtagId = Long.parseLong(key.split(":")[1]); - User user = userRepository.findById((Long)userId) + Long userIdLong = Long.parseLong(String.valueOf(userId)); + + User user = userRepository.findById(userIdLong) .orElseThrow(() -> new IllegalArgumentException("해당 사용자를 찾을 수 없습니다.")); Hashtag hashtag = hashtagRepository.findById(hashtagId) .orElseThrow(() -> new IllegalArgumentException("해당 해시태그 찾을 수 없습니다. "));