디지털 컨버전스/Spring

[Spring Framework] WebChat - 익명채팅

gimyeondong 2020. 6. 12. 14:18

HTTP 프로토콜은 클라이언트가 요청하고 서버가 응답을 보내는게 기본

 

클라이언트가 req를 쓰면 다른 클라이언트에게 전달달

2번 클라이언트 입장에서는 req없이 서버에게 받는게 먼저

 

 

1. 원초적인 방법

각각의 클라이언트가 계속 리퀘스트를 쏘도록 함

submit, href 등으로 req 보내는 경우 페이지 전환 -> AJAX 활용

-> 서버 과부하

5초정도 딜레이를 준다면? 부하는 줄어들지만 사용이 불편


HTTP 말고 실시간으로 통신을 하기 위해

 socket을 활용

 

웹소캣 라이브러리 필요

		<!-- 웹소캣 라이브러리 추가 -->
		<dependency>
			<groupId>javax.websocket</groupId>
			<artifactId>javax.websocket-api</artifactId>
			<version>1.1</version>
		</dependency>

scope는 어디에 적용될지 정하는 태그 (dependency scope를 검색하면 설명 나온다)

생략하면 전체 적용

HTTP 프로토콜이 아닌 

WS (웹소캣)


읽는 순간 소캣 연결 요청

 

소캣 연결 요청 받는 위치

@OnOpen : 접속시 실행


웹소캣 프로토콜의 세션

import javax.websocket.Session;

Spring Bean이 아니기 떄문에 Autowired 못한다

 

 

client.getId() : 16진수 숫자

F5를 누를 때마다 페이지가 다시 로딩될때 웹소캣 새로 발급


<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script>
	$(function(){
		var ws = new WebSocket("ws://localhost/chat")
	})
</script>
<style>
.chat-box {
	width: 500px;
	height: 500px;
	float: left;
	position: absolute;
	margin: -250px 0 0 -250px;
	top: 50%;
	left: 50%;
}

.message-area {
	width: 100%;
	height: 90%;
	border: 1px solid #616161;
}

.input-area {
	width: 100%;
	height: 10%;
	border: 1px solid #616161;
}
</style>

</head>
<body>
	<div class="chat-box">
		<div class="message-area"></div>
		<div class="input-area" contenteditable="true"></div>
	</div>
</body>
</html>

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>

<style>
.chat-box {
	width: 500px;
	height: 500px;
	float: left;
	
}

.message-area {
	width: 100%;
	height: 90%;
	border: 1px solid #616161;
	overflow-y: auto;
	 word-break : break-all; 
}

.input-area {
	width: 100%;
	height: 10%;
	border: 1px solid #616161;
	overflow-y: auto;
}
</style>
<script>

function updateScroll(){
	var element = document.getElementById("message-area")
}
	$(function() {
		var ws = new WebSocket("ws://localhost/chat")

		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var msg = $(".input-area").html();
				var tr = $("<tr></tr");
				tr.append("<td>글쓴이 : " + msg);
				$(".message-area").append(tr);
				$(".input-area").html("");


			}
		})


	})
</script>
</head>
<body>
	<div class="chat-box">
		<div class="message-area"></div>
		<div class="input-area" contenteditable="true"></div>
	</div>
</body>
</html>

updateScroll 함수로 만들어 호출하는건 실패고 제이쿼리로 안에 넣은것 동작? 왜?


	$(function() {
		var ws = new WebSocket("ws://localhost/chat")

		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var text = $(".input-area").html();
				var line = $("<div>");
				line.append("글쓴이 : " + text);
				$(".message-area").append(line);
				$(".input-area").html("");
				
				ws.send(text);
				
				updateScroll();
				return false;
			}
		})

	})

 

@OnMessage

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>

<style>
.chat-box {
	width: 500px;
	height: 500px;
	float: left;
}

.message-area {
	width: 100%;
	height: 90%;
	border: 1px solid #616161;
	overflow-y: auto;
	word-break: break-all;
}

.input-area {
	width: 100%;
	height: 10%;
	border: 1px solid #616161;
	overflow-y: auto;
}
</style>
<script>

	
	$(function() {
		var ws = new WebSocket("ws://localhost/chat")

		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var text = $(".input-area").html();
				var line = $("<div>");
				line.append("글쓴이 : " + text);
				$(".message-area").append(line);
				$(".input-area").html("");
				
				ws.send(text);
				
				$('.message-area').scrollTop($('.message-area')[0].scrollHeight);
				return false;
			}
		})

	})
</script>
</head>
<body>
	<div class="chat-box">
		<div class="message-area"></div>
		<div class="input-area" contenteditable="true"></div>
	</div>
</body>
</html>

package kh.spring.chat;

import java.io.IOException;

import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/chat")
public class WebChat {

	@OnOpen
	public void onConnect(Session client) {
		System.out.println(client.getId()+" 클라이언트가 접속했습니다.");
	}
	
