版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_16855077/article/details/82858214
1.pom.xml
<!-- webSocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.后台代码
package com.cloudtech.web.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.cloudtech.web.dubbo.BaseDataResult;
import com.cloudtech.web.entity.WarnNoticeInfo;
import com.cloudtech.web.util.Constans;
import com.cloudtech.web.util.JacksonUtil;
//@ServerEndpoint("/websocket/{user}")
@Component
@ServerEndpoint(value = "/websocket/{id}/{operatorId}")
public class WebSocketServer{
private static final Logger log = LoggerFactory.getLogger(WarnController.class);
//静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
private static int onlineCount = 0;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
static public final ConcurrentMap<Integer, ConcurrentMap<String,WebSocketServer>> webSocketSet = new ConcurrentHashMap<>();
//用户集合 key:账号id value:账号明细
static public final ConcurrentMap<Integer, Integer> principalMaps = new ConcurrentHashMap<>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
/**
* 连接建立成功调用的方法
* @param id 账号id
* @param operatorId 运营商id
* @param session
*/
@OnOpen
public void onOpen(@PathParam("id") Integer id,@PathParam("operatorId") Integer operatorId,Session session) {
this.session = session;
ConcurrentMap<String, WebSocketServer> concurrentMap = webSocketSet.get(id);
if(concurrentMap == null){
concurrentMap = new ConcurrentHashMap<>();
}
concurrentMap.put(session.getId(),this);
webSocketSet.put(id, concurrentMap);
//遗留问题:如果没有预警权限可能也会创建连接,这里暂不考虑
//按道理应该可以从session中取到对应的值,卡了半天,通过前端传值
principalMaps.put(id, operatorId);
addOnlineCount(); //在线数加1
log.info("有新连接加入!当前在线人数为" + getOnlineCount());
}
// //连接打开时执行
// @OnOpen
// public void onOpen(@PathParam("user") String user, Session session) {
// currentUser = user;
// System.out.println("Connected ... " + session.getId());
// }
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam("id") Integer id,Session session) {
ConcurrentMap<String, WebSocketServer> concurrentMap = webSocketSet.get(id);
if(concurrentMap != null){
concurrentMap.remove(session.getId());
}else{
webSocketSet.remove(id);
}
//webSocketSet.remove(this); //从set中删除
principalMaps.remove(this);
subOnlineCount(); //在线数减1
log.info("有一连接关闭!当前在线人数为" + getOnlineCount());
}
/**
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("发生错误");
error.printStackTrace();
}
/**
* 群发消息
* @param warnNoticeInfo
* @throws IOException
*/
public void sendMessage(WarnNoticeInfo warnNoticeInfo) throws IOException {
//转出json发送
session.getBasicRemote().sendText(JacksonUtil.bean2Json(warnNoticeInfo));
}
/**
* 群发自定义消息(系统主动推送)
* @param noticeInfo
* @throws IOException
*/
public BaseDataResult pushBySys(WarnNoticeInfo noticeInfo) throws IOException {
log.info(noticeInfo.toString());
boolean flag = false;
for (Entry<Integer, ConcurrentMap<String, WebSocketServer>> item: webSocketSet.entrySet()) {
ConcurrentMap<String, WebSocketServer> value = item.getValue();
for (Entry<String, WebSocketServer> socket: value.entrySet()) {
Integer operatorId = principalMaps.get(item.getKey());
//不向该预警下不是对应的运营商明下的用户推送消息
if(operatorId == null || operatorId.intValue() != noticeInfo.getOperatorId().intValue()){ //
continue;
}
try {
socket.getValue().sendMessage(noticeInfo);
} catch (IOException e) {
flag = true;
continue;
}
}
}
if(flag){
return new BaseDataResult(Constans.FAILED, "推送预警信息出现异常!");
}
return new BaseDataResult(Constans.FAILED, "推送预警信息成功!");
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
if(WebSocketServer.onlineCount > 0){
WebSocketServer.onlineCount--;
}
}
}
3.前端代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>
<%-- <jsp:include page="../common/head.jsp"></jsp:include> --%>
<link rel="stylesheet" type="text/css"
href="${pageContext.request.contextPath}/assets/css/layui.css" />
<link rel="stylesheet" type="text/css"
href="${pageContext.request.contextPath}/assets/css/css.css" />
<script
src="${pageContext.request.contextPath}/assets/js/jquery-3.2.0.min.js"></script>
<script src="${pageContext.request.contextPath}/assets/js/layui.js"></script>
<script src="${pageContext.request.contextPath}/assets/js/style.js"></script>
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<!-- 音频 -->
<audio autoplay="autoplay" id="auto" src=""></audio>
<div class="layui-logo">气象站数据采集平台</div>
<!-- 头部区域(可配合layui已有的水平导航) -->
<ul class="layui-nav layui-layout-left">
<shiro:hasPermission name="admin:base">
<li class="layui-nav-item"><a href="${pageContext.request.contextPath}/admin/index" target="list">账号管理</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="station:base">
<li class="layui-nav-item"><a href="${pageContext.request.contextPath}/station/index" target="list">站点管理</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="warnInfo:base">
<li class="layui-nav-item"><a href="${pageContext.request.contextPath}/warn/index" target="list">预警管理</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="realtime:base">
<li class="layui-nav-item"><a href="">统计分析</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="realtime:base">
<li class="layui-nav-item layui-this"><a href="${pageContext.request.contextPath}/statis/index" target="list">实时展示</a></li>
</shiro:hasPermission>
<shiro:hasPermission name="system:base">
<li class="layui-nav-item"><a href="${pageContext.request.contextPath}/system/index" target="list">系统管理</a></li>
</shiro:hasPermission>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item"><a href="javascript:;"> <img
src="${pageContext.request.contextPath}/images/common/userIcon.jpg" class="layui-nav-img"> ${principal.name}
</a> <!-- <dl class="layui-nav-child">
<dd>
<a href="">基本资料</a>
</dd>
<dd>
<a href="">安全设置</a>
</dd>
</dl> --></li>
<li class="layui-nav-item"><a onClick="self.parent.location = '${pageContext.request.contextPath}/index/loginout';">注销</a>
</li>
</ul>
</div>
</div>
<script>
layui.use('element', function() {
var element = layui.element;
});
$("#changeP").click(function() {
window.parent.$("#rigth")[0].contentWindow.passwordC();
})
</script>
<script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket
var id = ${principal.id};
var operatorId = ${principal.operatorId};
if ('WebSocket' in window) {
websocket = new WebSocket("ws://192.168.1.161:8080/climate/websocket/"+id+"/"+operatorId);
}
else {
alert('当前浏览器 Not support websocket')
}
//连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("WebSocket连接成功");
}
//接收到消息的回调方法
websocket.onmessage = function (event) {
if(event.data != null){
//音频
var auto = $("#auto");
auto.attr("src",'../assets/audio/6124.wav');
}
var obj = JSON.parse(event.data);
console.log("test:"+obj.id);
setMessageInnerHTML(event.data);
}
//连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("WebSocket连接关闭");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
//document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</head>
<!-- 音频 -->
<audio autoplay="autoplay" id="auto" src=""></audio>
package com.cloudtech.web.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
上面这句话是后台推送后,声音提醒
websocket坑点1:ws://192.168.1.161:8080/climate/websocket
项目访问的地址需要跟websocket一样,不然会有问题