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] 채팅기능 #24

Merged
merged 31 commits into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
cc9e179
[feat] #5 socket test 페이지 cors 추가
OJOJIN Jan 1, 2024
bf414e3
[feat] #5 socket config 추가
OJOJIN Jan 1, 2024
fcdb365
[feat] #5 socket interceptor 추가
OJOJIN Jan 1, 2024
7ce9923
[feat] #5 socket error handler 추가
OJOJIN Jan 1, 2024
8bcc33c
[feat] #5 socket exception 추가
OJOJIN Jan 1, 2024
277ccb7
[feat] #5 socket code 추가
OJOJIN Jan 1, 2024
2ee34f0
[feat] #5 socket jwt provider 추가
OJOJIN Jan 1, 2024
5050f70
Merge remote-tracking branch 'origin/develop' into feature/5-chat
OJOJIN Jan 1, 2024
765853f
Merge remote-tracking branch 'origin/develop' into feature/5-chat
OJOJIN Jan 3, 2024
4cdf5ab
Merge remote-tracking branch 'origin/develop' into feature/5-chat
OJOJIN Jan 5, 2024
490ce6f
[feat] #5 gradle에 socket & message & mongodb 추가
OJOJIN Jan 5, 2024
1714e69
[feat] #5 chat entity 추가
OJOJIN Jan 5, 2024
402ca9d
[feat] #5 채팅방 관련 entity 추가
OJOJIN Jan 5, 2024
aaa7e2a
[fix] #5 jpa config 범위 변경
OJOJIN Jan 5, 2024
0d08828
[feat] #5 mongodb config 추가
OJOJIN Jan 5, 2024
0479805
[feat] #5 StompInterceptor 추가
OJOJIN Jan 5, 2024
5ebdaab
[feat] #5 socket 예외처리 관련 코드 추가
OJOJIN Jan 5, 2024
9bd6b2a
[feat] #5 socket jwt provider 추가
OJOJIN Jan 5, 2024
8535297
[feat] #5 socket jwt provider 추가
OJOJIN Jan 5, 2024
fc76695
[feat] #5 socket 도메인 내 dto 추가
OJOJIN Jan 5, 2024
cd8acb4
[feat] #5 SocketBaseResponse 추가
OJOJIN Jan 5, 2024
02ed988
[feat] #5 응답 MessageType enum 추가
OJOJIN Jan 5, 2024
682dcac
[feat] #5 Chat 관련 repository 추가
OJOJIN Jan 5, 2024
fa9cc89
[feat] #5 ChatRoom 관련 repository 생성
OJOJIN Jan 5, 2024
1212d67
[feat] #5 ChatRoomListDto 정렬 클래스 추가
OJOJIN Jan 5, 2024
7043c79
[feat] #5 ChatController 추가
OJOJIN Jan 5, 2024
bc4cd24
[feat] #5 ChatService 추가
OJOJIN Jan 5, 2024
9684a02
[feat] #5 whitelist /ws 경로 추가
OJOJIN Jan 5, 2024
646d6ed
[feat] #5 UserQuerydslRepository 추가
OJOJIN Jan 5, 2024
f08adad
[fix] #5 채팅 유저 알림전송 메소드 분리
OJOJIN Jan 6, 2024
1ed0ae0
[fix] #5 collect(Collectors.toList())로 변경
OJOJIN Jan 6, 2024
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
12 changes: 10 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,24 @@ dependencies {
annotationProcessor "jakarta.annotation:jakarta.annotation-api" // java.lang.NoClassDefFoundError (javax.annotation.Generated) 대응 코드
annotationProcessor "jakarta.persistence:jakarta.persistence-api" // java.lang.NoClassDefFoundError (javax.annotation.Entity) 대응 코드

// websocket
implementation 'org.springframework.boot:spring-boot-starter-websocket'

// Messaging
implementation 'org.springframework:spring-messaging:6.1.0'

// 이메일 SMTP
implementation 'org.springframework.boot:spring-boot-starter-mail'

// thymeleaf
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'

// mongoDB
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

}

