Sangil's blog

https://github.com/ChoiSangIl Admin

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