Skip to content

Commit

Permalink
Merge branch 'develop' into feature/join
Browse files Browse the repository at this point in the history
  • Loading branch information
easyoungcode authored Feb 6, 2024
2 parents 595177d + cd0841f commit 4222da8
Show file tree
Hide file tree
Showing 21 changed files with 453 additions and 97 deletions.
22 changes: 22 additions & 0 deletions src/main/java/com/wooyeon/yeon/chat/controller/ChatController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.wooyeon.yeon.chat.controller;

import com.wooyeon.yeon.chat.dto.ChatDto;
import com.wooyeon.yeon.chat.service.ChatService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/chat")
public class ChatController {

private final ChatService chatService;

@GetMapping("/list")
public ChatDto.Response getChatList(@RequestParam Long matchId) {
return chatService.getChatList(matchId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import com.wooyeon.yeon.chat.dto.RoomDto;
import com.wooyeon.yeon.chat.service.RoomService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.List;
import java.util.Set;

@RestController
@RequiredArgsConstructor
Expand All @@ -17,12 +17,12 @@ public class RoomController {
private final RoomService roomService;

@GetMapping("/list")
public List<RoomDto.RoomResponse> findMatchRoomList() {
public RoomDto.RoomResponse findMatchRoomList() {
return roomService.matchRoomList();
}

@GetMapping("/search/list")
public Set<RoomDto.SearchRoomResponse> searchMatchRoomList(@Valid @RequestBody RoomDto.SearchRoomRequest request) {
return roomService.searchMatchRoomList(request);
public List<RoomDto.SearchRoomResponse> searchMatchRoomList(String searchWord) {
return roomService.searchMatchRoomList(searchWord);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,57 @@

import com.wooyeon.yeon.chat.dto.StompDto;
import com.wooyeon.yeon.chat.service.ChatService;
import com.wooyeon.yeon.common.fcm.dto.FcmDto;
import com.wooyeon.yeon.common.fcm.service.FcmService;
import com.wooyeon.yeon.common.security.SecurityService;
import com.wooyeon.yeon.exception.ExceptionMessage;
import com.wooyeon.yeon.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;

@RestController
@RequiredArgsConstructor
public class StompController {
private final SimpMessageSendingOperations simpMessageSendingOperations;
private final ChatService chatService;
private final SecurityService securityService;
private final FcmService fcmService;
private final UserRepository userRepository;


/*
/queue/chat/room/{matchId} - 구독
/app/chat/message - 메시지 발생
/queue/chat/room/{matchId} - 채팅방 메시지 URL
/app/chat/message - 메시지 발생 이벤트 URL
/app/unsubscribe - 구독 취소 URL
*/

@MessageMapping("/chat/message")
public void enter(StompDto stompDto) {
chatService.saveChat(stompDto);
public void enter(StompDto stompDto, WebSocketSession session, StompHeaderAccessor accessor) {
String loginEmail = securityService.getCurrentUserEmail();
session.getAttributes().put(loginEmail, accessor.getUser().getName());
simpMessageSendingOperations.convertAndSend("/queue/chat/room/" + stompDto.getRoomId(), stompDto);

int sessionCount = chatService.calculateUserCount();

if(1 == sessionCount) {
try {
fcmService.sendMessageTo(FcmDto.buildRequest(loginEmail, stompDto, userRepository));
} catch (IOException e) {
throw new RuntimeException(ExceptionMessage.FCM_SEND_FAIL_ERROR.toString());
}
}

chatService.saveChat(stompDto);
}

@MessageMapping("/unsubscribe")
public void handleUnsubscription(WebSocketSession session) {
session.getAttributes().remove(securityService.getCurrentUserEmail());
}
}
6 changes: 4 additions & 2 deletions src/main/java/com/wooyeon/yeon/chat/domain/Chat.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import lombok.*;

import javax.persistence.*;
import java.sql.Timestamp;
import java.time.LocalDateTime;

@Entity
Expand All @@ -27,6 +26,9 @@ public class Chat {
@Column(length = 2000)
private String message;

@Column
@Column(name = "is_checked")
private boolean isChecked;

@Column(name = "send_time")
private LocalDateTime sendTime;
}
35 changes: 35 additions & 0 deletions src/main/java/com/wooyeon/yeon/chat/dto/ChatDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.wooyeon.yeon.chat.dto;

import lombok.Builder;
import lombok.Getter;

import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.List;

public class ChatDto {

@Getter
@Builder
public static class Request {
@NotNull
private Long matchId;
}

@Getter
@Builder
public static class Response {
private List<ChatResponse> chatData;
}

@Getter
@Builder
public static class ChatResponse {
private String message;
private LocalDateTime sendTime;
private String sender;
private Boolean isChecked;
private Boolean isSender;
}

}
45 changes: 42 additions & 3 deletions src/main/java/com/wooyeon/yeon/chat/dto/RoomDto.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,74 @@
package com.wooyeon.yeon.chat.dto;


import com.wooyeon.yeon.chat.domain.Chat;
import com.wooyeon.yeon.user.domain.Profile;
import com.wooyeon.yeon.user.domain.ProfilePhoto;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;

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

public class RoomDto {

@Getter
@Builder
public static class RoomResponse {
private List<ChatResponse> chatRoomList;
}

@Getter
@Builder
public static class ChatResponse {
private Long matchId;
private Long profilePhoto;
private String profilePhoto;
private String name;
private LocalDateTime lastTime;
private String lastMessage;
private boolean pinToTop;
private int unReadChatCount;
private Long unReadChatCount;
}

@Getter
public static class SearchRoomRequest {
@NonNull
private String SearchWord;
}

@Getter
@Builder
public static class SearchRoomResponse {
private Long matchId;
private Long profilePhoto;
private String profilePhoto;
private String name;
}

public static ChatResponse updateChatInfo(ChatResponse response, Chat chat) {
response.lastMessage = chat.getMessage();
response.lastTime = chat.getSendTime();

return response;
}

public static ChatResponse updateProfilePhoto(ChatResponse response, ProfilePhoto profilePhoto) {
response.profilePhoto = profilePhoto.getPhotoUrl();
return response;
}

public static SearchRoomResponse updateProfilePhoto(SearchRoomResponse response, ProfilePhoto profilePhoto) {
response.profilePhoto = profilePhoto.getPhotoUrl();
return response;
}

public static SearchRoomResponse updateProfile(SearchRoomResponse response, Profile profile) {
response.name = profile.getNickname();
return response;
}

public static ChatResponse updateProfile(ChatResponse response, Profile profile) {
response.name = profile.getNickname();
return response;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import org.springframework.stereotype.Repository;

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

@Repository
public interface ChatRepository extends JpaRepository<Chat, Long> {
Chat findFirstByUserMatchOrderBySendTimeDesc(UserMatch userMatch);
Optional<Chat> findFirstByUserMatchOrderBySendTimeDesc(UserMatch userMatch);
List<Chat> findAllByMessageContains(String searchWord);
Long countByIsCheckedAndUserMatch(boolean isChecked, UserMatch userMatch);
List<Chat> findAllByUserMatchOrderBySendTime(UserMatch userMatch);
}
73 changes: 72 additions & 1 deletion src/main/java/com/wooyeon/yeon/chat/service/ChatService.java
Original file line number Diff line number Diff line change
@@ -1,32 +1,103 @@
package com.wooyeon.yeon.chat.service;

import com.wooyeon.yeon.chat.domain.Chat;
import com.wooyeon.yeon.chat.dto.ChatDto;
import com.wooyeon.yeon.chat.dto.StompDto;
import com.wooyeon.yeon.chat.repository.ChatRepository;
import com.wooyeon.yeon.common.security.SecurityService;
import com.wooyeon.yeon.exception.ExceptionMessage;
import com.wooyeon.yeon.profileChoice.domain.UserMatch;
import com.wooyeon.yeon.profileChoice.repository.MatchRepository;
import com.wooyeon.yeon.user.domain.Profile;
import com.wooyeon.yeon.user.domain.User;
import com.wooyeon.yeon.user.repository.ProfileRepository;
import com.wooyeon.yeon.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.socket.WebSocketSession;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;

@Service
@RequiredArgsConstructor
public class ChatService {

private final ChatRepository chatRepository;
private final MatchRepository matchRepository;
private final SecurityService securityService;
private final UserRepository userRepository;
private final ProfileRepository profileRepository;

private final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();

@Transactional
public void saveChat(StompDto stompDto) {
UserMatch userMatch = matchRepository.findById(stompDto.getRoomId())
.orElseThrow(() -> new IllegalArgumentException());
.orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.USER_MATCH_NOT_FOUND.toString()));

Chat chat = Chat.builder()
.message(stompDto.getMessage())
.sendTime(LocalDateTime.now())
.userMatch(userMatch)
.sender(getLoginUserNickName())
// .isChecked() //stomp 연결되어 있으면 check
.build();

chatRepository.save(chat);
}

public ChatDto.Response getChatList(Long matchId) {

UserMatch userMatch = matchRepository.findById(matchId)
.orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.USER_MATCH_NOT_FOUND.toString()));

List<Chat> chatList = chatRepository.findAllByUserMatchOrderBySendTime(userMatch);
List<ChatDto.ChatResponse> responseList = new ArrayList<>();

String userName = getLoginUserNickName();

for (Chat chat : chatList) {
responseList.add(makeResponse(chat, userName));
}

return ChatDto.Response.builder()
.chatData(responseList)
.build();
}

public ChatDto.ChatResponse makeResponse(Chat chat, String userName) {
return ChatDto.ChatResponse.builder()
.message(chat.getMessage())
.sender(chat.getSender())
.sendTime(chat.getSendTime())
.isChecked(chat.isChecked())
.isSender(chat.getSender().equals(userName))
.build();
}

public String getLoginUserNickName() {
User loginUser = userRepository.findOptionalByEmail(securityService.getCurrentUserEmail())
.orElseThrow(() -> new IllegalArgumentException(ExceptionMessage.LOGIN_USER_NOT_FOUND.toString()));

Optional<Profile> profile;
String loginUserNickname = null;

if (null != loginUser.getUserProfile()) {
profile = profileRepository.findById(loginUser.getUserProfile().getId());
loginUserNickname = profile.get().getNickname();
}

return loginUserNickname;
}

public int calculateUserCount() {
// 중복된 사용자를 고려하여 사용자 수를 계산
return (int) sessions.stream().map(s -> s.getAttributes().get("userId")).distinct().count();
}

}
Loading

0 comments on commit 4222da8

Please sign in to comment.