웹소켓 세션 Channel(room)을 이용해서 개인간 통신이 아닌 channel에 등록되어 있는 멤버들끼리의 통신을 해보기로 한다.

필자는 일단 handler에서 모든걸 구현했다

다시 클래스를 나눠서 구현해보자!!

 

 

1.Java단

package ercg.common.websocket;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import ercg.sys.log.cmm.UserDetailsHelper;
import ercg.sys.log.vo.SysLog0101VO;


public class EchoHandler extends TextWebSocketHandler{
	//연결된 모든 sessions 저장
	//List<WebSocketSession> sessions = new ArrayList<>();
	//userId의 webSession을 저장한다
	Map<String, WebSocketSession> userSessions = new HashMap<>();
	
	//ROOM마다 연결되어있는 userId list를 저장
	Map<String, List<String>> roomUsers = new HashMap<>();
	
	//클라이언트 접속 성공 시 연결 성공시
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception{
		System.out.println("afterConnectionEstablished:" + session);
		
		//userId 알아내기
		Map<String, Object> sessionVal =  session.getAttributes();
		SysLog0101VO sysLog0101VO = (SysLog0101VO) sessionVal.get("sysLog0101VO"); 
		System.out.println(sysLog0101VO.getUserId());
		String userId = sysLog0101VO.getUserId();
		
		if(userSessions.get(userId) != null) {
			//userId에 원래 웹세션값이 저장되어 있다면 update
			userSessions.replace(userId, session);
		} else {
			//userId에 웹세션값이 없다면 put
			userSessions.put(userId, session);
		}
	}
	
	//소켓에 메시지를 보냈을때 js에서 on.message
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		System.out.println("handleTextmessage: " + session + " : " + message);
		
		//protocol: RoomNum, 보내는id, 내용 
		String msg = message.getPayload();
		if(StringUtils.isNotEmpty(msg)) {
			String[] strs = msg.split(",");
			if(strs != null && strs.length == 3) {
				String roomNum = strs[0];
				String sendId = strs[1];
				String content = strs[2];
				
				//입장일시 
				if(content.equals("ENTER")) {
					//해당 roomNum의 Map의 userId 리스트에 sendId를 넣어준다.
					System.out.println("ENTER안에 있음");
					
					if(roomUsers.get(roomNum) == null) {
						List<String> list = new ArrayList<>();
						roomUsers.put(roomNum, list);
					}
					
					roomUsers.get(roomNum).add(sendId);
					System.out.println(sendId + "가 들어왔습니다.");
					
					List<String> roomUserList = roomUsers.get(roomNum);
					for(int i = 0; i < roomUserList.size(); i++) {
						System.out.println(i + roomUserList.get(i) + " " + userSessions.get(roomUserList.get(i)));
					}
				} 
				//퇴장일시
				else if(content.equals("OUT")) {
					// room을 나갈시 Map의 userId 리스트에 sendId를 지운다.
					roomUsers.get(roomNum).remove(sendId);
					System.out.println("나갔습니다.");
					List<String> roomUserList = roomUsers.get(roomNum);
					for(int i = 0; i < roomUserList.size(); i++) {
						System.out.println(i + roomUserList.get(i) + " " + userSessions.get(roomUserList.get(i)));
					}
				}
				
				//해당 room의 userList를 가져옴
				List<String> roomUserList = roomUsers.get(roomNum);
				
				for(int i = 0; i < roomUserList.size(); i++) {
					//room의 userId의 session에 보내기
					userSessions.get(roomUserList.get(i)).sendMessage(new TextMessage(sendId + "," + content));
				}
			}
		}
	}

	
	//소켓이 close 됐을 때
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception{
		//sessions.remove(session);
		System.out.println("afterHandleTextmessage: " + session + " : " + status);
	}
}

 

 

2. JSP단

(1) ROOM 목록

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">
<title>chats</title>
<link rel="stylesheet" type="text/css" href="/ercg/css/talk.css">
</head>

