CARVIEW |
Select Language
HTTP/2 200
date: Wed, 30 Jul 2025 20:49:07 GMT
content-type: text/html; charset=utf-8
vary: X-PJAX, X-PJAX-Container, Turbo-Visit, Turbo-Frame, X-Requested-With,Accept-Encoding, Accept, X-Requested-With
etag: W/"d4633117e869c45972934c4f679055eb"
cache-control: max-age=0, private, must-revalidate
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
x-xss-protection: 0
referrer-policy: no-referrer-when-downgrade
content-security-policy: default-src 'none'; base-uri 'self'; child-src github.githubassets.com github.com/assets-cdn/worker/ github.com/assets/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.github.com www.githubstatus.com collector.github.com raw.githubusercontent.com api.github.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com *.rel.tunnels.api.visualstudio.com wss://*.rel.tunnels.api.visualstudio.com objects-origin.githubusercontent.com copilot-proxy.githubusercontent.com proxy.individual.githubcopilot.com proxy.business.githubcopilot.com proxy.enterprise.githubcopilot.com *.actions.githubusercontent.com wss://*.actions.githubusercontent.com productionresultssa0.blob.core.windows.net/ productionresultssa1.blob.core.windows.net/ productionresultssa2.blob.core.windows.net/ productionresultssa3.blob.core.windows.net/ productionresultssa4.blob.core.windows.net/ productionresultssa5.blob.core.windows.net/ productionresultssa6.blob.core.windows.net/ productionresultssa7.blob.core.windows.net/ productionresultssa8.blob.core.windows.net/ productionresultssa9.blob.core.windows.net/ productionresultssa10.blob.core.windows.net/ productionresultssa11.blob.core.windows.net/ productionresultssa12.blob.core.windows.net/ productionresultssa13.blob.core.windows.net/ productionresultssa14.blob.core.windows.net/ productionresultssa15.blob.core.windows.net/ productionresultssa16.blob.core.windows.net/ productionresultssa17.blob.core.windows.net/ productionresultssa18.blob.core.windows.net/ productionresultssa19.blob.core.windows.net/ github-production-repository-image-32fea6.s3.amazonaws.com github-production-release-asset-2e65be.s3.amazonaws.com insights.github.com wss://alive.github.com wss://alive-staging.github.com api.githubcopilot.com api.individual.githubcopilot.com api.business.githubcopilot.com api.enterprise.githubcopilot.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com copilot-workspace.githubnext.com objects-origin.githubusercontent.com; frame-ancestors 'none'; frame-src viewscreen.githubusercontent.com notebooks.githubusercontent.com; img-src 'self' data: blob: github.githubassets.com media.githubusercontent.com camo.githubusercontent.com identicons.github.com avatars.githubusercontent.com private-avatars.githubusercontent.com github-cloud.s3.amazonaws.com objects.githubusercontent.com release-assets.githubusercontent.com secured-user-images.githubusercontent.com/ user-images.githubusercontent.com/ private-user-images.githubusercontent.com opengraph.githubassets.com copilotprodattachments.blob.core.windows.net/github-production-copilot-attachments/ github-production-user-asset-6210df.s3.amazonaws.com customer-stories-feed.github.com spotlights-feed.github.com objects-origin.githubusercontent.com *.githubusercontent.com; manifest-src 'self'; media-src github.com user-images.githubusercontent.com/ secured-user-images.githubusercontent.com/ private-user-images.githubusercontent.com github-production-user-asset-6210df.s3.amazonaws.com gist.github.com; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com; upgrade-insecure-requests; worker-src github.githubassets.com github.com/assets-cdn/worker/ github.com/assets/ gist.github.com/assets-cdn/worker/
server: github.com
content-encoding: gzip
accept-ranges: bytes
set-cookie: _gh_sess=ExT%2Fq%2F%2BAaIc8Fe%2F2Nfuri8vzUrhdaUJ27hiFdAkkGw0zUgfrT2DZCg9I3bFWnfNjzNQuZ4kkn%2FosxZZVgBp15P1%2BHXnl0L0s9rpvM7fPCKyt%2FCffxIO1fC8pgeW29Ys%2FbcNTXIEHr7qFm9V63jXfEDbwwAcyqX6%2FzmaFqkjuZ3xcIQG0Iyp2h3xChccXLWTNzK28SL2s818LVjn1YbC1nlPZuYaAgYFaIQmQhRT6bsNDVHGnLtKcdleP%2BM1noVFhgiGKucZLPw431%2BRUFzNd1A%3D%3D--2yQh7M9WFK9gxuy5--2%2FZqKwQjyLTifZ4Fj1JE1Q%3D%3D; Path=/; HttpOnly; Secure; SameSite=Lax
set-cookie: _octo=GH1.1.1566092103.1753908546; Path=/; Domain=github.com; Expires=Thu, 30 Jul 2026 20:49:06 GMT; Secure; SameSite=Lax
set-cookie: logged_in=no; Path=/; Domain=github.com; Expires=Thu, 30 Jul 2026 20:49:06 GMT; HttpOnly; Secure; SameSite=Lax
x-github-request-id: 88C4:373DAE:20316:2D0DA:688A8542
WebSocket消息推送 · sqmax/springboot-project Wiki · GitHub
Skip to content
Navigation Menu
{{ message }}
-
Notifications
You must be signed in to change notification settings - Fork 625
WebSocket消息推送
sqmax edited this page Dec 7, 2018
·
6 revisions
WebSocket是客户端和服务器端的一个通信,WebSocket分为客户端和服务端,所以我们两个端都要开发,前端的WebSocket在卖家订单管理界面的js代码里,会进行一个监听,一旦微信点餐的前端对服务端产生一个新的订单,服务端WebSocket就会对含有WebSocket的前端卖家订单管理界面发送消息,收到消息的前端就可以进行一系列的动作,如弹出提醒框、播放音乐等。
菜鸟教程:浏览器端WebSocket介绍
阮一峰博客:WebSocket教程
第一步 要引入SpringBoot对WebSocket的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
第二步
@Component
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
第三步 在订单业务类的的创建订单方法完成后,后端向前端商家管理系统的订单界面发送WebSocket消息。
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Autowired
private ProductService productService;
@Autowired
private OrderDetailRepository orderDetailRepository;
@Autowired
private WebSocket webSocket;
@Override
@Transactional
public OrderDTO create(OrderDTO orderDTO) {
String orderId= KeyUtil.genUniqueKey();
BigDecimal orderAmount=new BigDecimal(BigInteger.ZERO);
// List<CartDTO> cartDTOList=new ArrayList<>();
//1.查询商品(数量,价格)
for(OrderDetail orderDetail:orderDTO.getOrderDetailList()){
ProductInfo productInfo=productService.findOne(orderDetail.getProductId());
if(productInfo==null){
// throw new SellException(ResultEnum.PRODUCT_NOT_EXIT);
throw new ResponseBankException();
}
//2.计算订单总价
orderAmount=productInfo.getProductPrice()
.multiply(new BigDecimal(orderDetail.getProductQuantity()))
.add(orderAmount);
//订单详情入库
orderDetail.setDetailId(KeyUtil.genUniqueKey());
orderDetail.setOrderId(orderId);
BeanUtils.copyProperties(productInfo,orderDetail);
orderDetailRepository.save(orderDetail);
// CartDTO cartDTO=new CartDTO(orderDetail.getProductId(),orderDetail.getProductQuantity());
// cartDTOList.add(cartDTO);
}
//3,写入订单数据库(orderMaster和orderDetail)
OrderMaster orderMaster=new OrderMaster();
orderDTO.setOrderId(orderId);
BeanUtils.copyProperties(orderDTO,orderMaster);
// orderMaster.setOrderId(orderId);
orderMaster.setOrderAmount(orderAmount);
orderMaster.setOrderStatus(OrderStatusEnum.NEW.getCode());
orderMaster.setPayStatus(PayStatusEnum.WAIT.getCode());
orderMasterRepository.save(orderMaster);
//4.扣库存
List<CartDTO> cartDTOList=orderDTO.getOrderDetailList().stream().map(e->
new CartDTO(e.getProductId(),e.getProductQuantity()))
.collect(Collectors.toList());
productService.decreaseStock(cartDTOList);
//发送websocket消息
webSocket.sendMessage(orderDTO.getOrderId());
return orderDTO;
}
这样我们后端WebSocket相关的业务逻辑类已全部完成。
第四步 写一个响应前端WebSocket的后端WebSocket,这也是一个Controller,但比较特殊,是用WS协议进行通信的,我们写在Service包里。
@Component
@ServerEndpoint("/webSocket")
@Slf4j
public class WebSocket {
private Session session;
private static CopyOnWriteArraySet<WebSocket> webSocketSet=new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session session){
this.session=session;
webSocketSet.add(this);
log.info("【websocket消息】 有新的连接,总数:{}",webSocketSet.size());
}
@OnClose
public void onClose(){
webSocketSet.remove(this);
log.info("【websocket消息】 连接断开,总数:{}",webSocketSet.size());
}
@OnMessage
public void onMessage(String message){
log.info("【websocket消息】 收到客户端发来的消息:{}",message);
}
public void sendMessage(String message){
for(WebSocket webSocket:webSocketSet){
log.info("【websocket消息】 广播消息,message={}",message);
try {
webSocket.session.getBasicRemote().sendText(message);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
前端卖家商品管理前端界面的WebSocket如下:
<script>
var websocket=null;
if('WebSocket' in window){
websocket=new WebSocket('ws://sqmax.natapp1.cc/sell/webSocket');
}else{
alert('该浏览器不支持websocket');
}
websocket.onopen=function (ev) {
console.log('建立连接');
}
websocket.onclose=function (ev) {
console.log('连接关闭');
}
websocket.onmessage=function (ev) {
console.log('收到消息:'+ev.data);
//弹窗提醒,播放消息
$('#myModal').modal('show');
document.getElementById('notice').play();
}
window.onbeforeunload=function (ev) {
websocket.close();
}
</script>
以下是WebSocket js代码控制HTML。
<div class="modal fade" id="myModal" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">
提醒
</h4>
</div>
<div class="modal-body">
你有新的订单
</div>
<div class="modal-footer">
<button onclick="javascript:document.getElementById('notice').pause()" type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button onclick="location.reload()" type="button" class="btn btn-primary">查看新的订单</button>
</div>
</div>
</div>
</div>
<#--播放音乐-->
<audio id="notice" loop="loop">
<source src="/sell/mp3/song.mp3" type="audio/mpeg" />
</audio>
当前端收到后端的WebSocket消息后,会弹出一个对话框,并播放音乐。
最后我们来测试一下代码。
我们用Postman这个工具代替前端微信点餐,向指定url发送一个如下的post请求。
在前端的商家管理界面可以看到如下的效果:
目录
Clone this wiki locally
You can’t perform that action at this time.