Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]: SQS를 활용한 자체적인 유저 정보 저장 #15

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bootstrap/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ spring:
import:
- application-persistence.yml
- application-internal.yml
- application-message.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package gloddy.user.port.`in`.dto

import gloddy.user.User

data class UserSaveRequest(
val id: Long,
val isCertifiedStudent: Boolean,
val profileImage: String,
val nickName: String,
val countryName: String?,
val countryImage: String?,
val reliabilityLevel: String
)

fun UserSaveRequest.toDomain(): User =
User(
id = this.id,
isCertifiedStudent = this.isCertifiedStudent,
profileImage = this.profileImage,
nickname = this.nickName,
countryName = this.countryName,
countryImage = this.countryImage,
reliabilityLevel = this.reliabilityLevel
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gloddy.user.port.out

import gloddy.user.User

interface UserCommandPort {
fun save(user: User): User
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package gloddy.user.service

import gloddy.user.port.`in`.dto.UserSaveRequest
import gloddy.user.port.`in`.dto.toDomain
import gloddy.user.port.out.UserCommandPort
import org.springframework.stereotype.Service

@Service
class UserCommandService(
private val userCommandPort: UserCommandPort
) {

fun save(request: UserSaveRequest) {
userCommandPort.save(request.toDomain())
}
}
5 changes: 4 additions & 1 deletion community-domain/src/main/kotlin/gloddy/core/ErrorCode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ enum class ErrorCode(
ARTICLE_NO_AUTHORIZATION(401, "ARTICLE_003", "해당 게시글에 권한이 없습니다."),

// Category
CATEGORY_NOT_FOUND(404, "CATEGORY_001", "해당 카테고리를 찾을 수 없습니다.")
CATEGORY_NOT_FOUND(404, "CATEGORY_001", "해당 카테고리를 찾을 수 없습니다."),

// User
USER_NOT_FOUND(404, "COMMUNITY_USER_001", "해당 유저를 찾을 수 없습니다.")
}
11 changes: 11 additions & 0 deletions community-domain/src/main/kotlin/gloddy/user/User.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package gloddy.user

data class User(
val id: Long,
val isCertifiedStudent: Boolean,
val profileImage: String,
val nickname: String,
val countryName: String?,
val countryImage: String?,
val reliabilityLevel: String
)
10 changes: 10 additions & 0 deletions community-domain/src/main/kotlin/gloddy/user/UserException.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package gloddy.user

import gloddy.core.ErrorCode
import gloddy.core.GloddyCommunityException

class UserNotFoundException : GloddyCommunityException(
statusCode = ErrorCode.USER_NOT_FOUND.statusCode,
errorCode = ErrorCode.USER_NOT_FOUND.errorCode,
message = ErrorCode.USER_NOT_FOUND.message
)
7 changes: 7 additions & 0 deletions community-infrastructure/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ dependencies {
implementation(project(":community-application"))
implementation(project(":community-domain"))

//jpa, db
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("com.querydsl:querydsl-jpa:5.0.0:jakarta")
kapt("com.querydsl:querydsl-apt:5.0.0:jakarta")
Expand All @@ -26,7 +27,13 @@ dependencies {
kapt("org.springframework.boot:spring-boot-configuration-processor")
runtimeOnly("com.h2database:h2")
runtimeOnly("com.mysql:mysql-connector-j")
//openfeing
implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
//sqs
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.5")
implementation(platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.3"))
implementation("io.awspring.cloud:spring-cloud-aws-starter-sqs")
//test
testImplementation(testFixtures(project(":community-domain")))
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package gloddy.inMessage.payload

import java.time.LocalDateTime

data class UserMessagePayload(
val userId: Long,
val eventType: UserMessagePayloadType,
val eventDateTime: LocalDateTime
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gloddy.inMessage.payload

enum class UserMessagePayloadType {
JOIN,
UPDATE_PROFILE,
UPGRADE_RELIABILITY
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package gloddy.inMessage.payload.handler

import gloddy.inMessage.payload.UserMessagePayload
import gloddy.internal.client.UserQueryClient
import gloddy.user.port.`in`.dto.UserSaveRequest
import gloddy.user.service.UserCommandService
import org.springframework.stereotype.Component

@Component
class UserMessagePayloadHandler(
private val userQueryClient: UserQueryClient,
private val userCommandService: UserCommandService
) {

fun handle(payload: UserMessagePayload) {
val userPreviewPayload = userQueryClient.getUserPreview(payload.userId)
userCommandService.save(
UserSaveRequest(
id = userPreviewPayload.id,
isCertifiedStudent = userPreviewPayload.isCertifiedStudent,
profileImage = userPreviewPayload.profileImage,
nickName = userPreviewPayload.nickName,
countryName = userPreviewPayload.countryName,
countryImage = userPreviewPayload.countryImage,
reliabilityLevel = userPreviewPayload.reliabilityLevel
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package gloddy.inMessage.sqs

import gloddy.inMessage.payload.handler.UserMessagePayloadHandler
import gloddy.inMessage.sqs.util.MessageParser
import gloddy.user.service.UserCommandService
import io.awspring.cloud.sqs.annotation.SqsListener
import org.springframework.stereotype.Component

@Component
class SqsSubscriber(
private val userMessagePayloadHandler: UserMessagePayloadHandler
) {

@SqsListener(value = ["\${sqs.queue.user}"])
fun handleApplyEvent(message: String) {
val payload = MessageParser.parseUserMessage(message)
userMessagePayloadHandler.handle(payload)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package gloddy.inMessage.sqs.util

import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import gloddy.inMessage.payload.UserMessagePayload

class MessageParser {

companion object{
private val objectMapper = jacksonObjectMapper().registerModule(JavaTimeModule())

fun parseUserMessage(message: String): UserMessagePayload {
val payload = parsePayloadFromMessage(message)
return objectMapper.readValue(payload, UserMessagePayload::class.java)
}

private fun parsePayloadFromMessage(message: String): String {
val outerMessage: Map<String, Any> = objectMapper.readValue(message, Map::class.java) as Map<String, Any>
return outerMessage["Message"] as String
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package gloddy.persistence.user

import jakarta.persistence.*

@Entity
@Table(name = "users")
class UserJpaEntity(
@Id
val id: Long,
@Column(nullable = false)
val isCertifiedStudent: Boolean,
@Column(nullable = false)
val profileImage: String,
@Column(nullable = false)
val nickname: String,
val countryName: String?,
val countryImage: String?,
@Column(nullable = false)
val reliabilityLevel: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package gloddy.persistence.user.adapter

import gloddy.persistence.user.repository.UserJpaRepository
import gloddy.persistence.util.mapper.toDomain
import gloddy.persistence.util.mapper.toEntity
import gloddy.user.User
import gloddy.user.port.out.UserCommandPort
import org.springframework.stereotype.Component

@Component
class UserCommandAdapter(
private val userJpaRepository: UserJpaRepository,
) : UserCommandPort {

override fun save(user: User): User {
return userJpaRepository.save(user.toEntity()).toDomain()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gloddy.persistence.user.repository

import gloddy.persistence.user.UserJpaEntity
import org.springframework.data.jpa.repository.JpaRepository

interface UserJpaRepository : JpaRepository<UserJpaEntity, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package gloddy.persistence.util.mapper

import gloddy.persistence.user.UserJpaEntity
import gloddy.user.User

fun User.toEntity(): UserJpaEntity =
UserJpaEntity(
id = this.id,
isCertifiedStudent = this.isCertifiedStudent,
profileImage = this.profileImage,
nickname = this.nickname,
countryName = this.countryName,
countryImage = this.countryImage,
reliabilityLevel = this.reliabilityLevel
)

fun UserJpaEntity.toDomain(): User =
User(
id = this.id,
isCertifiedStudent = this.isCertifiedStudent,
profileImage = this.profileImage,
nickname = this.nickname,
countryName = this.countryName,
countryImage = this.countryImage,
reliabilityLevel = this.reliabilityLevel
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
spring:
cloud:
aws:
region:
static: ap-northeast-2
credentials:
access-key: ${AWS_ACCESS_KEY}
secret-key: ${AWS_SECRET_KEY}
sqs:
listener:
poll-timeout: 20000

sqs:
queue:
user: ${USER_SQS_QUEUE_NAME}
Loading