<script type="text/javascript" src="/ercg/js/jquery-3.1.1.min.js"></script>
<script language="javascript">
$(document).ready(function() {
	$("#room1").on('click', function() {
		location.replace("ROOM1.jsp");
	});
	
	$("#room2").on('click', function() {
		location.replace("ROOM2.jsp");
	});
});

</script>

<body>
<div class="talkTool">
	<!-- Title 채팅 -->
	<header class= "top-header">
		<div class="header__column">
			<span class="header__text">채팅</span>
		</div>
	</header>
	
	<!-- 채팅방들 리스트 -->
	<main class="chats">
	
		<div class="search-bar">
			<input type="text" placeholder="검색">
		</div>
		<ul class="chats__list">
			<li class="chats__chat" id="room1">
					<div class="chat__content">
						<div class="chat__preview">
							<h3 class="chat__user">ROOM1</h3>
						</div>
					</div>
			</li>
			
			<li class="chats__chat" id="room2">
					<div class="chat__content">
						<div class="chat__preview">
							<h3 class="chat__user">ROOM2</h3>
						</div>
					</div>
			</li>

		</ul>
	</main>
	
	<nav class="tab-bar">
		<a href="index.jsp" class="tab-bar__tab">
			<i class="fa fa-user"></i>
			<span class="tabl-bar_title">친구</span>
		</a>
		
		<a href="chats.jsp" class="tab-bar__tab--selected">
			<i class="fas fa-commet"></i>
			<span class="tab-bar__title">채팅</span>
		</a>
	   
	   <a href="" class="tab-bar__tab">
     	 <i class="fa fa-search"></i>
      	<span class="tab-bar__title">채널</span>
    	</a>

    	<a href="" class="tab-bar__tab">
      		<i class="fa fa-ellipsis-h"></i>
      		<span class="tab-bar__title">더보기</span>
    	</a>
	</nav>
</div>
</body>
</html>

 

 

 

 

(2) ROOM1(2)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">
<title>Insert title here</title>
<%@ include file="/apps/common/include/ercgHeader.jsp"%>
<style>
.body-chat{
  padding-bottom: 0;
}
.chat-header,
.chat-header a {
  background-color: #a1c0d6;
  color: black;
}

.chat-header {
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.chat {
  background-color: #a1c0d6;
  height: 100vh;
  padding-top: 15px;
  padding-left:10px;
  padding-right: 10px;
}

.chat .date-divider {
  text-align: center;
  font-size: 12px;
  color: rgba(0, 0, 0, 0.5);
  margin-bottom: 15px;
}

.chat__message{
margin-bottom: 10px;
display: flex;
}

.chat__message-from-me {
  justify-content: flex-end;
  align-items: flex-end;
}

.chat__message-to-me {
  justify-content: flex-start;
  align-items: flex-start;
}
.chat__message-time {
  font-size: 10px;
  color : rgba(0, 0, 0, 0.5);
}

.chat__message-from-me .chat__message-body{
  background-color: #ffe934;
  padding : 10px 5px;
  border-radius: 2px;
  margin-right: 10px;
  margin-left: 10px;
  font-size: 15px;
}

.chat__message-to-me img{
  height: 35px;
  border-radius: 50%;
  margin-right: 10px;
}

.chat__message-username{
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 5px;
}

.chat__message-to-me .chat__message-body {
  background-color: white;
  padding : 10px 5px;
  border-radius: 2px;
  font-size: 15px;
}

.chat__message-center {
  display: flex;
  flex-direction: column;
}

.chat__message-time {
  margin-top: 50px;
  margin-left: 5px;
}

.type-message {
  width: 100%;
  bottom:0;
  position: fixed;
  height: 45px;
  background-color: #eeeeee;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-left:  10px;
  padding-right: 5px;
}

.type-message .fa-plus {
  color: #b4b4b4;
}

.type-message__input {
  width: 100%;
  display: flex;
  align-items: center;
}

.type-message__input input {
  width: 100%;
  padding: 10px;
  border-style: none;
  border-bottom-left-radius: 5px;
  border-top-left-radius: 5px;
}

.type-message__input #btnSend {
  color: #523737;
  background-color: #ffe934;
  padding: 10px;
  margin-right: 5px;
  width: 13%;
}

