فهرست منبع

提交初步调试后的边缘端报警

lgy 4 سال پیش
والد
کامیت
489972d2c4
29فایلهای تغییر یافته به همراه1143 افزوده شده و 487 حذف شده
  1. 27 100
      src/main/java/com/persagy/cache/AlarmInfoCache.java
  2. 15 2
      src/main/java/com/persagy/client/GroupNettyClient.java
  3. 88 21
      src/main/java/com/persagy/client/GroupNettyClientHandler.java
  4. 37 9
      src/main/java/com/persagy/client/WebSocketClientFactory.java
  5. 93 5
      src/main/java/com/persagy/controller/HelloWorld.java
  6. 48 43
      src/main/java/com/persagy/entity/AlarmDefine.java
  7. 76 33
      src/main/java/com/persagy/entity/AlarmRecord.java
  8. 0 74
      src/main/java/com/persagy/entity/CommandResult.java
  9. 1 1
      src/main/java/com/persagy/entity/Condition.java
  10. 42 0
      src/main/java/com/persagy/entity/ExpireAlarmMessage.java
  11. 15 12
      src/main/java/com/persagy/entity/NettyMessage.java
  12. 98 0
      src/main/java/com/persagy/entity/ZktAlarmRecordDO.java
  13. 4 4
      src/main/java/com/persagy/init/InitRunner.java
  14. 104 13
      src/main/java/com/persagy/job/AlarmExpireJob.java
  15. 51 0
      src/main/java/com/persagy/job/ExpireAlarmQueue.java
  16. 30 0
      src/main/java/com/persagy/job/SpringSchedule.java
  17. 18 0
      src/main/java/com/persagy/repository/AlarmRecordRepository.java
  18. 5 1
      src/main/java/com/persagy/service/AlarmDefineService.java
  19. 4 1
      src/main/java/com/persagy/service/AlarmHandleService.java
  20. 8 0
      src/main/java/com/persagy/service/AlarmQuartzService.java
  21. 68 52
      src/main/java/com/persagy/service/impl/AlarmDefineServiceImpl.java
  22. 132 39
      src/main/java/com/persagy/service/impl/AlarmHandleServiceImpl.java
  23. 68 27
      src/main/java/com/persagy/service/impl/AlarmQuartzServiceImpl.java
  24. 25 0
      src/main/java/com/persagy/utils/DateUtils.java
  25. 34 17
      src/main/java/com/persagy/utils/LockUtil.java
  26. 0 4
      src/main/resources/application.properties
  27. 33 23
      src/main/resources/application.yml
  28. 14 1
      src/main/resources/zkt_alarm_tables_mysql_innodb.sql
  29. 5 5
      src/test/java/com/persagy/zktprojectalarm/Mytest.java

+ 27 - 100
src/main/java/com/persagy/cache/AlarmInfoCache.java

@@ -1,6 +1,7 @@
 package com.persagy.cache;
 
 
