MQTT+RocketMq+ICE规则引擎+BladeX实现车辆预警功能
1.MQTT与车辆终端通讯接收V2X数据。
2.消费emqx,监听同时将数据发送到rocketMQ的生产者。
3.MQ消费者监听V2X的topic,且要保证消费顺序。
4.feigin调用报警服务中的规则引擎
其中规则引擎包含车辆与交通规则
车辆规则:通过页面配置的方式定义 超速、超载、急加速、急刹车等预警情况并记录。
ice控制面板
交通规则:通过页面配置的方式定义 例如 指定矿区、指定设备类型(有人矿卡、无人矿卡等等)、指定同向或者对向行驶、指定上坡下坡平路、指定避让规则(A车减速B车加速、A车停B车停)
两个预警处理后会进入预警表中
代码实现:MQTT client部分
import com.yx_catl.dispatcher.official.communication.DeviceBasicsMqttMonitorUtils; import com.yx_catl.mine.mqtt.utils.MqttUtils; import lombok.extern.log4j.Log4j2; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.integration.annotation.ServiceActivator; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessagingException; import org.springframework.stereotype.Component; /** * <p>描述:配置channel1消息处理 </p> * * @author qichenhu */ @Slf4j @Component public class Mqtt2MessageHandler implements MessageHandler { @Autowired private DeviceBasicsMqttMonitorUtils deviceBasicsMqttMonitorUtils; @ServiceActivator(inputChannel = "channel2") @Override public void handleMessage(Message<?> message) throws MessagingException { MqttUtils.put(message.getHeaders().get("mqtt_receivedTopic").toString(), MqttUtils.getDefaultHeadler()); deviceBasicsMqttMonitorUtils.analysisPublishMessage(message.getHeaders().get("mqtt_receivedTopic").toString(),message.getPayload().toString()); } }
DeviceBasicsMqttMonitorUtils.java
import com.alibaba.fastjson.JSONObject; import com.yx_catl.dispatcher.official.constant.MqttClientTopicConstant; import com.yx_catl.dispatcher.official.model.sys.SysConnected; import com.yx_catl.dispatcher.official.model.sys.SysDisconnected; import com.yx_catl.dispatcher.official.service.*; import com.yx_catl.dispatcher.official.util.DeviceIdUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component @Slf4j public class DeviceBasicsMqttMonitorUtils { @Autowired private DeviceOTAService deviceOTAService; @Autowired private IBogieMonitorService iBogieMonitorService; @Autowired private DeviceBasicFileResultService deviceBasicFileResultService; @Autowired private DeviceOnlineMonitorService deviceOnlineMonitorService; @Autowired private ITbox808MonitorService tbox808MonitorService; public boolean analysisPublishMessage(String topic,String message) { try { String deviceid = DeviceIdUtil.getDeviceId(topic); if(StringUtils.isNoneBlank(deviceid)){ String topicName = DeviceIdUtil.interceptTopic(topic); log.info("topicName_______"+topicName + "-------message--------"+message); switch (topicName) { case MqttClientTopicConstant.DEVICE_CAR_REPROT_ERROR_INFO: iBogieMonitorService.analysisError(deviceid, message); break; case MqttClientTopicConstant.DEVICE_CAR_REPROT_OTA_SOFT_INFO: deviceOTAService.analysisOTASoft(deviceid,message); break; case MqttClientTopicConstant.DEVICE_CAR_REPROT_OTA_UPDATE_STATUS: deviceOTAService.analysisOTAUpdateStatus(deviceid,message); break; case MqttClientTopicConstant.DEVICE_REPORT_PARAMS_UPLOAD: deviceBasicFileResultService.analysisParamsUpload(deviceid,message); break; case MqttClientTopicConstant.DEVICE_REPORT_PARAMS_UPDATE_RESULT: deviceBasicFileResultService.analysisParamsUpdateResult(deviceid,message); break; case MqttClientTopicConstant.DEVICE_CONNECTED: deviceOnlineMonitorService.deviceOnline(deviceid, JSONObject.parseObject(message, SysConnected.class)); break; case MqttClientTopicConstant.DEVICE_DISCONNECTED: deviceOnlineMonitorService.deviceOffline(deviceid, JSONObject.parseObject(message, SysDisconnected.class)); break; case MqttClientTopicConstant.DEVICE_CAR_TBOX: tbox808MonitorService.analysisMonitor(deviceid , message); break; } return true; } } catch (Exception e) { log.error("不是需要解析的协议数据"); } return false; } }
ITbox808MonitorService.java
/** * 矿卡监控器 */ public interface ITbox808MonitorService { //矿卡TBOX 监控——设备上报 boolean analysisMonitor(String deviceId, String message); }
Tbox808ServiceImpl.java(黑色部分为MQ有序插入)
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.yx_catl.dispatcher.elastic.entity.ElasticCarMoveDtl; import com.yx_catl.dispatcher.elastic.feign.IElasticCarMoveDtlClient; import com.yx_catl.dispatcher.integrated.entity.DeviceEntity; import com.yx_catl.dispatcher.integrated.feign.IDeviceClient; import com.yx_catl.dispatcher.integrated.vo.DeviceVO; import com.yx_catl.dispatcher.official.model.PlatformHeader; import com.yx_catl.dispatcher.official.model.Stamp; import com.yx_catl.dispatcher.official.model.bogie.vo.BogieVo; import com.yx_catl.dispatcher.official.model.device.vo.DeviceOnlineStatusVo; import com.yx_catl.dispatcher.official.service.ITbox808MonitorService; import com.yx_catl.dispatcher.official.service.MQProducerService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springblade.common.constant.MqttServerConstant; import org.springblade.common.utils.DateTimeUtil; import org.springblade.core.tool.api.R; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import java.util.*; import java.util.concurrent.TimeUnit; @Slf4j @Component public class Tbox808ServiceImpl implements ITbox808MonitorService { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private MQProducerService mqProducerService; @Value("${mq.namespace}%${mq.producer.iotBogieGroup.topic}") private String topic; @Value("${mq.producer.iotBogieGroup.tag.bogie}") private String tagOrder; private String CAR_DIGG_FLAG = "1"; //车辆类型 挖机 private String TBOX_COMMAND_TYPE_FLAG = "实时信息上报";//tbox 上传数据类型 commandTypeNm @Autowired private IDeviceClient deviceClient; @Autowired private IElasticCarMoveDtlClient elasticCarMoveDtlClient; @Override public boolean analysisMonitor(String deviceId, String message) { try { DeviceEntity deviceEntity = new DeviceEntity(); deviceEntity.setCode(deviceId); R<DeviceVO> r = deviceClient.detail(deviceEntity); if (r.getCode() == 200 && r.getData() != null) { try { Map<String, JSONObject> map = JSONObject.parseObject(message, Map.class); JSONObject header = map.get("Header"); JSONObject v2x = map.get("V2X"); StringBuilder rediskey = new StringBuilder();//"device:car:" + deviceId; StringBuilder datakey = new StringBuilder();//"device:car:" + deviceId; rediskey.append("device"); datakey.append("device");
DeviceOnlineStatusVo vo = new DeviceOnlineStatusVo(); rediskey.append(":onlineflag:").append(r.getData().getTypeId()); datakey.append(":data:").append(r.getData().getTypeId()); Integer deviceType = Integer.parseInt(String.valueOf(header.get("deviceType"))); String commandTypeNm = String.valueOf(header.get("commandTypeNm")); Long dataTime = Long.parseLong(String.valueOf(header.get("time")));//header.put("time", date); if (deviceType == 32960 && "车辆登出".equals(commandTypeNm)) { //log.error("车辆登出***********out******************"); Object deviceOnlineStatus = stringRedisTemplate.opsForHash().get(rediskey.toString(), deviceId); if (!ObjectUtils.isEmpty(deviceOnlineStatus)) { vo = JSONObject.parseObject(String.valueOf(deviceOnlineStatus), DeviceOnlineStatusVo.class); vo.setOnlineStatus(0); vo.setOfflineTime(new Date()); stringRedisTemplate.opsForHash().put(rediskey.toString(), deviceId, JSONObject.toJSONString(vo)); } } else if (deviceType == 808 && v2x != null) { Object deviceOnlineStatus = stringRedisTemplate.opsForHash().get(rediskey.toString(), deviceId); if (!ObjectUtils.isEmpty(deviceOnlineStatus)) { vo = JSONObject.parseObject(String.valueOf(deviceOnlineStatus), DeviceOnlineStatusVo.class); vo.setOnlineStatus(1); } else { handleOnlineStatus(r, vo); } stringRedisTemplate.opsForHash().put(rediskey.toString(), deviceId, JSONObject.toJSONString(vo)); handleLocation(deviceId, datakey, v2x , r.getData() , dataTime , header , message); //log.error(" 808 上传数据*****************************"); } else if (deviceType == 32960 && ("实时信息上报".equals(commandTypeNm) || "补发信息上报".equals(commandTypeNm))) { handleLocation(deviceId, datakey, v2x, r.getData() , dataTime , header , message); Object obj = stringRedisTemplate.opsForHash().get(rediskey.toString(), deviceId); if (ObjectUtils.isEmpty(obj)) { handleOnlineStatus(r, vo); stringRedisTemplate.opsForHash().put(rediskey.toString(), deviceId, JSONObject.toJSONString(vo)); } //log.error("车辆32960 实时数据*****************************"); } if (deviceType == 32960 && "车辆登入".equals(commandTypeNm)) { //log.error("车辆登入*****************************"); handleOnlineStatus(r, vo); stringRedisTemplate.opsForHash().put(rediskey.toString(), deviceId, JSONObject.toJSONString(vo)); } } catch (Exception e) { log.error("消息内容转换map错误,异常信息为:", e); } } return true; } catch (Exception e) { log.error("非法的数据类型:" + message); e.printStackTrace(); } return false; } /** * 封装位置实体 * * @param code * @param datakey * @param v2x */ private void handleLocation(String code, StringBuilder datakey, JSONObject v2x , DeviceEntity deviceEntity , Long dataTime , JSONObject header , String message) { JSONObject o = JSONObject.parseObject(message); BogieVo bogieVo = new BogieVo(); PlatformHeader platformHeader = new PlatformHeader(); bogieVo.setDeviceId(code);//设备ID bogieVo.setCar(code); bogieVo.setCarId(code); bogieVo.setSatelliteStatus(1); bogieVo.setCarType(3); //1挖机 2矿卡 3有人车 4推土机 bogieVo.setAltitude(Double.parseDouble(v2x.getString("altitude"))); //目标点高度 bogieVo.setHeading(Double.parseDouble(v2x.getString("heading"))); // #朝向 north夹角 角度(弧度) bogieVo.setLongitude(Double.parseDouble(v2x.getString("longitude")));//目标点经度 bogieVo.setLatitude(Double.parseDouble(v2x.getString("latitude"))); //目标点纬度 bogieVo.setSpeed(Double.parseDouble(v2x.getString("speed"))); //km/h#速率 //locationData.put("powerNum", 0);//'电量', //powerNum if(StringUtils.isNotEmpty(v2x.getString("powerNum"))){ bogieVo.setPowerNum(Integer.parseInt(v2x.getString("powerNum"))); // 剩余电量 }else{ bogieVo.setPowerNum(100); // 剩余电量 } String commandTypeNm = String.valueOf(header.get("commandTypeNm")); if(TBOX_COMMAND_TYPE_FLAG.equals(commandTypeNm) ) { bogieVo.setDataFlag("0"); }else{ bogieVo.setDataFlag("1"); } bogieVo.setWidth(0); // #宽度 bogieVo.setLength(0); // #长度 bogieVo.setHeight(0); // #高 bogieVo.setLoadCapacity(0);//#载重 bogieVo.setAcceleration(0); //加速度 m/s bogieVo.setTurnRate(0); //转向速率 bogieVo.setGear(0); bogieVo.setDriveMode(1); //bogieVo.setStamp(d.getTime()); if(StringUtils.isNotEmpty(header.getString("stamp"))){ bogieVo.setStamp(Long.parseLong(header.getString("stamp")) ); }else{ bogieVo.setStamp( (System.currentTimeMillis() / 1000)); } bogieVo.setOther(new ArrayList<>()); platformHeader.setStamp(Stamp.now()); platformHeader.setFrameId(""); bogieVo.setHeader(platformHeader); String bogieMqTopic = topic + ":" + tagOrder; String bogieMqOrderTopic = topic + "-order:" + tagOrder + "_order"; if(CAR_DIGG_FLAG.equals(deviceEntity.getTypeId())){ //挖机 mqProducerService.producerSend(topic + ":" + tagOrder, JSONObject.toJSONString(bogieVo)); } else { //有人卡车 mqProducerService.producerSend(bogieMqTopic, JSONObject.toJSONString(bogieVo)); mqProducerService.producerSendOrder(bogieMqOrderTopic, JSONObject.toJSONString(bogieVo), code);//单队列有序 } stringRedisTemplate.opsForHash().put(datakey.toString(), code, JSON.toJSONString(bogieVo)); } /** * 上线默认 * * @param deviceVO * @param vo */ private void handleOnlineStatus(R<DeviceVO> deviceVO, DeviceOnlineStatusVo vo) { vo.setOnlineTime(new Date()); vo.setDeviceType(Integer.valueOf(deviceVO.getData().getTypeId())); vo.setDeviceCode(deviceVO.getData().getCode()); vo.setOnlineStatus(1); vo.setOfflineTime(null); vo.setOnlineDuration(null); } }
代码实现:RocketMQ client部分
IOTMQListener.java
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Maps; import com.ice.core.Ice; import com.ice.core.context.IcePack; import com.ice.core.context.IceRoam; import com.yx_catl.dispatcher.alarm.dto.IceVehicleDTO; import com.yx_catl.dispatcher.integrated.entity.DeviceEntity; import com.yx_catl.dispatcher.official.model.bogie.vo.BogieVo; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.MapUtils; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.MessageModel; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.annotation.SelectorType; import org.apache.rocketmq.spring.core.RocketMQListener; import org.springblade.common.constant.CommonConstant; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.Set; @Slf4j @Component @RocketMQMessageListener( consumerGroup = "${mq.namespace}%${mq.consumer.alarmGroup.group}", topic = "${mq.namespace}%${mq.consumer.alarmGroup.topic}", selectorType = SelectorType.TAG, selectorExpression = "${mq.consumer.alarmGroup.subExpression}", consumeMode = ConsumeMode.ORDERLY, messageModel = MessageModel.CLUSTERING) public class IOTMQListener implements RocketMQListener<BogieVo> { static final String REDISKEY = CommonConstant.REDIS_DEVICE_KEY; @Value("${mq.namespace}%${mq.consumer.alarmGroup.topic}") public String topic; @Autowired private StringRedisTemplate redisTemplate; private static Map<String, Object> map = Maps.newConcurrentMap(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS"); @Override public void onMessage(BogieVo bogieVo) { try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS"); //String time1 = sdf.format(new Date(Long.parseLong(bogieVo.getStamp()))); IcePack pack = new IcePack(); IceRoam roam = new IceRoam(); //v2x String deviceId = bogieVo.getDeviceId(); Object obj = redisTemplate.opsForHash().get(REDISKEY, deviceId); if (null == obj) { return; } DeviceEntity device = JSONObject.parseObject(obj.toString(), DeviceEntity.class); Long miningId = device.getMiningId(); Integer driveMode = bogieVo.getDriveMode(); Integer vehicleType = bogieVo.getCarType(); roam.put("carType", vehicleType + "");//1挖机 2矿卡 3有人车 4推土机 roam.put("deviceId", deviceId); log.info("=======================deviceid:{}=======速度:{}=======加速度:{}=======载重:{}", deviceId, bogieVo.getSpeed(), bogieVo.getAcceleration(), bogieVo.getLoadCapacity()); roam.put("driveMode", driveMode == null ? 0 + "" : driveMode + ""); roam.put("deviceName", device.getName()); roam.put("deviceCode", device.getCode()); roam.put("deviceType", device.getTypeId()); roam.put("diggingsId", miningId); //todo 等琦琛把时间戳加进去 //roam.put("time", bogieVo.getStamp()); roam.put("time", new Date().getTime()); roam.put("lng", bogieVo.getLongitude()); roam.put("lat", bogieVo.getLatitude()); roam.put("alt", bogieVo.getAltitude()); roam.put("tenantId", device.getTenantId()); roam.put("isDelete", device.getIsDeleted()); Object dto = MapUtils.getString(map, miningId + "");//一级缓存取 if (dto == null) {//一级缓存没有 dto = redisTemplate.opsForHash().get(CommonConstant.ICE_VEHICLE_KEY, miningId+"");//查询二级缓存 if (null == dto) {//二级缓存没有查数据库 //查询数据库(三级缓存) } } IceVehicleDTO iceVehicleDTO = JSONObject.parseObject(String.valueOf(dto), IceVehicleDTO.class); if (null == iceVehicleDTO) { return; } Long iceId = iceVehicleDTO.getIceId(); roam.put("speed", bogieVo.getSpeed() + "");//km/h#速率 roam.put("loadCapacity", bogieVo.getLoadCapacity() + "");//#载重 roam.put("acceleration", bogieVo.getAcceleration() + "");//加速度 m/s pack.setIceId(iceId); pack.setRoam(roam); //System.out.println("*******************传入时间:" + sdf.format(new Date(bogieVo.getStamp()))); String result = JSON.toJSONString(Ice.processCtx(pack));//此处调用规则引擎 log.info("================{}",result); } catch (Exception e) { log.info("执行线程出现异常", e); } finally { log.info("执行结束时间{}", new Date()); } } }
配置部分:
#数据源配置 spring: datasource: url: jdbc:mysql://192.168.11.10:3306/db_dev_alarm_service?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true username: ${blade.datasource.dev.username} password: ${blade.datasource.dev.password} #ICE规则引擎 rule-engine: ip: 192.168.12.57 port: 8120 ice: #ice client配置 app: 11 #与后台配置app对应 # server: zookeeper:localhost:2181,localhost:2182,localhost:2183 #server高可用配置 server: 192.168.12.57:18122 #server 地址(serverHost:serverPort) scan: com.yx_catl.dispatcher.alarm.flow,com.yx_catl.dispatcher.alarm.none,com.yx_catl.dispatcher.alarm.result #用于扫描叶子节点,多个包用','分隔(默认扫描全部,扫描全部会拖慢应用启动速度) pool: #线程池配置(用于并发关系节点) parallelism: -1 #默认-1,≤0表示采用默认配置 rocketmq: name-server: 192.168.12.57:9876 #name-server: 192.168.1.199:9876 producer: group: iotBogieMonitor mq: # 用户自定义配置 instanceId: instance_001 # 实例ID,可扩展。部署生产环境时,对应集群 + 服务 + 实例 # 命名空间的名称,是不同的业务场景一般都可以通过命名空间做隔离,并且针对不同的业务场景设置专门的配置,例如消息保留时间。 # 不同命名空间之间的 Topic 相互隔离,订阅相互隔离,角色权限相互隔离。 namespace_rule: dispatch-traffic-rule|${mq.instanceId} #命名空间的名称 consumer_rule: dispatchGroup: group: dispatch-alarm-consumer #处理消费组(暂定) topic: dispatch-traffic #消息主题 subExpression: tag_traffic # 用来设置消息的 TAG tag: dispatch: tag_alarm namespace: iotMqttMonitor|${mq.instanceId} #命名空间的名称 consumer: alarmGroup: group: dispatch-consumer-order #处理消费组(暂定) topic: iot-bogie-monitor-order #消息主题 subExpression: bogie_monitor_order # 用来设置消息的 TAG tag: dispatch: tag_rule iotBogieGroup: group: iot-bogie-consumer-order #处理消费组(暂定) topic: iot-bogie-monitor #消息主题 subExpression: tag_alarm # 用来设置消息的 TAG tag: alarm: tag_alarm namespace_rule_truck: dispatch-truck-rule|${mq.instanceId} #命名空间的名称 consumer_rule_truck: dispatchGroup: group: dispatch-truck-alarm-consumer #处理消费组(暂定) topic: dispatch-truck #消息主题 subExpression: tag_truck # 用来设置消息的 TAG tag: dispatch: tag_alarm #交通相关使用的字典主键 rules: traffic-keys: driving_type,working_condition,road_conditions,vehicle_weight_type,traffic_handling_mode vehicle-keys: vehicle_type,drive_mode,alarm_field,alarm_operator
规则引擎引引入:
<dependency> <groupId>com.waitmoon.ice</groupId> <artifactId>ice-client-spring-boot-starter</artifactId> <version>${ice.version}</version> </dependency>
资料查询:
规则引擎使用:http://waitmoon.com/zh/guide/getting-started.html
bladex框架使用:https://bladex.vip/#/doc/introduction
后续:
因为确实ICE后台对于用户而言不便于操作,所以又通过ICE所开放出来的API,构建一个新的页面,也就是上面所展示的那两个列表
后台实现过程:
以车辆规则为例:
表结构
CREATE TABLE `yx_dispatch_truck_rules` (
`id` bigint(20) NOT NULL COMMENT '主键id' ,
`create_user` bigint(20) NULL DEFAULT NULL COMMENT '创建人ID' ,
`create_dept` bigint(20) NULL DEFAULT NULL COMMENT '创建部门ID' ,
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间' ,
`update_user` bigint(20) NULL DEFAULT NULL COMMENT '修改人ID' ,
`update_time` datetime NULL DEFAULT NULL COMMENT '修改时间' ,
`status` int(2) NULL DEFAULT NULL COMMENT '状态 1.启用 2 禁用' ,
`tenant_id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '000000' COMMENT '租户ID' ,
`app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规则引擎小组id' ,
`rule_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规则id' ,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '交通规则名称' ,
`ore_district_id` bigint(20) NULL DEFAULT NULL COMMENT '矿区id' ,
`ore_district_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '矿区名称' ,
`vehicle_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '车辆类型:1挖车 2矿车 3挖掘机' ,
`drive_mode` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '工况:1有人 2无人 3遥控' ,
`alarm_field` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '比较字段:1.速度speed 2.加速度acceleration 3.载重loadCapacity' ,
`operator` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '关系符号 1> 2< 3≤ 4≥ 5=' ,
`expire` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '解除报警延长时间' ,
`threshold` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '阈值' ,
`start_time` datetime NULL DEFAULT NULL COMMENT '开始时间' ,
`end_time` datetime NULL DEFAULT NULL COMMENT '结束时间' ,
`priority` int(1) NULL DEFAULT NULL COMMENT '优先级' ,
`treatment_method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '对应车重类型处理方式' ,
`content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '规则标识唯一' ,
`is_deleted` int(2) NULL DEFAULT NULL COMMENT '是否已删除' ,
`handle_status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '处理状态' ,
PRIMARY KEY (`id`)
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=utf8mb4 COLLATE=utf8mb4_general_ci
COMMENT='车辆规则表'
ROW_FORMAT=DYNAMIC
;
/** * 保存规则 */ @PostMapping("/save") @ApiOperationSupport(order = 4) @ApiOperation(value = "新增", notes = "传入dispatch_traffic_rules") public R save(@Valid @RequestBody TrafficRulesEntity dispatch_traffic_rules) { TrafficDTO dto = new TrafficDTO(); BeanUtils.copyProperties(dispatch_traffic_rules, dto); // dto.setStartTime(DateUtil.formatDateTime(dispatch_traffic_rules.getStartTime())); // dto.setEndTime(DateUtil.formatDateTime(dispatch_traffic_rules.getEndTime())); // dto.setRuleId(ruleId); dto.setOption(1); dto.setApp(app); // String edit = ruleClient.edit(dto); // dispatch_traffic_rules.setRuleId(ruleId); dispatch_traffic_rules.setApp(app); dispatch_traffic_rules.setHandleStatus("1"); boolean save = dispatchTrafficRulesService.save(dispatch_traffic_rules); dto.setTraceId(String.valueOf(dispatch_traffic_rules.getId())); log.info("新增交通规则与规则引擎MQ交互,发送消息内容为{}", dto); rocketMQTemplate.syncSend(topic + ":" + tagOrder, MessageBuilder.withPayload(dto).build()); return R.status(save); }
alarm监听
import com.alibaba.fastjson.JSONObject; import com.yx_catl.dispatcher.alarm.dto.VehicleDTO; import com.yx_catl.dispatcher.alarm.feign.VehicleRuleClient; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.MessageModel; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.annotation.SelectorType; import org.apache.rocketmq.spring.core.RocketMQListener; import org.apache.rocketmq.spring.core.RocketMQTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.messaging.support.MessageBuilder; import org.springframework.stereotype.Component; @Slf4j @Component @RocketMQMessageListener( consumerGroup = "${mq.namespace_rule_truck}%${mq.consumer_rule_truck.dispatchGroup.group}", topic = "${mq.namespace_rule_truck}%${mq.consumer_rule_truck.dispatchGroup.topic}", selectorType = SelectorType.TAG, selectorExpression = "${mq.consumer_rule_truck.dispatchGroup.subExpression}", consumeMode = ConsumeMode.CONCURRENTLY, messageModel = MessageModel.CLUSTERING) public class TruckMqListener implements RocketMQListener<VehicleDTO> { @Value("${mq.namespace_rule_truck}%${mq.consumer_rule_truck.dispatchGroup.topic}") public String topic; @Value("${mq.consumer_rule_truck.dispatchGroup.tag.dispatch}") public String tagOrder; @Value("${mq.consumer_rule_truck.dispatchGroup.subExpression}") public String selectorExpression; @Autowired private VehicleRuleClient vehicleRuleClient; @Autowired private RocketMQTemplate rocketMQTemplate; @Override public void onMessage(VehicleDTO dto) { log.info("======TrafficDTO:{}", JSONObject.toJSONString(dto)); String json = vehicleRuleClient.build(dto); VehicleDTO result = JSONObject.parseObject(json, VehicleDTO.class); rocketMQTemplate.syncSend(topic + ":" + tagOrder, MessageBuilder.withPayload(result).build()); } }
实体 TrafficRulesEntity
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import org.springblade.core.tenant.mp.TenantEntity; import lombok.Data; import lombok.EqualsAndHashCode; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import java.time.LocalDateTime; /** * 实体类 * * @author 技术中心-代码生成工具 */ @Data @TableName("yx_dispatch_traffic_rules") @EqualsAndHashCode(callSuper = true) @ApiModel(value = "DispatchTrafficRules对象", description = "") public class TrafficRulesEntity extends TenantEntity { private static final long serialVersionUID = 1L; /** * 交通规则名称 */ @ApiModelProperty(value = "交通规则名称") private String name; /** * 矿区id */ @ApiModelProperty(value = "矿区id") private Long oreDistrictId; /** * 矿区名称 */ @ApiModelProperty(value = "矿区名称") private String oreDistrictName; /** * 行车类型 */ @ApiModelProperty(value = "行车类型") private String drivingType; /** * 工况 */ @ApiModelProperty(value = "工况") private String workingCondition; /** * 路况 */ @ApiModelProperty(value = "路况") private String roadConditions; /** * 开始时间 */ @ApiModelProperty(value = "开始时间") private LocalDateTime startTime; /** * 结束时间 */ @ApiModelProperty(value = "结束时间") private LocalDateTime endTime; /** * 优先级 */ @ApiModelProperty(value = "优先级") private Integer priority; /** * 规则id */ @ApiModelProperty(value = "规则id") private String ruleId; /** * 车重类型 */ @ApiModelProperty(value = "车重类型") private String vehicleWeightType; /** * 对应车重类型处理方式 */ @ApiModelProperty(value = "对应车重类型处理方式") private String treatmentMethod; /** * 预留字段一 */ @ApiModelProperty(value = "预留字段一") private String reserveOne; /** * 预留字段二 */ @ApiModelProperty(value = "预留字段二") private String reserveTwo; @ApiModelProperty(value = "规则唯一标识") private String content; @ApiModelProperty(value = "规则小组id") private String app; @ApiModelProperty(value = "处理状态") private String handleStatus; @TableField(exist = false) @ApiModelProperty(value = "矿区名称") private String miningName; }
import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * 车辆报警 模型DTO * */ @Data public class VehicleDTO { /** * 规则名称 */ @ApiModelProperty(value = "name") private String name; /** * appid */ @ApiModelProperty(value = "appid") private String app; /** * 矿区id */ @ApiModelProperty(value = "矿区id") private Long oreDistrictId; /** * 规则id */ @ApiModelProperty(value = "规则id") private String ruleId; /** * 处理方式 1新增 2编辑 3删除 */ @ApiModelProperty(value = "处理方式 1新增 2编辑 3删除") private Integer option; /** * 报警类型 1.超速、2.急加速、3.急减速、4.超载预警 */ @ApiModelProperty(value = "报警类型 1.超速、2.急加速、3.急减速、4.超载预警") private String alarmType; /** * 车辆类型 */ @ApiModelProperty(value = "车辆类型") private String vehicleType; /** * 启动模式 */ @ApiModelProperty(value = "启动模式 1有人 2无人 3遥控") private String driveMode; /** * 比较字段 1.速度speed 2.加速度acceleration 3.载重loadCapacity */ private String alarmField; /** * 关系符号 1> 2< 3≤ 4≥ 5= * */ @ApiModelProperty(value = "关系符号") private String operator; /** * 解除报警延长时间 */ @ApiModelProperty(value = "解除报警延长时间") private String expire; /** * 阈值 */ @ApiModelProperty(value = "阈值") private String threshold; /** * 规则唯一标识 */ @ApiModelProperty(value = "规则唯一标识") private String content; /** * 规则唯一标识 */ @ApiModelProperty("规则唯一标识") private String dict; /** * 数据传输唯一标识 */ @ApiModelProperty("数据传输唯一标识") private String traceId; /** * 成功失败返回标识 */ @ApiModelProperty("标识:0成功 -1失败") private Integer res; }
新增ICE后返回成功失败,同时再发mq到dispatch服务,其中0,1,2..对应bladex中的业务字典
import com.yx_catl.dispatcher.alarm.dto.TrafficDTO; import com.yx_catl.dispatcher.dispatch.entity.TrafficRulesEntity; import com.yx_catl.dispatcher.dispatch.service.IDispatchTrafficRulesService; import lombok.extern.slf4j.Slf4j; import org.apache.rocketmq.spring.annotation.ConsumeMode; import org.apache.rocketmq.spring.annotation.MessageModel; import org.apache.rocketmq.spring.annotation.RocketMQMessageListener; import org.apache.rocketmq.spring.annotation.SelectorType; import org.apache.rocketmq.spring.core.RocketMQListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Slf4j @Component @RocketMQMessageListener( consumerGroup = "${mq.namespace_rule}%${mq.consumer_rule.dispatchGroup.group}", topic = "${mq.namespace_rule}%${mq.consumer_rule.dispatchGroup.topic}", selectorType = SelectorType.TAG, selectorExpression = "${mq.consumer_rule.dispatchGroup.subExpression}", consumeMode = ConsumeMode.CONCURRENTLY, messageModel = MessageModel.CLUSTERING) public class TrafficMqListener implements RocketMQListener<TrafficDTO> { @Autowired IDispatchTrafficRulesService dispatchTrafficRulesService; @Override public void onMessage(TrafficDTO trafficDTO) { log.info("交通规则监听内容{}",trafficDTO); TrafficRulesEntity id = dispatchTrafficRulesService.getById(trafficDTO.getTraceId()); if(null!=id){ id.setRuleId(trafficDTO.getRuleId()); //根据操作判断如何给处理状态 if(trafficDTO.getOption()==1){ //根据返回给定具体的操作处理成功或者失败 if(trafficDTO.getRes()==0){ id.setHandleStatus("2"); }else{ id.setHandleStatus("3"); } }else if(trafficDTO.getOption()==2){ if(trafficDTO.getRes()==0){ id.setHandleStatus("5"); }else{ id.setHandleStatus("6"); } }else{ if(trafficDTO.getRes()==0){ id.setHandleStatus("8"); }else{ id.setHandleStatus("9"); } } if(null!=trafficDTO.getContent()){ id.setContent(trafficDTO.getContent()); } if(id.getHandleStatus().equals("8")){ dispatchTrafficRulesService.removeById(id); }else{ dispatchTrafficRulesService.updateById(id); } } } }