WebSocket是客户端和服务器端的一个通信,WebSocket分为客户端和服务端,所以我们两个端都要开发,前端的WebSocket在卖家订单管理界面的js代码里,会进行一个监听,一旦微信点餐的前端对服务端产生一个新的订单,服务端WebSocket就会对含有WebSocket的前端卖家订单管理界面发送消息,收到消息的前端就可以进行一系列的动作,如弹出提醒框、播放音乐等。
菜鸟教程:浏览器端WebSocket介绍
博客:https://blog.youkuaiyun.com/weixin_43580824/article/details/129990935?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22129990935%22%2C%22source%22%3A%22weixin_43580824%22%7D
先是进行后端的开发
第一步 要引入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();
}
}
第三步 在排查业务里面产生新的排查项目推送消息给前端
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
@Override
@Transactional(rollbackFor = Exception.class)
public void submit(ReportDTO dto) {
SysUser user = LoginUserContextHolder.getUser();
Report report = dto.getReport();
Long reportId = report.getId();
Assert.notNull(reportId, "报告id为空");
Long n = baseMapper.selectCount(Wrappers.query(Report.builder().id(reportId).build()));
Assert.isTrue(n == 1, "报告不存在");
Long followerId = report.getFollowerId();
Assert.notNull(followerId, "陪同人员为空");
String followerName = report.getFollowerName();
Assert.notBlank(followerName, "陪同人员为空");
FileAttachment checkerSignPic = dto.getCheckerSignPic();
Assert.isTrue(Objects.nonNull(checkerSignPic)
&& StrUtil.isNotBlank(checkerSignPic.getFileUrl()), "陪同人签名为空");
FileAttachment followSignPic = dto.getFollowSignPic();
Assert.isTrue(Objects.nonNull(followSignPic)
&& StrUtil.isNotBlank(followSignPic.getFileUrl()), "排查人签名为空");
//更新排查内容,计算隐患项目
List<Integer> resultList = subjectService.batchUpd(dto.getSubjectList());
/*List<ReportSubjectDTO> subjectList = dto.getSubjectList();
List<Integer> resultList = new ArrayList<>();
subjectList.forEach(s -> resultList.add(s.getSubject().getCheckResult()));*/
Integer reportResult = resultList.stream().max(Integer::compareTo).orElse(-1);
Assert.isTrue(reportResult > -1, "错误的排查结果");
report.setCheckResult(reportResult);
//维护隐患状态
report.setHiddenState(reportResult);
report.setSubmitTime(LocalDateTime.now());
long dangerNum = resultList.stream().filter(e -> e > 0).count();
report.setDangerNum((int) dangerNum);
report.setRestDangerNum((int) dangerNum);
report.setReviewStatus(dangerNum > 0 ? 0 : -1);
Long unitId = report.getUnitId();
report.setSubmitFlag(1);
if (dangerNum > 0) {
LocalDate deadline = report.getDeadline();
Assert.notNull(deadline, "截止日期为空");
}
//维护签名
addSignInfo(reportId, checkerSignPic, followSignPic);
baseMapper.updateById(report);
//开始维护额外信息
//个人工作统计
workStatService.insertAndUpdateNumberOfHiddenDangersFound(report.getProjectId(), (int) dangerNum);
//todo 维护 隐患变动记录(暂时不开发)
if (Objects.equals(report.getRenewFlag(), 1)
&& Objects.nonNull(report.getRenewReportId())) {
//维护 给上份报告增加复查记录(重新排查覆盖了上份报告的隐患)
checkReportReviewService.updateUpCheckReportReview(report.getRenewReportId().toString());
//每次创建报告清空单位的排查信息
CheckUnitStatus newCheckUnitStatus = checkUnitStatusService.findNewCheckUnitStatus(unitId.toString());
newCheckUnitStatus.setReviewStatus(0);
newCheckUnitStatus.setIsPeriod(1);
newCheckUnitStatus.setLastDangerNum(0);
newCheckUnitStatus.setLastRestDangerNum(0);
newCheckUnitStatus.setPeriodDangerNum(0);
newCheckUnitStatus.setLastReviewSuccessNum(0);
newCheckUnitStatus.setLastReviewFailedNum(0);
newCheckUnitStatus.setHiddenState(reportResult);
checkUnitStatusService.updateById(newCheckUnitStatus);
}
//维护 单位排查状态表
checkUnitStatusService.updateCheckUnitStatus(report.getUnitId());
CheckUnitStatus newCheckUnitStatus = checkUnitStatusService.findNewCheckUnitStatus(report.getUnitId().toString());
newCheckUnitStatus.setHiddenState(reportResult);
newCheckUnitStatus.setCreateBy(user.getNickname());
checkUnitStatusService.updateById(newCheckUnitStatus);
//额外信息维护完毕
CheckUnitDynamics checkUnitDynamics = new CheckUnitDynamics();
checkUnitDynamics.setEventType(2);
checkUnitDynamics.setReportId(reportId);
checkUnitDynamics.setUnitId(report.getUnitId());
Integer checkResult = report.getCheckResult();
checkUnitDynamics.setCheckResult(checkResult);
checkUnitDynamics.setCreateTime(LocalDateTime.now().plusSeconds(2));
checkUnitDynamicsService.insertCheck(checkUnitDynamics);
//解锁
checkUnitStatusService.updateTodayCheckNumber(report);
Map<String, Object> messageMap = new HashMap<>();
messageMap.put("checkResult", report.getCheckResult());
messageMap.put("unitName", report.getUnitName());
messageMap.put("submitTime", report.getSubmitTime());
messageMap.put("createBy", user.getNickname());
//发送websocket消息
webSocket.sendMessage(messageMap.toString());
unLockUnit(dto.getReport().getUnitId());
}
}
这样我们后端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消息后,会弹出一个对话框,并播放音乐。