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;
	}
}

 

 

잘됨 흑흑 ㅠ