CLASS/SPRINGBOOT
#5-1 / websocket 통신...
hingu
2024. 9. 26. 11:36
socket
Front ( 가 어려움... ㅎ ), Back
new Websocket : 소켓 라이브러리를 인스턴스로 신규 오픈
=> socket.io 대체 가능 (양방향 통신을 사용하는 서버를 구축하는 형태 )
Client(1) <=> Client(2) ===> 이 2개가 socket.io에 접속 => connect() => back으로 전송 => back에서 각 Client로 return
터미널로 실행..;;; (node.js에 npm으로 설치해야함)
👀 타이틀
dependencies {
//socket - 요거 추가
implementation 'org.springframework.boot:spring-boot-starter-websocket'
}
- index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello WebSocket</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<!-- socket을 핸들링하는 엔진(CDN) - TCP -->
<script src="https://cdn.jsdelivr.net/npm/@stomp/stompjs@7.0.0/bundles/stomp.umd.min.js"></script>
<script src="./chat.js?v=1"></script>
</head>
<body>
<div id="main-content" class="container">
<div class="row">
<div class="col-md-6">
<!-- socket 연결 및 해제 form 형태 -->
<form class="form-inline">
<div class="form-group">
<label for="connect">웹소켓 연결:</label>
<button id="connect" class="btn btn-default" type="submit">채팅연결</button>
<button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">채팅종료
</button>
</div>
</form>
</div>
<div class="col-md-6">
<!-- 메세지를 전송하는 form -->
<form class="form-inline">
<div class="form-group">
<label for="name">고객명</label>
<input type="text" name="name" id="name" class="form-control" placeholder="사용자 이름을 입력하세요..."><br>
<label for="name">메세지명</label>
<input type="text" name="msg" id="msg" class="form-control" placeholder="메세지를 입력하세요...">
</div>
<button id="send" class="btn btn-default" type="submit">보내기</button>
</form>
</div>
</div>
<div class="row">
<div class="col-md-12">
<table id="conversation" class="table table-striped">
<thead>
<tr>
<th>내용출력</th>
</tr>
</thead>
<tbody id="greetings">
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
- chat.js
var host = window.location.host;
//가상의 TCP socket 오픈 및 연결 (Back과 연결) - 신규포트 생성x 가상으로 사용
var chat = new StompJs.Client({
brokerURL : "ws://"+host+"/se-websocket"
})
//socket 연결 실패 발생시 사용되는 함수
chat.onWebSocketError = function(error){
console.log("소켓 서버 연결 실패!!" + error)
}
//메세지를 주고 받는 구조가 잘못 되었을 경우
chat.onStompError = function(error){
console.log("메세지를 주고 받는 구조가 잘못 되었을 경우" + error.body)
}
chat.onConnect = function(z){
setConnect(true); //socket.open 형태와 동일한 형태
console.log("연결 정보 확인 :" + z);
//chat room 생성하는 역할
//fetch와 비슷한 성격을 가짐
chat.subscribe('/room/greetings',function(z){
console.log(z)
showGreeting(JSON.parse(z.body).content);
})
}
function showGreeting(msg){
console.log(msg)
$("#greetings").append("<tr><td>"+ msg +"</td></tr>");
}
//메세지를 주고 받는 가상의 back 경로 (API 경로)
//JSON 배열화 하여 back-end에게 전달
function sends(){
chat.publish({
destination : "/app/conchat", //메세지를 주고 받는 API경로
body : JSON.stringify({
'name':$("#name").val(),
'msg':$("#msg").val()
})
});
}
function setConnect(c){
$("#connect").prop("disabled",c);
$("#disconnect").prop("disabled",!c);
if(c){
$("#conversation").show();
}else{
$("#conversation").hide();
}
$("#greeting").html("");
}
function connect(){
chat.activate(); //연결 StompJs 함수
}
function disconnect(){
chat.deactivate(); //연결해제 StompJs 함수
setConnect(false)
console.log("socket 서버 종료!!")
}
//jquery
$(function(){
$("form").on("submit",(e) => e.preventDefault()); //전송 안되게 막음
$("#connect").click(() => connect()); //연결 함수 호출
$("#disconnect").click(() => disconnect()); //연결 해제 함수 호출
//메세지 전송 버튼 역할
$("#send").click(function(){ //화살표로 써두 대궁 이걸로 써두 대궁ㅎ
sends();
})
})
- websocketConfig.java : 환경설정 class ( stomp에서 사용할 수 있는 소켓 URL )
package kr.co.sen.socket;
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;
//stomp에서 사용할 수 있는 소켓 URL
@Configuration //환경설정 anotation
@EnableWebSocketMessageBroker
public class websocketConfig implements WebSocketMessageBrokerConfigurer{
//ws 주소를 셋팅하는 메소드
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("se-websocket");
}
//소켓 room 생성하는 메소드
@Override
public void configureMessageBroker(MessageBrokerRegistry reg) {
reg.enableSimpleBroker("/room");
reg.setApplicationDestinationPrefixes("/app");
//가상의 주고받는 application prefix (아무거나써도됨ㅎ , 단 실제 디렉토리가 존재해선 안됨)
// 가상의 메세지가 도착하는 경로 /app/conchat
}
}
- socketController.java
package kr.co.sen.socket;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.util.HtmlUtils;
@Controller
public class SocketController {
//메세지를 보내는 역할
@CrossOrigin(origins="*", allowedHeaders = "*")
@MessageMapping("/conchat") //메세지를 받는 API
@SendTo("/room/greetings") //socket API
public Greeting greeting(chatDTO dto) throws Exception{
Thread.sleep(1000); //동기화 - 연결이 안된 상태에서 메세지 날아감 방지
//htmlEscape : print write처럼 찍어주는거ㅎ
String mid = HtmlUtils.htmlEscape(dto.getName());
String msg = HtmlUtils.htmlEscape(dto.getMsg());
System.out.println(mid + ":" + msg);
//해당 socket room에 접속한 모든 사용자에게 메세지를 전송
return new Greeting(mid + " : " + msg);
}
}
- Greeting.java - 주고받는애 (socket room이름에 대한 연결정보를 setter,getter)
package kr.co.sen.socket;
//socket room이름에 대한 연결정보를 setter,getter
public class Greeting {
private String content;
public Greeting(String content) { //setter 역할 (즉시실행)
this.content = content;
}
public String getContent() { //getter
return content;
}
}
- chatDTO.java - 채팅에 참여하는 사용자 이름 및 메세지를 주고받는 역할 ( front -> back -> front )
package kr.co.sen.socket;
import lombok.Data;
//채팅에 참여하는 사용자 이름 및 메세지를 주고받는 역할
@Data
public class chatDTO {
private String name; //이름
private String msg; //메세지
public chatDTO() {
}
public chatDTO(String name,String msg) {
this.name = name;
this.msg = msg;
}
}