Skip to content

Commit

Permalink
Merge pull request #98 from EveryUniv/dev
Browse files Browse the repository at this point in the history
fix: FCM 기능 수정 (단, 아직 완벽하진 않아서 향후 사용시 수정 필요)
  • Loading branch information
gutanbug authored Feb 2, 2024
2 parents dd9c575 + a73edda commit 63750e7
Show file tree
Hide file tree
Showing 9 changed files with 367 additions and 93 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,6 @@ api.pdf
/pinpoint-agent/
/logs/.DS_Store
.DS_Store

### Firebase ###
**/src/main/resources/**/**.json
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ dependencies {
implementation 'com.googlecode.json-simple:json-simple:1.1.1'

// firebase sdk
implementation 'com.google.firebase:firebase-admin:9.1.1'
implementation 'com.google.firebase:firebase-admin:9.2.0'
implementation 'com.squareup.okhttp3:okhttp:4.10.0'

// swagger
annotationProcessor 'com.github.therapi:therapi-runtime-javadoc-scribe:0.15.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import com.dku.council.domain.chatmessage.service.ChatRoomMessageService;
import com.dku.council.domain.user.service.UserService;
import com.dku.council.global.auth.role.UserAuth;
import com.dku.council.infra.fcm.service.FirebaseCloudMessageService;
import com.google.firebase.messaging.FirebaseMessagingException;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -49,6 +51,7 @@ public class ChatController {
private final ChatService chatService;
private final ChatRoomMessageService chatRoomMessageService;
private final MessageSender sender;
private final FirebaseCloudMessageService firebaseCloudMessageService;

/**
* 채팅방 별, 입장 이벤트 발생시 처리되는 기능
Expand All @@ -62,32 +65,40 @@ public class ChatController {
@MessageMapping("/chat/enterUser")
public void enterUser(@Payload RequestChatDto chat,
SimpMessageHeaderAccessor headerAccessor) {
// 채팅방 유저+1
chatService.plusUserCnt(chat.getRoomId());

// 채팅방에 유저 추가 및 UserUUID 반환
String username = chatService.addUser(chat.getRoomId(), chat.getSender());
if(chatService.alreadyInRoom(chat.getRoomId(), chat.getUserId())) {
// 반환 결과를 socket session 에 userUUID 로 저장
headerAccessor.getSessionAttributes().put("username", chat.getSender());
headerAccessor.getSessionAttributes().put("userId", chat.getUserId());
headerAccessor.getSessionAttributes().put("roomId", chat.getRoomId());
} else {
// 채팅방 유저+1
chatService.plusUserCnt(chat.getRoomId());

// 반환 결과를 socket session 에 userUUID 로 저장
headerAccessor.getSessionAttributes().put("username", username);
headerAccessor.getSessionAttributes().put("userId", chat.getUserId());
headerAccessor.getSessionAttributes().put("roomId", chat.getRoomId());
// 채팅방에 유저 추가 및 UserUUID 반환
String username = chatService.addUser(chat.getRoomId(), chat.getSender());

String enterMessage = chat.getSender() + " 님 입장!!";
LocalDateTime messageTime = LocalDateTime.now();
// 반환 결과를 socket session 에 userUUID 로 저장
headerAccessor.getSessionAttributes().put("username", username);
headerAccessor.getSessionAttributes().put("userId", chat.getUserId());
headerAccessor.getSessionAttributes().put("roomId", chat.getRoomId());

// 입장 메시지 저장
chatRoomMessageService.create(chat.getRoomId(), chat.getType().toString(), chat.getUserId(), chat.getSender(), enterMessage, messageTime);
String enterMessage = chat.getSender() + " 님 입장!!";
LocalDateTime messageTime = LocalDateTime.now();

Message message = Message.builder()
.type(chat.getType())
.roomId(chat.getRoomId())
.sender(chat.getSender())
.message(enterMessage)
.messageTime(messageTime)
.build();
// 입장 메시지 저장
chatRoomMessageService.create(chat.getRoomId(), chat.getType().toString(), chat.getUserId(), chat.getSender(), enterMessage, messageTime);

sender.send(topic, message);
Message message = Message.builder()
.type(chat.getType())
.roomId(chat.getRoomId())
.sender(chat.getSender())
.message(enterMessage)
.messageTime(messageTime)
.build();

sender.send(topic, message);
}
}

/**
Expand Down Expand Up @@ -117,47 +128,47 @@ public void sendMessage(@Payload RequestChatDto chat) {
*
* 유저 퇴장 시에는 EventListener 을 통해서 유저 퇴장을 확인
*/
@EventListener
public void webSocketDisconnectListener(SessionDisconnectEvent event) {
log.info("DisConnEvent {}", event);

StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());

// stomp 세션에 있던 username과 roomId 를 확인해서 채팅방 유저 리스트와 room 에서 해당 유저를 삭제
String username = (String) headerAccessor.getSessionAttributes().get("username");
Long userId = (Long) headerAccessor.getSessionAttributes().get("userId");
String roomId = (String) headerAccessor.getSessionAttributes().get("roomId");
log.info("퇴장 controller에서 uuid " + username);
log.info("퇴장 controller에서 roomId " + roomId);

log.info("headAccessor {}", headerAccessor);

// 채팅방 유저 -1
chatService.minusUserCnt(roomId);

// 채팅방 유저 리스트에서 유저 삭제
chatService.delUser(roomId, username);

if (username != null) {
log.info("User Disconnected : ", username);

String exitMessage = username + " 님 퇴장!!";
LocalDateTime messageTime = LocalDateTime.now();

// 퇴장 메시지 저장
chatRoomMessageService.create(roomId, MessageType.LEAVE.toString(), userId, username, exitMessage, messageTime);
// builder 어노테이션 활용
Message message = Message.builder()
.type(MessageType.LEAVE)
.sender(username)
.roomId(roomId)
.message(exitMessage)
.messageTime(messageTime)
.build();

sender.send(topic, message);
}
}
// @EventListener
// public void webSocketDisconnectListener(SessionDisconnectEvent event) {
// log.info("DisConnEvent {}", event);
//
// StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
//
// // stomp 세션에 있던 username과 roomId 를 확인해서 채팅방 유저 리스트와 room 에서 해당 유저를 삭제
// String username = (String) headerAccessor.getSessionAttributes().get("username");
// Long userId = (Long) headerAccessor.getSessionAttributes().get("userId");
// String roomId = (String) headerAccessor.getSessionAttributes().get("roomId");
// log.info("퇴장 controller에서 uuid " + username);
// log.info("퇴장 controller에서 roomId " + roomId);
//
// log.info("headAccessor {}", headerAccessor);
//
// // 채팅방 유저 -1
// chatService.minusUserCnt(roomId);
//
// // 채팅방 유저 리스트에서 유저 삭제
// chatService.delUser(roomId, username);
//
// if (username != null) {
// log.info("User Disconnected : ", username);
//
// String exitMessage = username + " 님 퇴장!!";
// LocalDateTime messageTime = LocalDateTime.now();
//
// // 퇴장 메시지 저장
// chatRoomMessageService.create(roomId, MessageType.LEAVE.toString(), userId, username, exitMessage, messageTime);
// // builder 어노테이션 활용
// Message message = Message.builder()
// .type(MessageType.LEAVE)
// .sender(username)
// .roomId(roomId)
// .message(exitMessage)
// .messageTime(messageTime)
// .build();
//
// sender.send(topic, message);
// }
// }

/**
* 채팅방 별, 채팅에 참여한 유저 리스트 반환
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;

public interface ChatRoomUserRepository extends JpaRepository<ChatRoomUser, Long> {
@Query("select u.participant.nickname from ChatRoomUser u " +
Expand All @@ -20,4 +21,10 @@ public interface ChatRoomUserRepository extends JpaRepository<ChatRoomUser, Long
"where c.chat_room_id = :roomId and c.participant_id = :userId", nativeQuery = true)
void deleteChatRoomUserByRoomIdAndUserId(@Param("roomId") Long roomId,
@Param("userId") Long userId);

@Query("select u from ChatRoomUser u " +
"join ChatRoom r " +
"on u.chatRoom.id = r.id " +
"where u.chatRoom.id = :chatRoomId and u.participant.id = :userId")
Optional<ChatRoomUser> existsUserByRoomIdAndUserId(@Param("chatRoomId") Long chatRoomId, @Param("userId") Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,9 @@ public void delChatRoom(Long userId, String roomId, boolean isAdmin) {
}
log.info("삭제 완료 roomId : {}", roomId);
}

public boolean alreadyInRoom(String roomId, Long userId) {
long chatRoomId = chatRoomRepository.findChatRoomByRoomId(roomId).orElseThrow(ChatRoomNotFoundException::new).getId();
return chatRoomUserRepository.existsUserByRoomIdAndUserId(chatRoomId, userId).isPresent();
}
}
42 changes: 26 additions & 16 deletions src/main/java/com/dku/council/infra/fcm/config/FCMConfig.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,45 @@
package com.dku.council.infra.fcm.config;

import com.dku.council.infra.fcm.model.dto.request.FCMPushRequestDto;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.messaging.ApnsConfig;
import com.google.firebase.messaging.Aps;
import com.google.firebase.messaging.ApsAlert;
import com.google.firebase.messaging.FirebaseMessaging;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;

// TODO 향후 사용시 활성화
//@Configuration
@Configuration
@Slf4j
public class FCMConfig {

@Bean
public FirebaseMessaging firebaseMessaging() {
try (InputStream keyStream = FCMConfig.class.getResourceAsStream("/serviceAccountKey.json")) {
if (keyStream == null) {
throw new IOException("Not found serviceAccountKey.json file");
}
if (!FirebaseApp.getApps().isEmpty()) {
return FirebaseMessaging.getInstance();
}
@Value("${fcm.key.path}")
private String SERVICE_ACCOUNT_JSON;

@PostConstruct
public void init() {
try {
ClassPathResource resource = new ClassPathResource(SERVICE_ACCOUNT_JSON);
InputStream inputStream = resource.getInputStream();

FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.fromStream(keyStream))
.setCredentials(GoogleCredentials.fromStream(inputStream))
.setProjectId("next-dku-push-server")
.build();
FirebaseApp app = FirebaseApp.initializeApp(options);
return FirebaseMessaging.getInstance(app);

FirebaseApp.initializeApp(options);
log.info("파이어베이스 서버와의 연결에 성공했습니다.");
} catch (IOException e) {
throw new RuntimeException(e);
log.error("파이어베이스 서버와의 연결에 실패했습니다.", e);
}
}

}
33 changes: 33 additions & 0 deletions src/main/java/com/dku/council/infra/fcm/model/dto/FCMMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.dku.council.infra.fcm.model.dto;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class FCMMessage {

private boolean validateOnly;
private Message message;

@Builder
@AllArgsConstructor
@Getter
public static class Message {
private Notification notification;
private String token;
private String topic;
}

@Builder
@AllArgsConstructor
@Getter
public static class Notification {
private String title;
private String body;
private String image;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.dku.council.infra.fcm.model.dto.request;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.*;
import lombok.extern.slf4j.Slf4j;

@Getter
@Slf4j
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class FCMPushRequestDto {

private String targetToken;

@JsonInclude(JsonInclude.Include.NON_NULL)
private String title;

@JsonInclude(JsonInclude.Include.NON_NULL)
private String body;
}
Loading

0 comments on commit 63750e7

Please sign in to comment.