	@OnMessage
	public void onMessage(Session session, String message) {
		
//		System.out.println(session.getId()+" : "+message);
		
		Basic client = session.getBasicRemote();
		try {
			client.sendText(message);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		
	}
	
}

말한 그대로 돌아옴 : 에코

 

내가 아니라 상대방에서 보내야 함!

 

 


 

클라이언트들의 접속 정보가 서버의 램에는 저장되지만 제어할 수 있는 정보는 모름

 

매개변수로 받고 매서드가 끝나면 사라짐

정보를 저장해 놔야함

몇명이 들어올지 모르기 때문에 배열은 부적절

 

세션아이디는 중복되서는 안된다 -> set으로 중복 방지

 

모든 사용자가 공유할 수 있도록 Set<Session> clients에  static을 줘야함

package kh.spring.chat;

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

import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/chat")
public class WebChat {

	private static Set<Session> clients = new HashSet<>();
	
	@OnOpen
	public void onConnect(Session client) {
		System.out.println(client.getId()+" 클라이언트가 접속했습니다.");
		clients.add(client);
	}
	
	@OnMessage
	public void onMessage(Session session, String message) {
		for(Session client : clients) {
			Basic basic = client.getBasicRemote();
			try {
				basic.sendText(message);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}	
	}
}


<script>

	
	$(function() {
		var ws = new WebSocket("ws://localhost/chat")
		
		ws.onmessage = function(e){
			console.log(e.data);
			var line = $("<div>");
			line.append(e.data);
			$(".message-area").append(line);
		}

		
		
		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var text = $(".input-area").html();
				var line = $("<div>");
				line.append("글쓴이 : " + text);
				$(".message-area").append(line);
				$(".input-area").html("");
				
				ws.send(text);
				
				$('.message-area').scrollTop($('.message-area')[0].scrollHeight);
				return false;
			}
		})

	})
</script>

 

내가 친 채팅과 출력되는 채팅이 중복 되는 경우, 하나만 출력되도록 하기

	@OnMessage
	public void onMessage(Session session, String message) {
		for(Session client : clients) {

			if(!client.getId().contentEquals(session.getId())) {

				Basic basic = client.getBasicRemote();
				try {
					basic.sendText(message);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}


	}

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>

<style>
.chat-box {
	width: 500px;
	height: 500px;
	float: left;
}

.message-area {
	width: 100%;
	height: 90%;
	border: 1px solid #616161;
	overflow-y: auto;
	word-break: break-all;
}

.input-area {
	width: 100%;
	height: 10%;
	border: 1px solid #616161;
	overflow-y: auto;
}
</style>
<script>

	
	$(function() {
		var ws = new WebSocket("ws://localhost/chat")
		
		ws.onmessage = function(e){
			console.log(e.data);
			var line = $("<div>");
			line.append(e.data);
			$(".message-area").append(line);
		}

		
		
		$(".input-area").on("keydown", function(e) {
			if (e.keyCode == 13) {

				e.preventDefault();
				var text = $(".input-area").html();
				var line = $("<div>");
				line.append("글쓴이 : " + text);
				$(".message-area").append(line);
				$(".input-area").html("");
				
				ws.send(text);
				
				$('.message-area').scrollTop($('.message-area')[0].scrollHeight);
				return false;
			}
		})

	})
</script>
</head>
<body>
	<div class="chat-box">
		<div class="message-area"></div>
		<div class="input-area" contenteditable="true"></div>
	</div>
</body>
</html>
package kh.spring.chat;

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

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint.Basic;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/chat")
public class WebChat {

	private static Set<Session> clients = new HashSet<>();

	@OnOpen
	public void onConnect(Session client) {
		System.out.println(client.getId()+" 클라이언트가 접속했습니다.");
		clients.add(client);
	}

	@OnMessage
	public void onMessage(Session session, String message) {
		for(Session client : clients) {

			if(!client.getId().contentEquals(session.getId())) {

				Basic basic = client.getBasicRemote();
				try {
					basic.sendText(message);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}


	}

	@OnClose
	public void onClose(Session session) {
		clients.remove(session);
	}
}
더보기

 


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Home</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>

<style>
* {
	box-sizing: border-box;
}

.chat-box {
	width: 400px;
	height: 500px;
	margin: 100px auto;
	border: 1px solid #c9d8de;
	position: relative;
}

.message-area {
	padding: 20px;
	min-height: 400px;
	overflow-y: auto;
	background: #f0f9fd;
	width: 100%;
	height: 80%;
	word-wrap: break-word;
	word-break: break-all;
}

.input-area {
	width: 100%;
	height: 100px;
	overflow: auto;
}
</style>
<script>
		function updateScroll() {
			var element = document.getElementById("message-area");
			element.scrollTop = element.scrollHeight;
		}

		$(function() {
			
			var ws = new WebSocket("ws://175.125.124.73:11111//chat");
			ws.onmessage = function(e){
				var line = $("<div>");
				line.append(e.data);
				$(".message-area").append(line);
				updateScroll();
			}
			
			$(".input-area").on("keydown", function(e) {
				if (e.keyCode == 13) {
					
					if($(".input-area").html()=="" || $(".input-area").html()==" "){
						alert("글을 입력하세요.");
					}else {
					var text = $(".input-area").html();
					var line = $("<div>");
					line.append(text);
					$(".message-area").append(line);
					$(".input-area").html("");
					ws.send(text);
					updateScroll();
					return false;
				}
			}
			});

			

		});
	</script>


</head>
<body>
	<div class="chat-box">
		<div id="message-area" class="message-area"></div>
		<div id="input-area" class="input-area" contenteditable="true"></div>
	</div>

</body>
</html>