From bd74666e0ccce7d9cb0dd0abc640bf6c1a301042 Mon Sep 17 00:00:00 2001 From: Jungwoo Kim Date: Mon, 29 Jan 2024 19:19:01 +0900 Subject: [PATCH 1/7] =?UTF-8?q?conf:=20DynamoDB=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index a497710e..77aa6b4d 100644 --- a/build.gradle +++ b/build.gradle @@ -84,6 +84,10 @@ dependencies { // gson implementation 'com.google.code.gson:gson:2.9.0' + // dynamodb + implementation 'com.amazonaws:aws-java-sdk-s3:1.12.268' + implementation 'io.github.boostchicken:spring-data-dynamodb:5.2.5' + // test testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test' From 1819ae85c0a3d71291422f6038b84a02612966ff Mon Sep 17 00:00:00 2001 From: Jungwoo Kim Date: Mon, 29 Jan 2024 19:57:13 +0900 Subject: [PATCH 2/7] =?UTF-8?q?conf:=20DynamoDB=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=EC=97=90=20=EC=A0=91=EA=B7=BC=ED=95=A0=20=EC=88=98=20?= =?UTF-8?q?=EC=9E=88=EB=8F=84=EB=A1=9D=20=ED=95=98=EB=8A=94=20config=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../council/global/config/DynamoDBConfig.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/main/java/com/dku/council/global/config/DynamoDBConfig.java diff --git a/src/main/java/com/dku/council/global/config/DynamoDBConfig.java b/src/main/java/com/dku/council/global/config/DynamoDBConfig.java new file mode 100644 index 00000000..93a83f76 --- /dev/null +++ b/src/main/java/com/dku/council/global/config/DynamoDBConfig.java @@ -0,0 +1,67 @@ +package com.dku.council.global.config; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTypeConverter; +import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.stereotype.Repository; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; + +@Configuration +@EnableDynamoDBRepositories(basePackages = {"com.dku.council.domain.chatmessage.repository"}, + includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Repository.class)) +public class DynamoDBConfig { + + @Value("${aws.dynamodb.accessKey}") + private String awsAccessKey; + + @Value("${aws.dynamodb.secretKey}") + private String awsSecretKey; + + @Value("${aws.dynamodb.region}") + private String awsRegion; + + public AWSCredentials amazonAWSCredentials() { + return new BasicAWSCredentials(awsAccessKey, awsSecretKey); + } + + public AWSCredentialsProvider amazonAWSCredentialsProvider() { + return new AWSStaticCredentialsProvider(amazonAWSCredentials()); + } + + @Bean + public AmazonDynamoDB amazonDynamoDB() { + return AmazonDynamoDBClientBuilder.standard().withCredentials(amazonAWSCredentialsProvider()) + .withRegion(awsRegion).build(); + } + + /** + * Java DynamoDB SDK가 Java의 기본 Date 타입만 허용하므로 + * LocalDateTimeType과 Date를 상호 변환할 수 있는 컨버터 추가 + */ + public static class LocalDateTimeConverter implements DynamoDBTypeConverter { + @Override + public Date convert(LocalDateTime source) { + ZoneId seoulZoneId = ZoneId.of("Asia/Seoul"); + return Date.from(source.atZone(seoulZoneId).toInstant()); + } + + @Override + public LocalDateTime unconvert(Date source) { + return source.toInstant().atZone(ZoneId.of("Asia/Seoul")).toLocalDateTime(); + } + } + +} From 75614b63a76d647f145fef16447fafbf22488932 Mon Sep 17 00:00:00 2001 From: Jungwoo Kim Date: Mon, 29 Jan 2024 19:59:26 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20lombok=20setter=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=ED=95=B4=EC=A0=9C=20=EB=B0=8F=20DynamoDB=20?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Setter를 사용하는 것은 객체의 일관성을 유지하기 위해서 지양해야 합니다. 그러나 DynamoDB 공식 Docs에서도 Entity 구현 시 Setter 메소드를 필수적으로 사용합니다. DynamoDB Java SDK에서 DynamoDB를 편리하게 다루라고 제공하는 DynamoDBMapper가 객체 매핑 시 Setter를 사용하기 때문에, 해당 설정을 해제하는 선택을 하였습니다. DynamoDB쪽에서만 setter를 사용하도록 하겠습니다. --- lombok.config | 1 - .../chatmessage/model/ChatRoomMessageId.java | 24 ++++++++ .../model/entity/ChatRoomMessage.java | 61 +++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/dku/council/domain/chatmessage/model/ChatRoomMessageId.java create mode 100644 src/main/java/com/dku/council/domain/chatmessage/model/entity/ChatRoomMessage.java diff --git a/lombok.config b/lombok.config index 731b780d..bf221d0a 100644 --- a/lombok.config +++ b/lombok.config @@ -1,5 +1,4 @@ lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value lombok.copyableannotations += com.dku.council.global.config.webclient.ChromeAgentWebClient lombok.anyConstructor.addConstructorProperties = true -lombok.Setter.flagUsage = error lombok.data.flagUsage = error \ No newline at end of file diff --git a/src/main/java/com/dku/council/domain/chatmessage/model/ChatRoomMessageId.java b/src/main/java/com/dku/council/domain/chatmessage/model/ChatRoomMessageId.java new file mode 100644 index 00000000..63c08283 --- /dev/null +++ b/src/main/java/com/dku/council/domain/chatmessage/model/ChatRoomMessageId.java @@ -0,0 +1,24 @@ +package com.dku.council.domain.chatmessage.model; + +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBRangeKey; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTypeConverted; +import com.dku.council.global.config.DynamoDBConfig; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; +import java.time.LocalDateTime; + +@Getter +@Setter +public class ChatRoomMessageId implements Serializable { + private static final long serialVersionUID = 1L; + + @DynamoDBHashKey + private String roomId; + + @DynamoDBRangeKey + @DynamoDBTypeConverted(converter = DynamoDBConfig.LocalDateTimeConverter.class) + private LocalDateTime createdAt; +} diff --git a/src/main/java/com/dku/council/domain/chatmessage/model/entity/ChatRoomMessage.java b/src/main/java/com/dku/council/domain/chatmessage/model/entity/ChatRoomMessage.java new file mode 100644 index 00000000..e6f18d2c --- /dev/null +++ b/src/main/java/com/dku/council/domain/chatmessage/model/entity/ChatRoomMessage.java @@ -0,0 +1,61 @@ +package com.dku.council.domain.chatmessage.model.entity; + +import com.amazonaws.services.dynamodbv2.datamodeling.*; +import com.dku.council.domain.chatmessage.model.ChatRoomMessageId; +import com.dku.council.global.config.DynamoDBConfig; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.data.annotation.Id; + +import java.time.LocalDateTime; +@DynamoDBTable(tableName = "ChatRoomMessage") +@Getter +@Setter +@NoArgsConstructor() +public class ChatRoomMessage { + + @Id + @Getter(AccessLevel.NONE) + @Setter(AccessLevel.NONE) + private ChatRoomMessageId chatRoomMessageId; + + @DynamoDBHashKey(attributeName = "roomId") + public String getRoomId() { + return chatRoomMessageId != null ? chatRoomMessageId.getRoomId() : null; + } + + public void setRoomId(String roomId) { + if (chatRoomMessageId == null) { + chatRoomMessageId = new ChatRoomMessageId(); + } + chatRoomMessageId.setRoomId(roomId); + } + + @DynamoDBRangeKey(attributeName = "createdAt") + @DynamoDBTypeConverted(converter = DynamoDBConfig.LocalDateTimeConverter.class) + public LocalDateTime getCreatedAt() { + return chatRoomMessageId != null ? chatRoomMessageId.getCreatedAt() : null; + } + + @DynamoDBTypeConverted(converter = DynamoDBConfig.LocalDateTimeConverter.class) + public void setCreatedAt(LocalDateTime createdAt) { + if (chatRoomMessageId == null) { + chatRoomMessageId = new ChatRoomMessageId(); + } + chatRoomMessageId.setCreatedAt(createdAt); + } + + @DynamoDBAttribute + private String messageType; + + @DynamoDBAttribute + private Long userId; + + @DynamoDBAttribute + private String userNickname; + + @DynamoDBAttribute + private String content; +} \ No newline at end of file From a0a49da00cf15558ff84140a0ca457625624ae09 Mon Sep 17 00:00:00 2001 From: Jungwoo Kim Date: Mon, 29 Jan 2024 20:12:23 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=A0=80=EC=9E=A5,=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C,=20=EC=82=AD=EC=A0=9C=EC=97=90=20=EB=8C=80=ED=95=9C?= =?UTF-8?q?=20=EB=A6=AC=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20=EB=B0=8F=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ChatRoomMessageRepository.java | 17 +++++++ .../service/ChatRoomMessageService.java | 46 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/main/java/com/dku/council/domain/chatmessage/repository/ChatRoomMessageRepository.java create mode 100644 src/main/java/com/dku/council/domain/chatmessage/service/ChatRoomMessageService.java diff --git a/src/main/java/com/dku/council/domain/chatmessage/repository/ChatRoomMessageRepository.java b/src/main/java/com/dku/council/domain/chatmessage/repository/ChatRoomMessageRepository.java new file mode 100644 index 00000000..17d253ef --- /dev/null +++ b/src/main/java/com/dku/council/domain/chatmessage/repository/ChatRoomMessageRepository.java @@ -0,0 +1,17 @@ +package com.dku.council.domain.chatmessage.repository; + +import com.dku.council.domain.chatmessage.model.ChatRoomMessageId; +import com.dku.council.domain.chatmessage.model.entity.ChatRoomMessage; +import org.socialsignin.spring.data.dynamodb.repository.EnableScan; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@EnableScan +@Repository +public interface ChatRoomMessageRepository extends CrudRepository { + List findAllByRoomIdOrderByCreatedAtAsc(String roomId); + + void deleteAllByRoomId(String roomId); +} diff --git a/src/main/java/com/dku/council/domain/chatmessage/service/ChatRoomMessageService.java b/src/main/java/com/dku/council/domain/chatmessage/service/ChatRoomMessageService.java new file mode 100644 index 00000000..ceceb31f --- /dev/null +++ b/src/main/java/com/dku/council/domain/chatmessage/service/ChatRoomMessageService.java @@ -0,0 +1,46 @@ +package com.dku.council.domain.chatmessage.service; + +import com.dku.council.domain.chatmessage.model.entity.ChatRoomMessage; +import com.dku.council.domain.chatmessage.repository.ChatRoomMessageRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.List; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ChatRoomMessageService { + + private final ZoneId seoulZoneId = ZoneId.of("Asia/Seoul"); + + private final ChatRoomMessageRepository chatRoomMessageRepository; + + public void create(String roomId, + String messageType, + Long userId, + String userNickname, + String content) { + + ChatRoomMessage chatRoomMessage = new ChatRoomMessage(); + chatRoomMessage.setRoomId(roomId); + chatRoomMessage.setMessageType(messageType); + chatRoomMessage.setUserId(userId); + chatRoomMessage.setUserNickname(userNickname); + chatRoomMessage.setContent(content); + chatRoomMessage.setCreatedAt(LocalDateTime.now().atZone(seoulZoneId).toLocalDateTime()); + + chatRoomMessageRepository.save(chatRoomMessage); + } + + public List findAllChatRoomMessages(String roomId) { + return chatRoomMessageRepository.findAllByRoomIdOrderByCreatedAtAsc(roomId); + } + + public void deleteChatRoomMessages(String roomId) { + chatRoomMessageRepository.deleteAllByRoomId(roomId); + } +} From 992ea42f35b559c1209a9cf15141d09ee8b1d700 Mon Sep 17 00:00:00 2001 From: Jungwoo Kim Date: Mon, 29 Jan 2024 20:14:04 +0900 Subject: [PATCH 5/7] =?UTF-8?q?fix:=20=EC=B1=84=ED=8C=85=EC=9D=84=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20=EC=9C=A0=EC=A0=80=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/dto/response/ResponseUserInfoForChattingDto.java | 3 +-- .../java/com/dku/council/domain/user/service/UserService.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/dku/council/domain/user/model/dto/response/ResponseUserInfoForChattingDto.java b/src/main/java/com/dku/council/domain/user/model/dto/response/ResponseUserInfoForChattingDto.java index e3100098..0e24932d 100644 --- a/src/main/java/com/dku/council/domain/user/model/dto/response/ResponseUserInfoForChattingDto.java +++ b/src/main/java/com/dku/council/domain/user/model/dto/response/ResponseUserInfoForChattingDto.java @@ -6,8 +6,7 @@ @Getter @RequiredArgsConstructor public class ResponseUserInfoForChattingDto { - private final String studentId; - private final String username; + private final Long userId; private final String nickname; private final boolean isAdmin; } diff --git a/src/main/java/com/dku/council/domain/user/service/UserService.java b/src/main/java/com/dku/council/domain/user/service/UserService.java index 8eba9cde..7e42bdd2 100644 --- a/src/main/java/com/dku/council/domain/user/service/UserService.java +++ b/src/main/java/com/dku/council/domain/user/service/UserService.java @@ -120,6 +120,6 @@ public void isDkuChecked(Long userId) { public ResponseUserInfoForChattingDto getUserInfoForChatting(Long memberId) { User user = userRepository.findById(memberId).orElseThrow(UserNotFoundException::new); - return new ResponseUserInfoForChattingDto(user.getStudentId(), user.getName(), user.getNickname(), user.getUserRole().isAdmin()); + return new ResponseUserInfoForChattingDto(user.getId(), user.getNickname(), user.getUserRole().isAdmin()); } } From adf971736dc48821a3b0228d18b880346d3cbf2d Mon Sep 17 00:00:00 2001 From: Jungwoo Kim Date: Mon, 29 Jan 2024 20:16:41 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=EA=B4=80=EB=A6=AC=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20socket.js=20=EB=82=B4=EC=9A=A9=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EB=B0=8F=20html=20=EC=BD=94=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/static/js/chatroom/socket.js | 72 ++++++++++++++----- .../templates/page/chatting/chatroom.html | 3 +- .../templates/page/chatting/roomlist.html | 4 +- 3 files changed, 58 insertions(+), 21 deletions(-) diff --git a/src/main/resources/static/js/chatroom/socket.js b/src/main/resources/static/js/chatroom/socket.js index 3bc44feb..2c3cd27c 100644 --- a/src/main/resources/static/js/chatroom/socket.js +++ b/src/main/resources/static/js/chatroom/socket.js @@ -15,6 +15,7 @@ var connectingElement = document.querySelector('.connecting'); var stompClient = null; var username = null; +var userId = null; var colors = [ '#2196F3', '#32c787', '#00BCD4', '#ff5652', @@ -27,6 +28,7 @@ const roomId = url.get('roomId'); function connect(event) { username = document.querySelector('#name').value.trim(); + userId = document.querySelector('#userId').value.trim(); // chatPage 를 등장시킴 chatPage.classList.remove('hidden'); @@ -47,6 +49,8 @@ function onConnected() { // sub 할 url => /sub/chat/room/roomId 로 구독한다 stompClient.subscribe('/sub/chatRoom/enter' + roomId, onMessageReceived); + getPreviousMessageList(); + // 서버에 username 을 가진 유저가 들어왔다는 것을 알림 // /pub/chat/enterUser 로 메시지를 보냄 console.log("확인" + username); @@ -54,6 +58,7 @@ function onConnected() { {}, JSON.stringify({ "roomId": roomId, + "userId": userId, sender: username, type: 'ENTER' }) @@ -85,6 +90,32 @@ function getUserList() { }) } +function getPreviousMessageList() { + + $.ajax({ + type: "GET", + url: "/chat/message/list", + data: { + "roomId": roomId + }, + success: function (data) { + console.log("이전 메시지들 확인" + data); + for (let i = 0; i < data.length; i++) { + let previousChatMessage = { + "roomId": data[i]["roomId"], + "userId": data[i]["userId"], + sender: data[i]["userNickname"], + message: data[i]["content"], + type: data[i]["messageType"], + createdAt: data[i]["createdAt"] + }; + console.log(previousChatMessage); + previousMessageReceived(JSON.stringify(previousChatMessage)); + } + } + }) +} + function onError(error) { connectingElement.textContent = 'Could not connect to WebSocket server. Please refresh this page to try again!'; @@ -98,6 +129,7 @@ function sendMessage(event) { if (messageContent && stompClient) { var chatMessage = { "roomId": roomId, + "userId": userId, sender: username, message: messageInput.value, type: 'TALK' @@ -109,51 +141,55 @@ function sendMessage(event) { event.preventDefault(); } -// 메시지를 받을 때도 마찬가지로 JSON 타입으로 받으며, +// API를 통해 메시지를 받을 때도 마찬가지로 JSON 타입으로 받으며, // 넘어온 JSON 형식의 메시지를 parse 해서 사용한다. function onMessageReceived(payload) { - //console.log("payload 들어오냐? :"+payload); - var chat = JSON.parse(payload.body); + let chat = JSON.parse(payload.body); + let messageElement = document.createElement('li'); - var messageElement = document.createElement('li'); + addMessageToTheChatRoom(chat, messageElement); +} - if (chat.type === 'ENTER') { // chatType 이 enter 라면 아래 내용 - messageElement.classList.add('event-message'); - chat.content = chat.sender + chat.message; - getUserList(); +// 채팅방 입장 전에, 이전에 대화를 나눴던 메시지들을 보여주도록 처리하는 함수 +function previousMessageReceived(message) { + let chat = JSON.parse(message); + let messageElement = document.createElement('li'); + + addMessageToTheChatRoom(chat, messageElement); +} - } else if (chat.type === 'LEAVE') { // chatType 가 leave 라면 아래 내용 +function addMessageToTheChatRoom(chat, messageElement) { + if (chat.type === 'ENTER' || chat.type === 'LEAVE') { // chatType 이 enter 라면 아래 내용 messageElement.classList.add('event-message'); - chat.content = chat.sender + chat.message; getUserList(); } else { // chatType 이 talk 라면 아래 내용 messageElement.classList.add('chat-message'); - var avatarElement = document.createElement('i'); - var avatarText = document.createTextNode(chat.sender[0]); + let avatarElement = document.createElement('i'); + let avatarText = document.createTextNode(chat.sender[0]); avatarElement.appendChild(avatarText); avatarElement.style['background-color'] = getAvatarColor(chat.sender); messageElement.appendChild(avatarElement); - var usernameElement = document.createElement('span'); - var usernameText = document.createTextNode(chat.sender); + let usernameElement = document.createElement('span'); + let usernameText = document.createTextNode(chat.sender); usernameElement.appendChild(usernameText); messageElement.appendChild(usernameElement); } - var contentElement = document.createElement('p'); + let contentElement = document.createElement('p'); // 만약 s3DataUrl 의 값이 null 이 아니라면 => chat 내용이 파일 업로드와 관련된 내용이라면 // img 를 채팅에 보여주는 작업 if(chat.s3DataUrl != null){ - var imgElement = document.createElement('img'); + let imgElement = document.createElement('img'); imgElement.setAttribute("src", chat.s3DataUrl); imgElement.setAttribute("width", "300"); imgElement.setAttribute("height", "300"); - var downBtnElement = document.createElement('button'); + let downBtnElement = document.createElement('button'); downBtnElement.setAttribute("class", "btn fa fa-download"); downBtnElement.setAttribute("id", "downBtn"); downBtnElement.setAttribute("name", chat.fileName); @@ -166,7 +202,7 @@ function onMessageReceived(payload) { }else{ // 만약 s3DataUrl 의 값이 null 이라면 // 이전에 넘어온 채팅 내용 보여주기 - var messageText = document.createTextNode(chat.message); + let messageText = document.createTextNode(chat.message); contentElement.appendChild(messageText); } diff --git a/src/main/resources/templates/page/chatting/chatroom.html b/src/main/resources/templates/page/chatting/chatroom.html index 31c01d2d..9a3da25c 100644 --- a/src/main/resources/templates/page/chatting/chatroom.html +++ b/src/main/resources/templates/page/chatting/chatroom.html @@ -50,6 +50,7 @@

Sorry! Your browser doesn't support Javascript

+