반응형

스프링부트에서 소켓통신을 통한 채팅프로그램 만들기 2번째입니다.

 

이전까지의 소스는 아래 URL에서 참고해주세요.

https://myhappyman.tistory.com/100

 

SpringBoot - 스프링부트에서 채팅프로그램(소켓통신) 만들기-1

이번엔 소켓통신을 통하여 채팅프로그램을 스프링부트에서 만들어보겠습니다. 간단하게 프로젝트를 생성부터 채팅방 생성 및 채팅하는 과정까지 만들어보겠습니다. 소켓통신을 사용한 채팅프로그램 만들기 스프링..

myhappyman.tistory.com

 

 

 

1장에서는 단순하게 String 메시지 자체를 보냈는데, 이번엔 JSON형태로 메시지를 보내고 서버에서도 JSON형태의 메시지를 파싱하여 구분처리를 해보도록 하겠습니다.

추가적으로 내가보낸 메시지와 상대방을 구분해보겠습니다.

채팅구분처리


Server단

simple json 라이브러리 추가

pom.xml

<!-- json simple  -->
<dependency>
  <groupId>com.googlecode.json-simple</groupId>
  <artifactId>json-simple</artifactId>
  <version>1.1.1</version>
</dependency>
<!-- json simple  -->

pom.xml에 json파싱을 위해 json-simple 라이브러리를 추가합니다.

 

 

jsonToObjectParser 함수 추가

private static JSONObject JsonToObjectParser(String jsonStr) {
	JSONParser parser = new JSONParser();
	JSONObject obj = null;
	try {
		obj = (JSONObject) parser.parse(jsonStr);
	} catch (ParseException e) {
		e.printStackTrace();
	}
	return obj;
}

이전에 생성하였던 SocketHandler.java에 JSON파일이 들어오면 파싱해주는 함수를 추가하였습니다.

json형태의 문자열을 파라미터로 받아서 SimpleJson의 파서를 활용하여 JSONObject로 파싱처리를 해주는 함수입니다.

 

 

핸들러 로직 추가

SocketHandler.java

package com.psw.chating.handler;

import java.util.HashMap;

import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

@Component
public class SocketHandler extends TextWebSocketHandler {
	
	HashMap<String, WebSocketSession> sessionMap = new HashMap<>(); //웹소켓 세션을 담아둘 맵
	
	@Override
	public void handleTextMessage(WebSocketSession session, TextMessage message) {
		//메시지 발송
		String msg = message.getPayload();
		JSONObject obj = jsonToObjectParser(msg);
		for(String key : sessionMap.keySet()) {
			WebSocketSession wss = sessionMap.get(key);
			try {
				wss.sendMessage(new TextMessage(obj.toJSONString()));
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		//소켓 연결
		super.afterConnectionEstablished(session);
		sessionMap.put(session.getId(), session);
		JSONObject obj = new JSONObject();
		obj.put("type", "getId");
		obj.put("sessionId", session.getId());
		session.sendMessage(new TextMessage(obj.toJSONString()));
	}
	
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		//소켓 종료
		sessionMap.remove(session.getId());
		super.afterConnectionClosed(session, status);
	}
	
	private static JSONObject jsonToObjectParser(String jsonStr) {
		JSONParser parser = new JSONParser();
		JSONObject obj = null;
		try {
			obj = (JSONObject) parser.parse(jsonStr);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return obj;
	}
}

1. 소켓이 연결되면 동작하는 afterConnectionEstablished() 메소드부분에 로직이 추가되었습니다.

생성된 세션을 저장하면 발신메시지의 타입은 getId라고 명시 후 생성된 세션ID값을 클라이언트단으로 발송합니다.

클라이언트단에서는 type값을 통해 메시지와 초기 설정값을 구분할 예정입니다.

 

2. 메시지 전송시 JSON파싱을 위해 message.getPayload()를 통해 받은 문자열을 만든 함수 jsonToObjectParser에 넣어서 JSONObject값으로 받아서 강제 문자열 형태로 보내주는부분이 추가되었습니다.

 

 

Client 단

이제 발송하는 chat.jsp를 수정하겠습니다.

 

클라이언트단 뷰페이지 추가 및 json형태로 요청 및 파싱하기

chat.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<meta charset="UTF-8">
	<title>Chating</title>
	<style>
		*{
			margin:0;
			padding:0;
		}
		.container{
			width: 500px;
			margin: 0 auto;
			padding: 25px
		}
		.container h1{
			text-align: left;
			padding: 5px 5px 5px 15px;
			color: #FFBB00;
			border-left: 3px solid #FFBB00;
			margin-bottom: 20px;
		}
		.chating{
			background-color: #000;
			width: 500px;
			height: 500px;
			overflow: auto;
		}
		.chating .me{
			color: #F6F6F6;
			text-align: right;
		}
		.chating .others{
			color: #FFE400;
			text-align: left;
		}
		input{
			width: 330px;
			height: 25px;
		}
		#yourMsg{
			display: none;
		}
	</style>
</head>

<script type="text/javascript">
	var ws;

