package com.new3s.hydroJunction.websocket;
import com.alibaba.fastjson2.JSON;
import com.new3s.hydroJunction.domain.DeviceUpliftPressureEntity;
import com.new3s.hydroJunction.service.IDeviceUpliftPressureService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
/**
* WebSocket定时推送扬压力数据
*
*/
@Slf4j
@Component
@EnableScheduling
@ServerEndpoint(value = "/websocket/hydroJunction/upliftPressureData/{deviceId}", configurator = UpliftPressureConfigurator.class)
public class UpliftPressureSocketServer {
private static final ConcurrentHashMap<String, String> hashMap = new ConcurrentHashMap<>();
private static final Set<Session> sessionSet = new CopyOnWriteArraySet<>();
private static final AtomicInteger onlineCount = new AtomicInteger(0);
/**
* 确保一开始连接上时upliftPressureService有值,
*/
private final IDeviceUpliftPressureService upliftPressureService;
/**
* 构造函数注入的方式将IDeviceUpliftPressureService提供给UpliftPressureSocketServer
*
* @param upliftPressureService {@link IDeviceUpliftPressureService}
*/
public UpliftPressureSocketServer(IDeviceUpliftPressureService upliftPressureService) {
this.upliftPressureService = upliftPressureService;
}
public UpliftPressureSocketServer() {
// 创建一个默认构造函数
this.upliftPressureService = ApplicationContextProvider.getBean(IDeviceUpliftPressureService.class);
}
@OnOpen
public void onOpen(Session session, EndpointConfig config) {
sessionSet.add(session);
String deviceId = config.getUserProperties().get("deviceId").toString();
hashMap.put(session.getId(), deviceId);
onlineCount.incrementAndGet();
log.info("有新连接加入,当前连接数:{}", onlineCount.get());
// 在每个新连接建立时发送一条数据
sendUpliftPressureData(session, deviceId);
}
/**
* 发送扬压力数据
*
* @param session 会话
* @param deviceId 设备ID
*/
private void sendUpliftPressureData(Session session, String deviceId) {
if (upliftPressureService == null) {
log.error("upliftPressureService is null.");
return;
}
try {
List<DeviceUpliftPressureEntity> upliftPressureDataList = upliftPressureService.selectUpliftPressureList(DeviceUpliftPressureEntity.builder().deviceId(Long.parseLong(deviceId)).build());
if (!upliftPressureDataList.isEmpty()) {
DeviceUpliftPressureEntity upliftPressureData = upliftPressureDataList.get(0);
log.info("{}: 加入到 WebSocket. 当前连接数:{}", deviceId, onlineCount.get());
sendMessage(session, JSON.toJSONString(upliftPressureData));
} else {
log.warn("找不到deviceId的扬压力数据: {}", deviceId);
sendMessage(session, "暂无扬压力数据");
}
} catch (Exception e) {
log.error("发送扬压力数据失败: {}", e.getMessage());
}
}
/**
* 每隔5分钟发送一次数据
*/
@Scheduled(fixedRate = 60000)
public void sendBatchInfo() {
for (Session session : sessionSet) {
if (session.isOpen()) {
String deviceId = hashMap.get(session.getId());
sendUpliftPressureData(session, deviceId);
}
}
}
@OnMessage
public void onMessage(Session session, String message) {
log.info("收到来自客户端的消息: {}", message);
}
@OnClose
public void onClose(Session session) {
sessionSet.remove(session);
String deviceId = hashMap.remove(session.getId());
if (deviceId != null) {
log.info("设备 {} 断开连接", deviceId);
}
onlineCount.decrementAndGet();
log.info("有连接断开,当前连接数:{}", onlineCount.get());
}
@OnError
public void onError(Session session, Throwable error) {
log.error("WebSocket连接异常: {}", error.getMessage());
}
private void sendMessage(Session session, String message) {
try {
session.getBasicRemote().sendText(message);
} catch (Exception e) {
log.error("发送消息失败: {}", e.getMessage());
}
}
}
import org.springframework.context.annotation.Configuration;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;
import java.util.List;
import java.util.Map;
/**
* 扬压力socket参数配置
*
*/
@Configuration
public class UpliftPressureConfigurator extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
// 可获取request中的请求参数的集合
Map<String, List<String>> queryParam = request.getParameterMap();
Map<String, Object> userProperties = sec.getUserProperties();
// 以获取get请求中的id参数为例
userProperties.put("deviceId", queryParam.get("deviceId").get(0));
super.modifyHandshake(sec, request, response);
}
}
package com.new3s.hydroJunction.websocket;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* 获取应用程序上下文的提供者,用于手动获取Spring Bean实例
*
*/
@Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) {
applicationContext = context;
}
/**
* 根据Bean类获取Spring Bean实例
*
* @param beanClass Bean类
* @param <T> Bean类型
* @return Bean实例
*/
public static <T> T getBean(Class<T> beanClass) {
return applicationContext.getBean(beanClass);
}
}
完整代码如上所示
遇到的常见问题汇总:
1、带参数的websocket推送
@ServerEndpoint(value = "/websocket/hydroJunction/upliftPressureData/{deviceId}", configurator = UpliftPressureConfigurator.class)
public class UpliftPressureSocketServer {
socket地址的参数配置,如下图所示
2、定时任务推送
3、在每个新连接建立时发送一条数据,然后定时每1分钟推送一次消息
构造函数注入
手动获取bean实例