详细原理:
https://www.zhihu.com/question/20215561
简介
一种在单个 TCP 连接上进行全双工通讯的协议。
Http协议是通信只能有客户端发起,而且必须在一定时间内应答。所以要实现实时的数据展示,只能能采用轮询的方式,不断的向后台发送请求,从而浪费资源。而webSocket就是只需要发一次请求,就一直能保留。等到有数据了在返回。从而实现实时的数据展示。
用java代码实现
导包
<dependency>
<groupId>org.springframework.boot</groupId>
<artfactId>spring-boot-starter-websocker<artfactId>
</dependency>
新建配置类
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
新建Websocket枚举类,用于前端区分数据
public enum MessageTypeEnums implements IEnum {
/**
* 1 状态1,2 状态2
*/
STUTA_ONE(11, "状态1"),
STUTA_TWO(12, "状态2");
int code;
String description;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public Serializable getValue() {
return null;
}
MessageTypeEnums(int code, String description) {
this.code = code;
this.description = description;
}
}
实现类
@ServerEndpoint("/socketServer/{userId}")
@Component
@Slf4j
public class WebSocketServer {
//我自己的实现类 需替换
private static EmailDistributeService emailDistributeService;
@Autowired
public void setEmailDistributeService(EmailDistributeService emailDistributeService) {
WebSocketServer.emailDistributeService = emailDistributeService;
}
/**
* 用线程安全的CopyOnWriteArraySet来存放客户端连接的信息
*/
private static CopyOnWriteArraySet<ClientModel> webSocketSet = new CopyOnWriteArraySet<>();
/**
* websocket封装的session,信息推送,就是通过它来信息推送
*/
private Session session;
/**
* 用户连接时触发,我们将其添加到
* 保存客户端连接信息的socketServers中
*
* @param session
* @param userId
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
this.session = session;
webSocketSet.add(new ClientModel(userId, session));
log.info("用户:【{}】连接成功", userId);
}
/**
* 连接关闭触发,通过sessionId来移除
* socketServers中客户端连接信息
*/
@OnClose
public void onClose() {
webSocketSet.forEach(client -> {
if (client.getSession().getId().equals(session.getId())) {
log.info("用户:【{}】断开连接", client.getUserId());
webSocketSet.remove(client);
}
});
}
/**
* 发生错误时触发
*
* @param error
*/
@OnError
public void onError(Session session, Throwable error) {
webSocketSet.forEach(client -> {
if (client.getSession().getId().equals(session.getId())) {
webSocketSet.remove(client);
log.error("用户:【{}】发生异常", client.getUserId());
error.printStackTrace();
}
});
}
/**
* 收到客户端发送信息时触发
*
* @param message
*/
@OnMessage
public void onMessage(String message) {
ClientModel clientModel = webSocketSet.stream().filter(cl -> cl.getSession() == session)
.collect(Collectors.toList()).get(0);
log.info("用户:【{}】发送信息:{}", clientModel.getUserId(), message);
if (StringUtils.isBlank(message)) {
return;
}
ClientMessageModel clientMessageModel = JSON.parseObject(message, ClientMessageModel.class);
if (clientMessageModel.getMessageType() == MessageTypeEnums.READ_PERSON_ONLINE.getCode()) {
ReturnModel returnModel = emailDistributeService.pushSelectEmailMessage();
sendMessage(JSON.toJSONString(returnModel));
}
}
/**
* 服务端向客户端推送消息
*
* @param message
*/
public void sendMessage(String message) {
if (StringUtils.isEmpty(message)) {
return;
}
//消息示例 其中messageType代表我的枚举类的状态 ,其他都是我需要传的数据
//{"code":1,"data":{"allCount":21,"allNotSelectedCount":19,"count":21,"messageType":12,"readCount":19,"time":"2021-06-30"}}
webSocketSet.forEach(client -> {
try {
client.getSession().getBasicRemote().sendText(message);
log.info("服务端推送给客户端消息:【{}】", client.getUserId(), message);
} catch (IOException e) {
e.printStackTrace();
}
});
}
/**
* 服务端向客户端推送消息
*
* @param message
*/
public void sendMessage(String message, String userId) {
if (StringUtils.isEmpty(message)) {
return;
}
webSocketSet.forEach(client -> {
try {
if (StringUtils.isNotBlank(userId) && client.getUserId().equals(userId)) {
client.getSession().getBasicRemote().sendText(message);
log.info("服务端推送给客户端消息:【{}】", client.getUserId(), message);
}
} catch (IOException e) {
e.printStackTrace();
}
});
}
/**
* 获取在线用户
*
* @return
*/
public synchronized static List<String> getOnlineUsers() {
List<String> onlineUsers = webSocketSet.stream()
.map(client -> client.getUserId())
.collect(Collectors.toList());
return onlineUsers;
}
}
当我们需要使用方法是只需要在目标的实现类注入
@Autowired
private WebSocketServer webSocketServer
//在目标方法内使用
void test1(){
//我准备好的数据
Map<String,Object>map;
//服务端发送消息
webSocketServer.sendMessage(JSON.toJSONString(map));
}