1.依赖 socket
<!-- netty-socketio-->
<dependency>
<groupId>com.corundumstudio.socketio</groupId>
<artifactId>netty-socketio</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver</artifactId>
<version>4.1.15.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>4.1.15.Final</version>
</dependency>
<dependency>
<groupId>io.socket</groupId>
<artifactId>socket.io-client</artifactId>
<version>1.0.0</version>
</dependency>
mqtt依赖
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-mqtt</artifactId>
</dependency>
2.配置
socketIo:
serverIp: 127.0.0.1 #设置socket所在ip地址 前后端约定地址
socketPort: 9098 #socket端口 前后端约定端口
pingInterval: 25000 #Ping消息间隔(毫秒)
pingTimeout: 60000 #Ping消息超时时间(毫秒)
3.socketio配置类
package com.xgit.iot.service.nettySocketIo;
import com.bkrwin.ufast.infra.infra.log.LogHelper;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.SpringAnnotationScanner;
import com.xgit.iot.service.nettySocketIo.model.SocketProperties;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.net.InetAddress;
/**
* 配置socketIo的bean
*/
@Configuration
public class NettySocketConfig {
@Autowired
private SocketProperties socketProperties;
@Bean
public SocketIOServer socketIOServer() {
/*
* 创建Socket,并设置监听端口
*/
com.corundumstudio.socketio.Configuration config = new com.corundumstudio.socketio.Configuration();
// 设置主机名,默认是0.0.0.0
config.setHostname(socketProperties.getServerIp());
// 设置监听端口
config.setPort(socketProperties.getSocketPort());
// 协议升级超时时间(毫秒),默认10000。HTTP握手升级为ws协议超时时间
config.setUpgradeTimeout(10000);
// Ping消息间隔(毫秒),默认25000。客户端向服务器发送一条心跳消息间隔
config.setPingInterval(socketProperties.getPingInterval());
// Ping消息超时时间(毫秒),默认60000,这个时间间隔内没有接收到心跳消息就会发送超时事件
config.setPingTimeout(socketProperties.getPingTimeout());
// 握手协议参数使用JWT的Token认证方案
config.setAuthorizationListener(data -> {
// 这里可以做参数校验
//socketio 心跳功能,不间断的进行访问,可以不间断校验
//如果只想校验第一次,则不在这里做校验
String userId = data.getSingleUrlParam("userId");
return true;
});
return new SocketIOServer(config);
}
@Bean
public SpringAnnotationScanner springAnnotationScanner(SocketIOServer socketServer) {
return new SpringAnnotationScanner(socketServer);
}
4.启动类
package com.xgit.iot.service.nettySocketIo;
import com.bkrwin.ufast.infra.infra.log.LogHelper;
import com.corundumstudio.socketio.SocketIOServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* SpringBoot启动之后执行
*/
@Component
@Order(1)
public class ServerRunner implements CommandLineRunner {
@Autowired
private SocketIOServer server;
@Override
public void run(String... args) {
LogHelper.monitor("SocketIOServerRunner 开始启动啦...");
try {
server.start();
} catch (Exception e) {
LogHelper.fatal("socket.io启动失败!!! ", e);
String hostName = server.getConfiguration().getHostname();
LogHelper.fatal("hostName=" + hostName, e);
}
}
}
5.添加socket三大事件
package com.xgit.iot.service.nettySocketIo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.bkrwin.ufast.infra.infra.log.LogHelper;
import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.HandshakeData;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.xgit.iot.infra.ErrorCode;
import com.xgit.iot.infra.mqtt.MqttReceiveConfig;
import com.xgit.iot.service.machine.MocVariateConfigService;
import com.xgit.iot.service.nettySocketIo.model.ClientVariateConfig;
import com.xgit.iot.service.nettySocketIo.model.MachineVariateValueVo;
import com.xgit.iot.service.nettySocketIo.model.Message;
import com.xgit.iot.service.vo.machine.MocVariateConfigByCloudConfigVO;
/**
* 消息事件处理器 详细参考https://socket.io/
*/
@Component
public class MessageEventHandler {
@Autowired
MqttReceiveConfig mqttReceiveConfig;
@Autowired
private MocVariateConfigService mocVariateConfigService;
/**
* 添加connect事件,当客户端发起连接时调用
*
* @param client
*/
@OnConnect
public void onConnect(SocketIOClient client) {
try {
if (client != null) {
String sessionId = client.getSessionId().toString();
HandshakeData handData = client.getHandshakeData();
String userId = handData.getSingleUrlParam("userId");
String orgId = handData.getSingleUrlParam("orgId");// 之前业务用
String visionId = handData.getSingleUrlParam("visionId");
String machineCodeAndVariateCode = handData.getSingleUrlParam("machineCodeAndVariateCodeList");
String[] machineCodeAndVariateCodes = machineCodeAndVariateCode.split(",");
String frequency = handData.getSingleUrlParam("frequency");// icon表达式实时计算用
if (StringUtils.isBlank(orgId)) {
LogHelper.monitor("连接失败,租户为空");
return;
} else if (ObjectUtils.isNotEmpty(machineCodeAndVariateCodes) && StringUtils.isNotBlank(visionId)) {
//1.查询模板 业务逻辑 无须理会
List<MocVariateConfigByCloudConfigVO> mocVariateConfigList = mocVariateConfigService
.listByCloudConfig(machineCodeAndVariateCodes);
if (ObjectUtils.isEmpty(mocVariateConfigList)) {
LogHelper.monitor("连接失败,采点为空, visionId=" + visionId + ", sessionId=" + client.getSessionId());
return;
}
//2.存入推送池 存client 同时 讲业务模板存入 无须理会业务模板
SocketIoServerMapUtil.put(mocVariateConfigList, visionId + "|" + sessionId, client);
List<MocVariateConfigByCloudConfigVO> noNeedCaledConfigVo = new ArrayList<>();
Set<String> dpuList = noNeedCaledConfigVo.stream()
.map(MocVariateConfigByCloudConfigVO::getDpuCode).collect(Collectors.toSet());
//3.不计算部分mqtt加入订阅 这里通过mqtt 触发推送
mqttReceiveConfig.addVariateTopic(visionId + "|" + sessionId, orgId, dpuList);
LogHelper.monitor("连接成功, visionId=" + visionId);
} else {
client.joinRoom(orgId); // room房间通知 内置session socket自带功能 会通过roomid发送给所有此orgid的用户
LogHelper.monitor(
"连接成功, sessionId=" + sessionId + ", orgId=" + orgId);
}
} else {
LogHelper.error("客户端为空", ErrorCode.Failure.getCode());
}
} catch (Exception e) {
LogHelper.fatal("捕获到socket.io异常", e);
}
}
/**
* 添加@OnDisconnect事件,客户端断开连接时调用,刷新客户端信息
*
* @param client
*/
@OnDisconnect
public void onDisconnect(SocketIOClient client) {
String sessionId = client.getSessionId().toString();
LogHelper.monitor("客户端断开连接, sessionId=" + sessionId);
HandshakeData handData = client.getHandshakeData();
String userId = handData.getSingleUrlParam("userId");
String orgId = handData.getSingleUrlParam("orgId");// 之前业务用
String visionId = handData.getSingleUrlParam("visionId");
String machineCodeAndVariateCode = handData.getSingleUrlParam("machineCodeAndVariateCodeList");
String[] machineCodeAndVariateCodes = machineCodeAndVariateCode.split(",");
if (ObjectUtils.isNotEmpty(machineCodeAndVariateCodes) && StringUtils.isNotBlank(visionId) && StringUtils.isNotBlank(sessionId)) {
//清除池子 并清除mqtt
boolean isRemove = SocketIoServerMapUtil.remove(Arrays.asList(machineCodeAndVariateCodes), visionId + "|" + sessionId);
if (isRemove) {
//清除mqtt订阅 对接mqtt 无须理会
mqttReceiveConfig.removeVariateTopic(visionId + "|" + sessionId, orgId);
}
} else if (StringUtils.isNotBlank(orgId)) {
client.leaveRoom(orgId);
}
client.disconnect();
}
/**
* 前后端消息监听,确保消息链接无误
*
* @param client
* @param ackRequest
* @param message 前段参数
*/
//visionMessage 后台监测前段发送消息,确保消息无误 前段发送方法 emit socket.emit('visionMessage', JSON.stringify({userId:"xxxxxx"}));
@OnEvent(value = "visionMessage")
public void visionMessage(SocketIOClient client, AckRequest ackRequest, Message msg) {
//对服务器的响应
ackRequest.sendAckData("服务器回答message" + ",message=" + msg.getMessage());
//
//visionMessage 这里的的标签与前段约定一致,前段监测 visionMessage事件,与上面的visionMessage不是同一个
//若无法区分 可以改名 message 前段监控此事件 socket.on('message', function (data) {
client.sendEvent("visionMessage", "");
}
/**
* 获取变动的对象 组态画面后端主动推送
*
* @param alarmMessage
*/
public void batchSendVisionMessage(List<MachineVariateValueVo> machineVariateValueList) {
// visionID -->{client,configMap}
Map<String,ClientVariateConfig> configSet = SocketIoServerMapUtil.getClientList(machineVariateValueList);
configSet.values().forEach(clientVariateConfig -> {
List<MocVariateConfigByCloudConfigVO> configList = new ArrayList<MocVariateConfigByCloudConfigVO>(
clientVariateConfig.getConfigMap().values());
//取出 client 发 消息内容
clientVariateConfig.getClient().sendEvent("visionMessage", configList);
});
}
}
cleint池子
package com.xgit.iot.service.nettySocketIo;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.corundumstudio.socketio.SocketIOClient;
import com.xgit.iot.service.nettySocketIo.model.ClientVariateConfig;
import com.xgit.iot.service.nettySocketIo.model.MachineVariateValueVo;
import com.xgit.iot.service.vo.machine.MocVariateConfigByCloudConfigVO;
public class SocketIoServerMapUtil {
//根据id存放client 因为业务关系,写的比较复杂 无须理会,自己存自己client即可
// private static Map<String, List<SocketIOClient>> socketClientMap = new ConcurrentHashMap<>();
//Map<tag, Map<visionId|userId, ClientVariateConfig>>
private static Map<String, Map<String, ClientVariateConfig>> socketClientMap = new ConcurrentHashMap<>();
/**
* 为每个tag增加当前 visionId->client
*
* @param tagList machineCode + variateCode
* @param visionId
* @param client TODO 待自测
*/
public static void put(List<MocVariateConfigByCloudConfigVO> mocVariateConfigList, String visionAndUserId,
SocketIOClient client) {
//Map<tag,vo> 模板map 通过map 方便命中tag修改值
Map<String, MocVariateConfigByCloudConfigVO> configMap = mocVariateConfigList.stream().collect(
Collectors.toMap(v -> v.getMachineCode() + "|" + v.getVariateCode(), Function.identity(), (v1, v2) -> v2));
//这里不要直接用map循环,因为里面操作了map
mocVariateConfigList.forEach(variateConfigVo -> {
String tag = variateConfigVo.getMachineCode() + "|" + variateConfigVo.getVariateCode();
Map<String, ClientVariateConfig> cilentMap = socketClientMap.get(tag);
if (null == cilentMap) {
cilentMap = new HashMap<>();
}
// 池子已经存在 换新的模板 tag中 vision相同 则 存同 client 同 configMap
if (cilentMap.containsKey(visionAndUserId)) {
ClientVariateConfig clientVariateConfig = cilentMap.get(visionAndUserId);
clientVariateConfig.setNewClient(client, configMap);
}else {
// 有的tag可能是 第一次 有的tag可能是好几次 所以每次都搞新对象
ClientVariateConfig clientVariateConfig = new ClientVariateConfig(client, configMap);
cilentMap.put(visionAndUserId, clientVariateConfig);
}
socketClientMap.put(tag, cilentMap);
});
}
/**
* 移除每个tag中 visionId->client 如果tag没有visionId也移除
*
* @param tagList
* @param visionId
* @return false没有做清除操作 true 做了清除操作
*/
public static boolean remove(List<String> tagList, String visionAndUserId) {
boolean isNeedRemove = false;
for (String tag : tagList) {
Map<String, ClientVariateConfig> cilentMap = socketClientMap.get(tag);// tag下每个客户端
if (null != cilentMap) {
ClientVariateConfig clientVariateConfig = cilentMap.get(visionAndUserId);
//数量-1 如果>0则不动
if (clientVariateConfig.decrementAndGet() <= 0) {
cilentMap.remove(visionAndUserId);// 移除所有
isNeedRemove = true;
}
if (cilentMap.isEmpty()) {
socketClientMap.remove(tag);
}
}
}
return isNeedRemove;
}
/**
* 根据tag
* @param machineVariateValueList 大数据返回的对象
* @return
*/
public static Map<String, ClientVariateConfig> getClientList(List<MachineVariateValueVo> machineVariateValueList) {
//visionId ->ClientVariateConfig
//同一个画面 对象不同 但时对象 内 client跟map相同
Map<String, ClientVariateConfig> valueMap = new HashMap<>();
machineVariateValueList.forEach(machineVariateValueVo -> {
// Map<vision,ClientVariateConfig>
Map<String, ClientVariateConfig> cilentMap = socketClientMap.get(machineVariateValueVo.getTag());
if (null == cilentMap) {
return;// 等于continue
}
// Map<tag, Map<visionId|userId, ClientVariateConfig>> 同 client 同 configMap
// 只修改对象中tag自己的部分
cilentMap.forEach((visionAndUserId,variateconfig) -> {
Map<String,MocVariateConfigByCloudConfigVO> configMap = variateconfig.getConfigMap();
MocVariateConfigByCloudConfigVO configVo = configMap.get(machineVariateValueVo.getTag());
configVo.setVariateValue(machineVariateValueVo.getValue().toString());
valueMap.put(visionAndUserId, variateconfig);//根据id 存对象 避免一样内容对象反复出现
});
});
return valueMap;
}
/**
* 从tag:machineCode|variateCode 取 machineCode
* @return
*/
public static Set<String> getMachineListFromTag(){
Set<String> machineSet = new HashSet<String>();
socketClientMap.keySet().forEach(key->{
machineSet.add(key.split("\\|")[0]);
});
return machineSet;
}
}
mqtt配置类 +动态 订阅
package com.xgit.iot.infra.mqtt;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.integration.annotation.IntegrationComponentScan;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import com.alibaba.fastjson.JSONObject;
import com.xgit.iot.infra.mqtt.model.MachineAndVariateValueVo;
import com.xgit.iot.infra.mqtt.service.MqttReceiveService;
import lombok.extern.slf4j.Slf4j;
@Configuration
@IntegrationComponentScan
@Slf4j
public class MqttReceiveConfig {
@Value("${mqtt.username}")
private String username;
@Value("${mqtt.password}")
private String password;
@Value("${mqtt.host}")
private String hostUrl;
@Value("${mqtt.clientid}")
private String clientId;
@Value("${mqtt.timeout}")
private short timeOut;
@Value("${mqtt.keepalive}")
private short keepAlive;
@Value("${mqtt.defaulttopic}")
private String variateDefaultTopic;
/**
* 事实上不同的visionId dpu有可能是一样的 关闭当前不能影响其他画面
* 同一个画面允许多个租户打开 关闭当前画面 不能影响其他用户
* Map<dpu,List<visionAndUserId>>
*/
private static Map<String, Set<String>> topicMap = new ConcurrentHashMap<>();
private MqttPahoMessageDrivenChannelAdapter adapter;
@Autowired
private MqttReceiveService mqttReceiveService;
@Bean
public MqttConnectOptions getMqttConnectOptions() {
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setCleanSession(true);
mqttConnectOptions.setUserName(username);
mqttConnectOptions.setPassword(password.toCharArray());
mqttConnectOptions.setServerURIs(new String[] {hostUrl});
mqttConnectOptions.setConnectionTimeout(timeOut);
mqttConnectOptions.setKeepAliveInterval(keepAlive);
mqttConnectOptions.setAutomaticReconnect(true);
return mqttConnectOptions;
}
@Bean
public MqttPahoClientFactory mqttClientFactory() {
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
factory.setConnectionOptions(getMqttConnectOptions());
return factory;
}
/**
* 接收通道 可以配置多个 mqttInputChannel1 mqttInputChannel2
*
* @return
*/
@Bean
public MessageChannel mqttInputChannel() {
return new DirectChannel();
}
/**
* 每个inbound对应每个channel client 监听topic
*
* @return
*/
@Bean
public MessageProducer inbound() {
//默认主题模板
adapter = new MqttPahoMessageDrivenChannelAdapter(clientId + "_inbound", mqttClientFactory(), variateDefaultTopic);
adapter.setCompletionTimeout(timeOut);
adapter.setConverter(new DefaultPahoMessageConverter());
adapter.setQos(1);
adapter.setOutputChannel(mqttInputChannel());
log.info("mqtt receiver start success");
return adapter;
}
/**
* 获取通道数据 与channel一一对应
*
* @return
*/
@Bean
@ServiceActivator(inputChannel = "mqttInputChannel")
public MessageHandler handler() {
return new MessageHandler() {
@Override
public void handleMessage(Message<?> message) throws MessagingException {
// 不同的topic取不同的值
String topic = message.getHeaders().get("mqtt_receivedTopic").toString();
mqttReceiveService.handlerVariateMqttMsg(topic, JSONObject.parseObject(message.getPayload().toString(), MachineAndVariateValueVo.class));
}
};
}
/**
* 动态添加采点主题
* @param topicArr
*/
public void addVariateTopic(String visionAndUserId, String orgId, Set<String> dpuSet) {
if (StringUtils.isBlank(visionAndUserId) || StringUtils.isBlank(orgId) || ObjectUtils.isEmpty(dpuSet)) {
return;
}
if (null == adapter) {
adapter = new MqttPahoMessageDrivenChannelAdapter(clientId + "_inbound", mqttClientFactory(), variateDefaultTopic);
adapter.removeTopic(variateDefaultTopic);
}
dpuSet.forEach(dpu->{
Set<String> visionAndUserSet = topicMap.get(dpu);// Map<dpu,List<visionAndUserId>> 原先添加的tag
if (null == visionAndUserSet) {
visionAndUserSet = new HashSet<>();
topicMap.put(dpu, visionAndUserSet);
}
//visionId本身区分orgId 无需再判断
//已经存在 不需要订阅
if (!visionAndUserSet.contains(visionAndUserId)) {
visionAndUserSet.add(visionAndUserId);
adapter.addTopic(MessageFormat.format(variateDefaultTopic, orgId, dpu));
}
});
}
/**
* 动态移除主题
* @param topic
*/
public void removeVariateTopic(String visionAndUserId, String orgId) {
if (null == adapter) {
return;
}
topicMap.forEach((dpu, visionAndUserIdSet)->{
if (visionAndUserIdSet.remove(visionAndUserId)) {
adapter.removeTopic(MessageFormat.format(variateDefaultTopic, orgId, dpu));
}
if (visionAndUserIdSet.isEmpty()) {
topicMap.remove(dpu);
}
});
}
/**
* 动态添加主题
* @param topicArr
*/
public void addTopic(List<String> topicList) {
if (ObjectUtils.isEmpty(topicList)) {
return;
}
if (null == adapter) {
adapter = new MqttPahoMessageDrivenChannelAdapter(clientId + "_inbound", mqttClientFactory(), "");
}
for (String topic : topicList) {
adapter.addTopic(topic);
}
adapter.removeTopic();
}
/**
* 动态移除主题
* @param topic
*/
public void removeListenTopic(String topic) {
if (null == adapter) {
adapter = new MqttPahoMessageDrivenChannelAdapter(clientId + "_inbound", mqttClientFactory(), "");
}
adapter.removeTopic(topic);
}
}
处理类接口
package com.xgit.iot.infra.mqtt.service;
import com.xgit.iot.infra.mqtt.model.MachineAndVariateValueVo;
public interface MqttReceiveService {
void handlerVariateMqttMsg(String topic,MachineAndVariateValueVo valueVo);
}
核心处理类 接收消息,并发送socket
package com.xgit.iot.infra.mqtt.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.xgit.iot.infra.mqtt.model.MachineAndVariateValueVo;
import com.xgit.iot.infra.mqtt.service.MqttReceiveService;
import com.xgit.iot.infra.util.ht.CommUtil;
import com.xgit.iot.service.nettySocketIo.MessageEventHandler;
import com.xgit.iot.service.nettySocketIo.SocketIoServerMapUtil;
import com.xgit.iot.service.nettySocketIo.model.MachineVariateValueVo;
@Service
public class MqttReceiveServiceImpl implements MqttReceiveService {
@Autowired
private MessageEventHandler messageEventHandler;
/***
* {
* "t":timestamp,
* "d":dpucode,
* "id":machinecode,
* "v":{"value":value,"timxx":xxxx }
* }
*/
@Override
public void handlerVariateMqttMsg(String topic, MachineAndVariateValueVo valueVo) {
if (!CommUtil.isVariateValue(topic)) {
return;
}
//{variateCode:value,variateCode:value}
Map<String, Object> variateValueMap = valueVo.getV();
String machineCode = valueVo.getId();
//先判断是否命中machinCode
if (!SocketIoServerMapUtil.getMachineListFromTag().contains(machineCode)){
return;
}
List<MachineVariateValueVo> machineVariateValueList = new ArrayList<>();
variateValueMap.forEach((variateCode,value)->{
// 判断value是否是double clientid唯一
if (null != value && isDouble(value)) {
MachineVariateValueVo machineVariateValueVo = new MachineVariateValueVo();
machineVariateValueVo.setTag(machineCode + "|" + variateCode);
machineVariateValueVo.setValue(value);
machineVariateValueList.add(machineVariateValueVo);
}
});
//1.校验topic 通过则 采集tag
//调用sent 检测到订阅消息后,发送sockeio
messageEventHandler.batchSendVisionMessage(machineVariateValueList);
}
private static boolean isDouble(Object str) {
try {
Double.parseDouble(str.toString());
return true;
} catch (NumberFormatException ex) {
return false;
}
}
}
前段 支持数组
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>NETTY SOCKET.IO DEMO</title>
<base>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/socket.io/2.1.1/socket.io.js"></script>
<style>
body {
padding: 20px;
}
#console {
height: 450px;
overflow: auto;
}
.username-msg {
color: orange;
}
.connect-msg {
color: green;
}
.disconnect-msg {
color: red;
}
</style>
</head>
<body>
<div id="console" class="well"></div>
</body>
<script type="text/javascript">
var socket;
connect();
function connect() {
var opts = {
query: {
"token":"xxxxxxxxxxx",
"userId":"xxxxxxxxx",
"visionId":"menu1/menu2/name",
"frequency":"*/10 * * * * ?",
"machineCodeAndVariateCodeList":[
"XZZBZT-001|Q0.0",
"XZZBZT-001|Q0.1",
"XZZBZT-001|Q0.2",
"XZZBZT-001|Q0.3",
"XZZBZT-001|V1.0",
"XZZBZT-001|V1.1",
"XZZBZT-001|VD3048",
"XZZBZT-001|VD1126",
"XZZBZT-001|VD3008",
"XZZBZT-001|VW2004",
"XZZBZT-001|VD3060",
"XZZBZT-001|VD3036",
"XZZBZT-001|VW2016"
]
}
};
socket = io.connect('http://localhost:9098', opts);
socket.on('connect', function () {
socket.emit('visionMessage', JSON.stringify({userId:"xxxxxx"}));
console.log("连接成功");
serverOutput('<span class="connect-msg">连接成功</span>');
});
socket.on('visionMessage', function (data) {
output('<span class="username-msg">' + data + ' </span>');
console.log(data);
});
socket.on('disconnect', function () {
serverOutput('<span class="disconnect-msg">' + '已下线! </span>');
});
}
function output(message) {
var element = $("<div>" + " " + message + "</div>");
$('#console').prepend(element);
}
function serverOutput(message) {
var element = $("<div>" + message + "</div>");
$('#console').prepend(element);
}
</script>
</html>
预览
基于room聊天室的html 监听message
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>NETTY SOCKET.IO DEMO</title>
<base>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/socket.io/2.1.1/socket.io.js"></script>
<style>
body {
padding: 20px;
}
#console {
height: 450px;
overflow: auto;
}
.username-msg {
color: orange;
}
.connect-msg {
color: green;
}
.disconnect-msg {
color: red;
}
</style>
</head>
<body>
<div id="console" class="well"></div>
</body>
<script type="text/javascript">
var socket;
connect();
function connect() {
var opts = {
query : {
"userId" : "561937412343726080",
"orgId" : "100299"
}
};
socket = io.connect('http://10.100.2.254:9098', opts);
socket.on('connect', function() {
console.log("连接成功");
/* socket.emit('message', {orgId:"100299",userId : "567645317437063168"}
); */
serverOutput('<span class="connect-msg">连接成功</span>');
});
socket.on('message', function(data) {
output('<span class="username-msg">' + data + ' </span>');
console.log(data);
});
socket.on('disconnect', function() {
serverOutput('<span class="disconnect-msg">' + '已下线! </span>');
});
}
function output(message) {
var element = $("<div>" + " " + message + "</div>");
$('#console').prepend(element);
}
function serverOutput(message) {
var element = $("<div>" + message + "</div>");
$('#console').prepend(element);
}
</script>
</html>