[Spring Framework] WebChat - 익명채팅
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>
$(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>