오늘은 실시간 주문접수에 대해서 구현해보도록 하겠습니다
현재 관리자(사장님)는 지난시간에 구현한 주문접수 페이지에서 고객이 요청한 주문을
관리할수 있습니다 하지만 현재 관리자가 주문접수페이지 화면을 띄워놓고 있는상태에서
새로운 주문이 들어오면 해당 주문을 확인하기 위해서는 페이지를 새로고침 해야합니다
관리자 입장에서는 주문이 들어왔는지 아닌지 확인하기 위해서 계속 새로고침을 해야하는건
번거러울뿐더러 서버측에서도 새로고침을 할때마다 계속해서 데이터를 조회하고 보내줘야
하므로 좋은 방법이 아닙니다
따라서 우리는 웹소켓과 STOMP를 이용하여 새로운 주문이 접수되면 관리자페이지에
메세지를 보내고 이 메세지를 수신하면 새로운 주문 데이터를 서버에 요청하도록 할것입니다
그전에 수정해야할 부분이 하나 있습니다. home.js를 보면 우리는 이전에 홈화면에서
사용자가 지도Api를 이용하여 검색한 주소를 쿠키에 저장하여 사용자가 홈화면이나
주문페이지에 접근했을때 쿠키에서 주소를 꺼내어 자동으로 입력하도록 했었습니다
이때 쿠키에 한글을 그대로 저장하였었는데 서버측에서는 쿠키에 담긴 한글을 인식하지
못하므로 문제가 일어납니다 지금까지는 쿠키에 담긴 데이터를 서버측에서 사용하지 않아
별다른 문제가 없었지만 웹소켓 사용시에는 문제가 발생하게 됩니다
따라서 이를 적절한 언어로 인코딩 해줘야 합니다
다음으로 storeDetail.js에서 주문 버튼 클릭시 주문화면으로 넘어갈때
storeId 또한 같이 넘겨주도록 location주소를 변경해줍니다
마찬가지로 OrderController에서도 storeId를 받을수 있도록 수정해줍니다
기존 admin/order.jsp와 order/order.jsp 두곳 상단에 라이브러리를 추가합니다
<!-- sock js -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.5.2/sockjs.min.js"></script>
<!-- STOMP -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
order.js 최상단에 주소로부터 storeId를 얻기 위한 코드와 주문완료시
관리자 - 주문관리페이지에 메시지를 보낼 코드를 추가합니다
또 paymentCash function에서 messageSend() 주석처리를 해제해줍니다
const pathArr = location.pathname.split("/");
const storeId = pathArr[pathArr.length-1];
// 관리자 페이지로 주문요청 메세지
function messageSend() {
console.log("아이디" + storeId);
let socket = new SockJS('/websocket');
let stompClient = Stomp.over(socket);
stompClient.connect({}, function() {
const message = {
message : "새 주문이 들어왔습니다"
}
stompClient.send("/message/order-complete-message/" + storeId, {}, JSON.stringify(message));
stompClient.disconnect();
});
}
다음으로 관리자 - 주문접수 페이지에서 주문메시지를 받을수 있도록 코드를 추가합니다
// 주문 완료 메세지 받기
const socket = new SockJS('/websocket');
const stompClient = Stomp.over(socket);
stompClient.connect({}, function() {
stompClient.subscribe('/topic/order-complete/'+storeId, function(message) {
// 화면에 출력중인 view 갯수
const list = $(".order_list li").length;
if(list == listInfo.getWaitcount()) {
orderList();
}
});
});
이제 서버에서 로직 수행을 위해 웹소켓 라이브러리를 추가해줍니다
<!-- 웹소켓 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
웹소켓 사용시 설정파일을 생성해줘야 합니다 config패키지안에 클래스를 추가해줍시다
@EnableWebSocketMessageBroker
@Configuration
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/message");
}
}
웹소켓설정시에도 마찬가지로 필수적으로 구현해야할 메서드들이 있습니다
sockJs 클라이언트가 Websocket 핸드셰이크를 하기 위해 연결할 endpoint를 지정해야 하는데
클라이언트가 연결되고 http://localhost:8080/endpoint/info?t=??으로 웹소켓 통신이
가능한지 확인한 후, 응답이 websocket:true 이면 웹소켓이 연결됩니다
enableSimpleBroker은 특정 주소가 붙은 클라이언트에게 메세지를 전송하며
setApplicationDestinationPrefixes은 클라이언트에게서 메세지를 받을 서버주소의 경로입니다
이제 메시지를 관리할 컨트롤러를 하나 추가해줘야합니다
@Controller
public class MessageController {
@MessageMapping("/order-complete-message/{storeId}")
@SendTo("/topic/order-complete/{storeId}")
public String message(@DestinationVariable long storeId, String message) {
System.out.println("가게번호 : " + storeId);
System.out.println("메세지 도착 :" + message);
return message;
}
}
메세지 전송에는 @MessageMapping을 사용하고 주소에 들어가는 변수값은
@PathValiable 대신 @DestinationVariable을 사용합니다
사용자가 주문을 완료할시 /order-complete-message/{storeId}로 메시지를 보냅니다
우리가 위에서 설정한 setApplicationDestinationPrefixes로 인해
실제 주소는 /message/order-complete-message/{storeId} 이지만 message가 생략됩니다
SendTo는 해당 메시지를 보낼 주소를 나타냅니다 헷갈리게 쓴것 같아 정리하자면
사용자가 주문완료시 /message/order-complete-message/1과 같은 주소로 메시지를
보냅니다. 그럼 위의 컨트롤러에서 StoreId와 message를 받고 SendTo에 지정된 주소로
message를 리턴시켜줍니다.