관리 메뉴

웹개발자의 기지개

[JSP] WebSocket 을 이용한 간단한 JSP 채팅 본문

Java/JSP

[JSP] WebSocket 을 이용한 간단한 JSP 채팅

http://portfolio.wonpaper.net 2023. 7. 8. 03:39

우선 인텔리제이 상으로 기본 java 프로젝트로 새프로젝트를 만들었다.

그 다음 아래 그림과 같이 마우스 우클릭해서, Add Framework Support 창에서 Web 항목을 체크하여

/web 폴더 와 WEB-INF , web.xml 이 생성되도록 추가하도록 한다.

 

그리고 필자는 websocket 외부 jar 파일을 다운로드 받아서 아래와 같이 연동하였다.

https://mvnrepository.com/artifact/javax.websocket/javax.websocket-api

https://repo1.maven.org/maven2/javax/websocket/javax.websocket-api/1.1/

 

Central Repository: javax/websocket/javax.websocket-api/1.1

 

repo1.maven.org

javax.websocket-api-1.1.jar
0.04MB

필자는 /web/lib 폴더내 javax.websocket jar 파일을 복사하여 붙여넣고, 

File > Project Structure 에서 아래와 같이 jar 파일을 연결하였다.

이제는 별도로 로컬에 설치된  톰켓과 인텔리제이와의 연결작업이다.

 

이제 톰켓 아이콘의 실행 화살표 버튼을 클릭하면 톰켓이 정상적으로 실행하면서 index.jsp 파일이 기본 웹브라우저를 띄우면서 동작할 것이다.

 

 

이제 부터는 본격적으로 세부 파일들을 만들어 보자.

[ web.xml ]  jsp 환경설정 파일

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <display-name>MustHaveJSP</display-name>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
 
    <!-- 세션 유지 시간 설정(예제 6-1) -->
    <session-config>
        <session-timeout>20</session-timeout>
    </session-config>
 
 
    <!-- 첨부 파일 최대 용량 설정(예제 14-8) -->
    <context-param>
        <param-name>maxPostSize</param-name>
        <param-value>1024000</param-value>
    </context-param>
 
    <!-- 웹소켓 채팅을 위한 설정(예제 15-3) -->
    <context-param>
        <param-name>CHAT_ADDR</param-name>
        <param-value>ws://localhost:8081</param-value>
    </context-param>
 
 
    <!-- 한글 깨짐 방지를 위한 필터 설정(예제 7-9) -->
    <filter>
        <filter-name>SetCharEncoding</filter-name>
        <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>SetCharEncoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
 
</web-app>
cs

웹소켓이 실제  동작 URL은 

<context-param>
    <param-name>CHAT_ADDR</param-name>
    <param-value>ws://localhost:8081</param-value>
</context-param>

이 부분이다. 

 

[ src/websocket/ChatServer ] 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package websocket;
 
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
 
@ServerEndpoint("/ChatingServer")
public class ChatServer {
    private static Set<Session> clients
            = Collections.synchronizedSet(new HashSet<Session>());
 
    @OnOpen  // 클라이언트 접속 시 실행
    public void onOpen(Session session) {
        clients.add(session);  // 세션 추가
        System.out.println("웹소켓 연결:" + session.getId());
    }
 
    @OnMessage  // 메시지를 받으면 실행
    public void onMessage(String message, Session session) throws IOException {
        System.out.println("메시지 전송 : " + session.getId() + ":" + message);
        synchronized (clients) {
            for (Session client : clients) {  // 모든 클라이언트에 메시지 전달
                if (!client.equals(session)) {  // 단, 메시지를 보낸 클라이언트는 제외
                    client.getBasicRemote().sendText(message);
                }
            }
        }
    }
 
    @OnClose  // 클라이언트와의 연결이 끊기면 실행
    public void onClose(Session session) {
        clients.remove(session);
        System.out.println("웹소켓 종료 : " + session.getId());
    }
 
    @OnError  // 에러 발생 시 실행
    public void onError(Throwable e) {
        System.out.println("에러 발생");
        e.printStackTrace();
    }
}
 
cs

 

