- TempData
- asp.net dropdownlist
- 하드 윈도우 복사
- 하드 마이그레이션
- javascript redirection
- XSS방어
- asp.net core Select
- 맥 오라클설치
- 말줄임표시
- XSS PHP
- 강제이동
- 404에러페이지
- 파일업로드 유효성체크
- javascript 바코드 생성
- ASP.Net Core 404
- Mac Oracle
- jquery 바코드생성
- ViewBag
- 파일업로드 체크
- ViewData
- jquery 바코드
- django 엑셀불러오기
- php 캐쉬제거
- asp.net Select
- 타임피커
- javascript 바코드스캔
- 바코드 생성하기
- SSD 복사
- 바코드 스캔하기
- javascript 유효성체크
웹개발자의 기지개
[SpringBoot] WebSocket 을 이용한 채팅구현하기 본문
[SpringBoot] WebSocket 을 이용한 채팅구현하기
http://portfolio.wonpaper.net 2023. 12. 27. 06:23
Java SpringBoot , WebSocket 을 이용해서 채팅을 구현해보았다.
Java 17
SpringBoot 3.2.1
Gradle, War
[ build.gradle ]
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
|
plugins {
id 'java'
id 'war'
id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'kr.co.alwaysweb'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//implementation 'javax.servlet:jstl' //스프링부트 3.0 미만
implementation 'jakarta.servlet:jakarta.servlet-api' //스프링부트 3.0 이상
implementation 'jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api' //스프링부트 3.0 이상
implementation 'org.glassfish.web:jakarta.servlet.jsp.jstl' //스프링부트 3.0 이상
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'
}
tasks.named('test') {
useJUnitPlatform()
}
|
cs |
JSP와 Springboot3.0 이상, websocket 등의 의존성을 추가
[ /src/main/resources/application.properties ]
1
2
3
4
5
6
7
8
9
|
# 서버 포트
server.port=8071
# static
spring.mvc.static-locations=/resources/**
# JSP
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
|
cs |
[ WebSocketServer.java ]
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
|
package kr.co.alwaysweb.springbootwebsocket;
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
@Service
@ServerEndpoint(value="/chat")
public class WebSocketServer {
private static Set<Session> clients =
Collections.synchronizedSet(new HashSet<Session>());
@OnOpen
public void onOpen(Session s) {
System.out.println("open session : " + s.toString());
if(!clients.contains(s)) {
clients.add(s);
System.out.println("session open : " + s);
}else {
System.out.println("이미 연결된 session 입니다.");
}
}
@OnMessage
public void onMessage(String msg, Session session) throws Exception{
System.out.println("receive message : " + msg);
for(Session s : clients) {
System.out.println("send data : " + msg);
s.getBasicRemote().sendText(msg);
}
}
@OnClose
public void onClose(Session s) {
System.out.println("session close : " + s);
clients.remove(s);
}
@OnError
public void onError(Throwable e) {
System.out.println("onError : " + e.getMessage());
e.printStackTrace();
}
}
|
cs |
[ WebSocketConfig.java ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package kr.co.alwaysweb.springbootwebsocket;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Component
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
|
cs |
[ WebSocketChatController.java ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package kr.co.alwaysweb.springbootwebsocket;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
@RestController
public class WebSocketChatController {
@RequestMapping("/mychat")
public ModelAndView chat() {
ModelAndView mv = new ModelAndView();
mv.setViewName("websoket_chatting");
return mv;
}
}
|
cs |
[ /webapp/WEB-INF/views/webSocket_chatting.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
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel='stylesheet' type='text/css' href='./css/chat.css'>
</head>
<body>
<div id='chatt'>
<h1>WebSocket Chatting</h1>
<input type='text' id='mid' value='' placeholder="채팅명을 입력해주세요.">
<input type='button' value='로그인' id='btnLogin'>
<br/>
<div id='talk'></div>
<div id='sendZone'>
<textarea id='msg' ></textarea>
<input type='button' value='전송' id='btnSend'>
</div>
</div>
<script src='./js/chat.js'></script>
</body>
</html>
|
cs |
[ chat.js ]
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
|
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){
var data = JSON.parse(msg.data);
var css;
if(data.mid == mid.value){
css = 'class=me';
}else{
css = 'class=other';
}
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;//스크롤바 하단으로 이동
}
this.disabled = true;
mid.disabled = true;
}
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 ='';
}
|
cs |
[ chat.css ]
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
|
@charset "UTF-8";
*{
box-sizing: border-box;
}
#chatt{
width: 800px;
margin: 20px auto;
}
#chatt #talk{
width: 800px;
height: 400px;
overflow: scroll;
border : 1px solid #aaa;
}
#chatt #msg{
width: 740px;
height:100px;
display: inline-block;
}
#chatt #sendZone > *{
vertical-align: top;
}
#chatt #btnSend{
width: 54px;
height: 100px;
}
#chatt #talk div{
width: 70%;
display: inline-block;
padding: 6px;
border-radius:10px;
}
#chatt .me{
background-color : #ffc;
margin : 1px 0px 2px 30%;
}
#chatt .other{
background-color : #eee;
margin : 2px;
}
|
cs |
참고 : https://jobtc.tistory.com/59
참고 : https://dev-gorany.tistory.com/212
참고 : https://velog.io/@prettylee620/8%EC%9B%94-1
nginx + tomcat9 + springboot websocket
Ubuntu tomcat9 설치
다운로드
sudo wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.84/bin/apache-tomcat-9.0.84.tar.gz
압축풀기
sudo tar xzvf apache-tomcat-9.0.84.tar.gz
폴더명 변경
sudo mv apache-tomcat-9.0.84 tomcat9
디렉토리 권한 설정
sudo chown -R tomcat:tomcat tomcat9
포트 열린 전체 목록
sudo ufw status verbose
우분투 방화벽 8071 포트 열기
sudo ufw allow 8071/tcp
/etc/nginx/sites-enabled/default 설정 수정
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
proxy_pass http://localhost:8071;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
nginx 재가동
sudo systemctl restart nginx
참고 : https://yooloo.tistory.com/170
참고 : https://velog.io/@prettylee620/8%EC%9B%94-1
참고 : https://velog.io/@jinjinhyojin/WebSocket-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
참고 : https://spring.io/guides/gs/messaging-stomp-websocket