백엔드 구성
의존성 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocket 설정 클래스
package com.example.websocket.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfiguration {
@Bean
public ServerEndpointExporter endpointExporter() {
return new ServerEndpointExporter();
}
}
WebSocket 서버 엔드포인트
package com.example.websocket.endpoint;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
@ServerEndpoint("/api/ws/connect/{userId}")
@Component
public class NotificationEndpoint {
private static final ConcurrentHashMap<String, NotificationEndpoint> connections = new ConcurrentHashMap<>();
private Session clientSession;
private String userId;
@OnOpen
public void handleOpen(Session session, @PathParam("userId") String userId) {
this.userId = userId;
this.clientSession = session;
connections.put(userId, this);
try {
sendResponse("connected");
} catch (Exception e) {
e.printStackTrace();
}
}
@OnClose
public void handleClose() {
connections.remove(this.userId);
}
@OnMessage
public void handleMessage(String message, Session session) {
System.out.println("수신 메시지: " + message + " from " + session.getId());
}
@OnError
public void handleError(Session session, Throwable throwable) {
throwable.printStackTrace();
}
public void sendResponse(String response) {
try {
if (this.clientSession != null && this.clientSession.isOpen()) {
this.clientSession.getBasicRemote().sendText(response);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void pushToUser(String targetUser, String notification) {
NotificationEndpoint endpoint = connections.get(targetUser);
if (endpoint != null) {
endpoint.sendResponse(notification);
}
}
}
프론트엔드 구성
Vue 컴포넌트 (ChatView.vue)
<template>
<div class="notification-panel">
<button @click="transmitMessage('https://example.com 방문')">메시지 전송</button>
<div v-for="(msg, index) in receivedMessages" :key="index">
{{ msg }}
</div>
</div>
</template>
<script>
export default {
name: 'RealTimeNotifications',
data() {
return {
receivedMessages: [],
socketConnection: null
}
},
mounted() {
this.establishConnection()
},
beforeDestroy() {
if (this.socketConnection) {
this.socketConnection.close()
}
},
methods: {
establishConnection() {
const wsUrl = `ws://localhost:서버포트/api/ws/connect/${사용자ID}`
if (!window.WebSocket) {
console.error('브라우저가 WebSocket을 지원하지 않습니다')
this.$message.error('WebSocket 미지원으로 푸시 기능 사용 불가!')
return
}
this.socketConnection = new WebSocket(wsUrl)
this.socketConnection.onopen = () => {
this.transmitMessage('초기 연결 완료')
console.log('WebSocket 연결 성공')
}
this.socketConnection.onmessage = (event) => {
this.receivedMessages.push(event.data)
}
this.socketConnection.onerror = (error) => {
console.error('연결 오류:', error)
}
this.socketConnection.onclose = () => {
console.log('연결 종료됨')
}
},
transmitMessage(content) {
if (this.socketConnection && this.socketConnection.readyState === WebSocket.OPEN) {
this.socketConnection.send(content)
}
}
}
}
</script>