引入驱动
<!-- websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.7.1</version>
</dependency>
添加socket配置类
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
@ServerEndpoint("/webSocket/{addressId}")
@Component
@Slf4j
public class WebSocketServer {
//静态变量,用来记录当前在线连接数。
private static AtomicInteger onlineNum = new AtomicInteger();
//concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。
private static ConcurrentHashMap<String, List<Session>> sessionPools = new ConcurrentHashMap<>();
//发送消息
public void sendMessage(Session session, String message) throws IOException {
if (session != null) {
synchronized (session) {
System.out.println("发送数据:" + message);
session.getBasicRemote().sendText(message);
System.out.println("消息发送完毕");
}
}
}
//给指定用户发送信息
public void sendInfo(String addressId, String message) {
List<Session> sessionList = sessionPools.get(addressId);
try {
if (!CollectionUtils.isEmpty(sessionList)) {
for (Session session : sessionList) {
sendMessage(session, message);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 群发消息
public void broadcast(String message) {
for (ConcurrentHashMap.Entry<String, List<Session>> entry : sessionPools.entrySet()) {
List<Session> sessionList = entry.getValue();
sendMesInfo(sessionList, message);
}
}
public void sendMesInfo(List<Session> sessionList, String message) {
for (Session session : sessionList) {
try {
sendMessage(session, message);
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
//建立连接成功调用
@OnOpen
public void onOpen(Session session, @PathParam(value = "addressId") String addressId) {
List<Session> sessionList = new ArrayList<>();
if (sessionPools.containsKey(addressId)) {
sessionList = sessionPools.get(addressId);
} else {
addOnlineCount();
}
sessionList.add(session);
sessionPools.put(addressId, sessionList);
System.out.println(addressId + "加入webSocket!当前人数为" + onlineNum);
// 广播上线消息 TODO
MsgCountDTO dto = new MsgCountDTO();
dto.setNoticeNum(1);
dto.setWarnNum(123);
broadcast(JSON.toJSONString(dto, true));
}
//关闭连接时调用
@OnClose
public void onClose(Session session, @PathParam(value = "addressId") String addressId) {
System.out.println("退出");
List<Session> sessionList = sessionPools.get(addressId);
boolean flag = true;
if (!CollectionUtils.isEmpty(sessionList)) {
if (1 == sessionList.size() && sessionList.contains(session)) {
sessionPools.remove(addressId);
subOnlineCount();
} else if (1 != sessionList.size()) {
sessionList.remove(session);
sessionPools.put(addressId, sessionList);
}
}
System.out.println(addressId + "断开webSocket连接!当前人数为" + onlineNum);
// 广播下线消息
// MsgCountDTO dto = new MsgCountDTO();
// dto.setNoticeNum(1);
// dto.setWarnNum(123);
// broadcast(JSON.toJSONString(dto, true));
}
//收到客户端信息后,addressId
// to=-1群发消息
@OnMessage
public void onMessage(String message) {
System.out.println("server get" + message);
//TODO
MsgCountDTO dto = new MsgCountDTO();
dto.setNoticeNum(1);
dto.setWarnNum(123);
broadcast(JSON.toJSONString(dto, true));
//实际的所需数据 也可根据传入的信息进行接收者的指定
// SocketMessageResponseDTO msg = JSON.parseObject(message, SocketMessageResponseDTO.class);
// msg.setDate(Java8DateUtil.dateTimeFormat(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"));
// if (msg.getTo().equals("-1")) {
// broadcast(JSON.toJSONString(msg, true));
// } else {
// sendInfo(msg.getTo(), JSON.toJSONString(msg, true));
// }
}
//错误时调用
@OnError
public void onError(Session session, Throwable throwable) {
System.out.println("发生错误");
throwable.printStackTrace();
}
public static void addOnlineCount() {
onlineNum.incrementAndGet();
}
public static void subOnlineCount() {
onlineNum.decrementAndGet();
}
public static AtomicInteger getOnlineNumber() {
return onlineNum;
}
public static ConcurrentHashMap<String, List<Session>> getSessionPools() {
return sessionPools;
}
}
启动服务
访问:http://www.jsons.cn/websocket/
在地址栏中录入socket访问地址测试连接
服务端可以根据传递的参数进行不同数据的返回。
模拟后端定时触发进行数据推送
可以是满足某个条件后进行数据推送也可以是定时进行数据推送。此处举例为定时推送数据:
添加一个调度任务
@Component
@Slf4j
public class LargeScreenJob {
@Resource
private WebSocketServer socketServer;
@Scheduled(cron = "0/5 * * * * ?")
public void LargeScreenHandler() {
log.info("报警数提醒job开始执行........");
//TODO 业务数据
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("msg", "发送消息 使其广播");
socketServer.onMessage(JSON.toJSONString(paramMap));
log.info("报警数提醒job执行结束........");
}
}
启动服务:
服务端如图:
前端如图: