Description
我在搭建Online-Food-Ordering-System这个项目时,当用户在微信小程序上下单的时候,商家的后台系统要能够第一时间收到新订单的提醒。既然是发送即时通知,使用Web Socket是一个比较好的解决方案
-
首先引入Maven Dependency
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
-
配置一个ServerEndpointExporter 这一步很关键。通常情况下Tomcat会主动使用ServletContainerInitializer扫描带有@ServerEndpoint注解的类,但是Spring-Boot这种内嵌web container的框架并不会执行这一步。如果忽略掉这一步配置就会是无尽的404…
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
-
后台订单页面引入Web Socket js部分。首先判断当前浏览器是否支持Web Socket,之后对onopen(web socekt建立链接), onclose(断开web socket), onerror(web socket链接错误), onmessage(web socket接收到新信息) 以及onbeforunload(页面重新加载前对操作)进行设置。
var webSocket = null; if('WebSocket' in window){ webSocket = new WebSocket('ws://markzhang.natapp1.cc/sell/webSocket'); }else{ alert("current browser does not support web socket"); } webSocket.onopen = function(event){ console.log("connection set up"); } webSocket.onclose = function(event){ console.log("web socket disconnected"); }; webSocket.onerror = function(event){ alert("web socket connection error"); }; webSocket.onmessage = function(event){ console.log("new message received: " + event.data); $('#orderAlert').modal('show'); document.getElementById('altertAudio').play(); $('#orderDetail').on("click", function(){ location.href="/sell/vendor/order/detail?orderId="+event.data; }); }; window.onbeforeunload = function(event){ webSocket.close(); };
-
后台中@ServerEndpoint用来设置web socket 链接的地址。同样对onOpen, onClose, onMessage事件设置响应的程序。这里后端的@onMessage部分不要与前端页面的webSocket.onmessage搞混。@onMessage是前端页面向后端发送信息后端的响应。而webSocket.onmessage是后台有新下单事件发生,后台通过broadcast方法向前端页面发送信息后前端作出的反应。
@Component
@Slf4j
@ServerEndpoint("/webSocket")
public class WebSocket {
private Session session;
/**
* thread safe set
*/
private static Set<WebSocket> listeners = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session session) {
this.session = session;
listeners.add(this);
log.info("[web socket message] set up a connection, number of connections: {}", listeners.size());
}
@OnClose
public void onClose(Session session) {
listeners.remove(this);
log.info("[web socket message] close a connection, number of connections: {}", listeners.size());
}
/**
* server side receive message from the client side
* @param message
*/
@OnMessage
public void onMessage(String message) {
log.info("[web socket message] receive message from the client side={}", message);
}
/**
* server broadcast message to front end sockets
* @param message
*/
public void broadcast(String message) {
for (WebSocket listener : listeners) {
log.info("[web socket message] broadcast message={}", message);
try {
listener.session.getBasicRemote().sendText(message);
} catch (IOException e) {
log.error("[web socket message] broadcast message error: {}", e.getMessage());
}
}
}
}
- 这样接单的前台html就和后端打通了,只需要在service层中,下单之后调用boradcast方法就可以发送即时消息了。
//4. revise the number of stock List<CartDTO> cartDTOS = orderDTO.getOrderDetailList().stream(). map(e -> new CartDTO(e.getProductId(), e.getProductQuantity())).collect(Collectors.toList()); productInfoService.decreaseStock(cartDTOS); //5. send message to web socket webSocket.broadcast(orderDTO.getOrderId());