jsp(?)로 채팅 구현하기...21-06-12
728x90

공부 목적으로 올린거임.

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
package logicalcode.websocket;
 
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
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(value = "/websocket/main", configurator = WebSocketSessionConfigurator.class)
public class MainEndPoint {
    /* 위의 WebSocketSessionConfigurator.class는 밑에 나온다. 내 생각에는 configurator에 적힌
.class의 내용을 이 쪽으로 불러오는거 같다...
    * 현재 연결중인 세션관리용 변수
     */
    private static final Map<Session, HttpSession> sessionMap = new ConcurrentHashMap<Session, HttpSession>();
//우리가 로그인하면 아이디 값을 세션에 담아줄때의 세션은 HttpSession
//서버쪽 세션? 은 session 인거같다. 다르다고 들음.
    /*
     * 클라이언트가 정상적으로 웹소켓 서버 접근시 호출되는 메서드
     * 
     * @param session
     * 
     * @thorws IOException
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        // HttpSession 객체 획득
        HttpSession httpSession = (HttpSession) config.getUserProperties().get("PRIVATE_HTTP_SESSION");
        int currentInUserCount = 0;
        System.out.println(httpSession + "연결");
        System.out.println(session + "연결");
        String userID = (String) (httpSession.getAttribute("userID"));
        currentInUserCount++;
        sendNotice(userID + " : 님이 입장하셨습니다. 현재 사용자 : ", currentInUserCount);
        sessionMap.put(session, httpSession);
 
    }
 
    public void sendNotice(String userMassage, int currentInUserCount) {
 
        System.out.println(userMassage + currentInUserCount);
 
        Iterator<Session> it = sessionMap.keySet().iterator();
        while (it.hasNext()) {
            Session currentSession = it.next();
            try {
                currentSession.getBasicRemote().sendText(userMassage + currentInUserCount);
            } catch (IOException e) {
 
                e.printStackTrace();
            }
        }
 
    }
 
    @OnMessage
    public void onMessage(String message, Session session) {
        HttpSession httpSession = sessionMap.get(session);
        String userID = (String) (httpSession.getAttribute("userID"));
        System.out.println(userID + " : " + message);
 
        Iterator<Session> it = sessionMap.keySet().iterator();
        while (it.hasNext()) {
            Session currentSession = it.next();
            try {
                currentSession.getBasicRemote().sendText(userID + " : " + message);
            } catch (IOException e) {
 
                e.printStackTrace();
            }
 
        }
    }
 
    @OnError
    public void onError(Throwable e, Session session) {
        e.printStackTrace();
    }
 
    @OnClose
    public void onClose(Session session) {
        HttpSession httpSession = sessionMap.get(session);
 
        sessionMap.remove(session);
    }
}
이렇게 되면 새로고침을 누르면 채팅의 내용은 남지 않고 사라진다. 또 새로 접속햇다는 메세지가 나오기 때문에
수정이 필요하다.
 
cs

이제 밑에 코드들은 http세션을 프로퍼티스에 담아서 ServerEndpointConfig에 넣어준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package logicalcode.websocket;
 
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import javax.websocket.server.ServerEndpointConfig.Configurator;
 
public class WebSocketSessionConfigurator extends Configurator{
    /*
     웹 소켓 세션의 유저프로퍼티스에 키 값으로 private_htttp_session으로 현재 HTTPSession을 설정해준다.
        오버라이드해서 모디파이핸드셰이크 메서드를 가져와서 설정해준다
     */
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        HttpSession session = (HttpSession)request.getHttpSession();
        
        if(session!=null) {
            sec.getUserProperties().put("PRIVATE_HTTP_SESSION", session);
        }
    }    
}
 
cs

밑의 코드는 뭐.. 널값이 오면 방지해주는 거라는데 잘은 모르겠다..

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package modular.core.listener;
 
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
@WebListener
public class RequestListener implements ServletRequestListener{
    
    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        
    }
    
    //WebSocketSessionConfigurator 에서 HttpSession이 null 취득이되어 오버라이드 함.
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        ((HttpServletRequest)sre.getServletRequest()).getSession();
        
    }
}
 
cs

이제 이 3가지 클래스를 웹프로젝트 폴더에 만들어 놨으면 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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 
<%
String userID = (String)session.getAttribute("userID");
%>
<!DOCTYPE html>
<html>
<head>
<jsp:include page="Navbar2.jsp"></jsp:include>
<meta charset="UTF-8">
<title>DevEric Chatting</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
 
 
<style type="text/css">
    *{
        font-family: 나눔고딕;
    }
    #messageWindow{
        background: black;
        color: greenyellow;
    }
    #inputMessage{
        width:500px;
        height:20px
    }
    #btn-submit{
        background: white;
        background: #F7E600;
        width:60px;
        height:30px;
        color:#607080;
        border:none;
    }
    
    #main-container{
        width:600px;
        height:680px;
        border:1px solid black;
        margin:10px;
        display: inline-block;
        
    }
    #chat-container{
        vertical-align: bottom;
        border: 1px solid black;
        margin:10px;
        min-height: 600px;
        max-height: 600px;
        overflow: scroll;
        overflow-x:hidden;
        background: #9bbbd4;
    }
    
    .chat{
        font-size: 20px;
        color:black;
        margin: 5px;
        min-height: 20px;
        padding: 5px;
        min-width: 50px;
        text-align: left;
        height:auto;
        word-break : break-all;
        background: #ffffff;
        width:auto;
        display:inline-block;
        border-radius: 10px 10px 10px 10px;
    }
    
    .notice{
        color:#607080;
        font-weight: bold;
        border : none;
        text-align: center;
        background-color: #9bbbd4;
        display: block;
    }
 
    .my-chat{
        text-align: right;
        background: #F7E600;
        border-radius: 10px 10px 10px 10px;
    }
    
    #bottom-container{
        margin:10px;
    }
    
    .chat-info{
        color:#556677;
        font-size: 10px;
        text-align: right;
        padding: 5px;
        padding-top: 0px;
 
    }
    
    .chat-box{
        text-align:left;
    }
    .my-chat-box{
        text-align: right;
    }
    
    
    