+import cn.hutool.core.collection.CollectionUtil;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.googlecode.aviator.AviatorEvaluator;
@@ -130,6 +131,10 @@ public class AlarmInfoCache {
     public void putAlarmDefinitionById(String definitionId, AlarmDefine alarmDefine) {
         Condition condition = alarmDefine.getCondition();
         List<JSONObject> infoCodes = condition.getInfoCodes();
+        if(CollectionUtil.isEmpty(infoCodes)) {
+            log.error("报警定义ID为[{}],报警定义详情为[{}] 的报警定义信息点为空,请检查!!!!!  ",definitionId,alarmDefine.toString());
+            return;
+        }
         String trigger = condition.getTrigger();
         String end = condition.getEnd();
         try {
@@ -216,6 +221,27 @@ public class AlarmInfoCache {
         AviatorEvaluator.getInstance().clearExpressionCache();
     }
     /**
+     * @description:根据报警定义删除缓存
+     * @exception:
+     * @author: LuoGuangyi
+     * @company: Persagy Technology Co.,Ltd
+     * @param alarmDefine:
+     * @return: void
+     * @since: 2020/10/26 20:34
+     * @version: V1.0
+     */
+    public void clearAlarmDefine(AlarmDefine alarmDefine) {
+        String defineId = getAlarmDefineId(alarmDefine);
+        alarmDefineMap.remove(defineId);
+        List<JSONObject> infoCodes = alarmDefine.getCondition().getInfoCodes();
+        infoCodes.stream().forEach(info->{
+            String meterId = info.getString("meterId");
+            String funcId = info.getString("funcId");
+            List<AlarmDefine> AlarmDefineList = infoAlarmMap.getOrDefault(getKey(meterId, funcId),new ArrayList<>());
+            infoAlarmMap.put(getKey(meterId, funcId), AlarmDefineList.stream().filter(ad -> !getAlarmDefineId(ad).equals(defineId)).collect(Collectors.toList()));
+        });
+    }
+    /**
      * @description:获取报警定义id,
      * 中台报警定义ID没有实际意义,根据itemCode-objId拼接作为唯一标识
      * @exception:
@@ -225,7 +251,7 @@ public class AlarmInfoCache {
      * @since: 2020/10/19 17:28
      * @version: V1.0
      */
-    public String getAlarmDefineId(AlarmDefine alarmDefine) {
+    public static String getAlarmDefineId(AlarmDefine alarmDefine) {
         return alarmDefine.getItemCode()+"-"+alarmDefine.getObjId();
     }
 
@@ -253,104 +279,5 @@ public class AlarmInfoCache {
     private String getKey(String meterId,String funcId) {
         return meterId + "-" + funcId;
     }
-//
-//    /**
-//     * @description: 根据项目id, 对象id, 信息点编码获取表号功能号
-//     * @param: projectId 项目id
-//     * @param: objectId 对象id
-//     * @param: infoCode 信息点编码
-//     * @return: java.lang.String
-//     * @exception:
-//     * @author: fenghanchao
-//     * @company: Persagy Technology Co.,Ltd
-//     * @since: 10:34 2020/7/22
-//     * @version: V1.0
-//     */
-//    public String getMeterFuncIdByObjectInfoCode(String projectId, String objectId, String infoCode) {
-//        return (String) redisTemplate.opsForHash().get(RedisConstant.ALARM_DEFINITION_METER_FUNC_KEY + ":" + projectId, objectId + "-" + infoCode);
-//    }
-//
-//    /**
-//     * @description: 设置项目id, 对象id, 信息点编码获取表号功能号对应关系
-//     * @param: projectId 项目id
-//     * @param: objectId 对象id
-//     * @param: infoCode 信息点编码
-//     * @param: meterFuncId 表号功能号
-//     * @return: void
-//     * @exception:
-//     * @author: fenghanchao
-//     * @company: Persagy Technology Co.,Ltd
-//     * @since: 10:36 2020/7/22
-//     * @version: V1.0
-//     */
-//    public void putMeterFuncIdByObjectInfoCode(String projectId, String objectId, String infoCode, String meterFuncId) {
-//        redisTemplate.opsForHash().put(RedisConstant.ALARM_DEFINITION_METER_FUNC_KEY + ":" + projectId, objectId + "-" + infoCode, meterFuncId);
-//    }
-//
-//    /**
-//     * @description: 根据报警定义id获取预报警时间信息
-//     * @param: projectId 项目id
-//     * @param: definitionId 报警定义id
-//     * @return: java.lang.String (例 2020-07-21 00:00:00)
-//     * @exception:
-//     * @author: fenghanchao
-//     * @company: Persagy Technology Co.,Ltd
-//     * @since: 15:37 2020/7/20
-//     * @version: V1.0
-//     */
-//    public String getPreAlarmTimeByDefinitionId(String projectId, String definitionId) {
-//        return (String) redisTemplate.opsForHash().get(RedisConstant.ALARM_DEFINITION_PRE_ALARM_KEY + ":" + projectId, definitionId);
-//    }
-//
-//    public void deletePreAlarmTimeByDefinitionId(String projectId, String definitionId) {
-//        redisTemplate.opsForHash().delete(RedisConstant.ALARM_DEFINITION_PRE_ALARM_KEY + ":" + projectId, definitionId);
-//    }
-//
-//    /**
-//     * @description: 设置报警定义id与预报警时间信息的对应关系
-//     * @param: projectId
-//     * @param: definitionId
-//     * @param: preAlarmDate
-//     * @return: void
-//     * @exception:
-//     * @author: fenghanchao
-//     * @company: Persagy Technology Co.,Ltd
-//     * @since: 15:39 2020/7/20
-//     * @version: V1.0
-//     */
-//    public void putPreAlarmTimeByDefinitionId(String projectId, String definitionId, Date preAlarmDate) throws Exception{
-//        redisTemplate.opsForHash().put(RedisConstant.ALARM_DEFINITION_PRE_ALARM_KEY + ":" + projectId, definitionId, DateUtils.date2Str(preAlarmDate, DateUtils.SDF_SECOND));
-//    }
-//
-//    /**
-//     * @description: 根据报警定义id获取报警详情
-//     * @param: projectId 项目id
-//     * @param: definitionId 报警定义id
-//     * @return: java.lang.String 报警详情json字符串 {...}
-//     * @exception:
-//     * @author: fenghanchao
-//     * @company: Persagy Technology Co.,Ltd
-//     * @since: 15:42 2020/7/20
-//     * @version: V1.0
-//     */
-//    public String getAlarmInfoByDefinitionId(String projectId, String definitionId) {
-//        return (String) redisTemplate.opsForHash().get(RedisConstant.ALARM_DEFINITION_ALARM_INFO_KEY + ":" + projectId, definitionId);
-//    }
-//
-//    /**
-//     * @description: 设备报警定义id报警详情对应关系
-//     * @param: projectId 项目id
-//     * @param: definitionId 报警定义id
-//     * @param: alarmInfo 报警详情
-//     * @return: void
-//     * @exception:
-//     * @author: fenghanchao
-//     * @company: Persagy Technology Co.,Ltd
-//     * @since: 15:42 2020/7/20
-//     * @version: V1.0
-//     */
-//    public void putAlarmInfoByDefinitionId(String projectId, String definitionId, String alarmInfo) {
-//        redisTemplate.opsForHash().put(RedisConstant.ALARM_DEFINITION_ALARM_INFO_KEY + ":" + projectId, definitionId, alarmInfo);
-//    }
 
 }

+ 15 - 2
src/main/java/com/persagy/client/GroupNettyClient.java

@@ -1,5 +1,6 @@
 package com.persagy.client;
 
+import com.persagy.repository.AlarmRecordRepository;
 import com.persagy.service.AlarmDefineService;
 import io.netty.bootstrap.Bootstrap;
 import io.netty.channel.Channel;
@@ -30,13 +31,25 @@ import java.util.concurrent.ConcurrentHashMap;
 public class GroupNettyClient {
     @Autowired
     AlarmDefineService alarmDefineService;
-
+    @Autowired
+    AlarmRecordRepository alarmRecordRepository;
     static Bootstrap groupBootstrap = new Bootstrap();
     static Channel channelGroup;
     @Value("${group.alarm.host:127.0.0.1}")
     public String host;
     @Value("${group.alarm.port}")
     public int port;
+    /**
+     * 项目名称
+     */
+    @Value("${project.id}")
+    public String projectId;
+    /**
+     * 集团编码
+     */
+    @Value("${group.code}")
+    public String groupCode;
+
     //会话对象组
     public static Map<String, Channel> channelsMap = new ConcurrentHashMap<>();
 
@@ -69,7 +82,7 @@ public class GroupNettyClient {
                             ch.pipeline().addLast(new StringDecoder());
                             ch.pipeline().addLast(new StringEncoder());
                             // pipeline可以理解为所有handler的初始化容器
-                            ch.pipeline().addLast(new GroupNettyClientHandler(groupNettyClient, alarmDefineService));// 添加自定义handler
+                            ch.pipeline().addLast(new GroupNettyClientHandler(groupNettyClient, alarmDefineService,alarmRecordRepository));// 添加自定义handler
                         }
                     });
             // 连接远程节点,等待连接完成

+ 88 - 21
src/main/java/com/persagy/client/GroupNettyClientHandler.java

@@ -1,7 +1,16 @@
 package com.persagy.client;
 
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.date.TimeInterval;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.TypeReference;
+import com.persagy.entity.AlarmDefine;
 import com.persagy.entity.NettyMessage;
+import com.persagy.entity.ZktAlarmRecordDO;
+import com.persagy.repository.AlarmRecordRepository;
 import com.persagy.service.AlarmDefineService;
+import com.persagy.utils.LockUtil;
 import com.persagy.utils.StringUtil;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
@@ -9,12 +18,14 @@ import io.netty.handler.timeout.IdleState;
 import io.netty.handler.timeout.IdleStateEvent;
 import lombok.extern.slf4j.Slf4j;
 
+import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 /**
- * @ClassName: EchoClientHandler
- * @Description: 客户端处理类
  * @author lqshi
+ * @ClassName: EchoClientHandler
+ * @Description: 客户端处理类(处理云端数据)
  * @date 2020年8月29日 下午8:31:59
  */
 // 注意:SimpleChannelInboundHandler<ByteBuf>的<>中是什么,channelRead0第二参数是什么
@@ -25,15 +36,15 @@ public class GroupNettyClientHandler extends ChannelInboundHandlerAdapter {
     // Reconnect when the server sends nothing for 10 seconds.
     private static final int READ_TIMEOUT = Integer.parseInt(System.getProperty("readTimeout", "10"));
 
-   private AlarmDefineService alarmDefineService;
-   private GroupNettyClient groupNettyClient;
+    private AlarmDefineService alarmDefineService;
+    private GroupNettyClient groupNettyClient;
+    private AlarmRecordRepository alarmRecordRepository;
+
 
-    public GroupNettyClientHandler(GroupNettyClient groupNettyClient, AlarmDefineService alarmDefineService) {
+    public GroupNettyClientHandler(GroupNettyClient groupNettyClient, AlarmDefineService alarmDefineService, AlarmRecordRepository alarmRecordRepository) {
         this.alarmDefineService = alarmDefineService;
         this.groupNettyClient = groupNettyClient;
-    }
-
-    public GroupNettyClientHandler() {
+        this.alarmRecordRepository = alarmRecordRepository;
     }
 
     @Override
@@ -49,40 +60,94 @@ public class GroupNettyClientHandler extends ChannelInboundHandlerAdapter {
             // 长时间不操作的时候自动关闭连接; ctx.close();
         }
     }
-	 /**
+
+    /**
      * 在到服务器的连接已经建立之后将被调用
+     *
      * @param ctx
      * @throws Exception
      */
     @Override
     public void channelActive(ChannelHandlerContext ctx) throws Exception {
         System.out.println("Connected to: " + ctx.channel().remoteAddress());
-        //启动的时候发送消息
-       NettyMessage msg = new NettyMessage();
-        msg.setOpCode(3);
-        ctx.channel().writeAndFlush(msg.toString());
+        //启动的时候发送消息,获取全部报警定义
+        //{"groupCode":"wd", "projectId":"Pj123"}
+        NettyMessage nettyMessage = new NettyMessage();
+        nettyMessage.setRemark("连接已经建立;");
+        nettyMessage.setOpCode(4);
+        JSONObject content = new JSONObject();
+        content.put("groupCode", groupNettyClient.groupCode);
+        content.put("projectId", groupNettyClient.projectId);
+        nettyMessage.setContent(Arrays.asList(content));
+        log.info(nettyMessage.toString());
+        ctx.channel().writeAndFlush(nettyMessage.toString());
     }
+
     /**
      * 当从服务器接收到一个消息时被调用
+     *
      * @param ctx
      * @param msg
      * @throws Exception
      */
     @Override
-    public  void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
-        System.out.println("Client received: "+ msg);
+    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+         log.info("Client received: {}",msg);
         try {
+            TimeInterval timer = DateUtil.timer();
+            LockUtil.getInstance().setExecute(false);
             handlerMsg(ctx, msg);
+            log.info("处理消息时间[{}]",timer.interval());
         } catch (Exception e) {
-            log.error("channelRead",e);
+            log.error("channelRead", e);
         }
     }
 
     private void handlerMsg(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception {
-        if(StringUtil.isJSONObject((String) msg)) {
+        if (StringUtil.isJSONObject((String) msg)) {
             NettyMessage message = StringUtil.tranferItemToDTO((String) msg, NettyMessage.class);
+            if (message.getOpCode() == 9) {
+                NettyMessage<AlarmDefine> AlarmDefineMessage = JSONObject.parseObject(String.valueOf(msg), new TypeReference<NettyMessage<AlarmDefine>>() {
+                });
+                List<AlarmDefine> definesList = AlarmDefineMessage.getContent();
+                if (CollectionUtil.isNotEmpty(definesList)) {
+                    try {
+                        LockUtil.getInstance().lock.lock();
+                        LockUtil.getInstance().setExecute(false);
+                        //加个等待,保证正在执行的逻辑执行成功
+                        Thread.sleep(4000);
+                        alarmDefineService.listAllAlarmDefine(definesList);
+                        LockUtil.getInstance().setExecute(true);
+                        LockUtil.getInstance().condition.signalAll();
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    } finally {
+                        LockUtil.getInstance().lock.unlock();
+                    }
+                }
+            } else if (message.getOpCode() == 7) {
+                NettyMessage<AlarmDefine> AlarmDefineMessage = JSONObject.parseObject(String.valueOf(msg), new TypeReference<NettyMessage<AlarmDefine>>() {
+                });
+                List<AlarmDefine> definesList = AlarmDefineMessage.getContent();
+                if (CollectionUtil.isNotEmpty(definesList)) {
+                    alarmDefineService.listSomeAlarmDefine(definesList);
+                }
+            }else if (message.getOpCode() == 8) {
+                log.info("-----过期消息----[{}]",message);
+                //{"id":"","objId":"","itemCode":""}  id为报警记录ID
+                List content = message.getContent();
+                if (CollectionUtil.isNotEmpty(content)) {
+                    JSONObject parseObject = JSONObject.parseObject(JSONObject.toJSONString(content.get(0)));
+                    String defineId = parseObject.getString("itemCode") + "-" + parseObject.getString("objId");
+                    ZktAlarmRecordDO zktAlarmRecordDO = alarmRecordRepository.findById(defineId).orElse(new ZktAlarmRecordDO());
+                    zktAlarmRecordDO.setDefinitionId(defineId);
+                    zktAlarmRecordDO.setAlarmId(parseObject.getString("id"));
+                    alarmRecordRepository.save(zktAlarmRecordDO);
+                }
+            }
             NettyMessage response = new NettyMessage();
-            System.out.println(message.toString());
+            response.setOpCode(3);
+            response.setRemark("已经收到消息");
             channelHandlerContext.write(response.toString());
         }
     }
@@ -94,6 +159,7 @@ public class GroupNettyClientHandler extends ChannelInboundHandlerAdapter {
 
     /**
      * 在处理过程中引发异常时被调用
+     *
      * @param ctx
      * @param cause
      * @throws Exception
@@ -103,16 +169,17 @@ public class GroupNettyClientHandler extends ChannelInboundHandlerAdapter {
         cause.printStackTrace();
         ctx.close();
     }
-    
+
     /**
      * 通道处于非活跃状态动作,该方法只会在失效时调用一次
      */
     @Override
     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-    	//客户端自己不正常情况下自己在重连一次
+        //客户端自己不正常情况下自己在重连一次
         System.out.println("Disconnected from: " + ctx.channel().remoteAddress());
 
     }
+
     @Override
     public void channelUnregistered(final ChannelHandlerContext ctx) throws Exception {
         System.out.println("Sleeping for: " + RECONNECT_DELAY + "s,Reconnecting to: " + groupNettyClient.host + ':' + groupNettyClient.port);
@@ -120,7 +187,7 @@ public class GroupNettyClientHandler extends ChannelInboundHandlerAdapter {
             @Override
             public void run() {
                 System.out.println("Reconnecting to: " + groupNettyClient.host + ':' + groupNettyClient.port);
-                groupNettyClient.connect(groupNettyClient,ctx.channel());
+                groupNettyClient.connect(groupNettyClient, ctx.channel());
             }
         }, RECONNECT_DELAY, TimeUnit.SECONDS);
     }

+ 37 - 9
src/main/java/com/persagy/client/WebSocketClientFactory.java

@@ -4,6 +4,7 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.date.TimeInterval;
 import com.persagy.service.AlarmHandleService;
 import com.persagy.utils.GZIPCompressUtil;
+import com.persagy.utils.LockUtil;
 import com.persagy.utils.StringUtil;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
@@ -17,7 +18,6 @@ import org.springframework.stereotype.Component;
 
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -37,7 +37,6 @@ import java.util.concurrent.atomic.AtomicInteger;
  **/
 @Component
 @Slf4j
-@Data
 public class WebSocketClientFactory {
     /**
      * IP
@@ -62,10 +61,19 @@ public class WebSocketClientFactory {
     /**
      * 项目名称
      */
-    @Value("${project.id}")
-    String projectId;
+    @Value("${project.iotid}")
+    String iotProjectId;
 
     private WebSocketClient outCallWebSocketClientHolder;
+
+    public WebSocketClient getOutCallWebSocketClientHolder() {
+        return outCallWebSocketClientHolder;
+    }
+
+    public void setOutCallWebSocketClientHolder(WebSocketClient outCallWebSocketClientHolder) {
+        this.outCallWebSocketClientHolder = outCallWebSocketClientHolder;
+    }
+
     @Autowired
     AlarmHandleService alarmHandleService;
 
@@ -85,7 +93,7 @@ public class WebSocketClientFactory {
         WebSocketClient webSocketClient = new WebSocketClient(new URI(outCallWebSockertUrl)) {
             @Override
             public void onOpen(ServerHandshake serverHandshake) {
-                String msg = projectId;
+                String msg = iotProjectId;
                 sendMsg(getOutCallWebSocketClientHolder(), msg);
             }
 
@@ -100,9 +108,26 @@ public class WebSocketClientFactory {
                         log.error("解密失败!", e);
                     }
                 }
-                log.info("接收信息为:{}", message);
+//                log.info("接收信息为:{}", message);
 
                 try {
+                    while (!LockUtil.getInstance().isExecute()){
+                        try {
+                            log.warn("等待获取锁....");
+                            LockUtil.getInstance().lock.lock();
+                            log.warn("已经获取锁....");
+//                            try {
+//                                LockUtil.getInstance().condition.await();
+//                            } catch (InterruptedException e) {
+//                                e.printStackTrace();
+//                            }
+//                            log.warn("等待结束....");
+                        }catch (Exception e) {
+                            log.error("数据加锁处理发生异常", e);
+                        }finally {
+                            LockUtil.getInstance().lock.unlock();
+                        }
+                    }
                     alarmHandleService.handleIOTData(message);
                 } catch (Exception e) {
                     log.error("数据处理失败", e);
@@ -112,17 +137,20 @@ public class WebSocketClientFactory {
             }
 
             @Override
-            public void onClose(int i, String s, boolean b) {
-                log.info("关闭连接");
+            public void onClose(int code, String reason, boolean remote) {
+                //code, reason, remote
+                log.warn("关闭连接,code[{}],reson[{}],remote[{}]",code,reason,remote);
                 //retryOutCallWebSocketClient();
             }
 
             @Override
             public void onError(Exception e) {
-                log.error("连接异常");
+                log.error("连接异常",e);
                 //retryOutCallWebSocketClient();
             }
         };
+        //默认为60 ,阻塞时间稍长会超时,此处改成 1200
+        webSocketClient.setConnectionLostTimeout(1200);
         webSocketClient.connect();
         return webSocketClient;
     }

+ 93 - 5
src/main/java/com/persagy/controller/HelloWorld.java

@@ -1,15 +1,103 @@
 package com.persagy.controller;
 
 
-import com.googlecode.aviator.AviatorEvaluator;
+import com.alibaba.fastjson.JSONObject;
+import com.persagy.cache.AlarmInfoCache;
+import com.persagy.client.GroupNettyClient;
+import com.persagy.entity.NettyMessage;
+import com.persagy.entity.ZktAlarmRecordDO;
+import com.persagy.repository.AlarmRecordRepository;
+import com.persagy.service.AlarmHandleService;
+import com.persagy.utils.LockUtil;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@Api(tags = "hello")
+@RestController
+@RequestMapping("hello")
+@Slf4j
 public class HelloWorld {
-	public static void main(String[] args) {
+	@Autowired
+	AlarmHandleService alarmHandleService;
 
+	@Autowired
+	private GroupNettyClient groupNettyClient;
+	@Autowired
+	AlarmInfoCache alarmInfoCache;
+	@Autowired
+	AlarmRecordRepository alarmRecordRepository;
+	@PostMapping("/testMesage")
+	public String testMesage(@RequestBody JSONObject jsonObject) throws Exception {
+		NettyMessage nettyMessage = new NettyMessage();
+		nettyMessage.setRemark("连接已经建立;");
+		nettyMessage.setOpCode(4);
+		JSONObject content = new JSONObject();
+		content.put("groupCode", groupNettyClient.groupCode);
+		content.put("projectId", groupNettyClient.projectId);
+		nettyMessage.setContent(Arrays.asList(content));
+		groupNettyClient.sendMessage(nettyMessage.toString());
+		return "成功";
+	}
 
-//		Boolean result2 = (Boolean) AviatorEvaluator.execute("3>1 && 2!=4 || true");
-		Boolean result2 = (Boolean) AviatorEvaluator.execute("3>1 && !!(2!=4)");
-		System.out.println(result2);//true
+	@PostMapping("/test")
+	public String test(@RequestBody JSONObject jsonObject) throws Exception {
+		LockUtil.getInstance().lock.lock();
+		try {
+			LockUtil.getInstance().setExecute(!LockUtil.getInstance().isExecute());
+			//加个等待,保证正在执行的逻辑执行成功
+			Thread.sleep(2000);
+			if(LockUtil.getInstance().isExecute()){
+				LockUtil.getInstance().condition.signalAll();
+			}
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+		} finally {
+			LockUtil.getInstance().lock.unlock();
+		}
+		AtomicInteger atomicInteger = new AtomicInteger(0);
+		alarmInfoCache.getAlarmDefineMap().entrySet().forEach(entry->{
+//			log.info("[{}]的key:[{}],value:[{}]",atomicInteger.getAndIncrement(),entry.getKey(),entry.getValue());
+		});
+		return "成功";
 	}
+
+	@PostMapping("/test2")
+	public String test2(@RequestBody JSONObject jsonObject) throws Exception {
+		String message = jsonObject.getString("message");
+		alarmHandleService.handleIOTData(message);
+		return "成功";
+	}
+
+	@PostMapping("/test3")
+	public ArrayList<ZktAlarmRecordDO> test3(@RequestBody JSONObject jsonObject) throws Exception {
+		String defineId = jsonObject.getString("itemCode") + "-" + jsonObject.getString("objId");
+		ZktAlarmRecordDO zktAlarmRecordDO = alarmRecordRepository.findById(defineId).orElse(new ZktAlarmRecordDO());
+		zktAlarmRecordDO.setDefinitionId(defineId);
+		zktAlarmRecordDO.setItemCode(jsonObject.getString("itemCode"));
+		zktAlarmRecordDO.setObjId(jsonObject.getString("objId"));
+		zktAlarmRecordDO.setAlarmId(jsonObject.getString("id"));
+		ZktAlarmRecordDO save = alarmRecordRepository.save(zktAlarmRecordDO);
+		log.info("保存结果为:{}",save);
+		Iterable<ZktAlarmRecordDO> all = alarmRecordRepository.findAll();
+		Iterator<ZktAlarmRecordDO> iterator = all.iterator();
+		ArrayList<ZktAlarmRecordDO> list = new ArrayList<>();
+		while (iterator.hasNext()) {
+			list.add(iterator.next());
+		}
+		return list;
+	}
+
+
+
 }
 

+ 48 - 43
src/main/java/com/persagy/entity/AlarmDefine.java

@@ -13,46 +13,24 @@ import lombok.Data;
  *     "streamId": "",
  *     "opCode": "",
  *     "content": [
- *         {
- *             "id": 1,
- *             "objId": "obj1",
- *             "itemCode": "1055",
- *             "projectId": "xxx",
- *             "name": "室内高温",
- *             "dealFunc": "point",
- *             "category": "环境报警",
- *             "level": "B",
- *             "remark": "我是备注哈",
- *             "open": 1,
+ *        {
+ *             "id": "000f9609-685e-47b7-bb7d-e91d31f21f8d",
+ *             "objId": "Eq1101050029e8fa1f6e4c81483fbfd7c554e1cdcd2e",
+ *             "projectId": "Pj1101050029",
+ *             "itemCode": "1051",
+ *             "category": "Eq",
+ *             "level": "S",
+ *             "remark": "更改报警等级333",
  *             "condition": {
- *                 "infoCode": [
- *                     "$infoCode1",
- *                     "$infoCode1"
- *                 ],
- *                 "infoCodeId": [
- *                     {
- *                         "infoCode": "infoCode1",
- *                         "meterId": "11",
- *                         "funcId": "12"
- *                     },
- *                     {
- *                         "infoCode": "infoCode2",
- *                         "meterId": "21",
- *                         "funcId": "22"
- *                     }
- *                 ],
- *                 "trigger": "($infoCode1 > 10 && $infoCode1 < 20) && ($infoCode2 < 20)",
- *                 "end": "!($infoCode1 < 20 && $infoCode1 > 10)",
- *                 "$triggerUphold": 10,
- *                 "$endUphold": 5,
- *                 "$time": {
- *                     "type": "period",
- *                     "period": {
- *                         "$gt": "090000",
- *                         "$lt": "210000"
- *                     }
- *                 }
- *             }
+ *             },
+ *             "open": 0,
+ *             "concern": 0,
+ *             "userDefined": 0,
+ *             "createUser": "System",
+ *             "createTime": 1603268498000,
+ *             "updateUser": "systemId",
+ *             "updateTime": 1603372305000,
+ *             "valid": 1
  *         }
  *     ]
  * }
@@ -63,12 +41,29 @@ public class AlarmDefine {
     /**
      * 报警定义ID
      */
-    private Long id;
+    private String id;
     /**
      * 报警对象ID
      */
     private String objId;
     /**
+     * 项目ID
+     */
+    private String projectId;
+    /**
+     * 报警对象类型
+     */
+    private String category;
+    /**
+     * 严重程度
+     */
+    private String level;
+    /**
+     * 触发条件(信息点详情)
+     */
+    private Condition condition;
+
+    /**
      * 报警条目编码
      */
     private String itemCode;
@@ -76,11 +71,21 @@ public class AlarmDefine {
      * 报警名称
      */
     private String name;
-
     /**
-     * 信息点详情
+     * 备注
      */
-    private Condition condition;
+    private String remark;
+    /**
+     * 屏蔽状态
+     */
+    private int open;
+    /**
+     * 是否重点关注
+     */
+    private int concern;
+
+
+
 
     @Override
     public String toString() {

+ 76 - 33
src/main/java/com/persagy/entity/AlarmRecord.java

@@ -1,8 +1,10 @@
 package com.persagy.entity;
 
 import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONField;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
@@ -15,6 +17,7 @@ import java.util.Date;
  */
 @ApiModel(value = "报警记录")
 @Data
+@AllArgsConstructor
 @NoArgsConstructor
 @Builder
 public class AlarmRecord implements Serializable {
@@ -55,72 +58,112 @@ public class AlarmRecord implements Serializable {
      */
     @ApiModelProperty(value = "报警描述")
     private String remark;
+    /**
+     * 报警名称
+     */
+    @ApiModelProperty(value = "报警名称")
+    private String name;
+    /**
+     * 报警分类
+     */
+    @ApiModelProperty(value = "报警分类")
+    private String category;
 
     /**
-     * 创建用户
+     * 是否重点关注
      */
-    @ApiModelProperty(value = "创建用户")
-    private String createUser;
+    @ApiModelProperty(value = "是否重点关注")
+    private Integer concern;
 
     /**
-     * 创建时间 时间戳
+     * 报警状态
      */
-    @ApiModelProperty(value = "创建时间")
-    private Long createTime;
+    @ApiModelProperty(value = "报警状态")
+    private Integer state;
 
     /**
-     * 更新用户
+     * 有效期开始时间(目前置空)
      */
-    @ApiModelProperty(value = "更新用户")
-    private String updateUser;
+    @ApiModelProperty(value = "有效期开始时间")
+    private Date effectStartTime;
 
     /**
-     * 更新时间
+     * 有效期结束时间(自动恢复时间,为空表示是不过期)
      */
-    @ApiModelProperty(value = "更新时间")
-    private Date updateTime;
+    @ApiModelProperty(value = "有效期结束时间")
+    private Date effectEndTime;
 
     /**
-     * 删除标记 1:true,0:false
+     * 报警条件(产生+恢复)
      */
-    @ApiModelProperty(value = "删除标记 1:true,0:false")
-    private Integer valid;
+    @ApiModelProperty(value = "报警触发条件")
+    @JSONField(jsonDirect = true)
+    private String condition;
 
     /**
-     * 报警名称
+     * 报警触发值
      */
-    @ApiModelProperty(value = "报警名称")
-    private String name;
+    @ApiModelProperty(value = "报警触发值")
+    @JSONField(jsonDirect = true)
+    private String triggerInfo;
 
     /**
-     * 报警分类
+     * 报警时间
      */
-    @ApiModelProperty(value = "报警分类")
-    private String category;
+    @ApiModelProperty(value = "报警时间")
+    private Date triggerTime;
 
     /**
-     * 是否重点关注
+     * 报警结束值
      */
-    @ApiModelProperty(value = "是否重点关注")
-    private Integer concern;
+    @ApiModelProperty(value = "报警结束值")
+    @JSONField(jsonDirect = true)
+    private String endInfo;
 
     /**
-     * 报警状态
+     * 有效期结束时间
      */
-    @ApiModelProperty(value = "报警状态")
-    private Integer state;
+    @ApiModelProperty(value = "报警自动过期时间")
+    private Date endTime;
+
+
+
+
+
+
+
+
+
 
     /**
-     * 有效期开始时间
+     * 创建用户
      */
-    @ApiModelProperty(value = "有效期开始时间")
-    private Date effectStartTime;
+    @ApiModelProperty(value = "创建用户")
+    private String createUser;
 
     /**
-     * 有效期结束时间
+     * 创建时间 时间戳
      */
-    @ApiModelProperty(value = "有效期结束时间")
-    private Date effectEndTime;
+    @ApiModelProperty(value = "创建时间")
+    private Long createTime;
+
+    /**
+     * 更新用户
+     */
+    @ApiModelProperty(value = "更新用户")
+    private String updateUser;
+
+    /**
+     * 更新时间
+     */
+    @ApiModelProperty(value = "更新时间")
+    private Date updateTime;
+
+    /**
+     * 删除标记 1:true,0:false
+     */
+    @ApiModelProperty(value = "删除标记 1:true,0:false")
+    private Integer valid;
 
     /**
      * 报警性质

+ 0 - 74
src/main/java/com/persagy/entity/CommandResult.java

@@ -1,74 +0,0 @@
-package com.persagy.entity;
-
-import com.alibaba.fastjson.JSONObject;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.experimental.Accessors;
-
-import java.io.Serializable;
-import java.util.Date;
-
-/**
- * 要下发的定时指令、手动指令及结果(command_result)实体类
- *
- * @author lixing
- * @since 2020-09-10 15:54:33
- * @description 由 Mybatisplus Code Generator 创建
- */
-@Data
-@NoArgsConstructor
-@Accessors(chain = true)
-public class CommandResult implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 主键id
-     */
-	private String id;
-    /**
-     * projectId
-     */
-    private String projectId;
-    /**
-     * 功能号
-     */
-    private String funcId;
-    /**
-     * 表号id
-     */
-    private String meterId;
-    /**
-     * 执行指令的时间,手动时为空
-     */
-    private String commandTime;
-    /**
-     * 指令执行结果,0-成功;1-失败;2-超时不响应
-     */
-    private Integer commandResult;
-    /**
-     * createTime
-     */
-    private Date createTime;
-    /**
-     * updateTime
-     */
-	private Date updateTime;
-    /**
-     * 扩展字段
-     */
-    private String remark;
-    /**
-     * 信息点要执行的指令
-     */
-    private String pointAction;
-    /**
-     * 对象id
-     */
-    private String objectId;
-
-    @Override
-    public String toString() {
-        return JSONObject.toJSONString(this);
-    }
-
-}

+ 1 - 1
src/main/java/com/persagy/entity/Condition.java

@@ -50,7 +50,7 @@ public class Condition {
     private String end;
     private int triggerUphold;
     private int endUphold;
-    private JSONObject time;
+    private JSONObject effectTime;
     @Override
     public String toString() {
         return JSONObject.toJSONString(this);

+ 42 - 0
src/main/java/com/persagy/entity/ExpireAlarmMessage.java

@@ -0,0 +1,42 @@
+package com.persagy.entity;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.Data;
+import org.quartz.JobDataMap;
+
+import java.util.Date;
+
+/**
+ * @description:报警过期,取消报警过期的消息队列
+ * @author:LuoGuangyi
+ * @company:PersagyTechnologyCo.,Ltd
+ * @since:2020/10/27 00279:48
+ * @version:V1.0
+ **/
+@Data
+public class ExpireAlarmMessage {
+    /**
+     * 消息类型 1-过期消息  2-取消报警消息
+     */
+    String Type;
+    /**
+     * 报警过期时间
+     */
+    Date startTime;
+    /**
+     * 任务名称
+     */
+    String jobName;
+    /**
+     * 任务分组
+     */
+    String jobGroupName;
+    /**
+     * 定时任务数据
+     */
+    JobDataMap jobDataMap;
+    @Override
+    public String toString() {
+        return JSONObject.toJSONString(this);
+    }
+}

+ 15 - 12
src/main/java/com/persagy/entity/NettyMessage.java

@@ -19,30 +19,33 @@ public class NettyMessage<T> {
     private long streamId;
     @JSONField()
     private int version = 1;
-    /*
-    操作类型编码  1-请求、2 -响应、3-通知、4-边缘端获取报警定义、
-                5-边缘端主动推送报警记录、6-边缘端主动更新报警记录状态、7-云端推送修改的报警定义给边缘端
-                8-云端把报警记录的id推送到边缘端
+    /**
+     * 操作类型:1-请求、2 -响应、3-通知、
+     * 4-边缘端获取报警定义、5-边缘端主动推送报警记录、
+     * 6-边缘端主动更新报警记录状态、7-云端推送修改的报警定义给边缘端(增量报警定义)、
+     * 8-云端把报警记录的id推送到边缘端
+     * 9-边缘端取报警定义,云端推送给边缘端的标记(全量报警定义)
      */
     @JSONField()
     private int opCode;
-    /*
+    /**
     请求来源
      */
     @JSONField()
     private String source = "project";
 
-    /*
-     * 用于项目控制程序清除之前的时间和命令
-     */
-    @JSONField()
-    private String clearBeforeTimeFlag;
-    /*
+    /**
     传输内容
      */
     @JSONField(jsonDirect=true)
     private List<T> content;
-    /*
+    /**
+     * 备注说明
+     */
+    @JSONField()
+    private String remark;
+
+    /**
     成功标识
      */
     @JSONField()

+ 98 - 0
src/main/java/com/persagy/entity/ZktAlarmRecordDO.java

@@ -0,0 +1,98 @@
+package com.persagy.entity;
+
+
+import com.alibaba.fastjson.JSONObject;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+import java.io.Serializable;
+
+/**
+ * 报警记录
+ */
+@ApiModel(value = "报警记录")
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Entity
+@Table(name = "zkt_alarm_record")
+public class ZktAlarmRecordDO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 报警定义ID
+     */
+    @Id
+//    @GeneratedValue(strategy = GenerationType.IDENTITY) // strategy 设置使用数据库主键自增策略;
+//            ,generator = "JDBC") // generator 设置插入完成后,查询最后生成的 ID 填充到该属性中。
+    @Column(name = "definition_id", nullable = false)
+    private String definitionId;
+
+    /**
+     * 报警条目编码
+     */
+    @Column(name = "item_code", nullable = false)
+    @ApiModelProperty(value = "报警条目编码")
+    private String itemCode;
+
+    /**
+     * 报警对象ID
+     */
+    @Column(name = "obj_id", nullable = false)
+    @ApiModelProperty(value = "报警对象ID")
+    private String objId;
+
+    /**
+     * 报警定义对应最新一条报警记录状态
+     * 1-产生 2-恢复 3-过期
+     */
+    @Column(name = "state")
+    @ApiModelProperty(value = "报警定义对应最新一条报警记录状态")
+    private String state;
+
+    /**
+     * 报警定义对应最新一条报警记录ID
+     */
+    @Column(name = "alarm_id")
+    @ApiModelProperty(value = "报警定义对应最新一条报警记录ID")
+    private String alarmId;
+
+    /**
+     * 报警时间
+     */
+    @Column(name = "alarm_time")
+    @ApiModelProperty(value = "报警时间")
+    private String alarmTime;
+
+    /**
+     * 报警生效结束时间(报警过期时间)
+     */
+    @Column(name = "effect_end_time")
+    @ApiModelProperty(value = "报警生效结束时间(报警过期时间)")
+    private String effectEndTime;
+
+    /**
+     * 备注
+     */
+    @Column(name = "remark")
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    /**
+     * 报警名称
+     */
+    @Column(name = "name")
+    @ApiModelProperty(value = "报警名称")
+    private String name;
+
+    @Override
+    public String toString() {
+        return JSONObject.toJSONString(this);
+    }
+
+}

+ 4 - 4
src/main/java/com/persagy/init/InitRunner.java

@@ -2,8 +2,8 @@ package com.persagy.init;
 
 
 import com.googlecode.aviator.AviatorEvaluator;
+import com.persagy.client.GroupNettyClient;
 import com.persagy.client.WebSocketClientFactory;
-import com.persagy.demo.netty.websocket.server.NettyServer;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.CommandLineRunner;
@@ -18,8 +18,8 @@ public class InitRunner implements CommandLineRunner {
 
 	@Autowired
 	private WebSocketClientFactory webSocketClientFactory;
-//	@Autowired
-//	private GroupNettyClient groupNettyClient;
+	@Autowired
+	private GroupNettyClient groupNettyClient;
 
 
 
@@ -28,6 +28,6 @@ public class InitRunner implements CommandLineRunner {
 		//5.0 开始引入了 LRU 缓存,可指定缓存的表达式个数,比如设置为最大 1 万个缓存结果:
 		AviatorEvaluator.getInstance().useLRUExpressionCache(10000);
 		webSocketClientFactory.retryOutCallWebSocketClient();
-//		groupNettyClient.start();
+		groupNettyClient.start();
 	}
 }

+ 104 - 13
src/main/java/com/persagy/job/AlarmExpireJob.java

@@ -1,20 +1,27 @@
 package com.persagy.job;
 
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.persagy.client.GroupNettyClient;
-import com.persagy.entity.AlarmState;
-import com.persagy.entity.CommandResult;
 import com.persagy.entity.NettyMessage;
-import com.persagy.utils.DateUtils;
+import com.persagy.entity.ZktAlarmRecordDO;
+import com.persagy.repository.AlarmRecordRepository;
 import com.persagy.utils.StringUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.quartz.*;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.scheduling.quartz.QuartzJobBean;
 
+import java.util.Arrays;
+import java.util.Date;
 import java.util.concurrent.atomic.AtomicLong;
 
+import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
+
 @DisallowConcurrentExecution
 @PersistJobDataAfterExecution
 @Slf4j
@@ -22,8 +29,31 @@ public class AlarmExpireJob extends QuartzJobBean {
 
     @Autowired
     private GroupNettyClient groupNettyClient;
+    @Autowired
+    AlarmRecordRepository alarmRecordRepository;
+    /**
+     * 报警记录信息详情
+     */
+    private String alarmRecord;
+    /**
+     * 重试次数
+     */
+    private String refire;
+    /**
+     * 过期时间
+     */
+    private String expireTime;
+    /**
+     * 集团编码
+     */
+    @Value("${group.code}")
+    public String groupCode;
 
-    private String alarmStateString;
+    /**
+     * 项目名称
+     */
+    @Value("${project.id}")
+    String projectId;
 
     private AtomicLong nums = new AtomicLong(1L);
 
@@ -31,23 +61,84 @@ public class AlarmExpireJob extends QuartzJobBean {
     protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
         try {
             JobDataMap mergedJobDataMap = context.getMergedJobDataMap();
-            log.info("------------------");
-            if(StringUtils.isNotBlank(alarmStateString)) {
-                AlarmState alarmState = StringUtil.tranferItemToDTO(this.alarmStateString, AlarmState.class);
-                log.info("报警恢复参数为:",alarmState.toString());
-//                groupNettyClient.sendMessage();
+            log.info("----------------开始---------------------");
+            log.warn("refireCount:[{}],应该执行时间:[{}],实际执行时间:[{}]",context.getRefireCount(),expireTime,DateUtil.format(context.getFireTime(), DatePattern.ISO8601_PATTERN));
+            if(StringUtils.isNotBlank(alarmRecord)) {
+                ZktAlarmRecordDO zktAlarmRecordDO = StringUtil.tranferItemToDTO(this.alarmRecord, ZktAlarmRecordDO.class);
+                //立即过期,过期的时候可能还没有报警记录ID,需要重新执行下
+                String alarmId = alarmRecordRepository.findById(zktAlarmRecordDO.getDefinitionId()).orElse(new ZktAlarmRecordDO()).getAlarmId();
+                if(StringUtil.isEmpty(alarmId)) {
+                    log.info("refire:",refire);
+                    mergedJobDataMap.put("refire",String.valueOf(StringUtil.getInt(refire)+1));
+                    reFireJob(context,mergedJobDataMap);
+                }
+                log.info("报警恢复参数为:",zktAlarmRecordDO.toString());
+                NettyMessage<JSONObject> nettyMessage = new NettyMessage<>();
+                nettyMessage.setStreamId(nums.getAndIncrement());
+                nettyMessage.setOpCode(6);
+                JSONObject result = new JSONObject();
+                result.put("id",zktAlarmRecordDO.getAlarmId());
+                result.put("state","3");
+                result.put("groupCode",groupCode);
+                result.put("projectId",projectId);
+                nettyMessage.setContent(Arrays.asList(result));
+                //{"id","123", "state":1, "groupCode":"wd", "projectId":"Pj123"}
+                groupNettyClient.sendMessage(nettyMessage.toString());
+                if(alarmRecordRepository.existsById(zktAlarmRecordDO.getDefinitionId())){
+                    alarmRecordRepository.deleteById(zktAlarmRecordDO.getDefinitionId());
+                }
             }
+            log.info("----------------结束---------------------");
         } catch (Exception e) {
             log.error("job hander error",e);
         }
 
     }
 
-    public String getAlarmStateString() {
-        return alarmStateString;
+
+    private void reFireJob(JobExecutionContext context, JobDataMap mergedJobDataMap) {
+        try {
+            log.info("refire:",refire);
+            if (StringUtil.getInt(refire)>1) {
+               log.error("重新执行依然失败");
+            }else {
+                Scheduler scheduler = context.getScheduler();
+                Trigger trigger = context.getTrigger();
+                DateTime dateTime = DateUtil.offsetSecond(new Date(), 300);
+                DateBuilder.IntervalUnit unit = null;
+                    // 减去一个提前发单时间
+                Trigger newTrigger = TriggerBuilder.newTrigger()
+                        .startAt(dateTime.toJdkDate())
+                        .withIdentity(trigger.getKey())
+                        .usingJobData(mergedJobDataMap)
+                        .withSchedule(simpleSchedule().withMisfireHandlingInstructionIgnoreMisfires()).build();
+                Date rescheduleJob = scheduler.rescheduleJob(trigger.getKey(), newTrigger);
+            }
+        } catch (Exception e) {
+            log.error("获取不到报警记录ID.重新获取报错!", e);
+        }
+    }
+    public String getAlarmRecord() {
+        return alarmRecord;
+    }
+
+    public void setAlarmRecord(String alarmRecord) {
+        this.alarmRecord = alarmRecord;
+    }
+
+    public String getRefire() {
+        return refire;
+    }
+
+    public void setRefire(String refire) {
+        this.refire = refire;
+    }
+
+    public String getExpireTime() {
+        return expireTime;
     }
 
-    public void setAlarmStateString(String alarmStateString) {
-        this.alarmStateString = alarmStateString;
+    public void setExpireTime(String expireTime) {
+        this.expireTime = expireTime;
     }
 }

+ 51 - 0
src/main/java/com/persagy/job/ExpireAlarmQueue.java

@@ -0,0 +1,51 @@
+package com.persagy.job;
+
+import com.persagy.entity.ExpireAlarmMessage;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * @description:报警过期,取消过期的消息队列,防止同步阻塞
+ * @author:LuoGuangyi
+ * @company:PersagyTechnologyCo.,Ltd
+ * @since:2020/10/27 00279:43
+ * @version:V1.0
+ **/
+public class ExpireAlarmQueue {
+    //队列大小
+    static final int QUEUE_MAX_SIZE   = 2000;
+
+    static BlockingQueue<ExpireAlarmMessage> blockingQueue = new LinkedBlockingQueue<ExpireAlarmMessage>(QUEUE_MAX_SIZE);
+
+    /**
+     * 私有的默认构造子,保证外界无法直接实例化
+     */
+    private ExpireAlarmQueue(){};
+    /**
+     * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例
+     * 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
+     */
+    private static class SingletonHolder{
+        /**
+         * 静态初始化器,由JVM来保证线程安全
+         */
+        private  static ExpireAlarmQueue queue = new ExpireAlarmQueue();
+    }
+    //单例队列
+    public static ExpireAlarmQueue getExpireAlarmMessageQueue(){
+        return SingletonHolder.queue;
+    }
+    //生产入队
+    public  void  produce(ExpireAlarmMessage expireAlarmMessage) throws InterruptedException {
+        blockingQueue.put(expireAlarmMessage);
+    }
+    //消费出队
+    public  ExpireAlarmMessage consume() throws InterruptedException {
+        return blockingQueue.take();
+    }
+    // 获取队列大小
+    public int size() {
+        return blockingQueue.size();
+    }
+}

+ 30 - 0
src/main/java/com/persagy/job/SpringSchedule.java

@@ -0,0 +1,30 @@
+package com.persagy.job;
+
+import com.persagy.client.GroupNettyClient;
+import com.persagy.entity.NettyMessage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author LuoGuangyi
+ * @title: SpringSchedule
+ * @projectName spring-boot-examples
+ * @description: TODO
+ * @date 2019/09/17 16:54
+ */
+
+@Service
+public class SpringSchedule {
+    @Autowired
+    GroupNettyClient groupNettyClient;
+
+    //@Scheduled(cron="${alarm.get.all.alarmdefine.cron}")
+    @Scheduled(initialDelay=1000, fixedRate=60000)
+    public void demoCron() {
+//        NettyMessage message = new NettyMessage();
+//        message.setOpCode(4);
+//        groupNettyClient.sendMessage(message.toString());
+    }
+}

+ 18 - 0
src/main/java/com/persagy/repository/AlarmRecordRepository.java

@@ -0,0 +1,18 @@
+package com.persagy.repository;
+
+import com.persagy.entity.ZktAlarmRecordDO;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.PagingAndSortingRepository;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface AlarmRecordRepository extends PagingAndSortingRepository<ZktAlarmRecordDO, String> {
+
+
+    @Query(value = "SELECT * FROM zkt_alarm_record a WHERE a.item_code = :itemCode and a.obj_id = :objId" , nativeQuery = true)
+    ZktAlarmRecordDO findByItemCodeAndObjId(@Param("itemCode") String itemCode,@Param("objId") String objId);
+
+
+
+}

+ 5 - 1
src/main/java/com/persagy/service/AlarmDefineService.java

@@ -1,5 +1,7 @@
 package com.persagy.service;
 
+import com.persagy.entity.AlarmDefine;
+
 import java.util.List;
 
 /**
@@ -10,5 +12,7 @@ import java.util.List;
  * @version:V1.0
  **/
 public interface AlarmDefineService {
-    List listAlarmDefine();
+    List listAllAlarmDefine(List<AlarmDefine> definesList);
+
+    void listSomeAlarmDefine(List<AlarmDefine> alarmDefineList);
 }

+ 4 - 1
src/main/java/com/persagy/service/AlarmHandleService.java

@@ -1,4 +1,7 @@
 package com.persagy.service;
+
+import org.quartz.SchedulerException;
+
 /**
  * @description: 报警处理接口:包含报警产生和报警恢复
  * @author:LuoGuangyi
@@ -7,5 +10,5 @@ package com.persagy.service;
  * @version:V1.0
  **/
 public interface AlarmHandleService {
-    void handleIOTData(String msg);
+    void handleIOTData(String msg) throws SchedulerException, InterruptedException;
 }

+ 8 - 0
src/main/java/com/persagy/service/AlarmQuartzService.java

@@ -1,5 +1,10 @@
 package com.persagy.service;
 
+import org.quartz.JobDataMap;
+import org.quartz.SchedulerException;
+
+import java.util.Date;
+
 /**
  * @description:报警定时任务接口
  * @author:LuoGuangyi
@@ -8,4 +13,7 @@ package com.persagy.service;
  * @version:V1.0
  **/
 public interface AlarmQuartzService {
+    String addExpireJob(Date startTime, String jobName, String jobGroupName, JobDataMap jobDataMap) throws SchedulerException;
+
+    String deleteExpireJob(String jobName, String jobGroupName) throws SchedulerException;
 }

+ 68 - 52
src/main/java/com/persagy/service/impl/AlarmDefineServiceImpl.java

@@ -24,56 +24,56 @@ public class AlarmDefineServiceImpl implements AlarmDefineService {
     AlarmInfoCache alarmInfoCache;
 
     @Override
-    public List listAlarmDefine() {
-        String ad = "{\n" +
-                "    \"streamId\": \"\",\n" +
-                "    \"opCode\": \"\",\n" +
-                "    \"content\": [\n" +
-                "        {\n" +
-                "            \"id\": 1,\n" +
-                "            \"objId\": \"obj1\",\n" +
-                "            \"itemCode\": \"1055\",\n" +
-                "            \"projectId\": \"xxx\",\n" +
-                "            \"name\": \"室内高温\",\n" +
-                "            \"dealFunc\": \"point\",\n" +
-                "            \"category\": \"环境报警\",\n" +
-                "            \"level\": \"B\",\n" +
-                "            \"remark\": \"我是备注哈\",\n" +
-                "            \"open\": 1,\n" +
-                "            \"condition\": {\n" +
-                "                \"infoCode\": [\n" +
-                "                    \"$infoCode1\",\n" +
-                "                    \"$infoCode1\"\n" +
-                "                ],\n" +
-                "                \"infoCodeId\": [\n" +
-                "                    {\n" +
-                "                        \"infoCode\": \"infoCode1\",\n" +
-                "                        \"meterId\": \"11\",\n" +
-                "                        \"funcId\": \"12\"\n" +
-                "                    },\n" +
-                "                    {\n" +
-                "                        \"infoCode\": \"infoCode2\",\n" +
-                "                        \"meterId\": \"21\",\n" +
-                "                        \"funcId\": \"22\"\n" +
-                "                    }\n" +
-                "                ],\n" +
-                "                \"trigger\": \"($infoCode1 > 10 && $infoCode1 < 20) && ($infoCode2 < 20)\",\n" +
-                "                \"end\": \"!($infoCode1 < 20 && $infoCode1 > 10)\",\n" +
-                "                \"$triggerUphold\": 10,\n" +
-                "                \"$endUphold\": 5,\n" +
-                "                \"$time\": {\n" +
-                "                    \"type\": \"period\",\n" +
-                "                    \"period\": {\n" +
-                "                        \"$gt\": \"090000\",\n" +
-                "                        \"$lt\": \"210000\"\n" +
-                "                    }\n" +
-                "                }\n" +
-                "            }\n" +
-                "        }\n" +
-                "    ]\n" +
-                "}";
-        NettyMessage<AlarmDefine> message = JSONObject.parseObject(ad,  new TypeReference<NettyMessage<AlarmDefine>>(){});
-        List<AlarmDefine> alarmDefineList =message.getContent();
+    public List listAllAlarmDefine(List<AlarmDefine> alarmDefineList) {
+//        String ad = "{\n" +
+//                "    \"streamId\": \"\",\n" +
+//                "    \"opCode\": \"\",\n" +
+//                "    \"content\": [\n" +
+//                "        {\n" +
+//                "            \"id\": 1,\n" +
+//                "            \"objId\": \"obj1\",\n" +
+//                "            \"itemCode\": \"1055\",\n" +
+//                "            \"projectId\": \"xxx\",\n" +
+//                "            \"name\": \"室内高温\",\n" +
+//                "            \"dealFunc\": \"point\",\n" +
+//                "            \"category\": \"环境报警\",\n" +
+//                "            \"level\": \"B\",\n" +
+//                "            \"remark\": \"我是备注哈\",\n" +
+//                "            \"open\": 1,\n" +
+//                "            \"condition\": {\n" +
+//                "                \"infoCode\": [\n" +
+//                "                    \"$infoCode1\",\n" +
+//                "                    \"$infoCode1\"\n" +
+//                "                ],\n" +
+//                "                \"infoCodeId\": [\n" +
+//                "                    {\n" +
+//                "                        \"infoCode\": \"infoCode1\",\n" +
+//                "                        \"meterId\": \"11\",\n" +
+//                "                        \"funcId\": \"12\"\n" +
+//                "                    },\n" +
+//                "                    {\n" +
+//                "                        \"infoCode\": \"infoCode2\",\n" +
+//                "                        \"meterId\": \"21\",\n" +
+//                "                        \"funcId\": \"22\"\n" +
+//                "                    }\n" +
+//                "                ],\n" +
+//                "                \"trigger\": \"($infoCode1 > 10 && $infoCode1 < 20) && ($infoCode2 < 20)\",\n" +
+//                "                \"end\": \"!($infoCode1 < 20 && $infoCode1 > 10)\",\n" +
+//                "                \"$triggerUphold\": 10,\n" +
+//                "                \"$endUphold\": 5,\n" +
+//                "                \"$time\": {\n" +
+//                "                    \"type\": \"period\",\n" +
+//                "                    \"period\": {\n" +
+//                "                        \"$gt\": \"090000\",\n" +
+//                "                        \"$lt\": \"210000\"\n" +
+//                "                    }\n" +
+//                "                }\n" +
+//                "            }\n" +
+//                "        }\n" +
+//                "    ]\n" +
+//                "}";
+//        NettyMessage<AlarmDefine> message = JSONObject.parseObject(ad,  new TypeReference<NettyMessage<AlarmDefine>>(){});
+//        List<AlarmDefine> alarmDefineList =message.getContent();
         alarmInfoCache.clearAllAlarmDefine();
         for (AlarmDefine alarmDefine : alarmDefineList) {
             alarmInfoCache.putAlarmDefinitionById(alarmDefine);
@@ -81,6 +81,22 @@ public class AlarmDefineServiceImpl implements AlarmDefineService {
         return alarmDefineList;
     }
 
-
-
+    /**
+     * @description:批量修改(添加)报警定义
+     * (根据报警条目+对象Id先删除,再添加)
+     * @exception:
+     * @author: LuoGuangyi
+     * @company: Persagy Technology Co.,Ltd
+     * @param alarmDefineList:
+     * @return: void
+     * @since: 2020/10/26 20:38
+     * @version: V1.0
+     */
+    @Override
+    public void listSomeAlarmDefine(List<AlarmDefine> alarmDefineList) {
+        for (AlarmDefine alarmDefine : alarmDefineList) {
+            alarmInfoCache.clearAlarmDefine(alarmDefine);
+            alarmInfoCache.putAlarmDefinitionById(alarmDefine);
+        }
+    }
 }

+ 132 - 39
src/main/java/com/persagy/service/impl/AlarmHandleServiceImpl.java

@@ -7,18 +7,24 @@ import com.persagy.cache.AlarmInfoCache;
 import com.persagy.cache.CurrentDataCache;
 import com.persagy.client.GroupNettyClient;
 import com.persagy.entity.*;
+import com.persagy.job.ExpireAlarmQueue;
+import com.persagy.repository.AlarmRecordRepository;
 import com.persagy.service.AlarmHandleService;
+import com.persagy.service.AlarmQuartzService;
 import com.persagy.utils.DateUtils;
 import com.persagy.utils.StringUtil;
 import lombok.extern.slf4j.Slf4j;
+import org.quartz.JobDataMap;
+import org.quartz.SchedulerException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Objects;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
 
 /**
  * @description:报警处理实现类:包含报警产生和报警恢复
@@ -36,6 +42,10 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
     CurrentDataCache currentDataCache;
     @Autowired
     GroupNettyClient groupNettyClient;
+    @Autowired
+    AlarmQuartzService alarmQuartzService;
+    @Autowired
+    AlarmRecordRepository alarmRecordRepository;
     /**
      * 集团编码
      */
@@ -47,15 +57,21 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
     @Value("${system.id}")
     public String systemId;
 
+    /**
+     * 项目名称
+     */
+    @Value("${project.id}")
+    String projectId;
+
     @Override
-    public void handleIOTData(String msg) {
+    public void handleIOTData(String msg) throws SchedulerException, InterruptedException {
         String[] split = msg.split(";");
         if (split.length < 4) {
             return;
         }
         //返回的信息点个数
         int nums = (split.length) / 4;
-        System.out.println("length:"+split.length);
+        log.info("接收信息length:[{}]数据为:{}", nums,msg);
         for (int i = 0; i < nums; i++) {
             String dateTime = split[i * 4];
             String meterId = split[i * 4 + 1];
@@ -70,7 +86,7 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
                     List<JSONObject> codeDetail = condition.getInfoCodes();
                     boolean match = codeDetail.stream().allMatch(p -> currentDataCache.hasKey(p.getString("meterId"), p.getString("funcId")));
                     if (match) {
-                        String defineId = alarmInfoCache.getAlarmDefineId(alarmDefine);
+                        String defineId = AlarmInfoCache.getAlarmDefineId(alarmDefine);
                         String trigger = condition.getTrigger();
                         String end = condition.getEnd();
                         HashMap paramMap = new HashMap<>();
@@ -84,15 +100,24 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
                         Boolean endResult = (Boolean) endExp.execute(paramMap);
                         System.out.println("triggerResult:" + triggerResult);
                         System.out.println("endResult:" + endResult);
+                        if (triggerResult && endResult) {
+                            log.warn("报警触发条件和报警恢复条件同时满足,请检查,报警定义详情【{}】", alarmDefine.toString());
+                        }
                         AlarmState alarmState = alarmInfoCache.getAlarmState(defineId);
                         if (Objects.isNull(alarmState)) {
                             alarmState = new AlarmState(defineId);
                         }
                         //报警产生值满足(这里的满足不考虑报警持续时间)
                         if (triggerResult) {
+                            log.info("有一条满足报警条件");
+                            log.info("--"+alarmDefine.toString());
+                            log.info("--"+JSONObject.toJSONString(paramMap));
                             //报警的时候不考虑报警恢复,因为同时报警和报警恢复是不应该出现的
-                            handlerNowDataAlarm(alarmDefine,alarmState, dateTime, condition, defineId);
+                            handlerNowDataAlarm(alarmDefine, alarmState, dateTime, condition, defineId,paramMap);
                         } else {
+                            log.info("不满足报警条件");
+                            log.info("--"+alarmDefine.toString());
+                            log.info("--"+JSONObject.toJSONString(paramMap));
                             //当前数据正常
                             handlerNowDataNormal(alarmDefine, dateTime, condition, defineId, endResult, alarmState);
                         }
@@ -104,33 +129,34 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
 
         }
     }
+
     /**
-     * @description:当前数据正常判断逻辑
-     * @exception:
-     * @author: LuoGuangyi
-     * @company: Persagy Technology Co.,Ltd
-     * @param alarmDefine: 报警定义
+     * @param alarmDefine:       报警定义
      * @param dateTime:IOT采集时间
      * @param condition:报警条件
      * @param defineId:报警定义ID
      * @param endResult:报警恢复监测结果
-     * @param alarmState: 报警状态时间实体
+     * @param alarmState:        报警状态时间实体
+     * @description:当前数据正常判断逻辑
+     * @exception:
+     * @author: LuoGuangyi
+     * @company: Persagy Technology Co.,Ltd
      * @return: void
      * @since: 2020/10/21 16:46
      * @version: V1.0
      */
-    private void handlerNowDataNormal(AlarmDefine alarmDefine, String dateTime, Condition condition, String defineId, Boolean endResult, AlarmState alarmState) {
+    private void handlerNowDataNormal(AlarmDefine alarmDefine, String dateTime, Condition condition, String defineId, Boolean endResult, AlarmState alarmState) throws InterruptedException {
         //当前数据正常,报警状态为正常:清空之前的报警计时,重置回默认状态
-        if (AlarmState.State.NORMAL.getType().equals(alarmState.getState())){
+        if (AlarmState.State.NORMAL.getType().equals(alarmState.getState())) {
             alarmState = new AlarmState(defineId);
             alarmInfoCache.setAlarmState(defineId, alarmState);
-        }else if(AlarmState.State.NOT_DEAL.getType().equals(alarmState.getState())){
+        } else if (AlarmState.State.NOT_DEAL.getType().equals(alarmState.getState())) {
             //报警状态异常时候
             alarmState.setLatestDataNormalstate(true);
             //报警恢复条件满足,判断是否满足报警恢复持续时间
-            if(endResult){
+            if (endResult) {
                 String endTime = alarmState.getAlarmEndTime();
-                if(StringUtil.isEmpty(endTime)){
+                if (StringUtil.isEmpty(endTime)) {
                     endTime = dateTime;
                 }
                 alarmState.setAlarmEndTime(endTime);
@@ -138,9 +164,29 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
                 //设置开始恢复时间
                 int uphold = condition.getEndUphold();
                 //超过报警恢复设置的持续时间
-                if(DateUtils.betweenTwoTimeSecond(endTime, dateTime)>=0){
+                if (DateUtils.betweenTwoTimeSecond(endTime, dateTime) >= 0) {
                     log.error("产生一条报警恢复消息");
+                    NettyMessage<JSONObject> nettyMessage = new NettyMessage<>();
+                    nettyMessage.setOpCode(6);
+                    JSONObject result = new JSONObject();
+                    ZktAlarmRecordDO alarmRecordDO = alarmRecordRepository.findById(AlarmInfoCache.getAlarmDefineId(alarmDefine)).orElse(new ZktAlarmRecordDO());
+                    //TODO : 为空处理
+                    result.put("id", alarmRecordDO.getAlarmId());
+                    result.put("state", "2");
+                    result.put("groupCode", groupCode);
+                    result.put("projectId", projectId);
+                    nettyMessage.setContent(Arrays.asList(result));
+                    //{"id","123", "state":1, "groupCode":"wd", "projectId":"Pj123"}
+                    groupNettyClient.sendMessage(nettyMessage.toString());
+
                     log.error("产生一条取消报警过期定时任务的消息");
+                    String jobName = AlarmInfoCache.getAlarmDefineId(alarmDefine);
+                    ExpireAlarmMessage em = new ExpireAlarmMessage();
+                    //取消过期消息
+                    em.setType("2");
+                    em.setJobName(jobName);
+                    em.setJobGroupName("expire");
+                    ExpireAlarmQueue.getExpireAlarmMessageQueue().produce(em);
                     //报警恢复,报警状态重置回默认
                     alarmState.reset();
                 }
@@ -150,11 +196,11 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
     }
 
     /**
-     *
      * @param alarmDefine 报警定义
-     * @param dateTime :IOT数据采集时间
-     * @param condition :报警定义条件
-     * @param defineId :报警定义ID
+     * @param dateTime    :IOT数据采集时间
+     * @param condition   :报警定义条件
+     * @param defineId    :报警定义ID
+     * @param paramMap    报警触发值
      * @description:处理当前值报警的情况
      * @exception:
      * @author: LuoGuangyi
@@ -163,24 +209,25 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
      * @since: 2020/10/20 22:31
      * @version: V1.0
      */
-    private void handlerNowDataAlarm(AlarmDefine alarmDefine, AlarmState alarmState, String dateTime, Condition condition, String defineId) {
+    private void handlerNowDataAlarm(AlarmDefine alarmDefine, AlarmState alarmState, String dateTime, Condition condition, String defineId, HashMap paramMap) throws SchedulerException, InterruptedException {
         alarmState.setLatestDataNormalstate(false);
-        JSONObject time = condition.getTime();
+        JSONObject effectTime = condition.getEffectTime();
         boolean inEffectTime = false;
         boolean hasExpire = true;
         //生效时间段,有误过期时间判断
-        if (StringUtil.isEmpty(time) || StringUtil.isEmpty(time.getString("type"))) {
+        if (StringUtil.isEmpty(effectTime) || StringUtil.isEmpty(effectTime.getString("type"))) {
             //无生效时间设置,则任何时间生效
             inEffectTime = true;
             //没有设置生效时间,所以也没有设置过期时间
             hasExpire = false;
 
-        }else {
-            if("period".equals(time.getString("type")) && "0000".equals(time.getString("$gt").substring(0,4)) && "2359".equals(time.getString("$lt").substring(0,4))){
+        } else {
+            if ("period".equals(effectTime.getJSONObject("period").getString("type")) && "000000".equals(effectTime.getJSONObject("period").getString("startTime").substring(0, 6)) && "235959".equals(effectTime.getJSONObject("period").getString("endTime").substring(0, 6))) {
                 //架构师w确认 00:00-23:59的生效时间为一值生效,23:59分不过期
                 hasExpire = false;
             }
-            if ("period".equals(time.getString("type")) && time.getString("$gt").compareTo(DateUtils.getSdfTimeNotDate(dateTime)) >= 0 && time.getString("$lt").compareTo(DateUtils.getSdfTimeNotDate(dateTime)) <= 0) {
+
+            if ("period".equals(effectTime.getString("type")) && effectTime.getJSONObject("period").getString("startTime").compareTo(DateUtils.getSdfTimeNotDate(dateTime)) <= 0 && effectTime.getJSONObject("period").getString("endTime").compareTo(DateUtils.getSdfTimeNotDate(dateTime)) >= 0) {
                 //在生效时间
                 inEffectTime = true;
             } else {
@@ -191,39 +238,85 @@ public class AlarmHandleServiceImpl implements AlarmHandleService {
             //之前是报警状态,现在还是报警,报警值没变化
             //之前是是正常时候
             if (AlarmState.State.NORMAL.getType().equals(alarmState.getState())) {
-                //设置开始报警时间
-                alarmState.setAlarmStartTime(dateTime);
                 long timeSecond = 0;
                 if (StringUtil.isNotEmpty(alarmState.getAlarmStartTime())) {
                     timeSecond = DateUtils.betweenTwoTimeSecond(alarmState.getAlarmStartTime(), dateTime);
                 }
+                LocalDateTime expireDateTime = null;
+                Date expireDate = null;
+                if (hasExpire && "period".equals(effectTime.getString("type"))) {
+                    //过期时间
+                    String expireTime = effectTime.getJSONObject("period").getString("endTime");
+                    LocalTime localTime = LocalTime.parse(expireTime, DateTimeFormatter.ofPattern(DateUtils.sdfTimeNotDate));
+                    expireDateTime = LocalDateTime.of(LocalDate.now(), localTime);
+                    expireDate = DateUtils.localDateTime2Date(expireDateTime);
+                }
+                //设置开始报警时间
+                alarmState.setAlarmStartTime(dateTime);
                 if (timeSecond >= condition.getTriggerUphold()) {
                     log.error("大于持续时间了,产生一条报警");
                     AlarmRecord alarmRecord = AlarmRecord.builder()
+                            .category(alarmDefine.getCategory())
+                            .concern(alarmDefine.getConcern())
+                            .level(alarmDefine.getLevel())
+                            .projectId(projectId)
+                            .state(1)
+                            .triggerTime(DateUtils.parseDate(dateTime))
+                            .remark(alarmDefine.getRemark())
+                            .triggerInfo(JSONObject.toJSONString(paramMap))
+                            .condition(condition.toString())
+                            .effectEndTime(expireDate)
                             .groupCode(groupCode)
                             .itemCode(alarmDefine.getItemCode())
-                            .createUser(systemId)
-                            .createTime(DateUtils.getMilliByLocalDateTime(dateTime))
                             .objId(alarmDefine.getObjId())
+                            .createUser(systemId)
                             .build();
                     NettyMessage<AlarmRecord> nettyMessage = new NettyMessage<>();
-                    nettyMessage.setOpCode(1);
+                    nettyMessage.setOpCode(5);
                     nettyMessage.setContent(Arrays.asList(alarmRecord));
                     //推送一条报警记录给远端
                     groupNettyClient.sendMessage(nettyMessage.toString());
+                    ZktAlarmRecordDO zktAlarmRecordDO = alarmRecordRepository.findById(defineId).orElse(new ZktAlarmRecordDO());
+                    zktAlarmRecordDO.setDefinitionId(defineId);
+                    zktAlarmRecordDO.setObjId(alarmDefine.getObjId());
+                    zktAlarmRecordDO.setItemCode(alarmDefine.getItemCode());
+                    zktAlarmRecordDO.setState("1");
+                    alarmRecordRepository.save(zktAlarmRecordDO);
                     alarmState.setState(AlarmState.State.NOT_DEAL.getType());
                     //有过期时间,生成报警过期消息
-                    if(hasExpire && "period".equals(time.getString("type"))){
+                    if (hasExpire && "period".equals(effectTime.getString("type"))) {
                         //过期时间
-                        String expireTime = time.getString("$lt");
                         log.error("产生一条定时过期报警消息");
-
+                        String alarmId = alarmRecordRepository.findById(defineId).orElse(new ZktAlarmRecordDO()).getAlarmId();
+                        ZktAlarmRecordDO alarmRecordDO = ZktAlarmRecordDO.builder().alarmTime(alarmState.getAlarmStartTime())
+                                .effectEndTime(DateUtils.format(expireDateTime))
+                                .definitionId(defineId)
+                                .itemCode(alarmDefine.getItemCode())
+                                .name(alarmDefine.getName())
+                                .objId(alarmDefine.getObjId())
+                                .state("3")  //要变成已过期
+                                .alarmId(alarmId)
+                                .build();
+                        JobDataMap jobDataMap = new JobDataMap();
+                        jobDataMap.put("alarmRecord", alarmRecordDO.toString());
+                        jobDataMap.put("refire", "0");
+                        jobDataMap.put("expireTime", DateUtils.format(expireDateTime));
+                        String jobName = AlarmInfoCache.getAlarmDefineId(alarmDefine);
+                        ExpireAlarmMessage em = new ExpireAlarmMessage();
+                        //过期消息
+                        em.setType("1");
+                        em.setStartTime(DateUtils.localDateTime2Date(expireDateTime));
+                        em.setJobDataMap(jobDataMap);
+                        em.setJobName(jobName);
+                        em.setJobGroupName("expire");
+                        ExpireAlarmQueue.getExpireAlarmMessageQueue().produce(em);
+                        //alarmQuartzService.addExpireJob(DateUtils.localDateTime2Date(expireDateTime), jobName, "expire", jobDataMap);
                     }
                 } else {
                     alarmState.setState(AlarmState.State.NORMAL.getType());
                 }
             }
-        }else {
+        } else {
             //不在生效时间的段的产生报警,要保存最近一次的数值是否是是报警
             //其他条件全部改成默认值(不报警,不过期,报警开始时间和结束时间为空)
             alarmState.reset();

+ 68 - 27
src/main/java/com/persagy/service/impl/AlarmQuartzServiceImpl.java

@@ -1,13 +1,21 @@
 package com.persagy.service.impl;
 
+import com.persagy.entity.ExpireAlarmMessage;
+import com.persagy.job.AlarmExpireJob;
+import com.persagy.job.ExpireAlarmQueue;
 import com.persagy.service.AlarmQuartzService;
+import com.persagy.utils.DateUtils;
 import lombok.extern.slf4j.Slf4j;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
+import org.quartz.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.PostConstruct;
+import java.util.*;
+
+import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
+
 /**
  * @description:报警定时任务服务
  * @author:LuoGuanhyi
@@ -23,6 +31,22 @@ public class AlarmQuartzServiceImpl implements AlarmQuartzService {
     @Qualifier("quartzScheduler")
     Scheduler quartzScheduler;
 
+    @PostConstruct
+    public void init() {
+        try {
+            while (true){
+                ExpireAlarmMessage expireAlarmMessage = ExpireAlarmQueue.getExpireAlarmMessageQueue().consume();
+                log.info("剩余过期消息总数:{}",ExpireAlarmQueue.getExpireAlarmMessageQueue().size());
+                if("1".equals(expireAlarmMessage.getType())){
+                    addExpireJob(expireAlarmMessage.getStartTime(),expireAlarmMessage.getJobName(),expireAlarmMessage.getJobGroupName(),expireAlarmMessage.getJobDataMap());
+                }else if("2".equals(expireAlarmMessage.getType())){
+                    deleteExpireJob(expireAlarmMessage.getJobName(),expireAlarmMessage.getJobGroupName());
+                }
+            }
+        } catch (Exception e) {
+            log.info("报警过期消息队列消费失败,失败原因为---->",e.getMessage());
+        }
+    }
     /**
      * 添加定时器
      * @param startTime 添加报警恢复定时任务
@@ -32,31 +56,48 @@ public class AlarmQuartzServiceImpl implements AlarmQuartzService {
      * @return 
      * @throws SchedulerException
      */
-//    @Override
-//    public synchronized String addCommand(Date startTime, String jobName, String jobGroupName, JobDataMap jobDataMap) throws SchedulerException {
-//        if(startTime.before(new Date())){
-////            log.info("执行时间【{}】为历史时间,自动跳过",DateUtils.formatDate(startTime));
-//            return "2";
-//        }
-//        JobKey jobKey = new JobKey(jobName, jobGroupName);
-//        JobDetail jobDetail = JobBuilder.newJob(AlarmE.class).withIdentity(jobName, jobGroupName).build();
-//        Trigger trigger = TriggerBuilder.newTrigger().startAt(startTime)
-//                .withIdentity("trigger_" + jobName , jobName)
-//                .usingJobData(jobDataMap)
-//                .withSchedule(simpleSchedule().withMisfireHandlingInstructionIgnoreMisfires()).build();
-//        //已经存在的job实例和触发器自动覆盖 job实 例 唯 一标识:
-//        HashSet<Trigger> triggerSet = new HashSet<Trigger>();
-//        Date fireTime = trigger.getFireTimeAfter(new Date());
-//        if(fireTime != null){
-//            log.info("执行时间为:【{}】,设置时间为【{}】",DateUtils.formatDate(fireTime),DateUtils.formatDate(startTime));
-//        }else {
-//            log.info("执行时间为 空!");
-//        }
-//        triggerSet.add(trigger);
-//        quartzScheduler.scheduleJob(jobDetail, triggerSet, true);
-//
-//        return "success";
-//    }
+    @Override
+    public String addExpireJob(Date startTime, String jobName, String jobGroupName, JobDataMap jobDataMap) throws SchedulerException {
+        if(startTime.before(new Date())){
+            log.error("执行时间【{}】为历史时间,继续添加", DateUtils.formatDate(startTime));
+        }
+        JobKey jobKey = new JobKey(jobName, jobGroupName);
+        JobDetail jobDetail = JobBuilder.newJob(AlarmExpireJob.class).withIdentity(jobName, jobGroupName).requestRecovery().build();
+        Trigger trigger = TriggerBuilder.newTrigger().startAt(startTime)
+                .withIdentity("trigger_" + jobName , jobName)
+                .usingJobData(jobDataMap)
+                .withSchedule(simpleSchedule().withMisfireHandlingInstructionIgnoreMisfires()).build();
+        //已经存在的job实例和触发器自动覆盖 job实 例 唯 一标识:
+        HashSet<Trigger> triggerSet = new HashSet<Trigger>();
+        Date fireTime = trigger.getFireTimeAfter(startTime);
+        if(fireTime != null){
+            log.info("执行时间为:【{}】,设置时间为【{}】",DateUtils.formatDate(fireTime),DateUtils.formatDate(startTime));
+        }else {
+            log.info("执行时间为 空!");
+        }
+        triggerSet.add(trigger);
+        quartzScheduler.scheduleJob(jobDetail, triggerSet, true);
+        return "success";
+    }
+
+
+    /**
+     * @description:删除定时任务
+     * @exception:
+     * @author: LuoGuangyi
+     * @company: Persagy Technology Co.,Ltd
+     * @param jobName:job名称
+     * @param jobGroupName:job分组名称
+     * @return: java.lang.String
+     * @since: 2020/09/29 9:23
+     * @version: V1.0
+     */
+    @Override
+    public synchronized String deleteExpireJob(String jobName, String jobGroupName) throws SchedulerException {
+        JobKey jobKey = new JobKey(jobName, jobGroupName);
+        quartzScheduler.deleteJob(jobKey);
+        return "success!";
+    }
 
 
 }

+ 25 - 0
src/main/java/com/persagy/utils/DateUtils.java

@@ -11,6 +11,7 @@ import java.util.Date;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * 
@@ -20,6 +21,7 @@ import com.alibaba.fastjson.JSONObject;
  * @version 1.0
  * @since: 2019年8月5日: 下午4:44:21 Update By luoguangyi 2019年8月5日: 下午4:44:21
  */
+@Slf4j
 public class DateUtils {
 
 	private final static DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
@@ -310,5 +312,28 @@ public class DateUtils {
 	}
 
 	private static void test1() {
+		String dateTime = "20201026113042";
+		String condition = "{\"condition\":{\"effectTime\":{\"period\":{\"startTime\":\"090000\",\"endTime\":\"210000\"},\"type\":\"period\"},\"end\":\"supplyTemp < 0\",\"endUphold\":5,\"infoCode\":[\"supplyTemp\"],\"infoCodes\":[{\"meterId\":\"ACATFC_27_supplyTemp\",\"infoCode\":\"supplyTemp\",\"funcId\":\"901\"}],\"trigger\":\"supplyTemp > 0\",\"triggerUphold\":10},\"id\":\"01b7d0c5-c99e-4d4a-a11e-5961c6cb7b1e\",\"itemCode\":\"1051\",\"objId\":\"Eq1101050029058dda24eef14d1db12f398b5020877f\"}\n";
+		JSONObject c = JSONObject.parseObject(condition).getJSONObject("condition");
+		JSONObject effectTime = c.getJSONObject("effectTime");
+		System.out.println(effectTime.getJSONObject("period").getString("startTime"));
+		System.out.println(effectTime.getJSONObject("period").getString("startTime").substring(0, 6));
+		  if (
+		  		"period".equals(effectTime.getString("type"))
+				&& "000000".equals(effectTime.getJSONObject("period").getString("startTime").substring(0, 6))
+				&& "235959".equals(effectTime.getJSONObject("period").getString("endTime").substring(0, 6)))
+		  {
+			//架构师w确认 00:00-23:59的生效时间为一值生效,23:59分不过期
+
+		  }
+
+		if ("period".equals(effectTime.getString("type"))
+				&& effectTime.getJSONObject("period").getString("startTime").compareTo(DateUtils.getSdfTimeNotDate(dateTime)) <= 0
+				&& effectTime.getJSONObject("period").getString("endTime").compareTo(DateUtils.getSdfTimeNotDate(dateTime)) >= 0) {
+			//在生效时间
+
+		} else {
+			log.info("[{}]不在设置的生效时间段", dateTime);
+		}
 	}
 }

+ 34 - 17
src/main/java/com/persagy/utils/LockUtil.java

@@ -1,9 +1,8 @@
 package com.persagy.utils;
 
 import cn.hutool.core.date.DateUtil;
-import org.springframework.stereotype.Service;
+import lombok.extern.slf4j.Slf4j;
 
-import java.util.concurrent.Executor;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
@@ -19,43 +18,60 @@ import java.util.concurrent.locks.ReentrantLock;
  * @since:2020/10/19 00199:26
  * @version:V1.0
  **/
-@Service
+@Slf4j
 public class LockUtil {
-    static Lock lock = new ReentrantLock();
-    static Condition condition = lock.newCondition();
-    private static volatile boolean execute = true;
+
+    //创建 SingleObject 的一个对象
+    private static LockUtil instance = new LockUtil();
+
+    private LockUtil(){}
+
+    public static LockUtil getInstance(){
+        return instance;
+    }
+
+    public Lock lock = new ReentrantLock();
+    public Condition condition = lock.newCondition();
+
+    private volatile boolean execute = true;
     AtomicInteger num = new AtomicInteger(0);
-    public static boolean isExecute() {
+
+    public boolean isExecute() {
         return execute;
     }
 
-    public static void setExecute(boolean execute) {
-        LockUtil.execute = execute;
+    public void setExecute(boolean execute) {
+        this.execute = execute;
     }
 
+    public static void main(String[] args) throws InterruptedException {
+        LockUtil.getInstance().await();
+    }
     public void await() throws InterruptedException {
         System.out.println("----------");
+
         ExecutorService executorService = Executors.newFixedThreadPool(5);
         for (int j = 0; j < 20; j++) {
             executorService.execute(()->{
-                for (int i = 0; i < 10000; i++) {
+                for (int i = 0; i < 100000; i++) {
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
-                    if(LockUtil.isExecute()){
+                    if(LockUtil.getInstance().isExecute()){
                         System.out.println(num.getAndIncrement());
                     }else {
                         lock.lock();
                         try {
-                            System.out.println(DateUtil.now()+"等待");
+
+                            log.info("["+Thread.currentThread().getName()+"]"+"等待[{}]",lock);
                             try {
                                 condition.await();
                             } catch (InterruptedException e) {
                                 e.printStackTrace();
                             }
-                            System.out.println(DateUtil.now()+"["+Thread.currentThread().getName()+"]"+"等待执行"+num.getAndIncrement());
+                            log.info("["+Thread.currentThread().getName()+"]"+"等待执行"+num.getAndIncrement());
                         }finally {
                             lock.unlock();
                         }
@@ -69,10 +85,11 @@ public class LockUtil {
         Executors.newScheduledThreadPool(1).scheduleAtFixedRate(()->{
             lock.lock();
             try {
-                LockUtil.setExecute(!LockUtil.isExecute());
+                LockUtil.getInstance().setExecute(!LockUtil.getInstance().isExecute());
                 //加个等待,保证正在执行的逻辑执行成功
-                Thread.sleep(2000);
-                if(LockUtil.isExecute()){
+                Thread.sleep(1000);
+                if(LockUtil.getInstance().isExecute()){
+                    log.info("["+Thread.currentThread().getName()+"]"+"signalAll");
                     condition.signalAll();
                 }
             } catch (InterruptedException e) {
@@ -81,7 +98,7 @@ public class LockUtil {
                 lock.unlock();
             }
 
-        },0,5, TimeUnit.SECONDS);
+        },0,3, TimeUnit.SECONDS);
     }
 
 }

+ 0 - 4
src/main/resources/application.properties

@@ -1,4 +0,0 @@
-# 应用名称
-spring.application.name=zkt-project-alarm
-
-

+ 33 - 23
src/main/resources/application.yml

@@ -9,41 +9,51 @@ spring:
     driver-class-name: com.mysql.jdbc.Driver  # mysql8.0以前使用com.mysql.jdbc.Driver
     username: root
     password: brzj123456
-    druid:
-      initial-size: 1  # 初始化大小
-      min-idle: 1  # 最小
-      max-active: 3  # 最大
-      max-wait: 60000  # 配置获取连接等待超时的时间
-      time-between-eviction-runs-millis: 60000  # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
-      min-evictable-idle-time-millis: 300000  # 指定一个空闲连接最少空闲多久后可被清除,单位是毫秒
-      validationQuery: select 'x'
-      test-while-idle: true  # 当连接空闲时,是否执行连接测试
-      test-on-borrow: false  # 当从连接池借用连接时,是否测试该连接
-      test-on-return: false  # 在连接归还到连接池时是否测试该连接
-      filters: config,wall,stat  # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
-      poolPreparedStatements: true # 打开PSCache,并且指定每个连接上PSCache的大小
-      MaxPoolPreparedStatementPerConnectionSize: 20
-      maxOpenPreparedStatements: 50
-      # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
-      connectionProperties: druid.stat.slowSqlMillis=500;druid.stat.logSlowSql=true;config.decrypt=false
+    type: com.alibaba.druid.pool.DruidDataSource
+    initial-size: 5  # 初始化大小
+    min-idle: 5  # 最小
+    max-active: 20  # 最大
+    max-wait: 60000  # 配置获取连接等待超时的时间
+    time-between-eviction-runs-millis: 60000  # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+    min-evictable-idle-time-millis: 300000  # 指定一个空闲连接最少空闲多久后可被清除,单位是毫秒
+    validationQuery: select 'x'
+    test-while-idle: true  # 当连接空闲时,是否执行连接测试
+    test-on-borrow: false  # 当从连接池借用连接时,是否测试该连接
+    test-on-return: false  # 在连接归还到连接池时是否测试该连接
+    filters: config,wall,stat  # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
+    poolPreparedStatements: true # 打开PSCache,并且指定每个连接上PSCache的大小
+    MaxPoolPreparedStatementPerConnectionSize: 20
+    maxOpenPreparedStatements: 50
+    # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
+    connectionProperties: druid.stat.slowSqlMillis=500;druid.stat.logSlowSql=true;config.decrypt=false
   quartz:
     job-store-type: jdbc
     jdbc:
       initialize-schema: never  # always never
       comment-prefix: '#'
+  jpa:
+    show-sql: true # 打印 SQL 。生产环境,建议关闭
+    # Hibernate 配置内容,对应 HibernateProperties 类
+    hibernate:
+      ddl-auto: none
 group:
   code: wd   #标识哪个接团 比如万达使用wd
   alarm:
-    host: 127.0.0.1     #netty IP
-    port: 8082          #netty 端口
+    host: 127.0.0.1     #netty IP 127.0.0.1  192.168.43.104
+    port: 9986          #netty 端口9986
 terminal:  #边缘端IOT采集程序地址
   alarm:  # 拼接后的地址为ws://host:port/suffix
-    compress: false    #采用的是压缩方式还是不压缩方式  true-压缩 false-不压缩
+    compress: true    #采用的是压缩方式还是不压缩方式  true-压缩 false-不压缩
     host: 39.96.55.242
-    port: 9981
+    port: 9982
     suffix: websocket   #websocker后缀
 project:
-  id: 1101050029  #项目ID
+  iotid: 1101050029  #iot使用项目ID,不包含PJ
+  id: Pj1101050029   #项目ID
 system:
   id: system  #默认用户表示 ,用于报警记录的创建人
-
+alarm:
+  get:
+    all:
+      alarmdefine:
+        cron: 0 0 23 * * ?   #每天23点全量更新一次报警定义

+ 14 - 1
src/main/resources/zkt_alarm_tables_mysql_innodb.sql

@@ -17,6 +17,8 @@ DROP TABLE IF EXISTS ZKT_ALARM_BLOB_TRIGGERS;
 DROP TABLE IF EXISTS ZKT_ALARM_TRIGGERS;
 DROP TABLE IF EXISTS ZKT_ALARM_JOB_DETAILS;
 DROP TABLE IF EXISTS ZKT_ALARM_CALENDARS;
+DROP TABLE IF EXISTS `zkt_alarm_record`;
+
 
 CREATE TABLE ZKT_ALARM_JOB_DETAILS(
 SCHED_NAME VARCHAR(120) NOT NULL,
@@ -175,5 +177,16 @@ CREATE INDEX IDX_ZKT_ALARM_FT_J_G ON ZKT_ALARM_FIRED_TRIGGERS(SCHED_NAME,JOB_NAM
 CREATE INDEX IDX_ZKT_ALARM_FT_JG ON ZKT_ALARM_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
 CREATE INDEX IDX_ZKT_ALARM_FT_T_G ON ZKT_ALARM_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
 CREATE INDEX IDX_ZKT_ALARM_FT_TG ON ZKT_ALARM_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
-
+CREATE TABLE `zkt_alarm_record`  (
+  `definition_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '报警定义ID',
+  `item_code` varchar(42) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '报警条目编码',
+  `obj_id` varchar(60) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '报警对象ID',
+  `state` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报警定义对应最新一条报警记录状态',
+  `alarm_id` varchar(42) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报警定义对应最新一条报警记录ID',
+  `alarm_time` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报警时间',
+  `effect_end_time` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报警生效结束时间(报警过期时间)',
+  `remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '备注',
+  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '报警名称',
+  PRIMARY KEY (`definition_id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '报警记录ID' ROW_FORMAT = Dynamic;
 commit;

+ 5 - 5
src/test/java/com/persagy/zktprojectalarm/Mytest.java

@@ -11,8 +11,8 @@ import com.persagy.utils.LockUtil;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit4.SpringRunner;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
@@ -22,22 +22,22 @@ import java.util.concurrent.CountDownLatch;
 
 @SpringBootTest(classes = ZktProjectAlarmApplication.class)
 public class Mytest {
-    @Autowired
-    LockUtil lockUtil;
+
     @Autowired
     AlarmDefineService alarmDefineService;
     @Autowired
     AlarmInfoCache alarmInfoCache;
+
     @Test
     public void test1 () throws Exception {
-        lockUtil.await();
+        LockUtil.getInstance().await();
         new CountDownLatch(1).await();
     }
 
 
     @Test
     public void test2 () throws Exception {
-        alarmDefineService.listAlarmDefine();
+        alarmDefineService.listAllAlarmDefine(new ArrayList<>());
         ConcurrentHashMap<String, AlarmDefine> alarmDefineMap = alarmInfoCache.getAlarmDefineMap();
         for (Map.Entry entry :alarmDefineMap.entrySet()) {
             System.out.println("[key]:"+entry.getKey()+"[value]"+entry.getValue());