feat: 푸시 토큰 - 한 사람이 여러개의 디바이스로 로그인 해도 모든 푸시 토큰이 기록되어 있어서 모든 디바이스에 푸시가 가도록 수정
This commit is contained in:
@@ -14,7 +14,7 @@ import org.springframework.scheduling.annotation.Async
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class FcmService {
|
||||
class FcmService(private val pushTokenService: PushTokenService) {
|
||||
private val logger = LoggerFactory.getLogger(this::class.java)
|
||||
|
||||
@Async
|
||||
@@ -100,7 +100,8 @@ class FcmService {
|
||||
|
||||
if (exception?.messagingErrorCode == MessagingErrorCode.UNREGISTERED) {
|
||||
logger.error("[FCM] ❌ UNREGISTERED → $token")
|
||||
// 필요 시 DB에서 삭제
|
||||
// DB에서 삭제
|
||||
pushTokenService.unregisterInvalidToken(token)
|
||||
} else {
|
||||
logger.error("[FCM] ❌ 실패: $token / ${exception?.messagingErrorCode}")
|
||||
failedTokens.add(token)
|
||||
@@ -148,6 +149,8 @@ class FcmService {
|
||||
// "registration-token-not-registered" 예외 코드 확인
|
||||
if (e.messagingErrorCode == MessagingErrorCode.UNREGISTERED) {
|
||||
logger.error("[FCM] ❌ 실패: 토큰이 등록되지 않음 (등록 해제됨) → 재시도 안함")
|
||||
// DB에서 삭제
|
||||
pushTokenService.unregisterInvalidToken(token)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
18
src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt
Normal file
18
src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt
Normal file
@@ -0,0 +1,18 @@
|
||||
package kr.co.vividnext.sodalive.fcm
|
||||
|
||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||
import kr.co.vividnext.sodalive.member.Member
|
||||
import javax.persistence.Entity
|
||||
import javax.persistence.FetchType
|
||||
import javax.persistence.JoinColumn
|
||||
import javax.persistence.ManyToOne
|
||||
|
||||
@Entity
|
||||
data class PushToken(
|
||||
var token: String,
|
||||
var deviceType: String
|
||||
) : BaseEntity() {
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "member_id", nullable = true)
|
||||
var member: Member? = null
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package kr.co.vividnext.sodalive.fcm
|
||||
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||
import kr.co.vividnext.sodalive.fcm.QPushToken.pushToken
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
interface PushTokenRepository : JpaRepository<PushToken, Long>, PushTokenQueryRepository
|
||||
|
||||
interface PushTokenQueryRepository {
|
||||
fun findByToken(token: String): PushToken?
|
||||
fun findByMemberId(memberId: Long): List<PushToken>
|
||||
}
|
||||
|
||||
class PushTokenQueryRepositoryImpl(
|
||||
private val queryFactory: JPAQueryFactory
|
||||
) : PushTokenQueryRepository {
|
||||
override fun findByToken(token: String): PushToken? {
|
||||
return queryFactory
|
||||
.selectFrom(pushToken)
|
||||
.where(pushToken.token.eq(token))
|
||||
.fetchFirst()
|
||||
}
|
||||
|
||||
override fun findByMemberId(memberId: Long): List<PushToken> {
|
||||
return queryFactory
|
||||
.selectFrom(pushToken)
|
||||
.where(pushToken.member.id.eq(memberId))
|
||||
.fetch()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package kr.co.vividnext.sodalive.fcm
|
||||
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
@Service
|
||||
class PushTokenService(
|
||||
private val repository: PushTokenRepository,
|
||||
private val memberRepository: MemberRepository
|
||||
) {
|
||||
@Transactional
|
||||
fun registerToken(memberId: Long, token: String, deviceType: String) {
|
||||
val member = memberRepository.findByIdOrNull(memberId)
|
||||
|
||||
if (member != null) {
|
||||
val existing = repository.findByToken(token)
|
||||
if (existing != null) {
|
||||
existing.member = member
|
||||
existing.token = token
|
||||
existing.deviceType = deviceType
|
||||
} else {
|
||||
val newToken = PushToken(token, deviceType)
|
||||
newToken.member = member
|
||||
repository.save(newToken)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun logout(memberId: Long) {
|
||||
val tokens = repository.findByMemberId(memberId)
|
||||
|
||||
for (token in tokens) {
|
||||
token.member = null
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun unregisterInvalidToken(token: String) {
|
||||
val existing = repository.findByToken(token)
|
||||
if (existing != null) {
|
||||
repository.delete(existing)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user