화면을 개발하면서 생각보다 기록해두어야 할 부분이 많다고 생각하여 추가로 글을 작성합니다.
프로젝트 생성부분은 프로젝트 생성 부분을 참고해주세요
먼저 vue.config 부분입니다. spring과 vue를 같이 개발시 npm run serve로 front server를 띄울 때 back-end server와 통신을 하기위해 설정합니다.
const { defineConfig } = require('@vue/cli-service')
const host = "localhost"; //back-end host
const port = "8081"; //back-end port
module.exports = defineConfig({
transpileDependencies: true,
outputDir: "../back-end/src/main/resources/static", //webpack build 시 결과물 위치
devServer: {
hot: true,
proxy: {
//http://localhost:8080/api/ -> http://localhost:8081/api/
'/api/': {
target: `http://${host}:${port}`,
changeOrigin: true,
},
'/ws/': {
target: `ws://${host}:${port}`,
changeOrigin: false,
ws: true,
}
}
}
})
> outputDir path 설정은 resources/static 이거나, classpath 내 public 폴더도 가능합니다 참고
여기서 주의해서 봐야하는 부분은 proxy 부분입니다. 작성한 부분을 자세히 보자면
vue에서 /api/로 보내는 요청은 target 으로 변경되어 요청됩니다.
즉, 현재 front-server가 8080으로 떠있다면 axios를 이용해 localhost:8080/api/** 로의 요청은 localhost:8081/api/** 로 변경됩니다.
다음 /ws/또한 같은 의미로 사용됩니다. /ws/는 vue에서 웹소켓을 이용 할 때 사용합니다.
front에서 back-end와 통신 시 axios를 많이 사용하실텐데요,여기서 주의해야할 점은 fetch할 때 input 부분입니다. 처음 input 부분에 다음과 같이 입력했는데 오류가 발생했었습니다.
fetch("http://localhost:8081/api/v1/room, ...)
개발환경에서 개발 시 위에서 설정한 대로
fetch("http://localhost:8080/api/v1/room,) 또는
fetch("/api/v1/room", )
으로 사용하셔야 합니다.
배포 후 빌드 시에는 localhost:8081로 설정되어있어야 합니다
해당 프로젝트에서 사용한 @stomp/stompjs 사용법은 다음과 같습니다.
const client = new Client({//config});
config 부분에는 어떤 속성들이 있는지 확인해봅시다. Client를 따라 들어가보면
와 같은 생성자가 있는 것을 확인할 수 있습니다.
저희가 여기서 봐야하는 부분은 생성자의 인자에 있는 StompConfig 부분입니다.
export class StompConfig {
/**
* See [Client#brokerURL]{@link Client#brokerURL}.
*/
public brokerURL?: string;
/**
* See [Client#stompVersions]{@link Client#stompVersions}.
*/
public stompVersions?: Versions;
/**
* See [Client#webSocketFactory]{@link Client#webSocketFactory}.
*/
public webSocketFactory?: () => any;
/**
* See [Client#connectionTimeout]{@link Client#connectionTimeout}.
*/
public connectionTimeout?: number;
/**
* See [Client#reconnectDelay]{@link Client#reconnectDelay}.
*/
public reconnectDelay?: number;
/**
* See [Client#heartbeatIncoming]{@link Client#heartbeatIncoming}.
*/
public heartbeatIncoming?: number;
/**
* See [Client#heartbeatOutgoing]{@link Client#heartbeatOutgoing}.
*/
public heartbeatOutgoing?: number;
/**
* See [Client#splitLargeFrames]{@link Client#splitLargeFrames}.
*/
public splitLargeFrames?: boolean;
/**
* See [Client#forceBinaryWSFrames]{@link Client#forceBinaryWSFrames}.
*/
public forceBinaryWSFrames?: boolean;
/**
* See [Client#appendMissingNULLonIncoming]{@link Client#appendMissingNULLonIncoming}.
*/
public appendMissingNULLonIncoming?: boolean;
/**
* See [Client#maxWebSocketChunkSize]{@link Client#maxWebSocketChunkSize}.
*/
public maxWebSocketChunkSize?: number;
/**
* See [Client#connectHeaders]{@link Client#connectHeaders}.
*/
public connectHeaders?: StompHeaders;
/**
* See [Client#disconnectHeaders]{@link Client#disconnectHeaders}.
*/
public disconnectHeaders?: StompHeaders;
/**
* See [Client#onUnhandledMessage]{@link Client#onUnhandledMessage}.
*/
public onUnhandledMessage?: messageCallbackType;
/**
* See [Client#onUnhandledReceipt]{@link Client#onUnhandledReceipt}.
*/
public onUnhandledReceipt?: frameCallbackType;
/**
* See [Client#onUnhandledFrame]{@link Client#onUnhandledFrame}.
*/
public onUnhandledFrame?: frameCallbackType;
/**
* See [Client#beforeConnect]{@link Client#beforeConnect}.
*/
public beforeConnect?: () => void | Promise<void>;
/**
* See [Client#onConnect]{@link Client#onConnect}.
*/
public onConnect?: frameCallbackType;
/**
* See [Client#onDisconnect]{@link Client#onDisconnect}.
*/
public onDisconnect?: frameCallbackType;
/**
* See [Client#onStompError]{@link Client#onStompError}.
*/
public onStompError?: frameCallbackType;
/**
* See [Client#onWebSocketClose]{@link Client#onWebSocketClose}.
*/
public onWebSocketClose?: closeEventCallbackType;
/**
* See [Client#onWebSocketError]{@link Client#onWebSocketError}.
*/
public onWebSocketError?: wsErrorCallbackType;
/**
* See [Client#logRawCommunication]{@link Client#logRawCommunication}.
*/
public logRawCommunication?: boolean;
/**
* See [Client#debug]{@link Client#debug}.
*/
public debug?: debugFnType;
/**
* See [Client#discardWebsocketOnCommFailure]{@link Client#discardWebsocketOnCommFailure}.
*/
public discardWebsocketOnCommFailure?: boolean;
/**
* See [Client#onChangeState]{@link Client#onChangeState}.
*/
public onChangeState?: (state: ActivationState) => void;
}
간단하게 저희가 사용하는 것은 brokerURL, onConnect, onDisconnect, onStompError, onWebSocketClose, onWebSocketError 등이 있을 것 같습니다.
정의해야 하는 속성과 함께 client config를 완성시키면 다음과 같습니다.
this.websocketClient = new Client({
brokerURL: "ws://localhost:8080/ws/init",
onConnect: () => {
this.websocketClient.subscribe(`/sub/room/${this.currentRoom.id}`, msg => {
this.messages.push(msg.body);
});
this.websocketClient.publish({
destination: `/pub/room/${this.currentRoom.id}/entered`,
body: JSON.stringify({message: `${this.textMessage}`, writer: "user1"}),
});
},
onDisconnect: (frame) => {},
onStompError: (frame) => {},
onWebSocketClose: (_) => {}
onWebSocketError: (_) => {},
});
추가로 마지막에 client.activate()를 호출해주셔야 합니다.
클라이언트를 생성했다면 다음으로는 subscribe입니다. subscribe은 다음과 같습니다.
client.subscribe(destination, callback=(message:IMessage) => {}, headers=[key:String])
프로젝트에서 사용한 코드는 다음과 같습니다.
this.websocketClient.subscribe(`/sub/room/${this.currentRoom.id}`, msg => {
this.messages.push(msg.body);
})
destination =
/sub/room/${this.currentRoom.id}
callback = msg => { this.messages.push(msg.body); }
sub가 비슷합니다.
client.publish(params: IPublishParams) ==
client.publish({destination: "/queue/test", body: "Hello, STOMP"});
---
export interface IPublishParams {
/**
* destination end point
*/
destination: string;
/**
* headers (optional)
*/
headers?: StompHeaders;
/**
* body (optional)
*/
body?: string;
/**
* binary body (optional)
*/
binaryBody?: Uint8Array;
/**
* By default, a `content-length` header will be added in the Frame to the broker.
* Set it to `true` for the header to be skipped.
*/
skipContentLengthHeader?: boolean;
}
프로젝트에서 사용한 코드는 다음과 같습니다.
const body = {message: `${this.textMessage}`, writer: "user1"}
this.websocketClient.publish({
destination: `/pub/room/${this.currentRoom.id}`,
body: JSON.stringify(body),
});
disconnect는 activate 와 반대로 deactivate 를 사용하면 됩니다.
this.websocketClient.deactivate();
전체 코드는 github에서 확인 가능합니다.