	function wsOpen(){
		ws = new WebSocket("ws://" + location.host + "/chating");
		wsEvt();
	}
		
	function wsEvt() {
		ws.onopen = function(data){
			//소켓이 열리면 동작
		}
		
		ws.onmessage = function(data) {
			//메시지를 받으면 동작
			var msg = data.data;
			if(msg != null && msg.trim() != ''){
				var d = JSON.parse(msg);
				if(d.type == "getId"){
					var si = d.sessionId != null ? d.sessionId : "";
					if(si != ''){
						$("#sessionId").val(si); 
					}
				}else if(d.type == "message"){
					if(d.sessionId == $("#sessionId").val()){
						$("#chating").append("<p class='me'>나 :" + d.msg + "</p>");	
					}else{
						$("#chating").append("<p class='others'>" + d.userName + " :" + d.msg + "</p>");
					}
						
				}else{
					console.warn("unknown type!")
				}
			}
		}

		document.addEventListener("keypress", function(e){
			if(e.keyCode == 13){ //enter press
				send();
			}
		});
	}

	function chatName(){
		var userName = $("#userName").val();
		if(userName == null || userName.trim() == ""){
			alert("사용자 이름을 입력해주세요.");
			$("#userName").focus();
		}else{
			wsOpen();
			$("#yourName").hide();
			$("#yourMsg").show();
		}
	}

	function send() {
		var option ={
			type: "message",
			sessionId : $("#sessionId").val(),
			userName : $("#userName").val(),
			msg : $("#chatting").val()
		}
		ws.send(JSON.stringify(option))
		$('#chatting').val("");
	}
</script>
<body>
	<div id="container" class="container">
		<h1>채팅</h1>
		<input type="hidden" id="sessionId" value="">
		
		<div id="chating" class="chating">
		</div>
		
		<div id="yourName">
			<table class="inputTable">
				<tr>
					<th>사용자명</th>
					<th><input type="text" name="userName" id="userName"></th>
					<th><button onclick="chatName()" id="startBtn">이름 등록</button></th>
				</tr>
			</table>
		</div>
		<div id="yourMsg">
			<table class="inputTable">
				<tr>
					<th>메시지</th>
					<th><input id="chatting" placeholder="보내실 메시지를 입력하세요."></th>
					<th><button onclick="send()" id="sendBtn">보내기</button></th>
				</tr>
			</table>
		</div>
	</div>
</body>
</html>

 

 

아래는 chat.jsp의 로직 설명입니다.


css부분은 따로 설정하진 않겠습니다.

1. html 소스부분은 현재의 세션값을 저장해놓기 위해 sessionId가 ID인 input태그를 추가하였습니다.

2. send() 함수의 발송하기전에 단순 String데이터가 아닌 obj값으로 값을 세팅하고 JSON형태로 발신처리로 변경되었습니다.

메시지를 보낼땐 type값을 message로 구분하여 발송합니다.

 

3. Socket.onmessage의 메시지 전달시 받는 로직이 변경되었습니다.

서버에서도 데이터를 JSON형태로 전달해주기 때문에 받은 데이터를 JSON.parse메소드를 활용하여 파싱을 합니다.

파싱한 객체의 type값을 확인하여 getId값이면 초기 설정된 값이므로 채팅창에 값을 입력하는게 아니라 추가한 태그 sessionId에 값을 세팅해줍니다.

id값은 소켓이 종료되기 전까지 자기자신을 구분할 수 있는 session값이 될 예정입니다.

 

4. type이 message인 경우엔 채팅이 발생한 경우입니다.

상대방과 자신을 구분하기 위해 여기서 sessionId값을 사용합니다.

최초 이름을 입력하고 연결되었을때, 발급받은 sessionId값을 비교하여 같다면 자기 자신이 발신한 메시지이므로 오른쪽으로 정렬하는 클래스를 처리하고 메시지를 출력합니다.

비교하여 같지 않다면 타인이 발신한 메시지이므로 왼쪽으로 정렬하는 클래스를 처리하고 메시지를 출력합니다.

 

 

다음장에서는 방구분 처리를 해보겠습니다.

 

 

반응형