ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스프링 Spring + 웹소켓 WebSocket 채팅 초간단 구현
    Spring 2020. 5. 26. 12:16
    반응형

    Spring Tool Suite4 기준으로 메이븐 MVC프로젝트를 생성한다.

    File > New > Spring Lagacy Project > Templates목록에서 맨 아레 Spring MVC Project 클릭 하고 생성 

    ※만약에 Spring Lagacy Project가 보이지 않는다면 마켓플레이스에서 STS를 입력후 STS3 Add-On 설치한다.

    		<dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-websocket</artifactId>
                <version>${org.springframework-version}</version>
    		</dependency>
    		
    		<dependency>
    			<groupId>javax.websocket</groupId>
    			<artifactId>javax.websocket-api</artifactId>
    			<version>1.1</version>
    		</dependency>

    기본 pom.xml에 2개의 의존성을 추가한다.

    위 대로 디폴트 스프링mvc프로젝트를 생성하면 버전이 낮다. 그래서 웹소켓  인터페이스를 지원하는데 오류가 많이 났다 (자바 1.6/ 스프링3 / 웹모듈 2.5....)

    그래서 자바 1.8, 스프링4, 웹모듈 3.0로 버전 업그레이드를 하니 오류가 사라졌다.

    스프링 버전 올리기 ↓

    https://offbyone.tistory.com/16

     

    	<servlet>
    		<servlet-name>appServlet</servlet-name>
    		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    		<init-param>
    			<param-name>contextConfigLocation</param-name>
    			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
    		</init-param>
    		<load-on-startup>1</load-on-startup>
          	<async-supported>true</async-supported> <!-- 웹소켓을 위한 설정(비동기지원) -->
    	</servlet>

    기본 web.xml에 async-supported 속성을 추가한다.

     

    LoginController.java

    package com.devmg.app;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    
    /**
     * Handles requests for the application home page.
     */
    @Controller
    public class LoginController {
    	
    	private static final Logger logger = LoggerFactory.getLogger(LoginController.class);
    	
    	/**
    	 * Simply selects the home view to render by returning its name.
    	 */
    	@RequestMapping(value = "/login.do", method = RequestMethod.GET)
    	public String login() {
    		return "login";
    	}
    	
    	/**
    	 * Simply selects the home view to render by returning its name.
    	 */
    	@RequestMapping(value = "/loginProcess.do", method = RequestMethod.POST)
    	public String loginProcess(@RequestParam String id, HttpServletRequest request) {
    		
    		logger.info("Welcome "+id);
    		
        	HttpSession session = request.getSession();
        	session.setAttribute("id", id);
    		return "chat";
    	}
    	
    }
    

     

    로그인 페이지 이동 및 사용자 로그인 세션 만들기

     

    WebSocketChat.java

    package com.devmg.app;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.websocket.OnClose;
    import javax.websocket.OnError;
    import javax.websocket.OnMessage;
    import javax.websocket.OnOpen;
    import javax.websocket.RemoteEndpoint.Basic;
    import javax.websocket.Session;
    import javax.websocket.server.ServerEndpoint;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Controller;
    
    @Controller
    @ServerEndpoint(value="/echo.do")
    public class WebSocketChat {
        
        private static final List<Session> sessionList=new ArrayList<Session>();;
        private static final Logger logger = LoggerFactory.getLogger(WebSocketChat.class);
        public WebSocketChat() {
            // TODO Auto-generated constructor stub
            System.out.println("웹소켓(서버) 객체생성");
        }
        
        @OnOpen
        public void onOpen(Session session) {
            logger.info("Open session id:"+session.getId());
            try {
                final Basic basic=session.getBasicRemote();
                basic.sendText("대화방에 연결 되었습니다.");
            }catch (Exception e) {
                // TODO: handle exception
                System.out.println(e.getMessage());
            }
            sessionList.add(session);
        }
        
        /*
         * 모든 사용자에게 메시지를 전달한다.
         * @param self
         * @param sender
         * @param message
         */
        private void sendAllSessionToMessage(Session self, String sender, String message) {
        	
            try {
                for(Session session : WebSocketChat.sessionList) {
                    if(!self.getId().equals(session.getId())) {
                        session.getBasicRemote().sendText(sender+" : "+message);
                    }
                }
            }catch (Exception e) {
                // TODO: handle exception
                System.out.println(e.getMessage());
            }
        }
        
        /*
         * 내가 입력하는 메세지
         * @param message
         * @param session
         */
        @OnMessage
        public void onMessage(String message,Session session) {
        	
        	String sender = message.split(",")[1];
        	message = message.split(",")[0];
        	
            logger.info("Message From "+sender + ": "+message);
            try {
                final Basic basic=session.getBasicRemote();
                basic.sendText("<나> : "+message);
            }catch (Exception e) {
                // TODO: handle exception
                System.out.println(e.getMessage());
            }
            sendAllSessionToMessage(session, sender, message);
        }
        
        @OnError
        public void onError(Throwable e,Session session) {
            
        }
        
        @OnClose
        public void onClose(Session session) {
            logger.info("Session "+session.getId()+" has ended");
            sessionList.remove(session);
        }
    }
    

    웹소켓을 이용한 채팅 메세지 수신/발신 모듈이다.
    각 @어노테이션의 설명은 생략

     

    login.jsp

    <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <%@ page session="false" %>
    <html>
    <head>
    	<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
    	<script src="//maxcdn.bootstrapcdn.com/bootstrap/latest/js/bootstrap.min.js"></script>
    	<link href="//maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css" rel="stylesheet">
    	<style>
    	    body {
    	        background: #f8f8f8;
    	        padding: 60px 0;
    	    }
    	    
    	    #login-form > div {
    	        margin: 15px 0;
    	    }
    	
    	</style>
    	<title>Home</title>
    </head>
    <div class="container">
        <div class="col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2">
            <div class="panel panel-success">
                <div class="panel-heading">
                    <div class="panel-title">환영합니다!</div>
                </div>
                <div class="panel-body">
                    <form id="login-form" method="post" action="/loginProcess.do">
                        <div>
                            <input type="text"  name="id"	class="form-control" name="아이디 입력" placeholder="Username" autofocus>
                        </div>
                        <div>
                            <button type="submit" class="form-control btn btn-primary">로그인</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
    </html>
    

    로그인 폼

     

    chat.jsp

    <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Simple Chat</title>
    </head>
    <body>
        <div>
            <button type="button" onclick="openSocket();">대화방 참여</button>
            <button type="button" onclick="closeSocket();">대회방 나가기</button>
        	<br/><br/><br/>
      		메세지 입력 : 
            <input type="text" id="sender" value="${sessionScope.id}" style="display: none;">
            <input type="text" id="messageinput">
            <button type="button" onclick="send();">메세지 전송</button>
            <button type="button" onclick="javascript:clearText();">대화내용 지우기</button>
        </div>
        <!-- Server responses get written here -->
        <div id="messages">
        </div>
        <!-- websocket javascript -->
        <script type="text/javascript">
            var ws;
            var messages = document.getElementById("messages");
            
            function openSocket(){
                if(ws !== undefined && ws.readyState !== WebSocket.CLOSED ){
                    writeResponse("WebSocket is already opened.");
                    return;
                }
                //웹소켓 객체 만드는 코드
                ws = new WebSocket("ws://localhost:8080/echo.do");
                
                ws.onopen = function(event){
                    if(event.data === undefined){
                  		return;
                    }
                    writeResponse(event.data);
                };
                
                ws.onmessage = function(event){
                    console.log('writeResponse');
                    console.log(event.data)
                    writeResponse(event.data);
                };
                
                ws.onclose = function(event){
                    writeResponse("대화 종료");
                }
                
            }
            
            function send(){
               // var text=document.getElementById("messageinput").value+","+document.getElementById("sender").value;
                var text = document.getElementById("messageinput").value+","+document.getElementById("sender").value;
                ws.send(text);
                text = "";
            }
            
            function closeSocket(){
                ws.close();
            }
            
            function writeResponse(text){
                messages.innerHTML += "<br/>"+text;
            }
    
            function clearText(){
                console.log(messages.parentNode);
                messages.parentNode.removeChild(messages)
          	}
            
      </script>
    </body>
    </html>

    채팅방 폼

     

    원본소스의 깃

    github.com/DevMoonKi/SimpleChat

     

    반응형

    댓글

Designed by Tistory.