tasks.named('test') {
Expand All @@ -85,4 +93,4 @@ sourceSets {
// gradle clean 시에 QClass 디렉토리 삭제
clean {
delete file(generated)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.gachon.checkmate.domain.chat.controller;

import lombok.RequiredArgsConstructor;
import org.gachon.checkmate.domain.chat.dto.MessageType;
import org.gachon.checkmate.domain.chat.dto.request.ChatListRequestDto;
import org.gachon.checkmate.domain.chat.dto.request.ChatRequestDto;
import org.gachon.checkmate.domain.chat.dto.response.*;
import org.gachon.checkmate.domain.chat.service.ChatService;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RequiredArgsConstructor
@RestController
public class ChatController {

private final ChatService chatService;

private final SimpMessageSendingOperations sendingOperations;

// 채팅 전송
@MessageMapping("/chat")
public void sendChat(@Header("simpSessionAttributes") Map<String, Object> simpSessionAttributes,
@Payload final ChatRequestDto request) {
ChatResponseDto response = chatService.sendChat(simpSessionAttributes, request);
sendingOperations.convertAndSend("/queue/chat/"+simpSessionAttributes.get("roomId"), SocketBaseResponse.of(MessageType.CHAT, response));
}

// 채팅방 정보 조회
@MessageMapping("/room-list")
public void getChatRoomList(@Header("simpSessionAttributes") Map<String, Object> simpSessionAttributes) {
ChatRoomListResponseDto response = chatService.getChatRoomList(simpSessionAttributes);
sendingOperations.convertAndSend("/queue/user/"+simpSessionAttributes.get("userId"), SocketBaseResponse.of(MessageType.ROOM_LIST, response));
}

// 이전 채팅 불러오기
@MessageMapping("/chat-list")
public void getChatList(@Header("simpSessionAttributes") Map<String, Object> simpSessionAttributes,
@Payload final ChatListRequestDto request) {
final ChatListResponseDto response = chatService.getChatList(simpSessionAttributes, request);
sendingOperations.convertAndSend("/queue/user/" + simpSessionAttributes.get("userId"), SocketBaseResponse.of(MessageType.CHAT_LIST, response));
}

// 채팅방 입장하기
@MessageMapping("/room-enter")
public void enterRoom(@Header("simpSessionAttributes") Map<String, Object> simpSessionAttributes,
@Payload final ChatListRequestDto request) {
ChatRoomEnterResponseDto response = chatService.enterChatRoom(simpSessionAttributes, request);
sendingOperations.convertAndSend("/queue/chat/" + response.chatRoomId(), SocketBaseResponse.of(MessageType.ROOM_ENTER, response));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.gachon.checkmate.domain.chat.dto;

import lombok.Builder;
import org.gachon.checkmate.domain.chat.entity.Chat;

import java.time.LocalDateTime;

@Builder
public record ChatLastMessageDto (
String content,
LocalDateTime sendTime
) {
public static ChatLastMessageDto of(Chat chat) {
return ChatLastMessageDto.builder()
.content(chat.getContent())
.sendTime(chat.getSendTime())
.build();
}
public static ChatLastMessageDto createEmptyChat() {
return ChatLastMessageDto.builder()
.content(null)
.sendTime(null)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.gachon.checkmate.domain.chat.dto;


import lombok.Builder;
import org.gachon.checkmate.domain.chat.entity.Chat;

import java.time.LocalDateTime;

@Builder
public record ChatMessageDto (
Long userId,
String content,
Boolean isRead,
LocalDateTime sendTime
) {
public static ChatMessageDto of(Chat chat) {
return ChatMessageDto.builder()
.userId(chat.getSenderId())
.content(chat.getContent())
.isRead(chat.getIsRead())
.sendTime(chat.getSendTime())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.gachon.checkmate.domain.chat.dto;

import lombok.Builder;


@Builder
public record ChatRoomListDto(
ChatLastMessageDto lastChatInfo,
Long notReadCount,
ChatRoomListUserInfoDto userInfo
) {
public static ChatRoomListDto of(ChatLastMessageDto lastChatInfo, Long notReadCount, ChatRoomListUserInfoDto chatRoomListUserInfoDto) {
return ChatRoomListDto.builder()
.lastChatInfo(lastChatInfo)
.notReadCount(notReadCount)
.userInfo(chatRoomListUserInfoDto)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.gachon.checkmate.domain.chat.dto;

import com.querydsl.core.annotations.QueryProjection;
import org.gachon.checkmate.domain.member.entity.GenderType;

import java.time.LocalDate;

public record ChatRoomListUserInfoDto(
Long userId,
String name,
String profile,
String major,
GenderType gender,
LocalDate endDate
) {
@QueryProjection
public ChatRoomListUserInfoDto(Long userId, String name, String profile, String major, GenderType gender, LocalDate endDate) {
this.userId = userId;
this.name = name;
this.profile = profile;
this.major = major;
this.gender = gender;
this.endDate = endDate;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.gachon.checkmate.domain.chat.dto;

import com.querydsl.core.annotations.QueryProjection;

import java.time.LocalDate;

public record ChatUserInfoDto(
Long userId,
String name,
String profile,
Long postId,
String title,
LocalDate endDate
) {
@QueryProjection
public ChatUserInfoDto(Long userId, String name, String profile, Long postId, String title, LocalDate endDate) {
this.userId = userId;
this.name = name;
this.profile = profile;
this.postId = postId;
this.title = title;
this.endDate = endDate;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.gachon.checkmate.domain.chat.dto;

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

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public enum MessageType {
CHAT("CHAT"),
NEW_CHAT_NOTIFICATION("NEW_CHAT_NOTIFICATION"),
ROOM_ENTER("ROOM_ENTER"),
ROOM_LIST("ROOM_LIST"),
CHAT_LIST("CHAT_LIST");

private final String desc;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.gachon.checkmate.domain.chat.dto.request;

public record ChatListRequestDto(
Long otherUserId,
Integer pageNumber,
Integer pageSize
) {
public ChatListRequestDto(Long otherUserId, Integer pageNumber, Integer pageSize) {
this.otherUserId = otherUserId;
this.pageNumber = (pageNumber != null) ? pageNumber : 0;
this.pageSize = pageSize != null ? pageSize : 20;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.gachon.checkmate.domain.chat.dto.request;

public record ChatRequestDto(
String content
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.gachon.checkmate.domain.chat.dto.response;

import lombok.Builder;
import lombok.Getter;
import org.gachon.checkmate.domain.chat.dto.ChatMessageDto;
import org.gachon.checkmate.domain.chat.dto.ChatUserInfoDto;
import org.gachon.checkmate.domain.chat.entity.Chat;

import java.util.ArrayList;
import java.util.List;

@Builder
@Getter
public class ChatListResponseDto{

private String chatRoomId;

private ChatUserInfoDto chatUserInfoDto;

@Builder.Default
private List<ChatMessageDto> chatMessageList = new ArrayList<>();

@Builder.Default
private Boolean hasNextPage = null;

@Builder.Default
private Integer pageNumber = null;

public static ChatListResponseDto of(String chatRoomId, ChatUserInfoDto chatUserInfoDto) {
return ChatListResponseDto.builder()
.chatRoomId(chatRoomId)
.chatUserInfoDto(chatUserInfoDto)
.build();
}

public void addChatMessage(Chat chat) {
this.chatMessageList.add(ChatMessageDto.of(chat));
}

public void updatePageInfo(Boolean hasNextPage, Integer pageNumber) {
this.hasNextPage = hasNextPage;
this.pageNumber = pageNumber;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.gachon.checkmate.domain.chat.dto.response;

import lombok.Builder;
import org.gachon.checkmate.domain.chat.entity.Chat;

import java.time.LocalDateTime;

@Builder
public record ChatResponseDto (
Long senderId,
String content,
Boolean isRead,
LocalDateTime sendTime
) {
public static ChatResponseDto of(Chat chat) {
return ChatResponseDto.builder()
.senderId(chat.getSenderId())
.content(chat.getContent())
.isRead(chat.getIsRead())
.sendTime(chat.getSendTime())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.gachon.checkmate.domain.chat.dto.response;

import lombok.Builder;

@Builder
public record ChatRoomEnterResponseDto (
Long userId,
String chatRoomId
) {
public static ChatRoomEnterResponseDto of(Long userId, String chatRoomId) {
return ChatRoomEnterResponseDto.builder()
.userId(userId)
.chatRoomId(chatRoomId)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.gachon.checkmate.domain.chat.dto.response;

import lombok.Builder;
import org.gachon.checkmate.domain.chat.dto.ChatRoomListDto;

import java.util.List;


@Builder
public record ChatRoomListResponseDto(
List<ChatRoomListDto> chatRoomList
) {
public static ChatRoomListResponseDto of(List<ChatRoomListDto> chatRoomListDto) {
return ChatRoomListResponseDto.builder()
.chatRoomList(chatRoomListDto)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.gachon.checkmate.domain.chat.dto.response;

import lombok.Builder;
import org.gachon.checkmate.domain.chat.entity.Chat;

import java.time.LocalDateTime;

@Builder
public record NewChatResponseDto(
String chatRoomId,
Long senderId,
String content,
LocalDateTime sendTime
) {
public static NewChatResponseDto of(Chat chat) {
return NewChatResponseDto.builder()
.chatRoomId(chat.getChatRoomId())
.senderId(chat.getSenderId())
.content(chat.getContent())
.sendTime(chat.getSendTime())
.build();
}
}
Loading