Skip to content

Commit

Permalink
Merge pull request #130 from H-Hive/feature/chatmessage
Browse files Browse the repository at this point in the history
Feature: 실시간 채팅 기능 추가
  • Loading branch information
wkdehdgk159 authored Feb 4, 2024
2 parents ed4210a + 230960b commit bdb158f
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 31 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ dependencies {
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'

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

testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ public enum MajorCategory {
DANCE("댄스/무용"),
SOCIAL("사교/인맥"),
MEDIA("사진/영상"),
PET("반려동물");
PET("반려동물"),
ETC("기타");

private final String title;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
package com.HHive.hhive.domain.chatmessage.controller;

import com.HHive.hhive.domain.chatmessage.dto.ChatMessageRequestDTO;
import com.HHive.hhive.domain.chatmessage.dto.ChatMessageResponseDTO;
import com.HHive.hhive.domain.chatmessage.service.ChatMessageService;
import com.HHive.hhive.domain.user.UserDetailsImpl;
import com.HHive.hhive.global.common.CommonResponse;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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;

Expand All @@ -26,18 +21,6 @@ public class ChatMessageController {

private final ChatMessageService chatMessageService;

@PostMapping("/hives/{hiveId}")
public ResponseEntity<CommonResponse<Void>> sendChatMessage(
@PathVariable Long hiveId,
@RequestBody @Valid ChatMessageRequestDTO requestDTO,
@AuthenticationPrincipal UserDetailsImpl userDetails) {

chatMessageService.sendChatMessages(hiveId, requestDTO, userDetails.getUser());

return ResponseEntity.status(HttpStatus.CREATED).body(
CommonResponse.of("메시지 전송 성공", null));
}

@GetMapping("/hives/{hiveId}")
public ResponseEntity<CommonResponse<List<ChatMessageResponseDTO>>> getChatMessages(
@PathVariable Long hiveId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.HHive.hhive.domain.chatmessage.controller;

import com.HHive.hhive.domain.chatmessage.dto.ChatMessageRequestDTO;
import com.HHive.hhive.domain.chatmessage.dto.ChatMessageResponseDTO;
import com.HHive.hhive.domain.chatmessage.entity.ChatMessage;
import com.HHive.hhive.domain.chatmessage.service.ChatMessageService;
import lombok.RequiredArgsConstructor;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.stereotype.Controller;

@Controller
@RequiredArgsConstructor
public class SocketController {

private final SimpMessageSendingOperations sendingOperations;

private final ChatMessageService chatMessageService;

@MessageMapping("/chat")
public void socketHandler(ChatMessageRequestDTO requestDTO) {

ChatMessage chatMessage = chatMessageService.receiveAndSaveMessage(requestDTO);

sendingOperations.convertAndSend("/topic/chat/" + requestDTO.getHiveId(),
ChatMessageResponseDTO.from(chatMessage));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
@Getter
public class ChatMessageRequestDTO {

private Long hiveId;

private String username;

@Size(min = 1, max = 500)
private String message;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.HHive.hhive.domain.chatmessage.dto;

import com.HHive.hhive.domain.chatmessage.entity.ChatMessage;
import com.HHive.hhive.domain.user.entity.User;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -12,18 +12,16 @@ public class ChatMessageResponseDTO {

private String message;

private Long senderId;

private String senderName;
private String username;

@JsonFormat(pattern = "MM월 dd일 / HH시 mm분")
private LocalDateTime createdAt;

public static ChatMessageResponseDTO from(ChatMessage chatMessage) {

return ChatMessageResponseDTO.builder()
.message(chatMessage.getMessage())
.senderId(chatMessage.getSenderId())
.senderName(chatMessage.getSenderName())
.username(chatMessage.getSenderName())
.createdAt(chatMessage.getCreatedAt())
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
import com.HHive.hhive.domain.hive.service.HiveService;
import com.HHive.hhive.domain.relationship.hiveuser.validator.HiveUserValidator;
import com.HHive.hhive.domain.user.entity.User;
import com.HHive.hhive.domain.user.repository.UserRepository;
import com.HHive.hhive.global.exception.chatmessage.NotFoundChatMessageException;
import com.HHive.hhive.global.exception.chatmessage.NotSenderOfChatMessageException;
import com.HHive.hhive.global.exception.user.NotFoundUserException;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand All @@ -21,19 +23,24 @@ public class ChatMessageService {

private final ChatMessageRepository chatMessageRepository;

private final UserRepository userRepository;

private final HiveService hiveService;

private final HiveUserValidator hiveUserValidator;

public void sendChatMessages(Long hiveId, ChatMessageRequestDTO requestDTO, User user) {
public ChatMessage receiveAndSaveMessage(ChatMessageRequestDTO requestDTO) {

Hive hive = hiveService.findHiveById(hiveId);
User user = userRepository.findByUsername(requestDTO.getUsername()).orElseThrow(
NotFoundUserException::new);

hiveUserValidator.validateHiveUser(hive, user);
Hive hive = hiveService.findHiveById(requestDTO.getHiveId());

ChatMessage chatMessage = makeChatMessage(hive, requestDTO.getMessage(), user);
ChatMessage chatMessage = makeChatMessage(hive, user, requestDTO.getMessage());

chatMessageRepository.save(chatMessage);

return chatMessage;
}

public List<ChatMessageResponseDTO> getChatMessages(Long hiveId, User user) {
Expand All @@ -58,14 +65,14 @@ public void deleteChatMessage(Long chatMessageId, User user) {
chatMessage.updateDeletedAt();
}

public void validateLoginUserEqualsMessageSender(ChatMessage chatMessage, User user) {
private void validateLoginUserEqualsMessageSender(ChatMessage chatMessage, User user) {

if(!chatMessage.getSenderId().equals(user.getId())) {
if (!chatMessage.getSenderId().equals(user.getId())) {
throw new NotSenderOfChatMessageException();
}
}

private ChatMessage makeChatMessage(Hive hive, String message, User sender) {
private ChatMessage makeChatMessage(Hive hive, User sender, String message) {

return ChatMessage.builder()
.hive(hive)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.permitAll() // resource 접근 허용 설정
.requestMatchers("/api/users/**").permitAll() // '/api/users/'로 시작하는 요청 모두 접근 허가
.requestMatchers("/api/notifications/**").permitAll()
.requestMatchers("/ws/**").permitAll()
.anyRequest().authenticated() // 그 외 모든 요청 인증처리
);

Expand Down
33 changes: 33 additions & 0 deletions src/main/java/com/HHive/hhive/global/config/WebSocketConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.HHive.hhive.global.config;

import org.springframework.context.annotation.Configuration;
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;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {

//handshake를 위한 설정
registry.addEndpoint("/ws")
.setAllowedOriginPatterns("*")
//웹소켓 지원하지 않는 브라우저를 도움
.withSockJS();
}

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {

//SimpleBroker로 바로 이동할 경로설정. 스프링에서 제공하는 내장 브로커를 사용하겠다
registry.enableSimpleBroker("/topic", "/queue");

//SimpAnnotationMethod 로 가는 경로. 메시지 처리 후 SimpleBroker로 이동할
registry.setApplicationDestinationPrefixes("/pub");
}

}

0 comments on commit bdb158f

Please sign in to comment.