1.pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.config类配置
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3.server
package com;
import org.apache.commons.lang3.StringUtils;
import org.mamba.blue.model.DynamicBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
@Component
@ServerEndpoint("/noticewebsocket/{usrno}")
public class NoticeWebSocketServer {
private static Logger log = LoggerFactory.getLogger(NoticeWebSocketServer.class);
/**
* 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
*/
private static int onlineCount = 0;
/**
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
*/
private static ConcurrentHashMap<String, NoticeWebSocketServer> webSocketMap = new ConcurrentHashMap<>();
/**
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
*/
private Session session;
/**
* 接收usrno
*/
private String usrno = "";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("usrno") String usrno) {
this.session = session;
this.usrno = usrno;
if (webSocketMap.containsKey(usrno)) {
webSocketMap.remove(usrno);
webSocketMap.put(usrno, this);
//加入set中
} else {
webSocketMap.put(usrno, this);
//加入set中
addOnlineCount();
//在线数加1
}
log.info("用户连接:" + usrno + ",当前在线人数为:" + getOnlineCount());
try {
sendMessage("success");
} catch (IOException e) {
log.error("用户:" + usrno + ",网络异常!!!!!!");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose() {
if (webSocketMap.containsKey(usrno)) {
webSocketMap.remove(usrno);
//从set中删除
subOnlineCount();
}
log.info("用户退出:" + usrno + ",当前在线人数为:" + getOnlineCount());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message, Session session) throws IOException {
// log.info("用户消息:" + usrno + ",报文:" + message);
if("ping".equals(message)){
sendMessage("pong");
}
//可以群发消息
//消息保存到数据库、redis
// if (StringUtils.isNotBlank(message)) {
// try {
// //解析发送的报文
// DynamicBean jsonObject = JsonUtils.json2DynamicBean(message);
//
// //追加发送人(防止串改)
// jsonObject.put("fromusrno", this.usrno);
// String tousrno = jsonObject.getString("tousrno");
// //传送给对应tousrno用户的websocket
// if (StringUtils.isNotBlank(tousrno) && webSocketMap.containsKey(tousrno)) {
// webSocketMap.get(tousrno).sendMessage(JsonUtils.toString(jsonObject));
// } else {
// log.error("请求的usrno:" + tousrno + "不在该服务器上");
// //否则不在这个服务器上,发送到mysql或者redis
// }
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
}
/**
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("用户错误:" + this.usrno + ",原因:" + error.getMessage());
error.printStackTrace();
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
// for(Map.Entry<String, NoticeWebSocketServer> entry: webSocketMap.entrySet()) {
// System.out.println("用户"+entry.getKey());
// entry.getValue().session.getBasicRemote().sendText(message);
// }
}
/**
* 发送自定义消息
*/
public static DynamicBean sendInfo(String message, @PathParam("usrno") String usrno) throws IOException {
log.info("发送消息到:" + usrno + ",报文:" + message);
DynamicBean result=new DynamicBean();
if (StringUtils.isNotBlank(usrno) && webSocketMap.containsKey(usrno)) {
webSocketMap.get(usrno).sendMessage(message);
result.setSuccess();
return result;
} else {
log.error("用户" + usrno + ",不在线!");
result.setFailure("用户" + usrno + ",不在线!");
return result;
}
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
NoticeWebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
NoticeWebSocketServer.onlineCount--;
}
}
4.调用
@Service
public class NoticeServiceImpl implements INoticeService {
@Transactional(rollbackFor = Exception.class)
public DynamicBean insertJmGdNotice(String type,String tabseq, String wano, String title, String content, String createusrno, String createdate, String pushusrno) throws IOException {
//上面是service的逻辑.不同关心
// 发送消息,发送到某个人
NoticeWebSocketServer.sendInfo(JSON.toJSONString(vo),pushusrno);
// e.printStackTrace();
// result.setFailure("通告socket发送消息失败");
// return result;
result.setSuccess();
return result;
}
5.前端js
if ('WebSocket' in window) {
// var socketUrl ="ws://localhost:81/noticewebsocket/"+usrno;
// socketUrl=socketUrl.replace("https","ws").replace("http","ws");
// noticewebsocket = new WebSocket(socketUrl);
}
else {
alert('Not support websocket')
}
var lockReconnect = false;//避免重复连接
var wsUrl = baseWsPath + "noticewebsocket/" + usrno;
wsUrl = wsUrl.replace("https", "ws").replace("http", "ws");
var ws;
var tt;
function createWebSocket() {
try {
ws = new WebSocket(wsUrl);
init();
} catch (e) {
console.log('catch');
reconnect(wsUrl);
}
}
function init() {
ws.onclose = function () {
reconnect(wsUrl);
};
ws.onerror = function () {
reconnect(wsUrl);
};
ws.onopen = function () {
//心跳检测重置
heartCheck.start();
};
ws.onmessage = function (event) {
//拿到任何消息都说明当前连接是正常的
// console.log('接收到消息'+event.data);
if (event.data && event.data != 'pong' && event.data != 'success') {
// layer.msg("您有新的通告,请及时查看!",{icon:1})
if (noticeflag == false) {
getNotices();
} else {
addNewNotice(event.data);
}
}
heartCheck.start();
}
}
function reconnect(url) {
if (lockReconnect) {
return;
}
;
lockReconnect = true;
//没连接上会一直重连,设置延迟避免请求过多
tt && clearTimeout(tt);
tt = setTimeout(function () {
createWebSocket(url);
lockReconnect = false;
}, 4000);
}
//心跳检测
var heartCheck = {
timeout: 3000,
timeoutObj: null,
serverTimeoutObj: null,
start: function () {
var self = this;
this.timeoutObj && clearTimeout(this.timeoutObj);
this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
this.timeoutObj = setTimeout(function () {
//这里发送一个心跳,后端收到后,返回一个心跳消息,
// console.log('start.发送心跳 123456789');
ws.send("ping");
self.serverTimeoutObj = setTimeout(function () {
ws.close();
// createWebSocket();
}, self.timeout);
}, this.timeout)
}
}
createWebSocket(wsUrl);
上面js里的getNotices()和addNewNotice()的两个方法,只是页面怎么展示服务器传过来的消息,故没有写,别问为什么…baseWsPath,放在jsp里面,如下
<%
String baseWsPath="";
if(request.getServerPort()==443){
baseWsPath= "wss://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
baseTelPath= "wss://"
+ request.getServerName();
}else{
baseWsPath= "ws://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
}
%>
写的东西只是作为参考,三克油