🌀 스프링 소켓이란?

Spring Socket는 Spring Framework에서 제공하는 WebSocket 프로토콜을 지원하는 기능이다. 실시간 양방향 통신을 위한 프로토콜로, 서버와 클라이언트 간에 지속적인 연결을 유지하고 데이터를 실시간으로 주고받을 수 있게 해준다.

 


 

스프링에서 소켓을 다루기 전 JSP 에서 소켓을 만들어본다.

JSP 에서 작업함.

 

지난 시간 서버 측 작성

 

ChatServer.java - 서버

package websocket;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/ChatingServer") // 서버명
public class ChatServer {
	
	private static Set<Session> clients = Collections.synchronizedSet(new HashSet<Session>());

	@OnOpen   // 클라이언트 접속 시 실행
	public void onOpen(Session session) {
		clients.add(session);
		System.out.println("웹소켓 연결 :" + session.getId());
	}
	
	@OnMessage // 메세지를 받으면 실행
	public void onOMessgae(String message,Session session) throws IOException {
		System.out.println("메시지 전송 : " + session.getId() + ":" + message);
		synchronized(clients) {  
			for(Session client : clients) {  //모든 클라이언트에게 메세지 전달
				if(!clients.equals(session)) {
					client.getBasicRemote().sendText(message);				}
			}
		}
	}
	
	@OnClose // 클라이언트와 연결의 끊기면 실행
	public void onClose(Session session) {
		clients.remove(session);
		System.out.println("웹소켓 종료 :" + session.getId());
	}
	
	@OnError // 에레 발생 시 실행
	public void onError(Throwable e) {
		System.out.println("에러 발생");
		e.printStackTrace();
	}
	
}

 

web.xml 에서 

<!-- 웹소켓 채팅 서버 -->
  <context-param>
    <param-name>CHAT_ADDR</param-name>
    <param-value>http://localhost:9999/WebSocketProject</param-value>
  </context-param>

위 정보를 추가해줘야 한다.

 

추가된 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>FristJsp</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    <welcome-file>default.htm</welcome-file>
  </welcome-file-list>
  
  <context-param>
    <param-name>INIT_PARAM</param-name>
    <param-value>web.xl에 저장한 초기화 매개 변수</param-value>
  </context-param>
  
<!-- 오라클 설정 정보 -->
<!-- 지금 우리는 드라이버 정보를 초기화 시켜놓았다. 코드에 노출 시키지 않았으며, 앞으로도 이 방법을 쓸 것이다. -->
  <context-param>
    <param-name>OracleDriver</param-name>
    <param-value>oracle.jdbc.driver.OracleDriver</param-value>
  </context-param>
  
    <context-param>
    <param-name>OracleURL</param-name>
    <param-value>jdbc:oracle:thin:@localhost:1522:orcl1</param-value>
  </context-param>
  
    <context-param>
    <param-name>OracleId</param-name>
    <param-value>musthave</param-value>
  </context-param>
  
    <context-param>
    <param-name>OraclePwd</param-name>
    <param-value>1234</param-value>
  </context-param>
  
  
  <!-- 머스트 해브 -->

<!--     <context-param>
    <param-name>OracleId2</param-name>
    <param-value>musthave</param-value>
  </context-param> -->
  
  <!-- 페이징 정보 -->
    <context-param>
    <param-name>POSTS_PER_PAGE</param-name>
    <param-value>10</param-value>
  </context-param>
  <!-- 한 페이지에 출력할 갯수 -->
  
    <context-param>
    <param-name>PAGES_PER_BLOCK</param-name>
    <param-value>5</param-value>
  </context-param>
  <!-- 페이지 목록의 수 -->
  
<!-- 첨부 파일 최대 용량 설정(예제 14-8) -->
  <context-param>
    <param-name>maxPostSize</param-name>
    <param-value>1024000</param-value>
  </context-param>
  
<!-- 웹소켓 채팅 서버 -->
  <context-param>
    <param-name>CHAT_ADDR</param-name>
    <param-value>http://localhost:9999/WebSocketProject</param-value>
  </context-param>
  
  
  
  <filter>
    <filter-name>SetCharEncoding</filter-name>
    <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
      <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
      </init-param>
  </filter>
  <filter-mapping>
    <filter-name>SetCharEncoding</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  
  
</web-app>

 

 

 

 

