Skip to content

Commit

Permalink
Merge pull request #64 from KUIT-Space/feat/#62/채팅-api-개발
Browse files Browse the repository at this point in the history
Feat/#62: 채팅 �API 개발
  • Loading branch information
hyunn522 authored Aug 11, 2024
2 parents 2fa6e85 + 4fd573e commit d632069
Show file tree
Hide file tree
Showing 19 changed files with 429 additions and 73 deletions.
14 changes: 13 additions & 1 deletion src/main/java/space/space_spring/config/WebSocketConfig.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package space.space_spring.config;

import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import space.space_spring.interceptor.jwtSocket.JwtChannelInterceptor;

@Configuration
@EnableWebSocketMessageBroker
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

private final JwtChannelInterceptor jwtChannelInterceptor;

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// stomp 접속 주소 url = ws://localhost:8080/ws
Expand All @@ -23,6 +30,11 @@ public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");

// 메세지 발행(송신) 요청의 엔드 포인트
registry.setApplicationDestinationPrefixes("/app");
registry.setApplicationDestinationPrefixes("/app", "/topic");
}

@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(jwtChannelInterceptor);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package space.space_spring.controller;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.handler.annotation.*;
import org.springframework.messaging.simp.annotation.SubscribeMapping;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
import space.space_spring.dto.chat.request.ChatMessageRequest;
import space.space_spring.dto.chat.response.ChatMessageLogResponse;
import space.space_spring.dto.chat.response.ChatMessageResponse;
import space.space_spring.service.ChattingService;
import space.space_spring.service.UserChatRoomService;

import java.util.Map;

@Slf4j
@RestController
@RequiredArgsConstructor
public class ChattingController {

private final ChattingService chattingService;

private final UserChatRoomService userChatRoomService;

@MessageMapping("/chat/{chatRoomId}") // {chatRoomId} 채팅방으로 보낸 메세지 매핑
@SendTo("/topic/chat/{chatRoomId}") // {chatRoomId} 채팅방을 구독한 곳들로 메세지 전송
public ChatMessageResponse sendChatMessage (@Payload ChatMessageRequest chatMessageRequest, @DestinationVariable Long chatRoomId,
@Header("simpSessionAttributes") Map<String, Object> sessionAttributes) {
Long senderId = (Long) sessionAttributes.get("userId");
// log.info(senderId + " 님이 " + chatRoomId + " 채팅방으로 " + chatMessageRequest.getContent() + " 전송");

return chattingService.sendChatMessage(senderId, chatMessageRequest, chatRoomId);
}

@SubscribeMapping("/chat/{chatRoomId}") // {chatRoomId} 채팅방을 구독
public ChatMessageLogResponse subscribeChatRoom (@DestinationVariable Long chatRoomId, @Header("simpSessionAttributes") Map<String, Object> sessionAttributes) {
// log.info(chatRoomId + " 채팅방 구독");
sessionAttributes.put("chatRoomId", chatRoomId);
return chattingService.readChatMessageLog(chatRoomId);
}

// socket disconnect 시 호출
@EventListener
public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());
Map<String, Object> sessionAttributes = headerAccessor.getSessionAttributes();

Long userId = (Long) sessionAttributes.get("userId");
Long chatRoomId = (Long) sessionAttributes.get("chatRoomId");

userChatRoomService.saveLastReadTime(userId, chatRoomId);
}
}
20 changes: 0 additions & 20 deletions src/main/java/space/space_spring/controller/TestController.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
package space.space_spring.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.annotation.SubscribeMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import space.space_spring.argument_resolver.jwtLogin.JwtLoginAuth;

import space.space_spring.dao.PayDao;
import space.space_spring.dto.chat.request.ChatTestRequest;
import space.space_spring.dto.chat.response.ChatTestResponse;
import space.space_spring.response.BaseResponse;

@RestController
Expand All @@ -30,16 +22,4 @@ public BaseResponse<String> jwtLoginTest(@JwtLoginAuth Long userId) {
return new BaseResponse<>("jwt login test 성공");
}

@MessageMapping("/chat/{spaceChatId}") // {spaceChatId} 채팅방으로 보낸 메세지 매핑
@SendTo("/topic/chat/{spaceChatId}") // {spaceChatId} 채팅방을 구독한 곳들로 메세지 전송
public ChatTestResponse sendMsgTest(@Payload ChatTestRequest chat, @DestinationVariable String spaceChatId) {
log.info(spaceChatId + " 채팅방으로 " + chat.getMsg() + " 전송");
return ChatTestResponse.of(chat.getMsg());
}

@SubscribeMapping("/topic/chat/{spaceChatId}") // {spaceChatId} 채팅방을 구독
public void subscribeTest(@DestinationVariable String spaceChatId) {
log.info(spaceChatId + " 채팅방 구독");
}

}
17 changes: 17 additions & 0 deletions src/main/java/space/space_spring/dao/chat/ChattingDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package space.space_spring.dao.chat;

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import space.space_spring.entity.document.ChatMessage;

import java.time.LocalDateTime;
import java.util.List;