</style>
</head>
<body style="top:50px;">
    <div id="main-container">
        <div id="chat-container">
            
        </div>
        <div id="bottom-container">
            <input id="inputMessage" type="text">
            <input id="btn-submit" type="submit" value="전송" >
        </div>
    </div>
</body>
<script type="text/javascript">
    
 
    var textarea = document.getElementById("messageWindow");
    var webSocket = new WebSocket('ws://localhost:자신의포트번호/프로젝트파일명/websocket/main');
    
    // 로컬에서 테스트할 때 사용하는 URL입니다.
//     var webSocket = new WebSocket('ws://localhost/DevEricServers/webChatServer');
    var inputMessage = document.getElementById('inputMessage');
    
    webSocket.onerror = function(e){
        onError(e);
    };
    webSocket.onopen = function(e){
        onOpen(e);
    };
    webSocket.onmessage = function(e){
        onMessage(e);
    };
    
    
    function onMessage(e){
        var chatMsg = event.data;
        var date = new Date();
        var dateInfo = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
        if(chatMsg.substring(0,6== 'server'){
            var $chat = $("<div class='chat notice'>" + chatMsg + "</div>");
            $('#chat-container').append($chat);
        }else{
            var $chat = $("<div class='chat-box'><div class='chat'>" + chatMsg + "</div><div class='chat-info chat-box'>"+ dateInfo +"</div></div>");
            $('#chat-container').append($chat);
        }
        
        
        $('#chat-container').scrollTop($('#chat-container')[0].scrollHeight+20);
    }
    
    function onOpen(e){
        
    }
    
    function onError(e){
        alert(e.data);
    }
    
    function send(){
        var chatMsg = inputMessage.value;
        if(chatMsg == ''){
            return;
        }
        var date = new Date();
        var dateInfo = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
        var $chat = $("<div class='my-chat-box'><div class='chat my-chat'>" + chatMsg + "</div><div class='chat-info'>"+ dateInfo +"</div></div>");
        $('#chat-container').append($chat);
        webSocket.send(chatMsg);
        inputMessage.value = "";
        $('#chat-container').scrollTop($('#chat-container')[0].scrollHeight+20);
    }
    
</script>
 
<script type="text/javascript">
    $(function(){
        $('#inputMessage').keydown(function(key){
            if(key.keyCode == 13){
                $('#inputMessage').focus();
                send();
            }
        });
        $('#btn-submit').click(function(){
            send();
        });
        
    })
</script>
</html>
cs

끝!

 

아 마지막으로 이렇게 따라서 했는데 alert로 뭔가 뜨면서 연결이 않되길래 몇가지 찾아가면서 알아낸게 있다.

내 경우는 프로젝트의 이름과는 다른 걸로 되서 내프로젝트/websocket/main이 되야되는데 다른프로젝트/websocket/main이렇게 되있었다. 그래서 찾아본게 이클립스에서 내가 현재 쓰고 있는 서버의 폴더가 있길래

거기에 있는 server.xml을 보니  <Context docBase="내프로젝트" path="/다른프로젝트" reloadable="true" source="org.eclipse.jst.jee.server:내프로젝트"/></Host> 이렇게 되있어서 path 부분을 수정해주니 잘 되었다.

------------------------------------------수정부분-------------------------------------------------------------------------------

상대방과 채팅을하면 내 채팅창에 친 말이 메아리 쳐서 오고 상대방에 가는 문제점이 있었는데 세션으로 조건을 주니 한번에 해결 됬다.

 

추가.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    @OnMessage
    public void onMessage(String message, Session session) {
        HttpSession httpSession = sessionMap.get(session);
        String userID = (String) (httpSession.getAttribute("userID"));
        System.out.println(userID + " : " + message);
 
        Iterator<Session> it = sessionMap.keySet().iterator();
        while (it.hasNext()) {// 아이터레이터로 세션에 담긴 세션에 다 담가서 현재 유저의 정보가 담긴 userID와 그 유저가 보낸 메세지를 그 방에 있는 참가자들에게
                                // 담가 보낸다.
            Session currentSession = it.next();
            // key값 : currentSession value값 : httpSession 으로 가져온 httpSession 값이 이 메서드에서 처음으로
            // 얻은 httpSession과 같으면 나한테 않오게끔 하면된다.
            if (sessionMap.get(currentSession) == httpSession) {//현재 키값으로 맵에서 http세션
찾아서 현재 얻은 http 세션과 비교하면 자기 자신에게 메아리가 없어진다.
 
            } else {
                try {
                    currentSession.getBasicRemote().sendText(userID + " : " + message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
cs

 

참고사이트 : https://nowonbun.tistory.com/748

 

[Java] Websocket을 이용해서 유저(사이트 운영자)가 다른 유저와 채팅하는 방법

안녕하세요. 명월입니다. 이 글은 Java에서 Websocket을 이용해서 유저(사이트 운영자)가 다른 유저와 채팅하는 방법에 대한 글입니다. 이전 글에서 사이트 운영자와 유저간의 1:1 채팅을 하는 방법

nowonbun.tistory.com

 

728x90