웹소켓으로 채팅 구현 시 사용하는 5가지 어노테이션

 

@ServerEndpoint

@OnOpen

@OnMessage

@OnClose

@OnError

 

 💡 웹소켓 주소 구성 : ws://호스트명:포드번호/컨텍스트(프로젝트명)/서버명 ws://http://localhost:9999/WebSocketProject/WEB-INF/classes/websocket/ChatServer.java

 

MutiChatMain.jsp - 실행시킬 화면

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script>
	function chatWinOpen() {
		let id = document.getElementById("chatId");
		if (id.value == "") {
			alert("대화명을 입력 후 채팅창을 열어주세요");
			id.focus();
			return;
		}

		window.open("ChatWindow.jsp?chatId=" + id.value, "",
				"width=350, height=400");
		id.value = "";
	}
</script>
</head>
<body>
	<h2>웹소켓 채팅 - 대화명 적용해서 채팅창 띄워주기</h2>
	대화명 :
	<input type="text" id="chatId" />
	<button onclick="chatWinOpen();">채팅 참여</button>
</body>
</html>

 

ChatWindow.jsp - 채팅 화면이 보여지는 곳

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
// 서버에 접속
let webSocket = new WebSocket("<%=application.getInitParameter("CHAT_ADDR")%>/ChatingServer");

	// 필요한 값 가지고 오기
	window.onload = function() {
		chatWindow = document.getElementById("chatWindow");
		chatMessage = document.getElementById("chatMessage");
		chatId = document.getElementById("chatId").value;
	}
	
	// 소켓 끊기
	function disconnect(){
		webSocket.close();
	}
	
	//메세지 전송
	function sendMessage() {
		chatWindow.innerHTML += "<div class='myMsg'>" + chatMessage.value + "</div>";
		webSocket.send(chatId + '|' + chatMessage.value);
		chatMessage.value = "";
		// 메세지가 많아지면 스크롤처리
		chatWindow.scrollTop = chatWindow.scrollHeight;
	}
	
	function enterKey() {
		if (window.event.keyCode == 13){
			sendMessage();
		}
	}

	// 소켓이 서버로 가서 동작하는 메소드
	// 웹소켓이 서버에 연결되면 실행, 이 속성의 함수는 자동으로 실행
	webSocket.onopen = function(event) {
		chatWindow.innerHTML += "웹소켓 서버에 연결되었습니다.<br/>";
	}
	
	webSocket.onclose = function(event){
		 chatWindow.innerHTML += "웹소켓 서버가 종료되었습니다.<br/>";
	}

	webSocket.onmessage = function(event){
		// message를 배열 형식으로 받는다
		let message = event.data.split("|");
		let sender = message[0];
		let content = message[1];
		
		if (content != null) {
			chatWindow.innerHTML += "<div>" + sender + ":" + content + "</div>";
		}
		// 메세지가 많아지면 스크롤처리
		chatWindow.scrollTop = chatWindow.scrollHeight;
	}
	
</script>

<style type="text/css">
#chatWindow {
	border: 1px solid black;
	width: 270px;
	height: 310px;
	overflow: scroll;
	padding: 5px;
}

#chatMessage {
	width: 236px;
	height: 30px;
}

#sendBtn {
	height: 30px;
	position: relative;
	top: 2px;
	left: -2px;
}

#closeBtn {
	margin-bottom: 3px;
	position: relative;
	top: 2px;
	left: -2px;
}

#chatId {
	width: 158px;
	height: 24px;
	border: 1px solid #AAAAAA;
	background-color: #EEEEEE;
}

.myMsg {
	text-align: right;
}
</style>
</head>
<body>
	<!-- 나의 아이디를 묶어 보내야 한다 chatId,chatWindow,chatMessage 사용 -->
	대화명 :
	<input type="text" id="chatId" value="${param.chatId }" readonly>
	<button id="closeBtn" onclick="disconnect();">채팅 종료</button>

	<!-- 채팅이 표시되는 공간 -->
	<div id="chatWindow"></div>
	<div>
		<input type="text" id="chatMessage" onkeyup="enterKey();" />
		<button id="sendBtn" onclick="sendMessage()">전송</button>
	</div>
</body>
</html>

창을 여러 개 띄워 메세지를 주고 받을 수 있다.

 

