-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Feat/#61 : 채팅 푸시알림 기능 초기 개발
- Loading branch information
Showing
18 changed files
with
560 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
src/main/java/com/petmatz/domain/user/service/UserNicknameService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.petmatz.domain.user.service; | ||
|
||
import com.petmatz.common.security.utils.JwtExtractProvider; | ||
import com.petmatz.domain.user.repository.UserRepository; | ||
import com.petmatz.domain.user.entity.User; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class UserNicknameService { | ||
private final UserRepository userRepository; | ||
private final JwtExtractProvider jwtExtractProvider; | ||
|
||
public String getNicknameByEmail() { | ||
String accountId = jwtExtractProvider.findAccountIdFromJwt(); | ||
User user = userRepository.findByAccountId(accountId); | ||
if (user == null) { | ||
return "Unknown User"; // 예외 처리 | ||
} | ||
return user.getNickname(); // 닉네임 반환 | ||
} | ||
} |
38 changes: 38 additions & 0 deletions
38
src/main/java/com/petmatz/domain/user/service/UserStatusService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package com.petmatz.domain.user.service; | ||
|
||
import com.petmatz.infra.redis.service.RedisPublisher; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.redis.core.StringRedisTemplate; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class UserStatusService { | ||
|
||
private final StringRedisTemplate redisTemplate; | ||
private final RedisPublisher redisPublisher; | ||
private static final String STATUS_PREFIX = "userStatus:"; | ||
private static final String ONLINE_TOPIC = "user-online"; | ||
|
||
// 사용자 상태 업데이트 및 Pub/Sub 발행 | ||
public void updateUserStatus(String userId, boolean isOnline) { | ||
String key = STATUS_PREFIX + userId; | ||
if (isOnline) { | ||
redisTemplate.opsForValue().set(key, "online", 30, TimeUnit.MINUTES); // TTL 설정 | ||
redisPublisher.publish(ONLINE_TOPIC, userId); // Pub/Sub 발행 | ||
} else { | ||
redisTemplate.delete(key); | ||
} | ||
} | ||
|
||
// 사용자 온라인 상태 확인 | ||
public boolean isUserOnline(String userId) { | ||
String key = STATUS_PREFIX + userId; | ||
String status = redisTemplate.opsForValue().get(key); | ||
return "online".equals(status); | ||
} | ||
} | ||
|
||
|
28 changes: 28 additions & 0 deletions
28
src/main/java/com/petmatz/infra/firebase/config/FirebaseConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.petmatz.infra.firebase.config; | ||
import com.google.auth.oauth2.GoogleCredentials; | ||
import com.google.firebase.FirebaseApp; | ||
import com.google.firebase.FirebaseOptions; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.core.io.ClassPathResource; | ||
|
||
import javax.annotation.PostConstruct; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
@Configuration | ||
public class FirebaseConfig { | ||
|
||
@PostConstruct | ||
public void initializeFirebase() throws IOException { | ||
InputStream serviceAccount = | ||
new ClassPathResource("config/petmatz-f5d00-firebase-adminsdk-4vsnm-68589101cb.json").getInputStream(); | ||
|
||
FirebaseOptions options = FirebaseOptions.builder() | ||
.setCredentials(GoogleCredentials.fromStream(serviceAccount)) | ||
.build(); | ||
|
||
FirebaseApp.initializeApp(options); | ||
System.out.println("Firebase Admin SDK 초기화 완료"); | ||
} | ||
} | ||
|
35 changes: 35 additions & 0 deletions
35
src/main/java/com/petmatz/infra/firebase/controller/FcmController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.petmatz.infra.firebase.controller; | ||
|
||
import com.petmatz.common.security.utils.JwtExtractProvider; | ||
import com.petmatz.infra.firebase.service.FcmTokenService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import java.util.Map; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1/fcm") | ||
public class FcmController { | ||
|
||
private final FcmTokenService fcmTokenService; | ||
private final JwtExtractProvider jwtExtractProvider; | ||
|
||
@PostMapping("/register") | ||
public ResponseEntity<String> registerFcmToken(@RequestBody Map<String, String> request) { | ||
String userId = jwtExtractProvider.findAccountIdFromJwt(); | ||
String fcmToken = request.get("fcmToken"); | ||
|
||
if (fcmToken != null) { | ||
fcmTokenService.saveToken(userId, fcmToken); | ||
return ResponseEntity.ok("FCM 토큰이 등록되었습니다."); | ||
} else { | ||
return ResponseEntity.badRequest().body("FCM 토큰이 누락되었습니다."); | ||
} | ||
} | ||
} | ||
|
34 changes: 34 additions & 0 deletions
34
src/main/java/com/petmatz/infra/firebase/controller/NotificationController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package com.petmatz.infra.firebase.controller; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.petmatz.infra.firebase.dto.FcmMessage; | ||
import com.petmatz.infra.redis.service.RedisPublisher; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1/notifications") | ||
public class NotificationController { | ||
|
||
private final RedisPublisher redisPublisher; | ||
private final ObjectMapper objectMapper; | ||
|
||
@PostMapping | ||
public String sendNotification(@RequestBody FcmMessage fcmMessage){ | ||
try { | ||
|
||
// 객체를 JSON 문자열로 변환 | ||
ObjectMapper objectMapper = new ObjectMapper(); | ||
String messageJson = objectMapper.writeValueAsString(fcmMessage); | ||
|
||
// Redis Pub/Sub 채널에 발행 | ||
redisPublisher.publish("notifications", messageJson); | ||
|
||
return "메시지가 발행되었습니다."; | ||
} catch (JsonProcessingException e) { | ||
throw new RuntimeException("메시지 직렬화 실패: " + e.getMessage(), e); | ||
} | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
src/main/java/com/petmatz/infra/firebase/dto/FcmMessage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.petmatz.infra.firebase.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonCreator; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import lombok.*; | ||
|
||
@Getter | ||
@Setter | ||
@NoArgsConstructor | ||
public class FcmMessage { | ||
|
||
private String token; | ||
private String title; | ||
private String body; | ||
|
||
// 모든 필드를 초기화하는 생성자 | ||
@JsonCreator | ||
public FcmMessage(@JsonProperty("token") String token, | ||
@JsonProperty("title") String title, | ||
@JsonProperty("body") String body) { | ||
this.token = token; | ||
this.title = title; | ||
this.body = body; | ||
} | ||
|
||
// 정적 팩토리 메서드 | ||
public static FcmMessage of(@JsonProperty("token") String token, | ||
@JsonProperty("title") String title, | ||
@JsonProperty("body") String body) { | ||
return new FcmMessage(token, title, body); | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/main/java/com/petmatz/infra/firebase/service/FcmTokenService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.petmatz.infra.firebase.service; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.data.redis.core.StringRedisTemplate; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class FcmTokenService { | ||
|
||
private final StringRedisTemplate redisTemplate; | ||
private static final String TOKEN_PREFIX = "fcmToken:"; | ||
|
||
// FCM 토큰 저장 | ||
public void saveToken(String userId, String fcmToken) { | ||
String key = TOKEN_PREFIX + userId; | ||
redisTemplate.opsForValue().set(key, fcmToken, 30, TimeUnit.DAYS); // 30일 TTL | ||
} | ||
|
||
// FCM 토큰 조회 | ||
public String getToken(String userId) { | ||
String key = TOKEN_PREFIX + userId; | ||
return redisTemplate.opsForValue().get(key); | ||
} | ||
} | ||
|
||
|
Oops, something went wrong.