[ /web/MultiChatMain.jsp ] 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<html>
<head><title>웹소켓 채팅</title></head>
<body>
<script>
  function chatWinOpen() {
    var id = document.getElementById("chatId");
    if (id.value == "") {
      alert("대화명을 입력 후 채팅창을 열어주세요.");
      id.focus();
      return;
    }
    window.open("ChatWindow.jsp?chatId=" + id.value, """width=320,height=400");
    id.value = "";
  }
</script>
<h2>웹소켓 채팅 - 대화명 적용해서 채팅창 띄워주기</h2>
대화명 : <input type="text" id="chatId" />
<button onclick="chatWinOpen();">채팅 참여</button>
</body>
</html>
 
cs

 

[ /web/ChatWindow.jsp ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<html>
<head>
    <title>웹소켓 채팅</title>
    <script>
        var webSocket
            = new WebSocket("<%= application.getInitParameter("CHAT_ADDR") %>/ChatingServer");
        var chatWindow, chatMessage, chatId;
 
        // 채팅창이 열리면 대화창, 메시지 입력창, 대화명 표시란으로 사용할 DOM 객체 저장
        window.onload = function() {
            chatWindow = document.getElementById("chatWindow");
            chatMessage = document.getElementById("chatMessage");
            chatId = document.getElementById('chatId').value;
        }
 
        // 메시지 전송
        function sendMessage() {
            // 대화창에 표시
            chatWindow.innerHTML += "<div class='myMsg'>" + chatMessage.value + "</div>"
            webSocket.send(chatId + '|' + chatMessage.value);  // 서버로 전송
            chatMessage.value = "";  // 메시지 입력창 내용 지우기
            chatWindow.scrollTop = chatWindow.scrollHeight;  // 대화창 스크롤
        }
 
        // 서버와의 연결 종료
        function disconnect() {
            webSocket.close();
        }
 
        // 엔터 키 입력 처리
        function enterKey() {
            if (window.event.keyCode == 13) {  // 13은 'Enter' 키의 코드값
                sendMessage();
            }
        }
 
        // 웹소켓 서버에 연결됐을 때 실행
        webSocket.onopen = function(event) {
            chatWindow.innerHTML += "웹소켓 서버에 연결되었습니다.<br/>";
        };
 
        // 웹소켓이 닫혔을 때(서버와의 연결이 끊겼을 때) 실행
        webSocket.onclose = function(event) {
            chatWindow.innerHTML += "웹소켓 서버가 종료되었습니다.<br/>";
        };
 
        // 에러 발생 시 실행
        webSocket.onerror = function(event) {
            alert(event.data);
            chatWindow.innerHTML += "채팅 중 에러가 발생하였습니다.<br/>";
        };
 
        // 메시지를 받았을 때 실행
        webSocket.onmessage = function(event) {
            var message = event.data.split("|");  // 대화명과 메시지 분리
            var sender = message[0];   // 보낸 사람의 대화명
            var content = message[1];  // 메시지 내용
            if (content != "") {
                if (content.match("/")) {  // 귓속말
                    if (content.match(("/" + chatId))) {  // 나에게 보낸 메시지만 출력
                        var temp = content.replace(("/" + chatId), "[귓속말] : ");
                        chatWindow.innerHTML += "<div>" + sender + "" + temp + "</div>";
                    }
                }
                else {  // 일반 대화
                    chatWindow.innerHTML += "<div>" + sender + " : " + content + "</div>";
                }
            }
            chatWindow.scrollTop = chatWindow.scrollHeight;
        };
    </script>
    <style>  <!-- 대화창 스타일 지정 -->
    #chatWindow{border:1px solid black; width:270px; height:310px; overflow:scroll; padding:5px;}
    #chatMessage{width:236px; height:30px;}
    #sendBtn{height:30px; position:relative; top:2px; left:-2px;}
    #closeBtn{margin-bottom:3px; position:relative; top:2px; left:-2px;}
    #chatId{width:158px; height:24px; border:1px solid #AAAAAA; background-color:#EEEEEE;}
    .myMsg{text-align:right;}
    </style>
</head>
 
<body>  <!-- 대화창 UI 구조 정의 -->
대화명 : <input type="text" id="chatId" value="${ param.chatId }" readonly />
<button id="closeBtn" onclick="disconnect();">채팅 종료</button>
<div id="chatWindow"></div>
<div>
    <input type="text" id="chatMessage" onkeyup="enterKey();">
    <button id="sendBtn" onclick="sendMessage();">전송</button>
</div>
</body>
</html>
cs

 

 

 

WebSocketChat.zip
0.07MB

 

 

참고 : MUSTHAVE 성낙현의 JSP 자바웹프로그래밍 WebSocket 채팅 중에서

참고 : https://daesuni.github.io/Spring-websocket/

 

Comments