WebSocket?是一种网络通信协议,很多高级功能都需要它。
一、简介
WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。
它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
其他特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws (如果加密,则为wss ),服务器网址就是 URL。
ws://example.com:80/some/path
?二、springboot+webscoet整合
? ? ?1.maven
<!-- websocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.新建configuration文件夹,在里面创建以下几个文件
WebsocketConfig.java
package com.panku.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @Author: jack
* @Description: websocket配置
* @Date Create in 17:23 2020-02-05
**/
@Configuration
public class WebsocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
?WebSocketMessageResult.java
package com.panku.configuration;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @program: hycloudoa
* @description: webScoet消息返回实体
* @author: xwf
* @create: 2020-07-02 16:44
**/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class WebSocketMessageResult implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 消息标题
*/
private String title;
/**
* 消息内容
*/
private String content;
/**
* 消息连接,没有不填
*/
private String pageUrl;
/**
* 消息类型:success/warning/info/error
*/
private String msgType;
/**
* 发送成功消息
* @param title
* @param content
* @param pageUrl
* @return
*/
public static WebSocketMessageResult success(String title, String content, String pageUrl){
return new WebSocketMessageResult(title,content,pageUrl,"success");
}
public static WebSocketMessageResult success(String title, String content){
return success(title,content,null);
}
public static WebSocketMessageResult success(String content){
return success("成功",content,null);
}
/**
* 消息
* @param title
* @param content
* @param pageUrl
* @return
*/
public static WebSocketMessageResult info(String title, String content, String pageUrl){
return new WebSocketMessageResult(title,content,pageUrl,"info");
}
/**
* 错误
* @param title
* @param content
* @param pageUrl
* @return
*/
public static WebSocketMessageResult error(String title, String content, String pageUrl){
return new WebSocketMessageResult(title,content,pageUrl,"error");
}
public static WebSocketMessageResult error(String content){
return error("错误",content,null);
}
/**
* 警告
* @param title
* @param content
* @param pageUrl
* @return
*/
public static WebSocketMessageResult warning(String title, String content, String pageUrl){
return new WebSocketMessageResult(title,content,pageUrl,"warning");
}
}
WebSocketServer.java
package com.panku.configuration;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @program: hycloudoa
* @description: WebSocket配置
* @author: xwf
* @create: 2020-06-28 10:00
**/
@Slf4j
@ServerEndpoint("/imserver/{userIp}")
@Component
public class WebSocketServer {
/**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
private static AtomicInteger onlineCount = new AtomicInteger(0);
/**
* 的线程安全的HashMap,存放每个客户端对应的WebSocket对象。
*/
private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
/**
* 用户session会话连接,需通过他来发消息
*/
private Session session;
/**
* 连接用户ip,医生编号
*/
private String userIp;
/**
* 建立连接成功方法
* @param session session会话
* @param userIp 连接者id
*/
@OnOpen
public void onOpen(Session session, @PathParam("userIp") String userIp){
this.session = session;
this.userIp = userIp;
//如map中不存在用户信息,则添加;如存在,删除重新添加
if(webSocketMap.containsKey(userIp)){
webSocketMap.remove(userIp);
webSocketMap.put(userIp, this);
}else{
//加入map
webSocketMap.put(userIp, this);
//在线人数+1
onlineCount.incrementAndGet();
}
log.info("用户【{}】连接成功,当前在线人数为:{}",userIp,onlineCount.get());
sendMessage(WebSocketMessageResult.success("消息服务连接成功"));
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(){
if(webSocketMap.containsKey(userIp)){
webSocketMap.remove(userIp);
//在线人数-1
onlineCount.decrementAndGet();
}
log.info("用户【{}】退出成功,当前在线人数为:{}" ,userIp,onlineCount.get());
}
/**
* 接受客户端消息
*/
@OnMessage
public void onMessage(String message, Session session){
log.info("用户消息【{}】,报文:{}",userIp,message);
if(!StringUtils.isEmpty(message)){
JSONObject jsonObject= JSON.parseObject(message);
//发送人id
jsonObject.put("fromuserIp",userIp);
Object touserIp = jsonObject.get("touserIp");
//传送给对应touserIp用户的websocket
if(touserIp!=null&&webSocketMap.containsKey(touserIp)){
webSocketMap.get(touserIp).sendMessage(JSONObject.toJavaObject(jsonObject,WebSocketMessageResult.class));
}else{
//否则不在这个服务器上,发送到mysql或者redis
log.error("请求的userIp:"+touserIp+"不在该服务器上");
}
}
}
/**
* 实现服务器主动推送
* @param message 消息内容
*/
public void sendMessage(WebSocketMessageResult message){
try {
log.info("服务器推送消息【{}】", JSON.toJSONString(message));
this.session.getBasicRemote().sendText(JSON.toJSONString(message));
} catch (Exception e) {
e.printStackTrace();
log.error("用户【{}】推送消息失败,原因【{}】", userIp, e.getMessage());
}
}
/**
* 实现服务器主动推送
*/
public void sendMessage(String message) {
try {
this.session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 发送自定义消息
* @param bizMsg 消息
*/
public static void sendInfo(BizMsg bizMsg){
String macceptUser = bizMsg.getMacceptUser();
if(macceptUser!=null&&webSocketMap.containsKey(macceptUser)){
webSocketMap.get(macceptUser).sendMessage(JSONObject.toJSONString(bizMsg));
}else{
log.error("用户【{}】不在线!",macceptUser);
}
}
/**
*
* @param session
* @param error
*/
@OnError
public void onError(Session session, Throwable error){
log.error("用户【{}】错误,原因:{}" ,userIp,error.getMessage());
error.printStackTrace();
}
}
?BizMsg.java
package com.panku.configuration;
import lombok.Data;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author 盘古
* @since 2020-11-24
*/
@Data
public class BizMsg implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 消息类型 1刷新 2选呼,顺呼,重呼
*/
private Integer msgType;
/**
* 消息标题
*/
private String mtitle;
/**
* 排号ID
*/
private Long issueId;
/**
* 消息接收人
*/
private String macceptUser;
/**
* 诊室编号
*/
private String zsbh;
}
JavaScript调用浏览器接口实例如下:
var wsServer = 'ws://localhost:8888/Demo'; //服务器地址
var websocket = new WebSocket(wsServer); //创建WebSocket对象
websocket.send("hello");//向服务器发送消息
alert(websocket.readyState);//查看websocket当前状态
websocket.onopen = function (evt) {
//已经建立连接
};
websocket.onclose = function (evt) {
//已经关闭连接
};
websocket.onmessage = function (evt) {
//收到服务器消息,使用evt.data提取
};
websocket.onerror = function (evt) {
//产生异常
};
前端调用代码(完整代码见阿里云盘? ?"websocket前端测试代码")
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script src="./js/reconnecting-websocket.js" type="text/javascript" charset="utf-8"></script>
<script>
// const userId = `${Date.now()}_${Math.random()}`
const webHttp = "ws/url"
let websocket
function initWS () {
// 初始化websocket
websocket = new ReconnectingWebSocket(webHttp)
console.log(webHttp)
// 监听websocket 连接成功
websocket.onopen = function (e) {
console.log('-----websocket 连接成功-----')
}
// websocket 连接失败
websocket.onerror = function (e) {
console.log('-----websocket 连接失败-----')
}
// websocket 连接关闭
websocket.onclose = function (e) {
console.log('-----websocket 连接关闭------')
}
// websocket 收到消息
websocket.onmessage = function (e) {
console.log(e)
// 接收到消息后,找到对应的订单项目,然后将聊天记录加入
let msg = e.data
// instanceof 就是判断一个实例是否属于某种类型
msg = msg instanceof Object ? msg : JSON.parse(msg)
console.log(msg)
}
}
// 发送消息,格式化数据
function xiaoXis (msgObj) {
// 发送消息
console.log('发送消息', msgObj)
websocket.send(JSON.stringify(msgObj))
}
</script>
</body>
</html>
|