728x90
개요
웹 개발을 하면서 꼭 해봐야 하지만 잘 안해보는 2가지 기술중 하나였습니다.
채팅은 심심치 않게 볼수있는데 웹 서비스 기술이였지만 내가 한 회사, 외부 프로젝트에서는 적용한 적이 없는 기술이였습니다.
그래서 이번에 어디서든 쉽게 적용 할수있게 프로젝트를 하나 만들어 봤습니다.
스펙
Spring Boot2.7.7
Java 17
jsp 사용
dependencies
// Spring Boot Web Server Dependency implementation 'org.springframework.boot:spring-boot-starter-web' // Spring Web Socket implementation 'org.springframework.boot:spring-boot-starter-websocket' // Find Views Path implementation 'org.apache.tomcat.embed:tomcat-embed-jasper' // Develop Tool implementation 'org.springframework.boot:spring-boot-devtools' // Properties compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test'
설명
현재 게시글은 채팅 방 보다는 진짜 간단한 소켓 사용으로 인한 메시지 전송 테스트 용이며
다음 게시글에서 채팅 방을 만들고 방에 입장 하여 채팅을 하는 방식을 만들려고 합니다.
Git
프로젝트 구조
이해 하기 어려우시면 Git을 확인 하시면 도움이 됩니다.
└─ src
├─ main
│ ├─ java
│ │ └─ com
│ │ └─ server
│ │ └─ chat
│ │ ├─ ChatApplication.java // 단순 실행
│ │ ├─ config
│ │ │ └─ WebSocketConfig.java // ServerEndpointExporter 설정을 위한 Config
│ │ ├─ controller
│ │ │ └─ MainController.java // 단순히 화면 이동 페이지 입니다.
│ │ └─ service
│ │ └─ ChatService.java // 소켓 서비스가 실행되는 곳
│ ├─ resources
│ │ ├─ application.yml // application.properties
│ │ ├─ logback.xml // 추후 DB 때문에 넣은 파일 소켓과는 관련이 없다.
│ │ ├─ static // Static 파일인데 아래 파일은 JSP파일에 다 넣어 놓아서 확인할 필요는 없다.
│ │ │ ├─ css
│ │ │ │ └─ chat.css
│ │ │ └─ js
│ │ │ └─ chat.js
│ │ └─ templates
│ └─ webapp
│ └─ WEB-INF
│ └─ views
│ └─ index.jsp // 화면에 띄어지는 JSP CSS 및 JS 파일이 작성 되어 있습니다.
적용 방법
- dependency를 추가
- implementation 'org.springframework.boot:spring-boot-starter-websocket'
- WebSocketConfig.java를 생성 후 코드를 추가
@Component public class WebSocketConfig { // 서버 엔드 포인트를 탐색 하는 Bean을 설정 @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
- ChatService.java 추가
제가 익숙해서 Service라고 했지 개발자에 따라 달라 질수도 있다고 생각합니다.
@Slf4j
@Service
@ServerEndpoint("/chat")
public class ChatService {
private static Set<Session> clients = Collections.synchronizedSet(new HashSet<Session>());
/*
* 1) onOpen 메서드
* 클라이언트가 ServerEndpoint값인 "/chat" url로 서버에 접속하게 되면 onOpen 메서드가 실행되며,
* 클라이언트 정보를 매개변수인 Session 객체를 통해 전달받습니다.
* 이때 정적 필드인 clients에 해당 session이 존재하지 않으면 clients에 접속된 클라이언트를 추가합니다.
*/
@OnOpen
public void onOpen(Session session) {
log.info("Open Session : {}", session.toString());
if (clients.contains(session)) {
log.warn("Already Connect Session", session);
} else {
clients.add(session);
log.info("Session Ope : {}", session);
}
}
/*
* 2) onMessage 메서드
* 클라이언트로부터 메시지가 전달되면 WebSocketChat 클래스의 onMessage메서드에 의해 clients에 있는 모든
* session에 메시지를 전달합니다.
*/
@OnMessage
public void onMessage(String msg, Session session) throws Exception {
log.info("Receive Message : {}", msg);
for (Session client : clients) {
log.info("Send Data : {}", msg);
client.getBasicRemote().sendText(msg);
}
}
/*
* 3) onClose 메서드
* 클라이언트가 url을 바꾸거나 브라우저를 종료하면 자동으로 onClose() 메서드가 실행되며 해당 클라이언트 정보를 clients에서
* 제거합니다.
*/
@OnClose
public void onClose(Session session) {
log.info("Session Close : {}", session);
clients.remove(session);
}
}
jsp, js 코드 작성
<body> <div id='chat'> <h1>WebSocket chating</h1> <input type='text' id='mid' value='홍길동'> <input type='button' value='로그인' id='btnLogin'> <br /> <div id='talk'></div> <div id='sendZone'> <textarea id='msg' value='hi...'></textarea> <input type='button' value='전송' id='btnSend'> </div> </div> </body> <script> /* * Web Socket */ function getId(id) { return document.getElementById(id); } var data = {}; // 전송 데이터 (JSON); var ws; var mid = getId('mid'); var btnLogin = getId('btnLogin'); var btnSend = getId('btnSend'); var talk = getId('talk'); var msg = getId('msg'); btnLogin.onclick = function () { ws = new WebSocket("ws://" + location.host + "/chat"); ws.onmessage = function (msg) { console.log(msg) var data = JSON.parse(msg.data); var css; if (data.mid == mid.value) { css = "class='me'"; } else { css = "class='other'"; } console.log(data) var item = `<div ${css} > <span><b>\${data.mid}</b></span> [ \${data.date} ]<br/> <span>\${data.msg}</span> </div>`; talk.innerHTML += item; talk.scrollTop = talk.scrollHeight;//스크롤바 하단으로 이동 } } msg.onkeyup = function (ev) { if (ev.keyCode == 13) { send(); } } btnSend.onclick = function () { send(); } function send() { if (msg.value.trim() != '') { data.mid = getId('mid').value; data.msg = msg.value; data.date = new Date().toLocaleString(); var temp = JSON.stringify(data); ws.send(temp); } msg.value = ''; } </script>
간단한 순서 설명
- 닉네임 입력후 Login 버튼을 클릭하면 "btnLogin.onclick = function () {" 이 실행되면서 소켓에 연결 요청
- "@OnOpen "이 붙어있는 메소드가 실행되면서 세션을 추가 한다.
- 여기 까지 하면 소켓이 실행되고 연결 완료
- 메시지 입력 후 전송 버튼 클릭
- js안에 작성된"send()" 함수가 실행이 되면서 "ws.send(temp)"가 실행
- "@OnMessage" 가 실행되면서 clients에 등록된 모든 사용자 에게 메시지를 Response를 한다.
- js안에 작성된 "ws.onmessage = function (msg) {" 가 실행이 되면서 화면에 셋팅
- 만약 사용자가 브라우저를 종료 하거나 나가게 되면 @OnClose가 실행 되면서 Session을 제거 한다.
간단한 순서 설명은 알아 보기 쉽게 하기 위해 코드 그대로 복붙 하여 작성하였습니다.
후기
여기 까지는 인터넷에 검색 하면 바로 나온다.
이 다음은 STOMP를 사용하여 Socket에서 채팅 방을 자동으로 셋팅 하여 메시지 전송 하는 법을 작성 하겠습니다.
참고
728x90
'BackEnd > Spring Boot' 카테고리의 다른 글
Show JPA Query Log (0) | 2023.04.16 |
---|---|
채팅 만들기_2(chatting_room) (0) | 2023.04.16 |
Request PathVariable Enum Converter (0) | 2023.04.16 |
Enum 등록된 값 이외에 값 등록시 (0) | 2023.04.16 |
TypeHandler (0) | 2023.04.16 |