Spring Websocket - Kotlin을 이용한 좌석 예약 프로그램 만들기 With Vue DEV / WEB
2023-02-21 posted by sang12
Spring Websocket과 Vue를 이용하여 간단한 좌석 예약 프로그램을 만들어 보겠습니다~
간단한 데모성 프로젝트여서 서비스로직같은 거는 없고 웹소켓을 연결하고 사용하는 것만 참고하시면 좋을거 같습니다~ Github 예제소스도 첨부해놨습니다!
-소스코드 참고
bakcend: https://github.com/ChoiSangIl/sit-down-monkey-websocket
front: https://github.com/ChoiSangIl/websocket-front
Dependancy
implementation("org.springframework.boot:spring-boot-starter-websocket")
implementation("org.springframework.boot:spring-boot-starter-web")
Spring 설정
@Configuration
@EnableWebSocketMessageBroker
class WebSocketBrokerConfig: WebSocketMessageBrokerConfigurer {
override fun configureMessageBroker(registry: MessageBrokerRegistry) {
registry.enableSimpleBroker("/seat")
}
override fun registerStompEndpoints(registry: StompEndpointRegistry) {
registry.addEndpoint("/sit-down-monkey")
.setAllowedOrigins("http://localhost:8081")
.withSockJS()
}
}
Controller
simpleMessagingTemplate을 주입 받아서 원하는 Queue에 push 할 수 있다
@RestController
class ReservationController (
val seatReservationRepository: SeatReservationRepository,
val simpleMessagingTemplate: SimpMessagingTemplate
){
@RequestMapping("/api/v1/reservation/{id}")
fun reservationSeat(@PathVariable("id") id: Int){
try{
seatReservationRepository.reserveSeat(id)
simpleMessagingTemplate.convertAndSend("/seat", Seat(id, true))
println("좌석번호 $id 예약 되었습니다")
}catch (e: Exception){
e.printStackTrace()
}
}
@RequestMapping("/api/v1/reservation/cancel/{id}")
fun cancelReservation(@PathVariable("id") id: Int){
seatReservationRepository.cancelReservation(id)
simpleMessagingTemplate.convertAndSend("/seat", Seat(id, false))
println("좌석번호 $id 예약 취소 되었습니다")
}
}
data class Seat(
val id: Int,
val hasReservation: Boolean
)
persistence
object SeatMemoryDatabase{
private const val MAX_SEAT_SIZE = 100
private val seat: Array = Array(MAX_SEAT_SIZE) { false }
fun reserveSeat(id: Int){
if(seat[id]) throw Exception("이미 예약되었습니다")
seat[id] = true
}
fun cancelReservation(id: Int){
if(!seat[id]) throw Exception("이미 취소 되었습니다.")
seat[id] = false
}
}
@Repository
class SeatReservationRepository {
fun reserveSeat(id: Int){
SeatMemoryDatabase.reserveSeat(id)
}
fun cancelReservation(id: Int){
SeatMemoryDatabase.cancelReservation(id)
}
}
VUE
<template>
<div>
<template v-for="(item, index) in seatList" :key="item">
<template v-if="index % 10 == 0"> <br/> </template>
<v-chip v-if="item" @click="cancle(index)">
{{ item }}
</v-chip>
<v-chip v-else-if="item == false" color="green" @click="reservation(index)">
{{ item }}
</v-chip>
</template>
</div>
</template>
<script>
import Stomp from 'webstomp-client'
import SockJS from 'sockjs-client'
import axios from 'axios';
export default {
name: 'App',
data() {
return {
seatList: Array.from({length: 100}, () => false),
name: 'kukaro',
age: 26,
}
},
created() {
const serverURL = "http://localhost:8080/sit-down-monkey"
let socket = new SockJS(serverURL);
this.stompClient = Stomp.over(socket);
console.log(`소켓 연결을 시도합니다. 서버 주소: ${serverURL}`)
let ref = this
this.stompClient.connect(
{},
frame => {
this.connected = true;
console.log('소켓 연결 성공', frame);
this.stompClient.subscribe("/seat", res => {
console.log('구독으로 받은 메시지 입니다.', res.body)
let seat = JSON.parse(res.body)
ref.seatList[seat['id']] = seat['hasReservation']
});
},
error => {
console.log('소켓 연결 실패', error);
this.connected = false;
}
);
},
methods:{
reservation(seatId) {
axios.get( "/api/v1/reservation/" + seatId)
.then((response) => {
console.log(response)
})
.catch((error)=>{
console.log(error)
alert("서버가 아파요 ㅜㅜ")
})
},
cancle(seatId){
if(confirm(seatId + "취소하시겠습니까?")){
axios.get( "/api/v1/reservation/cancel/" + seatId)
.then((response) => {
console.log(response)
})
.catch((error)=>{
console.log(error)
alert("서버가 아파요 ㅜㅜ")
})
}
}
}
}
</script>
REPLY