Skip to content

Commit

Permalink
Merge pull request #264 from prgrms-web-devcourse-final-project/develop
Browse files Browse the repository at this point in the history
채팅메세지 로직수정
  • Loading branch information
Dom1046 authored Dec 31, 2024
2 parents bc261c1 + bf054ae commit 3560c27
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 69 deletions.
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,9 @@ dependencies {
// implementation 'org.springframework.ai:spring-ai-vertex-ai-gemini-spring-boot-starter:1.0.0-SNAPSHOT'
implementation 'com.google.cloud:google-cloud-vertexai:1.15.0'

//jackson 날짜변환 위한 의존성
//jackson 날짜변환 위한 의존성, json 의존성
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
implementation 'org.json:json:20240303'

//로드밸런서 헬스체크
implementation "org.springframework.boot:spring-boot-starter-actuator"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,6 @@ public ResponseEntity<ChatMessageSuccessResponse> sendMessage(ChatMessageRequest
return ResponseEntity.status(HttpStatus.CREATED).body(chatMessageService.sendMessage(message));
}

// //클리이언트로 부터 오는 이미지파일 수신
// @MessageMapping("/upload")
// @SendTo("/sub/uploadStatus")
// public String handleBinaryMessage(byte[] fileData) {
// try {
// // 파일 저장 로직
// return "File uploaded successfully!";
// } catch (Exception e) {
// return "File upload failed: " + e.getMessage();
// }
// }

//채팅메세지 조회
@GetMapping
@ResponseBody
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ public class ChatMessageRequest {
private Long memberId;
@Length(min = 1, max = 300)
private String message;
private String imageUrl;
private String base64Image;

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,20 @@ public class ChatMessageResponse {

private Long chatMessageId;
private Long chatRoomId;
private String chatMessageImage;
private String sender;
private String message;
private String base64Image;
private MessageType type;
private LocalDateTime createTime;

@Builder
public ChatMessageResponse(Long chatMessageId, Long chatRoomId,
String sender, String message,String chatMessageImage,
MessageType type, LocalDateTime createTime) {
String sender, String message, MessageType type, LocalDateTime createTime, String base64Image) {
this.chatMessageId = chatMessageId;
this.chatRoomId = chatRoomId;
this.base64Image = base64Image;
this.sender = sender;
this.message = message;
this.chatMessageImage = chatMessageImage;
this.type = type;
this.createTime = createTime;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class RedisSubscriber implements MessageListener {
private final SimpMessageSendingOperations messagingTemplate;
private final RedisTemplate redisTemplate;

//메세지를 구독자들에게 송신
//Stomp로 송신
public void sendMessage(ChatMessageResponse publishMessage) {
try {
log.info("레디스 펍섭의 publishMessage: {}", publishMessage);
Expand All @@ -28,7 +28,7 @@ public void sendMessage(ChatMessageResponse publishMessage) {
log.error("Exception {}", e.getMessage());
}
}
//stomp이용해서 구독자들에게 송신
//redis로 송수신
@Override
public void onMessage(Message message, byte[] pattern) {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.mallangs.domain.chat.service;

import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.mallangs.domain.chat.dto.request.ChatMessageRequest;
import com.mallangs.domain.chat.dto.request.UpdateChatMessageRequest;
import com.mallangs.domain.chat.dto.response.*;
Expand All @@ -19,10 +21,17 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Base64;
import java.util.Optional;
import java.util.UUID;

@Log4j2
@Service
Expand Down Expand Up @@ -52,8 +61,7 @@ public ChatMessageSuccessResponse sendMessage(ChatMessageRequest chatMessageRequ
.message(chatMessageRequest.getMessage())
.sender(foundPartRoom.getParticipant())
.senderRead(true)
.receiverRead(false)
.imageUrl(chatMessageRequest.getImageUrl()).build();
.receiverRead(false).build();
ChatMessage savedChatMessage = chatMessageRepository.save(chatMessage);
log.info("저장된 보낸 채팅 정보: {}", chatMessage.toString());

Expand All @@ -62,15 +70,15 @@ public ChatMessageSuccessResponse sendMessage(ChatMessageRequest chatMessageRequ
.chatMessageId(savedChatMessage.getChatMessageId())
.chatRoomId(chatRoom.getChatRoomId())
.message(savedChatMessage.getMessage())
.chatMessageImage(savedChatMessage.getImageUrl())
.base64Image(chatMessageRequest.getBase64Image())
.sender(savedChatMessage.getSender().getNickname().getValue())
.type(savedChatMessage.getType())
.createTime(savedChatMessage.getCreatedAt())
.build();

log.info("마지막 메세지 보낼 채팅 정보: {}", chatMessageResponse.toString());

//채팅 보내기
//redis로 채팅 보내기
redisSubscriber.sendMessage(chatMessageResponse);
return new ChatMessageSuccessResponse(savedChatMessage.getSender().getUserId().getValue());
} catch (Exception e) {
Expand Down Expand Up @@ -165,4 +173,5 @@ public ChatRoomResponse changeUnReadToRead(Long profileMemberId, Long myId) {
.changedIsRead(numChanged)
.build();
}

}
29 changes: 27 additions & 2 deletions src/main/java/com/mallangs/global/config/WebSocketConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
Expand All @@ -15,6 +16,9 @@
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 org.springframework.web.socket.messaging.SessionConnectEvent;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;

@Configuration
@EnableWebSocketMessageBroker
Expand All @@ -35,12 +39,21 @@ public void setMessageTaskScheduler(@Lazy TaskScheduler taskScheduler) {
@Override
public void configureMessageBroker(final MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/sub")
//heart beat 주기 (클라이언트_전송_간격, 서버_수신_간격) -> 서버에서 먼저 보내고, 클라가 응답하는 구조
.setHeartbeatValue(new long[] {10000, 20000})
//heart beat 주기 (클라이언트_전송_간격, 서버_수신_간격) -> 서버에서 먼저 보내고, 클라가 응답하는 구조 0.1초, 0.2초
.setHeartbeatValue(new long[] {100, 200})
.setTaskScheduler(this.messageBrokerTaskScheduler);
registry.setApplicationDestinationPrefixes("/pub");
}

@Bean
//글자,이미지 파일 제한 500바이트 까지(오류 방지위함)
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean(); // (3)
container.setMaxTextMessageBufferSize(500000); // (4)
container.setMaxBinaryMessageBufferSize(500000); // (5)
return container;
}

//endPoint 설정
@Override
public void registerStompEndpoints(final StompEndpointRegistry registry) {
Expand All @@ -61,4 +74,16 @@ public MappingJackson2MessageConverter mappingJackson2MessageConverter() {
jackson2MessageConverter.setStrictContentTypeMatch(false);
return jackson2MessageConverter;
}

@EventListener
public void connectEvent(SessionConnectEvent sessionConnectEvent){
log.info(sessionConnectEvent);
log.info("웹소켓 연결 성공");
}

@EventListener
public void onDisconnectEvent(SessionDisconnectEvent sessionDisconnectEvent) {
log.info(sessionDisconnectEvent.getSessionId());
log.info("웹소켓 연결 끊어짐");
}
}
35 changes: 0 additions & 35 deletions src/main/java/com/mallangs/global/handler/StompFileHandler.java

This file was deleted.

10 changes: 2 additions & 8 deletions src/main/java/com/mallangs/global/handler/StompHandler.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
package com.mallangs.global.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mallangs.domain.chat.entity.ParticipatedRoom;
import com.mallangs.domain.chat.repository.ParticipatedRoomRepository;
import com.mallangs.domain.chat.service.ChatMessageService;
import com.mallangs.domain.member.entity.Member;
import com.mallangs.domain.member.entity.embadded.UserId;
import com.mallangs.global.jwt.entity.CustomMemberDetails;
import com.mallangs.global.jwt.util.JWTUtil;
import com.mallangs.domain.member.repository.MemberRepository;
import com.mallangs.global.exception.ErrorCode;
import com.mallangs.global.exception.MallangsCustomException;
import com.mallangs.global.jwt.entity.CustomMemberDetails;
import com.mallangs.global.jwt.util.JWTUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.messaging.Message;
Expand Down
136 changes: 136 additions & 0 deletions src/main/resources/templates/chat.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>WebSocket Image Transfer Test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.5.2/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
}

.chat-container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
}

.messages {
border: 1px solid #ccc;
padding: 10px;
margin-bottom: 10px;
height: 300px;
overflow-y: auto;
background: #f9f9f9;
}

.input-container {
display: flex;
gap: 10px;
}

.input-container input {
flex-grow: 1;
padding: 8px;
}

.input-container button {
padding: 8px 15px;
background-color: #28a745;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}

.input-container button:hover {
background-color: #218838;
}

.image-preview img {
max-width: 100%;
max-height: 150px;
}
</style>
</head>
<body>
<div class="chat-container">
<h2>WebSocket Image Transfer Test</h2>

<div class="messages" id="messages">
<!-- Messages will be appended here -->
</div>

<div class="input-container">
<input type="text" id="messageInput" placeholder="Enter your message...">
<input type="file" id="imageInput">
<button onclick="sendMessage()">Send</button>
</div>

<div class="image-preview" id="imagePreview"></div>
</div>

<script>
let stompClient = null;

function connect() {
const socket = new SockJS('/ws-stomp'); // Your WebSocket endpoint
stompClient = Stomp.over(socket);

stompClient.connect({}, function () {
console.log('Connected to WebSocket');

// Subscribe to the chat topic
stompClient.subscribe('/sub/chat/room/test', function (messageOutput) {
const message = JSON.parse(messageOutput.body);
displayMessage(message);
});
});
}

function sendMessage() {
const messageInput = document.getElementById('messageInput');
const imageInput = document.getElementById('imageInput');
const file = imageInput.files[0];

let message = {
message: messageInput.value,
imageUrl: null
};

if (file) {
const reader = new FileReader();
reader.onload = function (e) {
message.imageUrl = e.target.result; // Base64 encoded image
stompClient.send('/pub/chat/send-message', {}, JSON.stringify(message));
};
reader.readAsDataURL(file);
} else {
stompClient.send('/pub/chat/send-message', {}, JSON.stringify(message));
}

messageInput.value = '';
imageInput.value = null;
}

function displayMessage(message) {
const messagesDiv = document.getElementById('messages');
const messageElement = document.createElement('div');

messageElement.innerHTML = `
<p><strong>Message:</strong> ${message.message}</p>
${message.imageUrl ? `<img src="${message.imageUrl}" alt="Image">` : ''}
<hr>
`;

messagesDiv.appendChild(messageElement);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}

// Connect on page load
connect();
</script>
</body>
</html>

0 comments on commit 3560c27

Please sign in to comment.