Skip to content

Commit

Permalink
feature: 채팅 구현 (#34)
Browse files Browse the repository at this point in the history
feature: 채팅 구현
  • Loading branch information
Lee-Dahyeon authored Nov 13, 2024
2 parents a943dee + 6d27ed8 commit d195b76
Show file tree
Hide file tree
Showing 12 changed files with 184 additions and 5 deletions.
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ dependencies {
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.12'
runtimeOnly 'com.h2database:h2'
testImplementation 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.webjars:stomp-websocket:2.3.4'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.hyunsolution.dangu.chatting.controller;

import com.hyunsolution.dangu.chatting.dto.request.ChatMessageRequest;
import com.hyunsolution.dangu.chatting.dto.response.ChatMessageDetailResponse;
import com.hyunsolution.dangu.chatting.dto.response.ChatMessageResponse;
import com.hyunsolution.dangu.chatting.service.ChatService;
import lombok.RequiredArgsConstructor;
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.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Controller;

@Slf4j
@Controller
@RequiredArgsConstructor
public class ChatController {
private final ChatService chatService;

//채팅기능
@MessageMapping("/chat/{chatRoomId}")
@SendTo("/topic/chat/{chatRoomId}")
public ChatMessageResponse sendChatMessage(
@DestinationVariable Long chatRoomId,
@Payload ChatMessageRequest requestMessage,
StompHeaderAccessor headerAccessor) {
Long userPk = Long.valueOf(headerAccessor.getFirstNativeHeader("Authorization"));

ChatMessageDetailResponse response =
chatService.sendMessage(chatRoomId, requestMessage.message(), userPk);

return new ChatMessageResponse("success", response, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.hyunsolution.dangu.chatting.domain;

import org.springframework.data.jpa.repository.JpaRepository;

public interface ChatRepository extends JpaRepository<Chatting, Long> {}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.hyunsolution.dangu.chatting;
package com.hyunsolution.dangu.chatting.domain;

import com.hyunsolution.dangu.user.domain.User;
import com.hyunsolution.dangu.workspace.domain.Workspace;
Expand Down Expand Up @@ -34,18 +34,17 @@ public class Chatting {
foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private User user;

@Column(length = 255, nullable = false)
@Column( nullable = false)
private String content;

@Column(name = "created_at", nullable = false)
@CreatedDate
private LocalDateTime createdAt;

@Builder
private Chatting(Workspace workspace, User user, String content, LocalDateTime createdAt) {
private Chatting(Workspace workspace, User user, String content) {
this.workspace = workspace;
this.user = user;
this.content = content;
this.createdAt = createdAt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.hyunsolution.dangu.chatting.dto.request;

public record ChatMessageRequest(String message) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.hyunsolution.dangu.chatting.dto.response;

import java.time.LocalDateTime;

public record ChatMessageDetailResponse(String message, String senderId, LocalDateTime createAt) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.hyunsolution.dangu.chatting.dto.response;

public record ChatMessageResponse(
String status, ChatMessageDetailResponse response, String error) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.hyunsolution.dangu.chatting.exception;

import com.hyunsolution.dangu.common.exception.BaseErrorCode;
import com.hyunsolution.dangu.common.exception.ExceptionDto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor
public enum ChatError implements BaseErrorCode {
CHATROOM_NOT_FOUND("CHAT_400", HttpStatus.BAD_REQUEST, "존재하지 않는 채팅방입니다.");

private final String code;
private final HttpStatus httpStatus;
private final String message;

@Override
public ExceptionDto getErrorReason(){
return ExceptionDto.builder().code(code).message(message).httpStatus(httpStatus).build();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.hyunsolution.dangu.chatting.exception;

import com.hyunsolution.dangu.common.exception.CustomException;

public class ChatRoomNotFoundException extends CustomException {
public static final ChatRoomNotFoundException EXCEPTION = new ChatRoomNotFoundException();

private ChatRoomNotFoundException() {
super(ChatError.CHATROOM_NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.hyunsolution.dangu.chatting.service;

import com.hyunsolution.dangu.chatting.domain.ChatRepository;
import com.hyunsolution.dangu.chatting.domain.Chatting;
import com.hyunsolution.dangu.chatting.dto.response.ChatMessageDetailResponse;
import com.hyunsolution.dangu.chatting.exception.ChatRoomNotFoundException;
import com.hyunsolution.dangu.user.domain.User;
import com.hyunsolution.dangu.user.domain.UserRepository;
import com.hyunsolution.dangu.user.exception.UserNotFoundException;
import com.hyunsolution.dangu.workspace.domain.Workspace;
import com.hyunsolution.dangu.workspace.domain.WorkspaceRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class ChatService {
private final ChatRepository chatRepository;
private final WorkspaceRepository workspaceRepository;
private final UserRepository userRepository;

@Transactional
public ChatMessageDetailResponse sendMessage(Long chatRoomId, String message, Long userPk) {

Workspace workspace =
workspaceRepository
.findById(chatRoomId)
.orElseThrow(() ->ChatRoomNotFoundException.EXCEPTION);
User user =
userRepository
.findById(userPk)
.orElseThrow(() -> UserNotFoundException.EXCEPTION);

Chatting chatMessage =
Chatting.builder().workspace(workspace).user(user).content(message).build();

chatRepository.save(chatMessage);

ChatMessageDetailResponse detailResponse =
new ChatMessageDetailResponse(message, user.getUid(), chatMessage.getCreatedAt());
return detailResponse;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.hyunsolution.dangu.common.config.webSocket;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOriginPatterns("*");
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.hyunsolution.dangu.common.config.webSocket;

import lombok.AllArgsConstructor;
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
@AllArgsConstructor
public class WebSocket implements WebSocketMessageBrokerConfigurer {

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat") // 접속 주소: ws://localhost:8080/chat
.setAllowedOriginPatterns("*");
System.out.println("websocket connected");
}

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic"); // 구독경로
registry.setApplicationDestinationPrefixes("/app"); // 발행경로
}
}

0 comments on commit d195b76

Please sign in to comment.