@Repository
public interface ChattingDao extends MongoRepository<ChatMessage, String> {
List<ChatMessage> findByChatRoomId(Long chatRoomId);

ChatMessage findTopByChatRoomIdOrderByCreatedAtDesc(Long chatRoomId);

int countByChatRoomIdAndCreatedAtBetween(Long chatRoomId, LocalDateTime lastReadTime, LocalDateTime lastUpdateTime);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package space.space_spring.dao.chat;

import org.springframework.data.jpa.repository.JpaRepository;
import space.space_spring.entity.ChatRoom;
import space.space_spring.entity.User;
import space.space_spring.entity.UserChatRoom;


public interface UserChatRoomDao extends JpaRepository<UserChatRoom, Long> {
UserChatRoom findByUserAndChatRoom(User userByUserId, ChatRoom chatRoomByChatRoomId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package space.space_spring.dto.chat.request;

import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.NoArgsConstructor;
import space.space_spring.entity.enumStatus.ChatMessageType;

import java.util.HashMap;

@Getter
@NoArgsConstructor
public class ChatMessageRequest {

@NotBlank(message = "메시지 내용은 공백일 수 없습니다.")
private HashMap<String, String> content;

@NotBlank(message = "스페이스 아이디는 공백일 수 없습니다.")
private Long spaceId;

@NotBlank(message = "메시지 타입은 공백일 수 없습니다.")
private ChatMessageType messageType;
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,5 @@ public class CreateChatRoomRequest {

private MultipartFile img;

// TODO: member 조회 API 개발 시 수정 예정
private List<String> memberList;
private List<Long> memberList;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package space.space_spring.dto.chat.response;

import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Getter
@Builder
public class ChatMessageLogResponse {
private List<ChatMessageResponse> chatMessageLog;

public static ChatMessageLogResponse of(List<ChatMessageResponse> chatMessageList) {
return ChatMessageLogResponse.builder()
.chatMessageLog(chatMessageList)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package space.space_spring.dto.chat.response;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import space.space_spring.entity.document.ChatMessage;
import space.space_spring.entity.enumStatus.ChatMessageType;

import java.util.HashMap;


@Builder
@Getter
@AllArgsConstructor
public class ChatMessageResponse {

private HashMap<String, String> content;

private String createdAt;

private ChatMessageType messageType;

private Long senderId;

private String senderName;

private String senderImg;

public static ChatMessageResponse of(ChatMessage chatMessage) {
return ChatMessageResponse.builder()
.content(chatMessage.getContent())
.createdAt(String.valueOf(chatMessage.getCreatedAt()))
.messageType(chatMessage.getMessageType())
.senderId(chatMessage.getSenderId())
.senderName(chatMessage.getSenderName())
.senderImg(chatMessage.getSenderImg())
.build();
}

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
@AllArgsConstructor
@Builder
public class CreateChatRoomResponse {
private Long id;
private Long chatRoomId;

public static CreateChatRoomResponse of(Long id) {
return CreateChatRoomResponse.builder()
.id(id)
.chatRoomId(id)
.build();
}
}
12 changes: 4 additions & 8 deletions src/main/java/space/space_spring/entity/ChatRoom.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import org.hibernate.annotations.Comment;
import space.space_spring.dto.chat.request.CreateChatRoomRequest;

import java.time.LocalDateTime;
import java.time.ZoneId;

@Entity
@Getter
@Builder
Expand Down Expand Up @@ -37,22 +40,15 @@ public class ChatRoom extends BaseEntity{
@Column(name = "chat_room_img")
private String img;

@Comment("마지막으로 전송된 메시지 ID")
@Nullable
@Column(name = "last_msg_id")
private int lastMsgId;

public static ChatRoom of(Space space, CreateChatRoomRequest createChatRoomRequest, String chatRoomImgUrl) {
return ChatRoom.builder()
.space(space)
.name(createChatRoomRequest.getName())
.img(chatRoomImgUrl)
// TODO: 메시지 관련 처리 예정
.lastMsgId(0)
.build();
}

// // 양방향 매핑
// // 양방향 매핑
// @OneToMany(mappedBy = "chatRoom", cascade = CascadeType.ALL)
// private List<UserChatRoom> userChatRooms;
}
16 changes: 11 additions & 5 deletions src/main/java/space/space_spring/entity/UserChatRoom.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Comment;

import java.time.LocalDateTime;

@Entity
@Getter
@NoArgsConstructor
Expand All @@ -32,16 +34,20 @@ public class UserChatRoom extends BaseEntity{
@JoinColumn(name = "user_id")
private User user;

@Comment("마지막으로 읽은 메시지 ID")
@Comment("마지막으로 읽은 시간")
@Nullable
@Column(name = "last_read_msg_id")
private Long lastReadMsgId;
@Column(name = "last_read_time")
private LocalDateTime lastReadTime;

public static UserChatRoom of(ChatRoom chatRoom, User user, Long lastReadMsgId) {
public static UserChatRoom of(ChatRoom chatRoom, User user, LocalDateTime lastReadTime) {
return UserChatRoom.builder()
.chatRoom(chatRoom)
.user(user)
.lastReadMsgId(lastReadMsgId)
.lastReadTime(lastReadTime)
.build();
}

public void setLastReadTime(LocalDateTime lastReadTime) {
this.lastReadTime = lastReadTime;
}
}
Loading

0 comments on commit d632069

Please sign in to comment.