윈도우는 터미널에서 ipconfig를 치면 본인의 ip 주소를 확인할 수 있다.

서버는 ip주소를 뿌리고 클라이언트는 서버의 ip 주소를 받으면 클라이언트끼리 채팅이 가능하다.

 

 

추가로 실험해본 채팅창의 색을 바꾸기(색 전송하기) 반 성공..

 

ChatWindow.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
// 서버에 접속
let webSocket = new WebSocket("<%=application.getInitParameter("CHAT_ADDR")%>/ChatingServer");

	// 필요한 값 가지고 오기
	window.onload = function() {
		chatWindow = document.getElementById("chatWindow");
		chatMessage = document.getElementById("chatMessage");
		chatId = document.getElementById("chatId").value;
	}
	
	// 소켓 끊기
	function disconnect(){
		webSocket.close();
	}
	
	//메세지 전송
	function sendMessage() {
		chatWindow.innerHTML += "<div class='myMsg'>" + chatMessage.value + "</div>";
		webSocket.send(chatcolor + chatId + '|' + chatMessage.value);
		chatMessage.value = "";
		// 메세지가 많아지면 스크롤처리
		chatWindow.scrollTop = chatWindow.scrollHeight;
	}
	
	function enterKey() {
		if (window.event.keyCode == 13){
			sendMessage();
		}
	}
	
	function changeColor() {
		let color = "tomato";
		webSocket.send("colorChange|" + color);
	}

	// 소켓이 서버로 가서 동작하는 메소드
	// 웹소켓이 서버에 연결되면 실행, 이 속성의 함수는 자동으로 실행
	webSocket.onopen = function(event) {
		chatWindow.innerHTML += "웹소켓 서버에 연결되었습니다.<br/>";
	}
	
	webSocket.onclose = function(event){
		 chatWindow.innerHTML += "웹소켓 서버가 종료되었습니다.<br/>";
	}

	webSocket.onmessage = function(event){
		// message를 배열 형식으로 받는다
		let message = event.data.split("|");
		let sender = message[0];
		let content = message[1];
		
		if (messageType === "colorChange") {
			chatWindow.style.backgroundColor = content;
		} else if (content != null) {
			chatWindow.innerHTML += "<div>" + sender + ":" + content + "</div>";
		}
		// 메세지가 많아지면 스크롤처리
		chatWindow.scrollTop = chatWindow.scrollHeight;
	}
	
	
</script>

<style type="text/css">
#chatWindow {
	border: 1px solid black;
	width: 270px;
	height: 310px;
	overflow: scroll;
	padding: 5px;
}

#chatMessage {
	width: 236px;
	height: 30px;
}

#sendBtn {
	height: 30px;
	position: relative;
	top: 2px;
	left: -2px;
}

#closeBtn {
	margin-bottom: 3px;
	position: relative;
	top: 2px;
	left: -2px;
}

#chatId {
	width: 158px;
	height: 24px;
	border: 1px solid #AAAAAA;
	background-color: #EEEEEE;
}

.myMsg {
	text-align: right;
}
</style>
</head>
<body>
	<!-- 나의 아이디를 묶어 보내야 한다 chatId,chatWindow,chatMessage 사용 -->
	대화명 :
	<input type="text" id="chatId" value="${param.chatId }" readonly>
	<button id="closeBtn" onclick="disconnect();">채팅 종료</button>

	<!-- 채팅이 표시되는 공간 -->
	<div id="chatWindow"></div>
	<div>
		<input type="text" id="chatMessage" onkeyup="enterKey();" />
		<button id="sendBtn" onclick="sendMessage()">전송</button>
		<button id="colorBtn" onclick="changeColor();">토마토</button>
	</div>
</body>
</html>

문제는 내 채팅창에 색은 바뀌지 않는다..

 

 


 

다시 스프링으로 넘어온다.

본격적으로 스프링 프레임 워크 사용해보기

 

 

스프링에서 오류가 났을 때 이런 메세지를 볼 수 있는데

💡 java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/action-servlet.xml]

이건 action-servlet.xml 이라는 파일을 찾는다는 뜻이다.

 

action-servlet.xml는 핸들러, 컨트롤러, 뷰리저버 정보를 가지고 있는 파일이다.

 

 

property ⇒ 맵 구조

(모든 객체의 구조 알아보기)

 

최종적인 파일 구조

+ Recent posts