-
스프링 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
반응형'Spring' 카테고리의 다른 글
STS툴에서 MVC프로젝트(Spring Legacy Project) 생성하기 (0) 2020.06.24 Spring으로 배치 만들기 (quartz, scheduler,task) (0) 2020.06.07 Spring @RequestBody 와 @ResponseBody (0) 2019.12.01 아이바티스(iBATIS) vs 마이바티스(MyBatis) 태그 비교 (0) 2019.09.29 스프링(Spring) 컨트롤러(Controller)가 아닌 곳에서 request session정보 가져오기 (0) 2019.02.06