반응형

이번엔 소켓통신을 통하여 채팅프로그램을 스프링부트에서 만들어보겠습니다.

 

프로젝트를 생성해서 단순한 채팅방과 추가적으로 방생성에 따른 채팅 구분 등의 과정까지 만들어보겠습니다.

 

 

소켓통신을 사용한 채팅프로그램 만들기

스프링부트 프로젝트 생성하기

먼저 프로젝트부터 만들어야겠죠?

Spring Starter Project로 생성합니다.

 

값을 채워넣었습니다.

프로젝트명, group, artifact, package명 등 위 내용으로 채워넣었습니다.

생성하고자 하는 프로젝트로 만드세요~

 

WebSocket 사용

라이브러리는 WebSocket을 사용할거니까 검색 후 추가해주고, 완료해주겠습니다.

 

스프링부트 프로젝트 생성!

 

부트 프로젝트 설정하기(pom.xml)

view페이지는 jsp를 사용할 예정입니다.

사용을 위해 pom.xml 설정을 하겠습니다. 아래의 dependency도 추가해주세요.

 

pom.xml

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- View JSP -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>
<!-- View JSP -->

 

 

다음은 properties의 설정값을 추가하겠습니다.

톰캣 포트를 80으로 변경하고, jsp를 바라볼 수 있도록 설정하겠습니다.

또한, 재시작없이 jsp가 적용되는 설정까지 하도록 하겠습니다.

 

application.properties

 

resources/application.properties

#Tomcat Server Setting
server.port=80

#JSP, HTML ModelAndView Path Setting
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

#JSP to Modify Not Restart Server
server.servlet.jsp.init-parameters.development=true

 

 

뷰 설정

디렉토리 생성 및 chat.jsp파일 생성

뷰 페이지 구조

뷰페이지를 생성합니다.

이제 컨트롤러를 구성하여 넘어가는 것을 보고 바로 소켓통신 설정을 진행해보겠습니다.

 

 

컨트롤러 추가

MainController 추가

controller패키지 추가 및 MainContoller.java파일을 생성합니다.

package com.psw.chating.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MainController {
	
	@RequestMapping("/chat")
	public ModelAndView chat() {
		ModelAndView mv = new ModelAndView();
		mv.setViewName("chat");
		return mv;
	}
}

chat파일을 넘겨주는 view컨트롤러를 생성 후 서버 구동하여 정상적으로 jsp페이지에 접근이 되는지 확인합니다.

 

127.0.0.1/chat 접근

localhost/chat으로 접근하니 정상적으로 chat.jsp페이지에 접근하는 모습을 볼 수 있습니다.

이제 본격적으로 WebSocket처리를 연결하고 통신 예제를 진행해보겠습니다.

 

WebSocket 설정

웹소켓 구현체와 구현체등록

웹소켓 구현체와 등록해주는 config파일을 생성해보겠습니다. 위 그림처럼 패키지와 자바파일을 생성합니다.

 

SocketHandler.java

@Component
public class SocketHandler extends TextWebSocketHandler {
	
	@Override
	public void handleTextMessage(WebSocketSession session, TextMessage message) {
		//메시지 발송
	}
	
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		//소켓 연결
	}
	
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		//소켓 종료
	}
}

구현체에 등록할 SocketHandler입니다.

afterConnectionEstablished 메소드는 웹소켓 연결이 되면 동작합니다.

acafterConnectionClosed 메소드는 반대로 웹소켓이 종료되면 동작합니다.

handleTextMessage 메소드는 메시지를 수신하면 실행됩니다. 상속받은 TextWebSocketHandler는 handleTextMessage를 실행시키며, 메시지 타입에따라 handleBinaryMessage또는 handleTextMessage가 실행됩니다.

 

소스를 완성해보겠습니다.

 

SocketHandler.java

package com.psw.chating.handler;

import java.util.HashMap;

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();
		for(String key : sessionMap.keySet()) {
			WebSocketSession wss = sessionMap.get(key);
			try {
				wss.sendMessage(new TextMessage(msg));
			}catch(Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		//소켓 연결
		super.afterConnectionEstablished(session);
		sessionMap.put(session.getId(), session);
	}
	
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		//소켓 종료
		sessionMap.remove(session.getId());
		super.afterConnectionClosed(session, status);
	}
}

 

 

 

구현체를 이제 등록해보겠습니다.

WebSocketConfig.java

package com.psw.chating.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

import com.psw.chating.handler.SocketHandler;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer{

	@Autowired
	SocketHandler socketHandler;
	
	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry.addHandler(socketHandler, "/chating");
	}
}

먼저 생성하였던 구현체를 등록하는 부분입니다.

 

마지막으로 chat.jsp를 완성하고 메시지가 주고 받아지는지 확인해보겠습니다.

 

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 p{
			color: #fff;
			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() != ''){
				$("#chating").append("<p>" + msg + "</p>");
			}
		}

		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 uN = $("#userName").val();
		var msg = $("#chatting").val();
		ws.send(uN+" : "+msg);
		$('#chatting').val("");
	}
</script>
<body>
	<div id="container" class="container">
		<h1>채팅</h1>
		<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>

 

동작 확인

3개의 브라우저 생성

부트 어플리케이션을 구동하고 localhost/chat으로 접근하면 위와같은 뷰를 확인 할수 있습니다.

혼자서 3개의 브라우저를 열고 사용자명을 입력 후 테스트를 해보았습니다.

채팅 테스트

 

다음장에는 상대방과 자신을 구분을 처리해보겠습니다.

반응형