STOMP가 뭔지는 다른 블로그에서도 잘 설명하고 있으니...그냥 바로 코드로..다른 블로그를 참고했는데...링크는 맨 아래에 올려놓을게요
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>stomp</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>stomp</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.example.stomp.config;
import lombok.RequiredArgsConstructor;
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
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
//클라이언트로 메세지를 응답 해 줄 때 prefix 정의 - 클라이언트가 메세지를 받을 때
registry.enableSimpleBroker("/sub"); //ex) stomp.subscribe("/sub/chat/room/",function(){})
//클라이언트에서 메세지 송신 시 붙일 prefix 정의 - 클라이언트가 메세지를 보낼때
registry.setApplicationDestinationPrefixes("/pub"); //ex) stomp.send("/sub/chat/room/",function(){})
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//the url is for Websocket handshake
registry.addEndpoint("/stomp/chat") //handshake가 될 endpoint지정
.setAllowedOrigins("*") //현재 구동되고 있는 서버와 다른 도메인에서도 접근 가능하게
.withSockJS(); //SockJS사용
}
}
package com.example.stomp.vo;
import lombok.Data;
import org.springframework.web.socket.WebSocketSession;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Data
public class ChatRoom {
private String roomId;
private String name;
private Set<WebSocketSession> sessions = new HashSet<>();
public static ChatRoom createChatRoom (String name) {
ChatRoom chatRoom = new ChatRoom();
chatRoom.roomId = UUID.randomUUID().toString();
chatRoom.name = name;
return chatRoom;
}
}
package com.example.stomp.vo;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ChatMessage {
private String roomId;
private String writer;
private String message;
}
package com.example.stomp.controller;
import com.example.stomp.repository.ChatRoomRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
@Controller
@RequiredArgsConstructor
@RequestMapping("/chat")
public class ChatRoomController {
private final ChatRoomRepository chatRoomRepository;
//채팅방 목록 조회
@GetMapping(value = "/rooms")
public ModelAndView rooms(){
ModelAndView mv = new ModelAndView("chat/rooms");
mv.addObject("list", chatRoomRepository.findAllRooms());
return mv;
}
//채팅방 개설
@PostMapping(value = "/room")
public String create(@RequestParam String name, RedirectAttributes rttr){
rttr.addFlashAttribute("roomName", chatRoomRepository.createChatRoom(name));
return "redirect:/chat/rooms";
}
//채팅방 조회
@GetMapping("/room")
public ModelAndView getRoom(@RequestParam(value = "roomId") String roomId){
ModelAndView mv = new ModelAndView("chat/room");
mv.addObject("room", chatRoomRepository.findByRoomId(roomId));
return mv;
}
}
package com.example.stomp.controller;
import com.example.stomp.vo.ChatMessage;
import lombok.RequiredArgsConstructor;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
@Controller
@RequiredArgsConstructor
public class StompChatClient {
private final SimpMessagingTemplate messagingTemplate;
@MessageMapping(value = "/chat/enter")
public void enter(ChatMessage chatMessage) {
System.out.println("연결성공");
chatMessage.setMessage(chatMessage.getWriter() + "님이 채팅방에 참여하셨습니다.");
messagingTemplate.convertAndSend("/sub/chat/room/" + chatMessage.getRoomId(), chatMessage);
}
@MessageMapping(value = "/chat/message")
public void message(ChatMessage chatMessage) {
messagingTemplate.convertAndSend("/sub/chat/room/"+chatMessage.getRoomId(),chatMessage);
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<script src="https://code.jquery.com/jquery-2.2.1.min.js"></script>
</head>
<body>
<div class="container">
<div>
<ul th:each="room : ${list}">
<li><a th:href="@{/chat/room(roomId=${room.roomId})}">[[${room.name}]]</a></li>
</ul>
</div>
</div>
<form th:action="@{/chat/room}" method="post">
<input type="text" name="name" class="form-control">
<button class="btn btn-secondary">개설하기</button>
</form>
</body>
<script th:inline="javascript">
$(document).ready(function(){
var roomName = /*[[${roomName}]]*/;
if(roomName != null)
alert( roomName.name+ "방이 개설되었습니다.");
$(".btn-create").on("click", function (e){
e.preventDefault();
var name = $("input[name='name']").val();
if(name == "")
alert("Please write the name.")
else
$("form").submit();
});
});
</script>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<!-- 합쳐지고 최소화된 최신 CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<!-- 부가적인 테마 -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css">
<!-- 합쳐지고 최소화된 최신 자바스크립트 -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
</head>
<body>
<div class="container">
<div class="col-6">
<h1>[[${room.name}]]</h1>
</div>
<div>
<div id="msgArea" class="col"></div>
<div class="col-6">
<div class="input-group mb-3">
<input type="text" id="msg" class="form-control">
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" id="button-send">전송</button>
</div>
</div>
</div>
</div>
<div class="col-6"></div>
</div>
</body>
<script th:inline="javascript">
/*<![CDATA[*/
$(document).ready(function(){
var roomName = /*[[${room.name}]]*/;
var roomId = /*[[${room.roomId}]]*/;
var username = prompt("what's your name?");
console.log(roomName + ", " + roomId + ", " + username);
var sockJs = new SockJS("/stomp/chat");
//1. SockJS를 내부에 들고있는 stomp를 내어줌
var stomp = Stomp.over(sockJs);
//2. connection이 맺어지면 실행
stomp.connect({}, function (){
console.log("STOMP Connection")
//4. subscribe(path, callback)으로 메세지를 받을 수 있음
stomp.subscribe("/sub/chat/room/" + roomId, function (chat) {
var content = JSON.parse(chat.body);
var writer = content.writer;
var message = content.message;
var str = '';
if(writer === username){
str = "<div class='col-6'>";
str += "<div class='alert alert-secondary'>";
str += "<b>" + writer + " : " + message + "</b>";
str += "</div></div>";
}
else{
str = "<div class='col-6'>";
str += "<div class='alert alert-warning'>";
str += "<b>" + writer + " : " + message + "</b>";
str += "</div></div>";
}
$("#msgArea").append(str);
});
//3. send(path, header, message)로 메세지를 보낼 수 있음
stomp.send('/pub/chat/enter', {}, JSON.stringify({roomId: roomId, writer: username}))
});
$("#button-send").on("click", function(e){
var msg = document.getElementById("msg");
console.log(username + ":" + msg.value);
stomp.send('/pub/chat/message', {}, JSON.stringify({roomId: roomId, message: msg.value, writer: username}));
msg.value = '';
});
});
/*]]>*/
</script>
</html>