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);
            }
        }

    }
}

 

posted @ 2023-01-11 17:57  蔡徐坤1987  阅读(938)  评论(0编辑  收藏  举报