.type-message__input .record-message i {
  display: flex;
  align-items: center;
  justify-content: center;
}

.header__column {
    height: 20px;
}

#receiver {
    text-align: center;
    margin-left: 233px;
    width: 5em;
    background-color: #a1c0d6;
    height: 1.5em;
}

.enter {
	text-align: center;
	color: gray;
}

</style>
<script language="javascript">

var socket = null;
connect();

function connect() {
	var ws = new WebSocket("ws://localhost:8080/ercg/echo.do");
	socket = ws;
	//이벤트 헨들러
	ws.onopen = function() {
		console.log('Info: connection opened.');
		socket.send("1" + "," + gUserId + "," + "ENTER");
	};
	
	//소켓한테 메시지 받아옴  
	ws.onmessage = function (event) {
		var sm = event.data;
		//sl에는 sendId, content가 들어있음
		var sl = sm.split(',');
		let sendId = sl[0];
		let content = sl[1];
		let html = $("#nextMsg").html();
		if(content == "ENTER") {
			html += "<div class='enter'>" + sendId + "님이 들어오셨습니다.</div>"; 
		} else if(content == "OUT") {
			html += "<div class='enter'>" + sendId + "님이 나가셨습니다.</div>"; 
		} else if(sendId != gUserId){
			let currT = new Date().getHours() + ":" + new Date().getMinutes(); 
			html += '<div class="chat__message chat__message-to-me"><div class="chat__message-center"><h3 class="chat__message-username">' + sendId 
						+ '</h3><span class="chat__message-body">' + content + '</span></div><span class="chat__message-time">' 
						+ currT + '</span></div>';
		}

		$("#nextMsg").html(html);

		console.log("ReceiveMessage:" + event.data+'\n');
	};
	
	ws.onclose = function (event) { 
		console.log('Info: connection closed'); 
		//setTimeout( function() {connect(); }, 1000); // retry connection!!
	};
	
	ws.onerror = function (err) { console.log('Error:', err); };
};

$(document).ready(function() {
	$('#backChats').on('click', function(evt) {
		location.replace("chats.jsp");
		socket.send("1," + gUserId + "," + "OUT");
	});
	
	$('#btnSend').on('click', function(evt) {
		let currT = new Date().getHours() + ":" + new Date().getMinutes(); 
		let msg = $('#msg').val();
		evt.preventDefault();
		if (socket.readyState !== 1 ) return;
		
		//protocol: RoomNum, 보내는id, 내용 
		socket.send("1," + gUserId + "," + msg);
		
		let html = $("#nextMsg").html() + '<div class="chat__message chat__message-from-me"><span class="chat__message-time">'
					+ currT + '</span><span class="chat__message-body">' + msg + '</span></div>';
		$("#nextMsg").html(html);
		$("#msg").val("");
	});	
	
	$('#wsClose').on('click', function(e) {
		socket.onclose();
		
	});
});

</script>
</head>
<body class="body-chat">
  <header class= "top-header chat-header">
  	  <div class="header__column">
          <i class="fa fa-chevron-left fa-lg" id="backChats"></i>
      </div>
      <div class="header__column">
      	<span class="header__text">ROOM1</span>
      </div>
  </header>
  <main class="chat">
    <div class="date-divider">
      <span class="date-divider__text">화요일, 2018년 6월 19일</span>
    </div>
        
        <div id="nextMsg"></div>

  </main>
    <div class="type-message">
    <div class="type-message__input">
      <input type="text" id="msg"/>
      <span id="btnSend">전송</span>
    </div>
  </div>
</body>
</html>

 

 

3. 결과화면

 

(1) Chats.jsp (채팅목록)

 

(2) ROOM1 대화방 모습

3개의 ID(dev, t1, t2)를 이용한 대화이다.

BELATED ARTICLES

more