Selaa lähdekoodia

数据质量项目

xuYongJian 2 vuotta sitten
vanhempi
commit
c5799d1248
36 muutettua tiedostoa jossa 3641 lisäystä ja 0 poistoa
  1. 257 0
      pom.xml
  2. 977 0
      src/main/java/com/sunwin/metro/StartRule.java
  3. 62 0
      src/main/java/com/sunwin/metro/bean/BasAtMes.java
  4. 63 0
      src/main/java/com/sunwin/metro/bean/BasTefMes.java
  5. 63 0
      src/main/java/com/sunwin/metro/bean/BasTvfMes.java
  6. 26 0
      src/main/java/com/sunwin/metro/bean/DroolsRule.java
  7. 66 0
      src/main/java/com/sunwin/metro/bean/Event.java
  8. 79 0
      src/main/java/com/sunwin/metro/bean/RuleBase.java
  9. 79 0
      src/main/java/com/sunwin/metro/bean/SimpleRule.java
  10. 25 0
      src/main/java/com/sunwin/metro/bean/SortByValue.java
  11. 61 0
      src/main/java/com/sunwin/metro/bean/UpsMes.java
  12. 57 0
      src/main/java/com/sunwin/metro/bean/UpsXjyMes.java
  13. 146 0
      src/main/java/com/sunwin/metro/bean/WindowRule.java
  14. 120 0
      src/main/java/com/sunwin/metro/constant/Descriptors.java
  15. 86 0
      src/main/java/com/sunwin/metro/drools/KieSessionHelper.java
  16. 25 0
      src/main/java/com/sunwin/metro/drools/MetroProcessor.java
  17. 97 0
      src/main/java/com/sunwin/metro/drools/MetroProcessorWithRules.java
  18. 105 0
      src/main/java/com/sunwin/metro/drools/NormalRuleProcess.java
  19. 25 0
      src/main/java/com/sunwin/metro/governance/bean/Expression.java
  20. 37 0
      src/main/java/com/sunwin/metro/governance/bean/Integrity.java
  21. 34 0
      src/main/java/com/sunwin/metro/governance/bean/Timeliness.java
  22. 36 0
      src/main/java/com/sunwin/metro/governance/bean/Uniformity.java
  23. 65 0
      src/main/java/com/sunwin/metro/process/BroadcastMeterMes.java
  24. 35 0
      src/main/java/com/sunwin/metro/process/ErrorMetersProcess.java
  25. 139 0
      src/main/java/com/sunwin/metro/process/PrometheusProcess.java
  26. 289 0
      src/main/java/com/sunwin/metro/source/CreateMetroMes.java
  27. 95 0
      src/main/java/com/sunwin/metro/source/MetroSubSource.java
  28. 79 0
      src/main/java/com/sunwin/metro/utils/DataType.java
  29. 54 0
      src/main/java/com/sunwin/metro/utils/DateUtils.java
  30. 64 0
      src/main/java/com/sunwin/metro/utils/DeletePush.java
  31. 55 0
      src/main/java/com/sunwin/metro/utils/Md5Util.java
  32. 19 0
      src/main/java/com/sunwin/metro/utils/MeterKey.java
  33. 104 0
      src/main/java/com/sunwin/metro/utils/MysqlUtil.java
  34. 53 0
      src/main/java/com/sunwin/metro/utils/StringUtils.java
  35. 12 0
      src/main/resources/rule.stg
  36. 52 0
      src/test/java/test/Test.java

+ 257 - 0
pom.xml

@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.example</groupId>
+    <artifactId>data_governance</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <properties>
+        <flink.version>1.13.3</flink.version>
+        <java.version>1.8</java.version>
+        <scala.binary.version>2.11</scala.binary.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <drools.version>7.63.0.Final</drools.version>
+        <java.version>1.8</java.version>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+
+    <dependencies>
+
+        <dependency>
+            <groupId>io.prometheus</groupId>
+            <artifactId>simpleclient</artifactId>
+            <version>0.10.0</version>
+        </dependency>
+        <dependency>
+            <groupId>io.prometheus</groupId>
+            <artifactId>simpleclient_pushgateway</artifactId>
+            <version>0.10.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.hadoop</groupId>
+            <artifactId>hadoop-common</artifactId>
+            <version>2.8.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.73</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-streaming-java_${scala.binary.version}</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-runtime-web_${scala.binary.version}</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-core</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>42.2.2</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-statebackend-rocksdb_${scala.binary.version}</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-clients_${scala.binary.version}</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-csv</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-table-api-java-bridge_${scala.binary.version}</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-table-planner-blink_${scala.binary.version}</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-table-common</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-json</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.ververica</groupId>
+            <artifactId>flink-connector-mysql-cdc</artifactId>
+            <version>1.4.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-core</artifactId>
+            <version>${drools.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-compiler</artifactId>
+            <version>${drools.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-decisiontables</artifactId>
+            <version>${drools.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.drools</groupId>
+            <artifactId>drools-templates</artifactId>
+            <version>${drools.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.kie</groupId>
+            <artifactId>kie-api</artifactId>
+            <version>${drools.version}</version>
+        </dependency>
+
+
+
+        <dependency>
+            <groupId>org.antlr</groupId>
+            <artifactId>ST4</artifactId>
+            <version>4.0.8</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>pro.husk</groupId>
+            <artifactId>mysql</artifactId>
+            <version>1.4.1-SNAPSHOT</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.5.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>5.1.37</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-connector-jdbc_${scala.binary.version}</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.flink</groupId>
+            <artifactId>flink-connector-kafka_${scala.binary.version}</artifactId>
+            <version>${flink.version}</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <artifactId>flink-connector-redis</artifactId>
+            <groupId>org.sunwin</groupId>
+            <version>1.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging-api</artifactId>
+            <version>1.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-dbcp2</artifactId>
+            <version>2.1.1</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                    <archive>
+                        <manifest>
+                            <mainClass>com.sunwin.metro.StartRule</mainClass>
+                        </manifest>
+                    </archive>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 977 - 0
src/main/java/com/sunwin/metro/StartRule.java

@@ -0,0 +1,977 @@
+package com.sunwin.metro;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.google.common.collect.Lists;
+import com.sunwin.metro.bean.*;
+import com.sunwin.metro.constant.Descriptors;
+import com.sunwin.metro.drools.MetroProcessor;
+import com.sunwin.metro.drools.NormalRuleProcess;
+import com.sunwin.metro.governance.bean.Expression;
+import com.sunwin.metro.governance.bean.Integrity;
+import com.sunwin.metro.governance.bean.Timeliness;
+import com.sunwin.metro.governance.bean.Uniformity;
+import com.sunwin.metro.process.BroadcastMeterMes;
+import com.sunwin.metro.process.ErrorMetersProcess;
+import com.sunwin.metro.process.PrometheusProcess;
+import com.sunwin.metro.source.CreateMetroMes;
+import com.sunwin.metro.source.MetroSubSource;
+
+import com.sunwin.metro.utils.*;
+import lombok.SneakyThrows;
+import org.apache.flink.api.common.functions.FilterFunction;
+import org.apache.flink.api.common.functions.FlatMapFunction;
+import org.apache.flink.api.common.functions.MapFunction;
+import org.apache.flink.api.common.restartstrategy.RestartStrategies;
+import org.apache.flink.api.common.state.BroadcastState;
+import org.apache.flink.api.common.state.MapState;
+import org.apache.flink.api.common.state.MapStateDescriptor;
+import org.apache.flink.api.common.state.ReadOnlyBroadcastState;
+import org.apache.flink.api.common.typeinfo.TypeInformation;
+import org.apache.flink.api.java.functions.KeySelector;
+import org.apache.flink.api.java.tuple.*;
+import org.apache.flink.configuration.Configuration;
+import org.apache.flink.connector.jdbc.JdbcConnectionOptions;
+import org.apache.flink.contrib.streaming.state.EmbeddedRocksDBStateBackend;
+import org.apache.flink.streaming.api.CheckpointingMode;
+import org.apache.flink.streaming.api.datastream.*;
+import org.apache.flink.streaming.api.environment.CheckpointConfig;
+import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
+import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
+import org.apache.flink.streaming.api.functions.co.BroadcastProcessFunction;
+import org.apache.flink.streaming.api.functions.co.KeyedBroadcastProcessFunction;
+import org.apache.flink.streaming.api.functions.sink.RichSinkFunction;
+import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
+import org.apache.flink.streaming.api.functions.windowing.ProcessWindowFunction;
+import org.apache.flink.streaming.api.windowing.assigners.TumblingProcessingTimeWindows;
+import org.apache.flink.streaming.api.windowing.time.Time;
+import org.apache.flink.streaming.api.windowing.windows.TimeWindow;
+import org.apache.flink.table.api.EnvironmentSettings;
+import org.apache.flink.table.api.Table;
+import org.apache.flink.table.api.bridge.java.StreamTableEnvironment;
+import org.apache.flink.types.Row;
+import org.apache.flink.util.Collector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+import pro.husk.mysql.MySQL;
+
+
+import java.math.BigDecimal;
+import java.sql.*;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.Date;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import static org.apache.flink.table.api.Expressions.$;
+
+
+/**
+ * @author xuYJ
+ * @description: 程序入口 区间隧道风机 BAS_TVF(环境与设备监控系统)  排热风机 BAS_TEF(环境与设备监控系统)  不间断电源 ups(不间断电源系统) ups巡检仪 UPS_XJY(不间断电源系统)  雨水泵 BAS_AT(环境与设备监控系统)
+ * @create: 2020-08-26 14:10
+ */
+public class StartRule {
+    private static final Logger logger = LoggerFactory.getLogger(StartRule.class);
+
+    public static void main(String[] args) throws Exception {
+        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
+        // 设置重启机制(固定重启机制,重启5次,每隔3秒)(测试过程可以关闭重启机制)
+        env.setRestartStrategy(RestartStrategies.fixedDelayRestart(10, org.apache.flink.api.common.time.Time.of(5, TimeUnit.SECONDS)));
+        // env.setStateBackend(new RocksDBStateBackend("hdfs://192.168.20.63:8020/flink/flink-checkpoint/rule/", true).getCheckpointBackend());
+        env.setStateBackend(new EmbeddedRocksDBStateBackend());
+        env.getCheckpointConfig().setCheckpointStorage("hdfs://192.168.20.63:8020/flink/flink-checkpoint/rules/");
+        // 每隔1分钟进行启动一个检查点
+        env.enableCheckpointing(10000 * 6);
+        env.getCheckpointConfig().setMinPauseBetweenCheckpoints(10000 * 3);
+        env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
+        env.getCheckpointConfig().setCheckpointTimeout(60000 * 10);
+        env.getCheckpointConfig().setTolerableCheckpointFailureNumber(100);
+        env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
+        env.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
+        EnvironmentSettings build = EnvironmentSettings.newInstance()
+                .useBlinkPlanner()
+                .inStreamingMode()
+                .build();
+        StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env, build);
+        //生成广播流
+        DataStreamSource<Map<String, List<String>>> addSource = env
+                .addSource(new MetroSubSource());
+        //用来删除Prometheus失效的节点
+        addSource.keyBy(new MeterKey()).process(new DeletePush()).print();
+        BroadcastStream<Map<String, List<String>>> broadcast = addSource
+                .setParallelism(1).broadcast(Descriptors.DESCRIPTOR);
+        DataStreamSource<String> source = env.addSource(new CreateMetroMes());
+        SingleOutputStreamOperator<Tuple2<String, String>> connect = source
+                .connect(broadcast)
+                .process(new BroadcastMeterMes());
+        SingleOutputStreamOperator<Tuple2<String, String>> process = connect.process(new ErrorMetersProcess(Descriptors.ERROR_METER));
+        connect.filter(new FilterFunction<Tuple2<String, String>>() {
+            @Override
+            public boolean filter(Tuple2<String, String> value) throws Exception {
+                return !(value.f1.contains("true"));
+            }
+        })
+                .keyBy((KeySelector<Tuple2<String, String>, String>) tuple2 -> tuple2.f0)
+                //整理后的数据发送到Prometheus
+                .process(new PrometheusProcess()).print();
+
+        //DataStream<Tuple2<String, String>> sideOutput = process.getSideOutput(Descriptors.ERROR_METER);
+        //SingleOutputStreamOperator<Tuple2<String, String>> filter = process.filter(new FilterFunction<Tuple2<String, String>>() {
+        //    @Override
+        //    public boolean filter(Tuple2<String, String> value) throws Exception {
+        //        return "ups巡检仪".equals(value.f0);
+        //    }
+        //});
+        //filter.addSink(org.apache.flink.connector.jdbc.JdbcSink.sink(
+        //        "insert ignore  ups_xjy_rule (name,create_time , zdl , zdy , wd ) values (?,?,?,?,?)",
+        //        (ps, t) -> {
+        //            UpsXjyMes upsXjyMes = JSONObject.parseObject(t.f1, UpsXjyMes.class);
+        //            ps.setString(1, upsXjyMes.getNum() + "_" + upsXjyMes.getStation() + "_" + upsXjyMes.getName());
+        //            ps.setString(2, upsXjyMes.getTime());
+        //            ps.setFloat(3, BigDecimal.valueOf(upsXjyMes.getZdl()).floatValue());
+        //            ps.setFloat(4, BigDecimal.valueOf(upsXjyMes.getZdy()).floatValue());
+        //            ps.setFloat(5, BigDecimal.valueOf(upsXjyMes.getWd()).floatValue());
+        //
+        //        },
+        //        new JdbcConnectionOptions.JdbcConnectionOptionsBuilder()
+        //                .withUrl("jdbc:mysql://192.168.20.61:3306/rule-engine?characterEncoding=utf-8&serverTimezone=UTC")
+        //                .withDriverName("com.mysql.jdbc.Driver")
+        //                .withPassword("root")
+        //                .withUsername("root")
+        //                .build()));
+
+        //SingleOutputStreamOperator<Tuple2<String, String>> filter2 = process.filter(new FilterFunction<Tuple2<String, String>>() {
+        //    @Override
+        //    public boolean filter(Tuple2<String, String> value) throws Exception {
+        //        return "排热风机".equals(value.f0);
+        //    }
+        //});
+        //filter2.addSink(org.apache.flink.connector.jdbc.JdbcSink.sink(
+        //        "insert ignore  bas_tvf_rule (name,create_time , x_vibr , y_vibr , faxlet ) values (?,?,?,?,?)",
+        //        (ps, t) -> {
+        //            BasTvfMes basTvfMes = JSONObject.parseObject(t.f1, BasTvfMes.class);
+        //            ps.setString(1, basTvfMes.getNum() + "_" + basTvfMes.getStation() + "_" + basTvfMes.getName());
+        //            ps.setString(2, basTvfMes.getTime());
+        //            ps.setFloat(3, BigDecimal.valueOf(basTvfMes.getAi_x_vibr()).floatValue());
+        //            ps.setFloat(4, BigDecimal.valueOf(basTvfMes.getAi_y_vibr()).floatValue());
+        //            ps.setFloat(5, BigDecimal.valueOf(basTvfMes.getAi_faxlet()).floatValue());
+        //
+        //        },
+        //        new JdbcConnectionOptions.JdbcConnectionOptionsBuilder()
+        //                .withUrl("jdbc:mysql://192.168.20.61:3306/rule-engine?characterEncoding=utf-8&serverTimezone=UTC")
+        //                .withDriverName("com.mysql.jdbc.Driver")
+        //                .withPassword("root")
+        //                .withUsername("root")
+        //                .build()));
+
+        String source1 =
+                "CREATE TABLE mes_governance (" +
+                        "  meter_type STRING ," +
+                        "  meter_mes  STRING " +
+                        ") WITH (" +
+                        "'connector' = 'mysql-cdc'," +
+                        "'hostname' = '192.168.20.61'," +
+                        "'port' = '3306'," +
+                        "'username' = 'root'," +
+                        "'password' = 'root'," +
+                        "'database-name' = 'rule-engine'," +
+                        "'table-name' = 'mes_governance'" +
+                        ")";
+
+        tableEnv.executeSql(source1);
+        Table testSink = tableEnv.from("mes_governance");
+        DataStream<Tuple2<Boolean, Row>> stream = tableEnv.toRetractStream(testSink, Row.class);
+        SingleOutputStreamOperator<Tuple2<String, String>> map = stream.filter((FilterFunction<Tuple2<Boolean, Row>>) value -> value.f0)
+                .map(new MapFunction<Tuple2<Boolean, Row>, Tuple2<String, String>>() {
+                    @Override
+                    public Tuple2<String, String> map(Tuple2<Boolean, Row> value) throws Exception {
+                        return new Tuple2<>(Objects.requireNonNull(value.f1.getField("meter_type")).toString(), Objects.requireNonNull(value.f1.getField("meter_mes")).toString());
+                    }
+                });
+        DataStream<Tuple2<String, String>> union = process.union(map);
+        long window = 60 * 15;
+        //long window = 60;
+        //专门适应采集及时性
+        SingleOutputStreamOperator<List<Tuple4<String, String, Long, String>>> process3 = union.map(new MapFunction<Tuple2<String, String>, Tuple4<String, String, Long, String>>() {
+            @Override
+            public Tuple4<String, String, Long, String> map(Tuple2<String, String> value) throws Exception {
+                String appType = JSONObject.parseObject(value.f1).getString("appType");
+                return new Tuple4<>(value.f0 + "_" + appType, value.f1, System.currentTimeMillis(), appType);
+            }
+        }).keyBy(new KeySelector<Tuple4<String, String, Long, String>, String>() {
+            @Override
+            public String getKey(Tuple4<String, String, Long, String> value) throws Exception {
+                return value.f0;
+            }
+        }).window(TumblingProcessingTimeWindows.of(Time.seconds(window))).process(new ProcessWindowFunction<Tuple4<String, String, Long, String>, List<Tuple4<String, String, Long, String>>, String, TimeWindow>() {
+            @Override
+            public void process(String s, Context context, Iterable<Tuple4<String, String, Long, String>> elements, Collector<List<Tuple4<String, String, Long, String>>> out) throws Exception {
+                ArrayList<Tuple4<String, String, Long, String>> arrayList = Lists.newArrayList(elements);
+                //窗口内部去重
+                List<Tuple4<String, String, Long, String>> newList = new ArrayList<>();
+                arrayList.stream().filter(distinctByKey(p -> p.f1))
+                        .forEach(newList::add);
+                out.collect(newList);
+            }
+        });
+
+        DataStreamSource<Tuple2<String, JSONObject>> source2 = env.addSource(new RichSourceFunction<Tuple2<String, JSONObject>>() {
+            Connection connection;
+            PreparedStatement pStatement;
+
+            @Override
+            public void open(Configuration parameters) throws Exception {
+                super.open(parameters);
+                connection = MysqlUtil.getCon();
+            }
+
+            @Override
+            public void close() throws Exception {
+                super.close();
+                if (pStatement != null) {
+                    pStatement.close();
+                }
+                if (connection != null) {
+                    connection.close();
+                }
+            }
+
+            @Override
+            public void run(SourceContext<Tuple2<String, JSONObject>> ctx) throws Exception {
+                while (true) {
+                    try {
+                        pStatement = connection.prepareStatement("SELECT *  FROM  t_data_rule;");
+                        ResultSet results = pStatement.executeQuery();
+                        while (results.next()) {
+                            JSONObject jsonObject = new JSONObject();
+                            String ruleId = String.valueOf(results.getInt("id"));
+                            jsonObject.put("rule_id", ruleId);
+                            jsonObject.put("model", results.getString("target_name"));
+                            jsonObject.put("type", getMeterName(results.getString("equipment_type_name")));
+                            jsonObject.put("appType", String.valueOf(results.getInt("application_id")));
+                            jsonObject.put("mes", results.getString("expr"));
+                            jsonObject.put("flag", results.getInt("flag"));
+                            ctx.collect(new Tuple2<>("1组", jsonObject));
+                        }
+                    } catch (Exception e) {
+                        System.out.println("连接postgres规则库异常");
+                        e.printStackTrace();
+                        connection = MysqlUtil.getCon2();
+                    }
+                    Thread.sleep(5000L);
+                }
+            }
+
+            @SneakyThrows
+            @Override
+            public void cancel() {
+                if (pStatement != null) {
+                    pStatement.close();
+                }
+                if (connection != null) {
+                    connection.close();
+                }
+            }
+        });
+        //侧边流输出3种规则
+        SingleOutputStreamOperator<String> outputStreamOperator1 = source2.keyBy(new KeySelector<Tuple2<String, JSONObject>, String>() {
+            @Override
+            public String getKey(Tuple2<String, JSONObject> value) throws Exception {
+                return value.f0;
+            }
+        }).process(new KeyedProcessFunction<String, Tuple2<String, JSONObject>, String>() {
+            private transient MapState<String, String> mapState;
+
+            @Override
+            public void open(Configuration parameters) throws Exception {
+                super.open(parameters);
+                MapStateDescriptor<String, String> descriptor = new MapStateDescriptor<>("mapState", TypeInformation.of(String.class), TypeInformation.of(String.class));
+                mapState = getRuntimeContext().getMapState(descriptor);
+            }
+
+            @Override
+            public void close() throws Exception {
+                super.close();
+            }
+
+            @Override
+            public void processElement(Tuple2<String, JSONObject> value, Context ctx, Collector<String> out) throws Exception {
+                JSONObject object = value.f1;
+                String ruleId = object.getString("rule_id");
+                String model = object.getString("model");
+                boolean flag = "1".equals(object.getString("flag"));
+                String type = object.getString("type");
+                String appType = object.getString("appType");
+
+                if (mapState.isEmpty()) {
+                    putMapState(value, ctx, object, ruleId, model, flag, type, appType);
+                    mapState.put(ruleId, Md5Util.getMd5(value.f1.toString()));
+                } else {
+                    ArrayList<String> arrayList = new ArrayList<>();
+                    mapState.keys().forEach(arrayList::add);
+                    if (!arrayList.contains(ruleId)) {
+                        putMapState(value, ctx, object, ruleId, model, flag, type, appType);
+                    } else {
+                        String s = mapState.get(ruleId);
+                        if (!s.equals(Md5Util.getMd5(object.toString()))) {
+                            putMapState(value, ctx, object, ruleId, model, flag, type, appType);
+                        } else {
+                            System.out.println("扫描到一样的规则");
+                        }
+                    }
+                }
+            }
+
+            private void putMapState(Tuple2<String, JSONObject> value, KeyedProcessFunction<String, Tuple2<String, JSONObject>, String>.Context ctx, JSONObject object, String ruleId, String model, boolean flag, String type, String appType) throws Exception {
+                if ("及时性(数据采集)".equals(model)) {
+                    JSONObject jsonObject = JSONObject.parseObject(object.getString("mes"));
+                    int inTime = jsonObject.getInteger("in");
+                    ctx.output(Descriptors.IN_TIME_RULE_1, new Timeliness(ruleId, type, inTime, flag, appType));
+                } else if ("及时性(数据入库)".equals(model)) {
+                    JSONObject jsonObject = JSONObject.parseObject(object.getString("mes"));
+                    int outTime = jsonObject.getInteger("out");
+                    ctx.output(Descriptors.OUT_TIME_RULE_1, new Timeliness(ruleId, type, outTime, flag, appType));
+                } else if ("完整性".equals(model)) {
+                    List<String> mes = JSONArray.parseArray(object.getString("mes"), String.class);
+                    ctx.output(Descriptors.COMPLETE_RULE_1, new Integrity(ruleId, type, mes, flag, appType));
+                } else if ("一致性".equals(model)) {
+                    List<JSONObject> mes = JSONArray.parseArray(object.getString("mes"), JSONObject.class);
+                    ctx.output(Descriptors.UNIFORMITY_RULE_1, new Uniformity(ruleId, type, mes, flag, appType));
+                } else if ("准确性".equals(model)) {
+                    ctx.output(Descriptors.CURRENT_RULE_1, value.f1);
+                }
+                mapState.put(ruleId, Md5Util.getMd5(value.f1.toString()));
+                System.out.println("成功加入缓存");
+            }
+        }).setParallelism(1);
+        BroadcastStream<Timeliness> broadcast2 = outputStreamOperator1.getSideOutput(Descriptors.IN_TIME_RULE_1).broadcast(Descriptors.IN_TIME_RULE);
+        BroadcastStream<Timeliness> broadcast3 = outputStreamOperator1.getSideOutput(Descriptors.OUT_TIME_RULE_1).broadcast(Descriptors.OUT_TIME_RULE);
+        BroadcastStream<Integrity> broadcastStream = outputStreamOperator1.getSideOutput(Descriptors.COMPLETE_RULE_1).broadcast(Descriptors.COMPLETE_RULE);
+        BroadcastStream<Uniformity> uniformityBroadcastStream = outputStreamOperator1.getSideOutput(Descriptors.UNIFORMITY_RULE_1).broadcast(Descriptors.UNIFORMITY_RULE);
+        DataStream<JSONObject> current = outputStreamOperator1.getSideOutput(Descriptors.CURRENT_RULE_1);
+        //进行数据采集时间及时性判断
+        SingleOutputStreamOperator<Tuple5<String, String, Integer, String, String>> result2 = process3.connect(broadcast2).process(new BroadcastProcessFunction<List<Tuple4<String, String, Long, String>>, Timeliness, Tuple5<String, String, Integer, String, String>>() {
+            @Override
+            public void processElement(List<Tuple4<String, String, Long, String>> value, ReadOnlyContext ctx, Collector<Tuple5<String, String, Integer, String, String>> out) throws Exception {
+                ReadOnlyBroadcastState<String, List<Timeliness>> broadcastState = ctx.getBroadcastState(Descriptors.IN_TIME_RULE);
+                JSONArray inArray = new JSONArray();
+                int countAll = value.size();
+                for (Tuple4<String, String, Long, String> tuple2 : value) {
+                    String[] s = tuple2.f0.split("_");
+                    if (broadcastState.contains(getMeterName(s[0]))) {
+                        List<Timeliness> timelinessList = broadcastState.get(getMeterName(s[0]));
+                        JSONObject inJson = JSONObject.parseObject(tuple2.f1);
+                        for (Timeliness item : timelinessList) {
+                            if (item.getAppType().equals(tuple2.f3)) {
+                                if (tuple2.f2 - inJson.getLong("eventTime") > item.getCollectTime()) {
+                                    if (inJson.containsKey("ruleId")) {
+                                        String ruleId = inJson.getString("ruleId");
+                                        inJson.put("ruleId", ruleId + "_" + item.getRuleId());
+                                    } else {
+                                        inJson.put("ruleId", item.getRuleId());
+                                    }
+                                }
+                            }
+                        }
+                        if (inJson.containsKey("ruleId")) {
+                            inArray.add(inJson);
+                        }
+                    }
+                }
+                //输出准确率 + 异常数据集合
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("记录及时性(数据采集)", getPercent(countAll - inArray.size(), countAll));
+                if (inArray.size() > 0) {
+                    out.collect(new Tuple5<>(value.get(0).f0, jsonObject.toString(), countAll, inArray.toString(), value.get(0).f3));
+                } else {
+                    out.collect(new Tuple5<>(value.get(0).f0, jsonObject.toString(), countAll, null, value.get(0).f3));
+                }
+            }
+
+            @Override
+            public void processBroadcastElement(Timeliness value, Context ctx, Collector<Tuple5<String, String, Integer, String, String>> out) throws Exception {
+                BroadcastState<String, List<Timeliness>> ctxBroadcastState = ctx.getBroadcastState(Descriptors.IN_TIME_RULE);
+                if (value.isFlag()) {
+                    if (ctxBroadcastState.contains(value.getType())) {
+                        List<Timeliness> timelines = ctxBroadcastState.get(value.getType());
+                        timelines.removeIf(item -> item.getRuleId().equals(value.getRuleId()));
+                        timelines.add(value);
+                        ctxBroadcastState.put(value.getType(), timelines);
+                    } else {
+                        ArrayList<Timeliness> arrayList = new ArrayList<>();
+                        arrayList.add(value);
+                        ctxBroadcastState.put(value.getType(), arrayList);
+                    }
+                } else {
+                    if (ctxBroadcastState.contains(value.getType())) {
+                        List<Timeliness> timelines = ctxBroadcastState.get(value.getType());
+                        timelines.removeIf(timeliness1 -> timeliness1.toString().equals(value.toString()));
+                        ctxBroadcastState.put(value.getType(), timelines);
+                    }
+                }
+            }
+        });
+
+        //进行数据输出及时性判断
+        SingleOutputStreamOperator<Tuple5<String, String, Integer, String, String>> result = process3.connect(broadcast3).process(new BroadcastProcessFunction<List<Tuple4<String, String, Long, String>>, Timeliness, Tuple5<String, String, Integer, String, String>>() {
+            @Override
+            public void processElement(List<Tuple4<String, String, Long, String>> value, ReadOnlyContext ctx, Collector<Tuple5<String, String, Integer, String, String>> out) throws Exception {
+                ReadOnlyBroadcastState<String, List<Timeliness>> broadcastState = ctx.getBroadcastState(Descriptors.OUT_TIME_RULE);
+                Long timestamp = ctx.timestamp();
+                JSONArray outArray = new JSONArray();
+                int countAll = value.size();
+                for (Tuple4<String, String, Long, String> tuple2 : value) {
+                    String[] s = tuple2.f0.split("_");
+                    if (broadcastState.contains(getMeterName(s[0]))) {
+                        List<Timeliness> timelinessList = broadcastState.get(getMeterName(s[0]));
+                        JSONObject outJson = JSONObject.parseObject(tuple2.f1);
+                        for (Timeliness item : timelinessList) {
+                            if (item.getAppType().equals(tuple2.f3)) {
+                                long l = ctx.currentProcessingTime();
+                                if (l - timestamp > item.getCollectTime()) {
+                                    if (outJson.containsKey("ruleId")) {
+                                        String ruleId = outJson.getString("ruleId");
+                                        outJson.put("ruleId", ruleId + "_" + item.getRuleId());
+                                    } else {
+                                        outJson.put("ruleId", item.getRuleId());
+                                    }
+                                }
+                            }
+                        }
+                        if (outJson.containsKey("ruleId")) {
+                            outArray.add(outJson);
+                        }
+                    }
+                }
+                //输出准确率 + 异常数据集合
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("记录及时性(数据入库)", getPercent(countAll - outArray.size(), countAll));
+                if (outArray.size() > 0) {
+                    out.collect(new Tuple5<>(value.get(0).f0, jsonObject.toString(), countAll, outArray.toString(), value.get(0).f3));
+                } else {
+                    out.collect(new Tuple5<>(value.get(0).f0, jsonObject.toString(), countAll, null, value.get(0).f3));
+                }
+            }
+
+            @Override
+            public void processBroadcastElement(Timeliness value, Context ctx, Collector<Tuple5<String, String, Integer, String, String>> out) throws Exception {
+                BroadcastState<String, List<Timeliness>> ctxBroadcastState = ctx.getBroadcastState(Descriptors.OUT_TIME_RULE);
+                if (value.isFlag()) {
+                    if (ctxBroadcastState.contains(value.getType())) {
+                        List<Timeliness> timelines = ctxBroadcastState.get(value.getType());
+                        timelines.removeIf(item -> item.getRuleId().equals(value.getRuleId()));
+                        timelines.add(value);
+                        ctxBroadcastState.put(value.getType(), timelines);
+                    } else {
+                        ArrayList<Timeliness> arrayList = new ArrayList<>();
+                        arrayList.add(value);
+                        ctxBroadcastState.put(value.getType(), arrayList);
+                    }
+                } else {
+                    if (ctxBroadcastState.contains(value.getType())) {
+                        List<Timeliness> timelines = ctxBroadcastState.get(value.getType());
+                        timelines.removeIf(timeliness1 -> timeliness1.toString().equals(value.toString()));
+                        ctxBroadcastState.put(value.getType(), timelines);
+                    }
+                }
+            }
+        });
+
+        //完整性
+        SingleOutputStreamOperator<Tuple5<String, String, Integer, String, String>> result3 = process3.connect(broadcastStream).process(new BroadcastProcessFunction<List<Tuple4<String, String, Long, String>>, Integrity, Tuple5<String, String, Integer, String, String>>() {
+            @Override
+            public void processElement(List<Tuple4<String, String, Long, String>> value, ReadOnlyContext ctx, Collector<Tuple5<String, String, Integer, String, String>> out) throws Exception {
+                ReadOnlyBroadcastState<String, List<Integrity>> broadcastState = ctx.getBroadcastState(Descriptors.COMPLETE_RULE);
+                int filedCount = 0;
+                int countError = 0;
+                JSONArray array = new JSONArray();
+                int countAll = value.size();
+                for (Tuple4<String, String, Long, String> tuple2 : value) {
+                    String[] s = tuple2.f0.split("_");
+                    JSONObject jsonObject = JSONObject.parseObject(tuple2.f1);
+                    Set<String> keySet = jsonObject.keySet();
+                    filedCount = filedCount + keySet.size();
+                    if (broadcastState.contains(getMeterName(s[0]))) {
+                        List<Integrity> timelinessList = broadcastState.get(getMeterName(s[0]));
+                        for (Integrity item : timelinessList) {
+                            if (item.getAppType().equals(tuple2.f3)) {
+                                List<String> fields = item.getFields();
+                                for (String field : fields) {
+                                    if (keySet.contains(field)) {
+                                        if (null == jsonObject.get(field) || jsonObject.getString(field).isEmpty() || jsonObject.getString(field).trim().isEmpty() || "null".equals(jsonObject.getString(field)) || "NULL".equals(jsonObject.getString(field))) {
+                                            jsonObject.putIfAbsent(field, null);
+                                            countError++;
+                                            if (jsonObject.containsKey("ruleId")) {
+                                                String ruleId = jsonObject.getString("ruleId");
+                                                jsonObject.put("ruleId", ruleId + "_" + item.getRuleId());
+                                            } else {
+                                                jsonObject.put("ruleId", item.getRuleId());
+                                            }
+                                            break;
+                                        }
+                                    } else {
+                                        countError++;
+                                        if (jsonObject.containsKey("ruleId")) {
+                                            String ruleId = jsonObject.getString("ruleId");
+                                            jsonObject.put("ruleId", ruleId + "_" + item.getRuleId());
+                                        } else {
+                                            jsonObject.put("ruleId", item.getRuleId());
+                                        }
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                        if (jsonObject.containsKey("ruleId")) {
+                            array.add(jsonObject);
+                        }
+                    }
+                }
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("字段完整性", getPercent(filedCount - countError, filedCount));
+                jsonObject.put("记录完整性", getPercent(countAll - array.size(), countAll));
+                if (array.size() > 0) {
+                    out.collect(new Tuple5<>(value.get(0).f0, jsonObject.toString(), countAll, array.toString(SerializerFeature.WriteMapNullValue), value.get(0).f3));
+                } else {
+                    out.collect(new Tuple5<>(value.get(0).f0, jsonObject.toString(), countAll, null, value.get(0).f3));
+                }
+            }
+
+            @Override
+            public void processBroadcastElement(Integrity value, Context ctx, Collector<Tuple5<String, String, Integer, String, String>> out) throws Exception {
+                BroadcastState<String, List<Integrity>> broadcastState = ctx.getBroadcastState(Descriptors.COMPLETE_RULE);
+                if (value.isFlag()) {
+                    if (broadcastState.contains(value.getType())) {
+                        List<Integrity> timelines = broadcastState.get(value.getType());
+                        timelines.removeIf(item -> item.getRuleId().equals(value.getRuleId()));
+                        timelines.add(value);
+                        broadcastState.put(value.getType(), timelines);
+                    } else {
+                        ArrayList<Integrity> arrayList = new ArrayList<>();
+                        arrayList.add(value);
+                        broadcastState.put(value.getType(), arrayList);
+                    }
+                } else {
+                    if (broadcastState.contains(value.getType())) {
+                        List<Integrity> timelines = broadcastState.get(value.getType());
+                        timelines.removeIf(timeliness1 -> timeliness1.toString().equals(value.toString()));
+                        broadcastState.put(value.getType(), timelines);
+                    }
+                }
+            }
+        });
+
+        //一致性
+        SingleOutputStreamOperator<Tuple3<String, List<Tuple3<String, String, String>>, String>> process2 = process3.connect(uniformityBroadcastStream).process(new BroadcastProcessFunction<List<Tuple4<String, String, Long, String>>, Uniformity, Tuple3<String, List<Tuple3<String, String, String>>, String>>() {
+            @Override
+            public void processElement(List<Tuple4<String, String, Long, String>> value, ReadOnlyContext ctx, Collector<Tuple3<String, List<Tuple3<String, String, String>>, String>> out) throws Exception {
+                ArrayList<Tuple3<String, String, String>> arrayList = new ArrayList<>();
+                ReadOnlyBroadcastState<String, List<Uniformity>> broadcastState = ctx.getBroadcastState(Descriptors.UNIFORMITY_RULE);
+                for (Tuple4<String, String, Long, String> tuple2 : value) {
+                    String[] s = tuple2.f0.split("_");
+                    JSONObject jsonObject = JSONObject.parseObject(tuple2.f1);
+                    if (broadcastState.contains(getMeterName(s[0]))) {
+                        JSONObject keys = new JSONObject();
+                        List<Uniformity> timelinessList = broadcastState.get(getMeterName(s[0]));
+                        for (Uniformity item : timelinessList) {
+                            if (item.getAppType().equals(tuple2.f3)) {
+                                List<JSONObject> fields = item.getFields();
+                                for (JSONObject field : fields) {
+                                    if (jsonObject.containsKey(field.getString("dataField")) && (null != jsonObject.get(field.getString("dataField")))) {
+                                        if (field.containsKey("dataType")) {
+                                            keys.put(item.getRuleId() + "-" + field.getString("dataField") + "-" + field.getString("dataType"), jsonObject.get(field.getString("dataField")));
+                                        } else {
+                                            keys.put(item.getRuleId() + "-" + field.getString("dataField") + "-" + "all", jsonObject.get(field.getString("dataField")));
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        arrayList.add(new Tuple3<>(tuple2.f0, tuple2.f1, keys.toString()));
+                    }
+                }
+                if (arrayList.isEmpty()) {
+                    out.collect(new Tuple3<>(value.get(0).f0 + "_" + value.size(), arrayList, value.get(0).f3));
+                } else {
+                    out.collect(new Tuple3<>(value.get(0).f0, arrayList, value.get(0).f3));
+                }
+            }
+
+            @Override
+            public void processBroadcastElement(Uniformity value, Context ctx, Collector<Tuple3<String, List<Tuple3<String, String, String>>, String>> out) throws Exception {
+                BroadcastState<String, List<Uniformity>> broadcastState = ctx.getBroadcastState(Descriptors.UNIFORMITY_RULE);
+                if (value.isFlag()) {
+                    if (broadcastState.contains(value.getType())) {
+                        List<Uniformity> timelines = broadcastState.get(value.getType());
+                        timelines.removeIf(item -> item.getRuleId().equals(value.getRuleId()));
+                        timelines.add(value);
+                        broadcastState.put(value.getType(), timelines);
+                    } else {
+                        ArrayList<Uniformity> arrayList = new ArrayList<>();
+                        arrayList.add(value);
+                        broadcastState.put(value.getType(), arrayList);
+                    }
+                } else {
+                    if (broadcastState.contains(value.getType())) {
+                        List<Uniformity> timelines = broadcastState.get(value.getType());
+                        timelines.removeIf(timeliness1 -> timeliness1.toString().equals(value.toString()));
+                        broadcastState.put(value.getType(), timelines);
+                    }
+                }
+            }
+        });
+
+        //输出一致性结果
+        SingleOutputStreamOperator<Tuple5<String, String, Integer, String, String>> result4 = process2.map(new MapFunction<Tuple3<String, List<Tuple3<String, String, String>>, String>, Tuple5<String, String, Integer, String, String>>() {
+            @Override
+            public Tuple5<String, String, Integer, String, String> map(Tuple3<String, List<Tuple3<String, String, String>>, String> value) throws Exception {
+                int filedCount = 0;
+                int countError = 0;
+                JSONArray array = new JSONArray();
+                int countAll = value.f1.size();
+                for (Tuple3<String, String, String> tuple3 : value.f1) {
+                    JSONObject input = JSONObject.parseObject(tuple3.f2);
+                    JSONObject output = JSONObject.parseObject(tuple3.f1);
+                    filedCount = filedCount + output.keySet().size();
+                    for (String s : input.keySet()) {
+                        String[] split = s.split("-");
+                        String ruleId = split[0];
+                        String key = split[1];
+                        String type = split[2];
+                        if (output.containsKey(key)) {
+                            if (!(output.get(key).equals(input.get(s)) && DataType.getType(output.get(key)).get("类型").equals(type)) && (!"all".equals(type))) {
+                                countError++;
+                                if (output.containsKey("ruleId")) {
+                                    output.put("ruleId", output.getString("ruleId") + "_" + ruleId);
+                                } else {
+                                    output.put("ruleId", ruleId);
+                                }
+                            }
+                        }
+                    }
+                    if (output.containsKey("ruleId")) {
+                        array.add(output);
+                    }
+                }
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("字段一致性", getPercent(filedCount - countError, filedCount));
+                jsonObject.put("记录一致性", getPercent(countAll - array.size(), countAll));
+                if (array.size() > 0) {
+                    return new Tuple5<>(value.f0, jsonObject.toString(), countAll, array.toString(), value.f2);
+                } else if (value.f1.isEmpty()) {
+                    String[] split = value.f0.split("_");
+                    return new Tuple5<>(split[0], "{\"记录一致性\":\"100.00%\",\"字段一致性\":\"100.00%\"}", Integer.parseInt(split[2]), null, value.f2);
+                } else {
+                    return new Tuple5<>(value.f0, jsonObject.toString(), countAll, null, value.f2);
+                }
+            }
+        });
+
+
+        //准确性
+        BroadcastStream<RuleBase> broadcast1 = current.keyBy((KeySelector<JSONObject, String>) value -> value.getString("model")).process(new KeyedProcessFunction<String, JSONObject, RuleBase>() {
+            private transient MapState<String, DroolsRule> mapState;
+            private boolean flag;
+
+            @Override
+            public void open(Configuration parameters) throws Exception {
+                MapStateDescriptor<String, DroolsRule> descriptor = new MapStateDescriptor<>("mapState", TypeInformation.of(String.class), TypeInformation.of(DroolsRule.class));
+                mapState = getRuntimeContext().getMapState(descriptor);
+                flag = true;
+                super.open(parameters);
+            }
+
+            @Override
+            public void processElement(JSONObject tuple2, Context ctx, Collector<RuleBase> out) throws Exception {
+                STGroup stg = new STGroupFile(Descriptors.RULE_ADDRESS);
+                if (flag) {
+                    ST sqlTemplate = stg.getInstanceOf("sqlTemplate");
+                    String ruleId = "0000000001";
+                    //计算表达式
+                    String expression = "(ai_faxlet<-1000000)";
+                    String type = "BasTefMes";
+                    String state = "1";
+                    sqlTemplate.add("ruleId", ruleId);
+                    sqlTemplate.add("expression", expression);
+                    sqlTemplate.add("class", type);
+                    String script = sqlTemplate.render();
+                    mapState.put(ruleId, new DroolsRule(ruleId, "logrules", script, state));
+                    flag = false;
+                }
+                JSONObject jsonObject = JSONObject.parseObject(tuple2.getString("mes"));
+                ST sqlTemplate = stg.getInstanceOf("sqlTemplate");
+                String ruleId = tuple2.getString("rule_id");
+                String expression = jsonObject.getString("expression");
+                String type = tuple2.getString("type");
+                String state = tuple2.getString("flag");
+                sqlTemplate.add("ruleId", ruleId);
+                sqlTemplate.add("expression", expression);
+                sqlTemplate.add("class", type);
+                String script = sqlTemplate.render();
+                if ("1".equals(state)) {
+                    mapState.put(ruleId, new DroolsRule(ruleId, "logrules", script, state));
+                } else {
+                    if (!mapState.isEmpty()) {
+                        if (mapState.contains(ruleId)) {
+                            mapState.remove(ruleId);
+                        }
+                    }
+                }
+                int count = 0;
+                if (!mapState.isEmpty()) {
+                    Iterable<DroolsRule> values = mapState.values();
+                    JSONArray array = new JSONArray();
+                    for (DroolsRule value : values) {
+                        count++;
+                        array.add(value);
+                    }
+                    RuleBase ruleBase = RuleBase.createRuleBase(array);
+                    out.collect(ruleBase);
+                }
+            }
+        }).setParallelism(1).broadcast(Descriptors.RULE_STATE_DESCRIPTOR);
+        //获取初始化规则
+        RuleBase ruleBase = getInitRuleBase();
+        logger.debug("第一次初始化规则 : " + ruleBase.toString());
+
+        SingleOutputStreamOperator<Tuple5<String, String, Integer, String, String>> result5 = process3.connect(broadcast1).process(new NormalRuleProcess(ruleBase));
+
+        DataStream<Tuple5<String, String, Integer, String, String>> unionRes = result2.union(result3).union(result4).union(result5).union(result);
+        SingleOutputStreamOperator<Tuple6<String, String, Integer, String, String, String>> operator = unionRes.map(new MapFunction<Tuple5<String, String, Integer, String, String>, Tuple6<String, String, Integer, String, String, String>>() {
+            @Override
+            public Tuple6<String, String, Integer, String, String, String> map(Tuple5<String, String, Integer, String, String> value) throws Exception {
+                return new Tuple6<>(value.f0, value.f1, value.f2, value.f3, UUID.randomUUID().toString(), value.f4);
+            }
+        });
+
+        operator.addSink(new RichSinkFunction<Tuple6<String, String, Integer, String, String, String>>() {
+            private Connection con;
+            private PreparedStatement statement;
+
+            @Override
+            public void open(Configuration parameters) throws Exception {
+                super.open(parameters);
+                con = MysqlUtil.getCon();
+
+            }
+
+            @Override
+            public void close() throws Exception {
+                super.close();
+                if (statement != null) {
+                    statement.close();
+                }
+                if (con != null) {
+                    con.close();
+                }
+            }
+
+            @Override
+            public void invoke(Tuple6<String, String, Integer, String, String, String> value, Context context) throws Exception {
+                Date date = new Date();
+                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                String dateStr = format.format(date);
+                String[] s = value.f0.split("_");
+                String device = s[0];
+                String appType = value.f5;
+                JSONObject jsonObject = JSONObject.parseObject(value.f1);
+                int count = value.f2;
+                String resMes = value.f3;
+                String uuid = value.f4;
+                char e = '%';
+                try {
+                    String sql = "insert into governance_result (app_type,model,field_res,record_res,rule_res,mes_count,create_time,uuid,device_type) values (?,?,?,?,?,?,?,?,?) ON CONFLICT(app_type,model,create_time,device_type) DO NOTHING";
+                    statement = con.prepareStatement(sql);
+                    statement.setString(1, appType);
+                    if (jsonObject.containsKey("记录一致性")) {
+                        Float recordRes = deleteChar(jsonObject.getString("记录一致性"), e);
+                        Float fieldRes = deleteChar(jsonObject.getString("字段一致性"), e);
+                        statement.setString(2, "一致性");
+                        statement.setFloat(3, fieldRes);
+                        statement.setFloat(4, recordRes);
+                        statement.setString(5, resMes);
+                    } else if (jsonObject.containsKey("记录完整性")) {
+                        Float recordRes = deleteChar(jsonObject.getString("记录完整性"), e);
+                        Float fieldRes = deleteChar(jsonObject.getString("字段完整性"), e);
+                        statement.setString(2, "完整性");
+                        statement.setFloat(3, fieldRes);
+                        statement.setFloat(4, recordRes);
+                        statement.setString(5, resMes);
+                    } else if (jsonObject.containsKey("记录准确性")) {
+                        Float recordRes = deleteChar(jsonObject.getString("记录准确性"), e);
+                        Float fieldRes = deleteChar(jsonObject.getString("字段准确性"), e);
+                        statement.setString(2, "准确性");
+                        statement.setFloat(3, fieldRes);
+                        statement.setFloat(4, recordRes);
+                        statement.setString(5, resMes);
+                    } else if (jsonObject.containsKey("记录及时性(数据入库)")) {
+                        statement.setString(2, "及时性(数据入库)");
+                        Float out = deleteChar(jsonObject.getString("记录及时性(数据入库)"), e);
+                        statement.setFloat(3, -1);
+                        statement.setFloat(4, out);
+                        statement.setString(5, resMes);
+                    } else if (jsonObject.containsKey("记录及时性(数据采集)")) {
+                        statement.setString(2, "及时性(数据采集)");
+                        Float in = deleteChar(jsonObject.getString("记录及时性(数据采集)"), e);
+                        statement.setFloat(3, -1);
+                        statement.setFloat(4, in);
+                        statement.setString(5, resMes);
+                    }
+                    statement.setInt(6, count);
+                    statement.setString(7, dateStr);
+                    statement.setString(8, uuid);
+                    statement.setString(9, device);
+                    statement.addBatch();
+                    statement.executeBatch();
+                    con.commit();
+                } catch (Exception e1) {
+                    System.out.println("存储postgres规则结果异常");
+                    e1.printStackTrace();
+                    con = MysqlUtil.getCon2();
+                }
+            }
+        });
+        operator.filter(new FilterFunction<Tuple6<String, String, Integer, String, String, String>>() {
+            @Override
+            public boolean filter(Tuple6<String, String, Integer, String, String, String> value) throws Exception {
+                return null != value.f3;
+            }
+        }).flatMap(new FlatMapFunction<Tuple6<String, String, Integer, String, String, String>, Tuple3<String, String, String>>() {
+            @Override
+            public void flatMap(Tuple6<String, String, Integer, String, String, String> value, Collector<Tuple3<String, String, String>> out) throws Exception {
+                JSONArray jsonArray = JSONArray.parseArray(value.f3);
+                for (Object o : jsonArray) {
+                    JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(o, SerializerFeature.WriteMapNullValue));
+
+                    if (jsonObject.containsKey("ruleId")) {
+                        String ruleIds = jsonObject.getString("ruleId");
+                        String[] s = ruleIds.split("_");
+                        for (String s1 : s) {
+                            out.collect(new Tuple3<>(s1.trim(), jsonObject.toString(SerializerFeature.WriteMapNullValue), value.f4));
+                        }
+                    } else {
+                        String ruleIds = jsonObject.getString("flag");
+                        String[] s = ruleIds.split("-/");
+                        for (String s1 : s) {
+                            if (s1.contains("规则:")) {
+                                s1 = s1.replace("规则:", "");
+                            }
+                            out.collect(new Tuple3<>(s1.trim(), jsonObject.toString(), value.f4));
+                        }
+                    }
+                }
+            }
+        }).addSink(org.apache.flink.connector.jdbc.JdbcSink.sink(
+                "insert into rule_mes (rule_id,rule_mes,create_time,uuid) values (?,?,?,?) ON CONFLICT(rule_id,rule_mes,uuid) DO NOTHING",
+                (ps, t) -> {
+                    Date date = new Date();
+                    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                    String dateStr = format.format(date);
+                    ps.setString(1, t.f0);
+                    ps.setString(2, t.f1);
+                    ps.setString(3, dateStr);
+                    ps.setString(4, t.f2);
+                },
+                new JdbcConnectionOptions.JdbcConnectionOptionsBuilder()
+                        .withUrl("jdbc:postgresql://192.168.20.72:5432/urtmpdb?characterEncoding=utf-8&serverTimezone=UTC")
+                        .withDriverName("org.postgresql.Driver")
+                        .withPassword("sw12345")
+                        .withUsername("postgres")
+                        .build()));
+        env.execute();
+    }
+
+    /**
+     * 删除某个字符
+     */
+    public static Float deleteChar(String str, char delChar) {
+        StringBuilder delStr = new StringBuilder();
+        char[] bytes = str.toCharArray();
+        int iSize = bytes.length;
+        for (int i = bytes.length - 1; i >= 0; i--) {
+            if (bytes[i] == delChar) {
+                if (iSize - 1 - i >= 0) {
+                    System.arraycopy(bytes, i + 1, bytes, i, iSize - 1 - i);
+                }
+                iSize--;
+            }
+        }
+        for (int i = 0; i < iSize; i++) {
+            delStr.append(bytes[i]);
+        }
+        return Float.parseFloat(delStr.toString());
+    }
+
+    /**
+     * 用来初始化规则,防止广播流规则为空
+     */
+    private static RuleBase getInitRuleBase() throws SQLException {
+        JSONArray array = new JSONArray();
+        STGroup stg = new STGroupFile(Descriptors.RULE_ADDRESS);
+        ST sqlTemplate = stg.getInstanceOf("sqlTemplate");
+        String ruleId = "0000000002";
+        String expression = "(ai_faxlet<-1000000)";
+        String type = "BasTefMes";
+        String state = "1";
+        sqlTemplate.add("ruleId", ruleId);
+        sqlTemplate.add("expression", expression);
+        sqlTemplate.add("class", type);
+        String script = sqlTemplate.render();
+        array.add(new com.sunwin.metro.bean.DroolsRule(ruleId, type, script, state));
+        System.out.println(array);
+        return RuleBase.createRuleBase(array);
+    }
+
+    /**
+     * 求百分比
+     */
+    public static String getPercent(int x, int y) {
+        double d1 = x * 1.0;
+        double d2 = y * 1.0;
+        // 设置保留几位小数, “.”后面几个零就保留几位小数,这里设置保留四位小数
+        DecimalFormat decimalFormat = new DecimalFormat("##.00%");
+        if (d1 == 0) {
+            return "0%";
+        }
+        return decimalFormat.format(d1 / d2);
+    }
+
+    private static String getMeterName(String name) {
+        switch (name) {
+            case "隧道风机":
+                return "BasTefMes";
+            case "雨水泵":
+                return "BasAtMes";
+            case "排热风机":
+                return "BasTvfMes";
+            case "ups巡检仪":
+                return "UpsXjyMes";
+            case "不间断电源":
+                return "UpsMes";
+            default:
+                return name;
+        }
+
+    }
+
+    /**
+     * 集合去重
+     */
+    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
+        Map<Object, Boolean> seen = new ConcurrentHashMap<>(16);
+        //putIfAbsent方法添加键值对,如果map集合中没有该key对应的值,则直接添加,并返回null,如果已经存在对应的值,则依旧为原来的值。
+        //如果返回null表示添加数据成功(不重复),不重复(null==null :TRUE)
+        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
+    }
+
+}

+ 62 - 0
src/main/java/com/sunwin/metro/bean/BasAtMes.java

@@ -0,0 +1,62 @@
+package com.sunwin.metro.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @program: sunwin_metro
+ * @description: 雨水泵报警信息
+ * @author: xuYJ
+ * @create: 2021-11-16 15:27
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class BasAtMes implements Serializable {
+
+    private String name;
+
+    private String num;
+
+    private String station;
+
+    private String time;
+
+    private Double ai_lr;
+
+    private Integer ai_fltno;
+
+    private Boolean di_m0vl1;
+
+    private Boolean di_commokst;
+
+    private Date eventTime;
+
+    private String flag = "规则:";
+
+    private String appType;
+
+
+    @Override
+    public String toString() {
+        return "BasAtMes{" +
+                "name='" + name + '\'' +
+                ", num=" + num +
+                ", station='" + station + '\'' +
+                ", time='" + time + '\'' +
+                ", ai_lr=" + ai_lr +
+                ", ai_fltno=" + ai_fltno +
+                ", di_m0vl1=" + di_m0vl1 +
+                ", di_commokst=" + di_commokst +
+                ", eventTime=" + eventTime +
+                ", flag='" + flag + '\'' +
+                '}';
+    }
+
+}

+ 63 - 0
src/main/java/com/sunwin/metro/bean/BasTefMes.java

@@ -0,0 +1,63 @@
+package com.sunwin.metro.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @program: sunwin_metro
+ * @description: 模拟区间隧道风机报警信息
+ * @author: xuYJ
+ * @create: 2021-11-16 15:27
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class BasTefMes implements Serializable {
+
+    private String name;
+
+    private String num;
+
+    private String station;
+
+    private String time;
+
+    private Double ai_faxlet;
+
+    private Double ai_comm_word;
+
+    private Double ai_y_vibr;
+
+    private Boolean di_vfflt;
+
+    private Boolean di_commokst;
+
+    private Date eventTime;
+
+    private String flag = "规则:";
+
+    private String appType;
+
+    @Override
+    public String toString() {
+        return "BasTefMes{" +
+                "name='" + name + '\'' +
+                ", num=" + num +
+                ", station='" + station + '\'' +
+                ", time='" + time + '\'' +
+                ", ai_faxlet=" + ai_faxlet +
+                ", ai_comm_word=" + ai_comm_word +
+                ", ai_y_vibr=" + ai_y_vibr +
+                ", di_vfflt=" + di_vfflt +
+                ", di_commokst=" + di_commokst +
+                ", eventTime=" + eventTime +
+                ", flag='" + flag + '\'' +
+                '}';
+    }
+}

+ 63 - 0
src/main/java/com/sunwin/metro/bean/BasTvfMes.java

@@ -0,0 +1,63 @@
+package com.sunwin.metro.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @program: sunwin_metro
+ * @description: 排热风机
+ * @author: xuYJ
+ * @create: 2021-11-16 15:27
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class BasTvfMes implements Serializable {
+
+    private String name;
+
+    private String num;
+
+    private String station;
+
+    private String time;
+
+    private Double ai_faxlet;
+
+    private Double ai_x_vibr;
+
+    private Double ai_y_vibr;
+
+    private Boolean di_vfflt;
+
+    private Boolean di_commokst;
+
+    private Date eventTime;
+
+    private String flag = "规则:";
+
+    private String appType;
+
+    @Override
+    public String toString() {
+        return "BasTvfMes{" +
+                "name='" + name + '\'' +
+                ", num=" + num +
+                ", station='" + station + '\'' +
+                ", time='" + time + '\'' +
+                ", ai_faxlet=" + ai_faxlet +
+                ", ai_x_vibr=" + ai_x_vibr +
+                ", ai_y_vibr=" + ai_y_vibr +
+                ", di_vfflt=" + di_vfflt +
+                ", di_commokst=" + di_commokst +
+                ", eventTime=" + eventTime +
+                ", flag='" + flag + '\'' +
+                '}';
+    }
+}

+ 26 - 0
src/main/java/com/sunwin/metro/bean/DroolsRule.java

@@ -0,0 +1,26 @@
+package com.sunwin.metro.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 规则对象
+ *
+ * @author kane
+ * @date 2020/01/27
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class DroolsRule implements Serializable {
+    private static final long serialVersionUID = 8259501552136811964L;
+    private String id;
+    private String type;
+    private String script;
+    private String state;
+}

+ 66 - 0
src/main/java/com/sunwin/metro/bean/Event.java

@@ -0,0 +1,66 @@
+package com.sunwin.metro.bean;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+
+/**
+ * @author kane
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class Event {
+    private String eventId;
+    private long eventTimestamp;
+    private String type;
+    private JSONObject event;
+    private List<SimpleRule> simpleRules;
+
+    public Event(JSONObject event) {
+        this.eventId = UUID.randomUUID().toString();
+        DateTime dateTime = DateUtil.parse(event.getString("time"), "yyyyMMddHHmmss");
+        this.eventTimestamp = dateTime.getTime();
+        this.type = event.getString("name").trim();
+        this.event = event;
+        this.simpleRules = new ArrayList<>();
+    }
+
+    public Object getValue(String field) {
+        return (Object) event.get(field);
+    }
+
+    public void setValue(String key, Object value) {
+        event.put(key, value);
+    }
+
+    public void setSimpleRules(SimpleRule simpleRule) {
+        this.simpleRules.add(simpleRule);
+    }
+
+    @Override
+    public String toString() {
+        String ruleStr = "";
+        if (simpleRules != null) {
+            ruleStr = simpleRules.toString();
+        }
+
+        return "{" +
+                "id='" + eventId + "'" +
+                ", eventTime='" + eventTimestamp + "'" +
+                ", type='" + type + "'" +
+                ", event='" + event.toString() + "'" +
+                ", rule='" + ruleStr + "'" +
+                "}";
+    }
+}

+ 79 - 0
src/main/java/com/sunwin/metro/bean/RuleBase.java

@@ -0,0 +1,79 @@
+package com.sunwin.metro.bean;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.sunwin.metro.utils.Md5Util;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 规则集合  可以包括多个规则
+ *
+ * @author sunwin
+ */
+public class RuleBase implements Serializable {
+    private static final long serialVersionUID = -6249685986229931397L;
+    private List<DroolsRule> droolsRules = new ArrayList<>();
+    private String name = "Empty-Name";
+    private String hash = "";
+
+    public static RuleBase createRuleBase(JSONArray jsonArray) {
+        RuleBase ruleBase = new RuleBase();
+        for (Object obj : jsonArray) {
+            //JSONObject job = (JSONObject) obj;
+            JSONObject job = JSONObject.parseObject(JSONObject.toJSONString(obj));
+            DroolsRule droolsRule = new DroolsRule();
+            droolsRule.setId(job.getString("id"));
+            droolsRule.setType(job.getString("type"));
+            droolsRule.setScript(job.getString("script"));
+            droolsRule.setState(job.getString("state"));
+            ruleBase.droolsRules.add(droolsRule);
+        }
+        String str = ruleBase.toString();
+        //给字符串取md5
+        ruleBase.hash = Md5Util.getMd5(str);
+        ruleBase.name = "rules-" + ruleBase.hash;
+        return ruleBase;
+    }
+
+    public static RuleBase createRuleBase(JSONArray jsonArray, String name) {
+        RuleBase ruleBase = createRuleBase(jsonArray);
+        ruleBase.name = name;
+        return ruleBase;
+    }
+
+    public List<DroolsRule> getDroolsRules() {
+        return droolsRules;
+    }
+
+    public void setDroolsRules(List<DroolsRule> droolsRules) {
+        this.droolsRules = droolsRules;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getHash() {
+        return hash;
+    }
+
+    public void setHash(String hash) {
+        this.hash = hash;
+    }
+
+    @Override
+    public String toString() {
+        return "RuleBase{" +
+                "rules=" + droolsRules +
+                ", name='" + name + '\'' +
+                ", hash='" + hash + '\'' +
+                '}';
+    }
+}

+ 79 - 0
src/main/java/com/sunwin/metro/bean/SimpleRule.java

@@ -0,0 +1,79 @@
+package com.sunwin.metro.bean;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @author kane
+ */
+@Data
+public class SimpleRule {
+
+    private int ruleRelationId;
+
+    private BigDecimal threshold;
+
+    private String operator;
+
+    private Long windowSeconds;
+
+    private Long windowSecondsSplit;
+
+    private String windowUnit;
+
+    private String filed;
+
+    private String aggFunction;
+
+    private int windowCounts;
+
+    private int windowCountsSplit;
+
+    private String countState;
+
+    private String timeState;
+
+    private String controlCmd;
+
+    public SimpleRule(WindowRule windowRule) {
+        this.ruleRelationId = windowRule.getRuleRelationId();
+        this.threshold = windowRule.getThreshold();
+        this.operator = windowRule.getOperator();
+        this.windowSeconds = windowRule.getWindowSeconds();
+        this.filed = windowRule.getAggField();
+        this.aggFunction = windowRule.getAggFunction();
+        this.windowCounts = windowRule.getWindowCounts();
+        this.windowCountsSplit = windowRule.getWindowCountsSplit();
+        this.windowSecondsSplit = windowRule.getWindowSecondsSplit()*1000;
+        this.countState = windowRule.getCountState();
+        this.timeState = windowRule.getTimeState();
+        this.controlCmd = windowRule.getControlCmd();
+    }
+    public boolean isCount(){
+        return "1".equals(this.countState.trim());
+    }
+    public boolean isTime(){
+        return "1".equals(this.timeState.trim());
+    }
+    public boolean apply(BigDecimal comparisonValue) {
+        switch (operator) {
+            case "=":
+                return comparisonValue.compareTo(threshold) == 0;
+            case "!=":
+                return comparisonValue.compareTo(threshold) != 0;
+            case ">":
+                return comparisonValue.compareTo(threshold) > 0;
+            case "<":
+                return comparisonValue.compareTo(threshold) < 0;
+            case "<=":
+                return comparisonValue.compareTo(threshold) <= 0;
+            case ">=":
+                return comparisonValue.compareTo(threshold) >= 0;
+            case "↑/↓":
+                return "1".equals(comparisonValue.toString());
+            default:
+                throw new RuntimeException("不能解析比较符 : " + operator);
+        }
+    }
+}

+ 25 - 0
src/main/java/com/sunwin/metro/bean/SortByValue.java

@@ -0,0 +1,25 @@
+package com.sunwin.metro.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * @program: sunwin_metro
+ * @description: 专门用来时序排序
+ * @author: xuYJ
+ * @create: 2021-11-26 16:57
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class SortByValue implements Serializable {
+    private Long time;
+    private BigDecimal value;
+    private String appType;
+}

+ 61 - 0
src/main/java/com/sunwin/metro/bean/UpsMes.java

@@ -0,0 +1,61 @@
+package com.sunwin.metro.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @program: sunwin_metro
+ * @description: 模拟 不间断电源 数据
+ * @author: xuYJ
+ * @create: 2021-11-16 15:27
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class UpsMes implements Serializable {
+
+    private String name;
+
+    private String num;
+
+    private String station;
+
+    private String time;
+
+    private Double dp29;
+
+    private Double dp36;
+
+    private Double dp32;
+
+    private Boolean dp23;
+
+    private Boolean dp30;
+
+    private Date eventTime;
+
+    private String flag="规则:" ;
+    private String appType;
+    @Override
+    public String toString() {
+        return "UpsMes{" +
+                "name='" + name + '\'' +
+                ", num=" + num +
+                ", station='" + station + '\'' +
+                ", time='" + time + '\'' +
+                ", dp29=" + dp29 +
+                ", dp36=" + dp36 +
+                ", dp32=" + dp32 +
+                ", dp23=" + dp23 +
+                ", dp30=" + dp30 +
+                ", eventTime=" + eventTime +
+                ", flag='" + flag + '\'' +
+                '}';
+    }
+}

+ 57 - 0
src/main/java/com/sunwin/metro/bean/UpsXjyMes.java

@@ -0,0 +1,57 @@
+package com.sunwin.metro.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @program: sunwin_metro
+ * @description: 模拟 不间断电源 数据
+ * @author: xuYJ
+ * @create: 2021-11-16 15:27
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class UpsXjyMes implements Serializable {
+
+    private String name;
+
+    private String num;
+
+    private String station;
+
+    private String time;
+
+    private Double wd;
+
+    private Double zdl;
+
+    private Double zdy;
+
+    private Date eventTime;
+
+    private String flag="规则:" ;
+
+    private String appType;
+
+    @Override
+    public String toString() {
+        return "UpsXjyMes{" +
+                "name='" + name + '\'' +
+                ", num=" + num +
+                ", station='" + station + '\'' +
+                ", time='" + time + '\'' +
+                ", wd=" + wd +
+                ", zdl=" + zdl +
+                ", zdy=" + zdy +
+                ", eventTime=" + eventTime +
+                ", flag='" + flag + '\'' +
+                '}';
+    }
+}

+ 146 - 0
src/main/java/com/sunwin/metro/bean/WindowRule.java

@@ -0,0 +1,146 @@
+package com.sunwin.metro.bean;
+
+
+import cn.hutool.json.JSONObject;
+import lombok.*;
+import org.apache.flink.types.Row;
+
+import java.math.BigDecimal;
+
+/**
+ * @author kane
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@ToString(exclude="rule")
+public class WindowRule {
+
+    private int ruleRelationId;
+
+    private String type;
+
+    private String aggField;
+
+    private String aggFunction;
+
+    private String operator;
+
+    private BigDecimal threshold;
+
+    private Long windowSeconds;
+
+    private String controlCmd;
+
+    private Long windowSecondsSplit;
+
+    private int windowCounts;
+
+    private int windowCountsSplit;
+
+    private String timeState;
+
+    private String countState;
+
+
+
+    public static String getWindowRule(Row rule) {
+        com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
+        if(rule.getField("rule_id")!=null){
+            jsonObject.put("rule_id",rule.getField("rule_id"));
+        }
+        if(rule.getField("type")!=null){
+            jsonObject.put("type",rule.getField("type"));
+        }
+        if(rule.getField("time_state")!=null){
+            jsonObject.put("time_state",rule.getField("time_state"));
+        }
+        if(rule.getField("count_state")!=null){
+            jsonObject.put("count_state",rule.getField("count_state"));
+        }
+        if(rule.getField("control_cmd")!=null){
+            jsonObject.put("control_cmd",rule.getField("control_cmd"));
+        }
+        if(rule.getField("agg_function")!=null){
+            jsonObject.put("agg_function",rule.getField("agg_function"));
+        }
+        if(rule.getField("operator")!=null){
+            jsonObject.put("operator",rule.getField("operator"));
+        }
+        if(rule.getField("threshold")!=null){
+            jsonObject.put("threshold",rule.getField("threshold"));
+        }
+        if(rule.getField("agg_field")!=null){
+            jsonObject.put("agg_field",rule.getField("agg_field"));
+        }
+        if(rule.getField("win_second")!=null){
+            jsonObject.put("win_second",rule.getField("win_second"));
+        }
+        if(rule.getField("win_count")!=null){
+            jsonObject.put("win_count",rule.getField("win_count"));
+        }
+        if(rule.getField("win_count_split")!=null){
+            jsonObject.put("win_count_split",rule.getField("win_count_split"));
+        }
+        if(rule.getField("win_second_split")!=null){
+            jsonObject.put("win_second_split",rule.getField("win_second_split"));
+        }
+       return jsonObject.toString();
+    }
+
+    public WindowRule(JSONObject rule) {
+        this.ruleRelationId = rule.getInt("rule_id");
+        this.type=rule.getStr("type");
+        this.timeState=rule.getStr("time_state","0");
+        this.countState=rule.getStr("count_state","0");
+        this.controlCmd=rule.getStr("control_cmd");
+        this.aggFunction=rule.getStr("agg_function");
+        this.operator=rule.getStr("operator","↑/↓");
+        this.threshold=new BigDecimal(rule.getStr("threshold","0"));
+        this.aggField=rule.getStr("agg_field");
+        this.windowSeconds=rule.getLong("win_second",0L);
+        this.windowSecondsSplit=rule.getLong("win_second_split",5L);
+        this.windowCounts=rule.getInt("win_count",0);
+        this.windowCountsSplit=rule.getInt("win_count_split",1);
+
+    }
+
+
+
+    /**
+    判断Event是否匹配该规则
+    */
+    public boolean filter(Event event, WindowRule windowRule){
+        String eType = windowRule.getType();
+        return event.getType().equals(eType);
+    }
+
+    public boolean isWindowTime(){
+        return "1".equals(this.timeState.trim());
+    }
+
+
+
+    public boolean apply(BigDecimal comparisonValue) {
+        switch (operator) {
+          case "=":
+            return comparisonValue.compareTo(threshold) == 0;
+          case "!=":
+            return comparisonValue.compareTo(threshold) != 0;
+          case ">":
+            return comparisonValue.compareTo(threshold) > 0;
+          case "<":
+            return comparisonValue.compareTo(threshold) < 0;
+          case "<=":
+            return comparisonValue.compareTo(threshold) <= 0;
+          case ">=":
+            return comparisonValue.compareTo(threshold) >= 0;
+          default:
+            throw new RuntimeException("Unknown limit operator type: " + operator);
+        }
+    }
+
+
+
+}

+ 120 - 0
src/main/java/com/sunwin/metro/constant/Descriptors.java

@@ -0,0 +1,120 @@
+package com.sunwin.metro.constant;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.sunwin.metro.bean.*;
+import com.sunwin.metro.governance.bean.Expression;
+import com.sunwin.metro.governance.bean.Integrity;
+import com.sunwin.metro.governance.bean.Timeliness;
+import com.sunwin.metro.governance.bean.Uniformity;
+import org.apache.flink.api.common.state.MapStateDescriptor;
+import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
+import org.apache.flink.api.common.typeinfo.TypeHint;
+import org.apache.flink.api.common.typeinfo.TypeInformation;
+import org.apache.flink.api.java.tuple.Tuple2;
+import org.apache.flink.api.java.tuple.Tuple4;
+import org.apache.flink.util.OutputTag;
+
+import java.util.List;
+
+/**
+ * @author kane
+ */
+public class Descriptors {
+    /**
+     * 侧边流存储规则流
+     */
+    public static final MapStateDescriptor<String, RuleBase> RULE_STATE_DESCRIPTOR = new MapStateDescriptor<>(
+            "rules-state",
+            BasicTypeInfo.STRING_TYPE_INFO,
+            TypeInformation.of(new TypeHint<RuleBase>() {
+            }));
+    public static final OutputTag<UpsXjyMes> ERROR_UPS_XYJ = new OutputTag<UpsXjyMes>(
+            "warn-ups-xyj",
+            TypeInformation.of(UpsXjyMes.class)) {
+    };
+    public static final OutputTag<String> DEMO_SINK_TAG = new OutputTag<String>(
+            "demo-sink") {
+    };
+    public static final OutputTag<Event> LATENCY_SINK_TAG = new OutputTag<Event>(
+            "latency-sink") {
+    };
+    public static final OutputTag<WindowRule> CURRENT_RULES_SINK_TAG = new OutputTag<WindowRule>(
+            "current-rules-sink") {
+    };
+    public static final OutputTag<Timeliness> IN_TIME_RULE_1 = new OutputTag<Timeliness>(
+            "IN_TIME_RULE_1") {
+    };
+    public static final OutputTag<Timeliness> OUT_TIME_RULE_1 = new OutputTag<Timeliness>(
+            "OUT_TIME_RULE_1") {
+    };
+    public static final OutputTag<Integrity> COMPLETE_RULE_1 = new OutputTag<Integrity>(
+            "COMPLETE_RULE_1") {
+    };
+    public static final OutputTag<Uniformity> UNIFORMITY_RULE_1 = new OutputTag<Uniformity>(
+            "UNIFORMITY_RULE_1") {
+    };
+    public static final OutputTag<JSONObject> CURRENT_RULE_1 = new OutputTag<JSONObject>(
+            "CURRENT_RULE_1") {
+    };
+    public static final MapStateDescriptor<Integer, WindowRule> RULES_DESCRIPTOR = new MapStateDescriptor<>(
+            "rules",
+            BasicTypeInfo.INT_TYPE_INFO,
+            TypeInformation.of(WindowRule.class
+            ));
+    public static final MapStateDescriptor<String, List<String>> DESCRIPTOR = new MapStateDescriptor<>(
+            "key-words",
+            //Key类型
+            BasicTypeInfo.STRING_TYPE_INFO,
+            //Value类型
+            TypeInformation.of(new TypeHint<List<String>>() {
+            }));
+    public static final MapStateDescriptor<String, List<Timeliness>> IN_TIME_RULE = new MapStateDescriptor<>(
+            "IN_TIME_RULE",
+            //Key类型
+            BasicTypeInfo.STRING_TYPE_INFO,
+            //Value类型
+            TypeInformation.of(new TypeHint<List<Timeliness>>() {
+            }));
+    public static final MapStateDescriptor<String, List<Timeliness>> OUT_TIME_RULE = new MapStateDescriptor<>(
+            "OUT_TIME_RULE",
+            //Key类型
+            BasicTypeInfo.STRING_TYPE_INFO,
+            //Value类型
+            TypeInformation.of(new TypeHint<List<Timeliness>>() {
+            }));
+    public static final MapStateDescriptor<String, List<Integrity>> COMPLETE_RULE = new MapStateDescriptor<>(
+            "COMPLETE_RULE",
+            //Key类型
+            BasicTypeInfo.STRING_TYPE_INFO,
+            //Value类型
+            TypeInformation.of(new TypeHint<List<Integrity>>() {
+            }));
+    public static final MapStateDescriptor<String, List<Uniformity>> UNIFORMITY_RULE = new MapStateDescriptor<>(
+            "UNIFORMITY_RULE",
+            //Key类型
+            BasicTypeInfo.STRING_TYPE_INFO,
+            //Value类型
+            TypeInformation.of(new TypeHint<List<Uniformity>>() {
+            }));
+    public static final OutputTag<Tuple2<String, String>> ERROR_METER = new OutputTag<Tuple2<String, String>>(
+            "error_meter") {
+    };
+    public static final OutputTag<Tuple4<String, String, Integer, String>> COMPLETE_RULE_RESULT = new OutputTag<Tuple4<String, String, Integer, String>>(
+            "COMPLETE_RULE_RESULT") {
+    };
+    public static final OutputTag<Tuple4<String, String, Integer, String>> UNIFORMITY_RULE_RESULT = new OutputTag<Tuple4<String, String, Integer, String>>(
+            "UNIFORMITY_RULE_RESULT") {
+    };
+    public static final OutputTag<Tuple4<String, String, Integer, String>> TIME_RULE_RESULT = new OutputTag<Tuple4<String, String, Integer, String>>(
+            "TIME_RULE_RESULT") {
+    };
+    public static final OutputTag<Tuple4<String, String, Integer, String>> CURRENT_RULE_RESULT = new OutputTag<Tuple4<String, String, Integer, String>>(
+            "CURRENT_RULE_RESULT") {
+    };
+
+    public static final String RULE_ADDRESS = "C:\\Users\\daoda\\Desktop\\地铁项目\\test_prometheus\\src\\main\\resources\\rule.stg";
+    //public static final String RULE_ADDRESS = "/home/flink-1.13.3/conf/rule.stg";
+
+
+}

+ 86 - 0
src/main/java/com/sunwin/metro/drools/KieSessionHelper.java

@@ -0,0 +1,86 @@
+package com.sunwin.metro.drools;
+
+
+import com.sunwin.metro.bean.DroolsRule;
+import com.sunwin.metro.bean.RuleBase;
+import org.kie.api.KieBase;
+import org.kie.api.KieServices;
+import org.kie.api.builder.KieBuilder;
+import org.kie.api.builder.KieFileSystem;
+import org.kie.api.builder.Message;
+import org.kie.api.builder.Results;
+import org.kie.api.builder.model.KieBaseModel;
+import org.kie.api.builder.model.KieModuleModel;
+import org.kie.api.builder.model.KieSessionModel;
+import org.kie.api.conf.EqualityBehaviorOption;
+import org.kie.api.conf.EventProcessingOption;
+import org.kie.api.runtime.conf.ClockTypeOption;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author kane
+ * @date 2020/01/29
+ */
+public class KieSessionHelper {
+    private static final Logger logger = LoggerFactory.getLogger(KieSessionHelper.class);
+
+    private final String rulePackage;
+    private final KieServices kieServices;
+
+    public KieSessionHelper(final String pkg) {
+        rulePackage = pkg;
+        kieServices = KieServices.Factory.get();
+    }
+
+    public KieBase createKieBase() {
+        return kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId()).getKieBase();
+    }
+
+
+
+    /**
+     * 解析规则RuleBase对象  写到xml文件中
+     */
+    public List<String> compileRules(RuleBase rb) {
+        KieModuleModel kieModuleModel = kieServices.newKieModuleModel();
+        KieBaseModel kieBaseModel = kieModuleModel.newKieBaseModel(rulePackage)
+                .setDefault(true)
+                .setEqualsBehavior(EqualityBehaviorOption.EQUALITY)
+                .setEventProcessingMode(EventProcessingOption.STREAM);
+
+        kieBaseModel.newKieSessionModel("ruleKieSession")
+                .setDefault(true)
+                .setType(KieSessionModel.KieSessionType.STATEFUL)
+                .setClockType(ClockTypeOption.get("realtime"));
+
+        KieFileSystem kfs = kieServices.newKieFileSystem();
+        kfs.writeKModuleXML(kieModuleModel.toXML());
+
+        for (DroolsRule droolsRule : rb.getDroolsRules()) {
+            //写到xml中
+            kfs.write("src/main/resources/" + droolsRule.getType() + "/" + droolsRule.getId() + ".drl", droolsRule.getScript());
+        }
+        KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll();
+        Results results = kieBuilder.getResults();
+        if (results.hasMessages(Message.Level.ERROR)) {
+            for (Message msg : results.getMessages(Message.Level.ERROR)) {
+                logger.error("解析异常 :{}", msg.getText());
+            }
+        }
+        //收集不能即系异常规则
+        List<String> res = new ArrayList<>();
+        if (results.hasMessages(Message.Level.ERROR)) {
+            for (Message msg : results.getMessages(Message.Level.ERROR)) {
+                logger.error("解析异常 :{}", msg.getText());
+                res.add(msg.getText());
+            }
+        }
+        return res;
+    }
+}
+

+ 25 - 0
src/main/java/com/sunwin/metro/drools/MetroProcessor.java

@@ -0,0 +1,25 @@
+package com.sunwin.metro.drools;
+
+
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.sunwin.metro.bean.RuleBase;
+
+
+import java.util.List;
+
+/**
+ *
+ * @author kane
+ * @date 2020/01/29
+ */
+public interface MetroProcessor {
+    String LOG_PKG = "metroRules";
+
+    List<JSONObject> execute(String msg);
+
+    List<JSONObject> execute(JSONObject entry);
+
+    boolean loadRules(RuleBase ruleBase);
+}

+ 97 - 0
src/main/java/com/sunwin/metro/drools/MetroProcessorWithRules.java

@@ -0,0 +1,97 @@
+package com.sunwin.metro.drools;
+
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.sunwin.metro.bean.*;
+import com.sunwin.metro.bean.RuleBase;
+import org.kie.api.KieBase;
+import org.kie.api.runtime.KieSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ * @author kane
+ * @date 2020/01/29
+ */
+public class MetroProcessorWithRules implements MetroProcessor {
+    private static final Logger logger = LoggerFactory.getLogger(MetroProcessorWithRules.class);
+
+    private KieBase kieBase = null;
+    private boolean isEmptyKie = true;
+    private final String rulePackage;
+
+    public MetroProcessorWithRules(String pkg) {
+        rulePackage = pkg;
+    }
+
+
+
+    @Override
+    public List<JSONObject> execute(String msg) {
+        return null;
+    }
+
+
+    @Override
+    public List<JSONObject> execute(JSONObject entry) {
+        List<JSONObject> result = new LinkedList<>();
+        KieSession kSession = kieBase.newKieSession();
+        try {
+            //新增日志对象log
+            if (!isEmptyKie) {
+                logger.info("kie对象不为空");
+            }
+            if(entry.toString().contains("ups巡检仪")){
+                UpsXjyMes upsXjyMes = JSONObject.parseObject(entry.toString(), UpsXjyMes.class);
+                kSession.insert(upsXjyMes);
+            }
+            if(entry.toString().contains("雨水泵")){
+                BasAtMes basAtMes = JSONObject.parseObject(entry.toString(), BasAtMes.class);
+                kSession.insert(basAtMes);
+            }
+            if(entry.toString().contains("不间断电源")){
+                UpsMes upsMes = JSONObject.parseObject(entry.toString(), UpsMes.class);
+                kSession.insert(upsMes);
+            }
+            if(entry.toString().contains("排热风机")){
+                BasTvfMes basTvfMes = JSONObject.parseObject(entry.toString(), BasTvfMes.class);
+                kSession.insert(basTvfMes);
+            }
+            if(entry.toString().contains("隧道风机")){
+                BasTefMes basTefMes = JSONObject.parseObject(entry.toString(), BasTefMes.class);
+                kSession.insert(basTefMes);
+            }
+            System.out.println("命中数目" + kSession.fireAllRules());
+            for (Object obj : kSession.getObjects()) {
+                result.add(JSONObject.parseObject(JSONObject.toJSONString(obj)));
+            }
+        } catch (Exception ex) {
+            logger.error("处理规则失败, 异常原因:{}", ex);
+        } finally {
+            kSession.dispose();
+        }
+        return result;
+    }
+
+    /**
+     * 加载规则
+     */
+    @Override
+    public boolean loadRules(RuleBase rb) {
+        KieSessionHelper ksHelper = new KieSessionHelper(rulePackage);
+        //解析采集到规则体 compileRules  判断返回结果  不为空则是解析规则失败
+        if (!ksHelper.compileRules(rb).isEmpty()) {
+            logger.error("加载规则失败, hash值:{}", rb.getHash());
+            return false;
+        }
+        //规则对象中是否为空
+        isEmptyKie = rb.getDroolsRules().isEmpty();
+        kieBase = ksHelper.createKieBase();
+        return true;
+    }
+}

+ 105 - 0
src/main/java/com/sunwin/metro/drools/NormalRuleProcess.java

@@ -0,0 +1,105 @@
+package com.sunwin.metro.drools;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.sunwin.metro.constant.Descriptors;
+import com.sunwin.metro.bean.RuleBase;
+import com.sunwin.metro.governance.bean.Expression;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.flink.api.common.state.BroadcastState;
+import org.apache.flink.api.java.tuple.Tuple2;
+import org.apache.flink.api.java.tuple.Tuple3;
+import org.apache.flink.api.java.tuple.Tuple4;
+import org.apache.flink.api.java.tuple.Tuple5;
+import org.apache.flink.configuration.Configuration;
+import org.apache.flink.streaming.api.functions.co.BroadcastProcessFunction;
+import org.apache.flink.util.Collector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.sunwin.metro.StartRule.getPercent;
+
+/**
+ * @author kane
+ * @date 2020/01/27
+ */
+public class NormalRuleProcess extends BroadcastProcessFunction<List<Tuple4<String, String, Long,String>>, RuleBase, Tuple5<String, String, Integer, String,String>> {
+    private static final Logger logger = LoggerFactory.getLogger(NormalRuleProcess.class);
+    private RuleBase latestRuleBase;
+
+    private transient MetroProcessor metroProcessor = null;
+
+    public NormalRuleProcess(RuleBase ruleBase) {
+        this.latestRuleBase = ruleBase;
+    }
+
+    @Override
+    public void open(Configuration parameters) throws Exception {
+        super.open(parameters);
+        metroProcessor = new MetroProcessorWithRules(MetroProcessor.LOG_PKG);
+        metroProcessor.loadRules(this.latestRuleBase);
+    }
+
+    @Override
+    public void processElement(List<Tuple4<String, String, Long,String>> logEntry, ReadOnlyContext readOnlyContext, Collector<Tuple5<String, String, Integer, String,String>> collector) throws Exception {
+        JSONArray array = new JSONArray();
+        int fieldAll = 0;
+        int countError = 0;
+        int countAll = logEntry.size();
+        for (Tuple4<String, String, Long,String> tuple2 : logEntry) {
+            JSONObject jsonObject = JSONObject.parseObject(tuple2.f1);
+            fieldAll = fieldAll + jsonObject.keySet().size();
+                try {
+                    List<JSONObject> result = metroProcessor.execute(jsonObject);
+                    for (JSONObject item : result) {
+                        String flag = item.getString("flag");
+                        if (!"规则:".equals(flag)) {
+                            array.add(item);
+                            String[] split = flag.split("/");
+                            countError = countError + split.length;
+                        }
+                    }
+                } catch (Exception ex) {
+                    logger.error("设备数据规则解析失败: " + ex.toString());
+                }
+        }
+
+        JSONObject jsonObject = new JSONObject();
+        //字段准确率
+        jsonObject.put("字段准确性", getPercent(fieldAll - countError, fieldAll));
+        //记录准确率
+        jsonObject.put("记录准确性", getPercent(countAll - array.size(), countAll));
+        if (array.size() > 0) {
+            collector.collect(new Tuple5<>(logEntry.get(0).f0, jsonObject.toString(), countAll, array.toString(),logEntry.get(0).f3));
+        } else {
+            collector.collect(new Tuple5<>(logEntry.get(0).f0, jsonObject.toString(), countAll, null,logEntry.get(0).f3));
+        }
+    }
+
+    @Override
+    public void processBroadcastElement(RuleBase ruleBase, Context context, Collector<Tuple5<String, String, Integer, String,String>> collector) throws Exception {
+        BroadcastState<String, RuleBase> ruleState = context.getBroadcastState(Descriptors.RULE_STATE_DESCRIPTOR);
+        ruleState.put("logRule", ruleBase);
+        if (latestRuleBase != null && StringUtils.equals(latestRuleBase.getHash(), ruleBase.getHash())) {
+            logger.info("接收到相同的规则: {}", ruleBase.getName());
+            return;
+        }
+        logger.info("更新 " + ruleBase.getDroolsRules().size() + " 规则, 规则名: " + ruleBase.getName());
+        //加载规则到模型中
+        if (metroProcessor != null) {
+            if (!metroProcessor.loadRules(ruleBase)) {
+                logger.error("加载规则失败");
+            } else {
+                logger.info("规则正在更新, hash值:{}", ruleBase.getHash());
+                latestRuleBase = ruleBase;
+            }
+        } else {
+            metroProcessor = new MetroProcessorWithRules(MetroProcessor.LOG_PKG);
+            metroProcessor.loadRules(latestRuleBase);
+            latestRuleBase = ruleBase;
+        }
+    }
+}

+ 25 - 0
src/main/java/com/sunwin/metro/governance/bean/Expression.java

@@ -0,0 +1,25 @@
+package com.sunwin.metro.governance.bean;
+
+import com.sunwin.metro.bean.RuleBase;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @program: data_governance
+ * @description: 准确性
+ * @author: xuYJ
+ * @create: 2022-02-18 13:09
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class Expression {
+    private String ruleId;
+    private String type;
+    private String expression1;
+    private RuleBase expression2;
+    private boolean flag;
+}

+ 37 - 0
src/main/java/com/sunwin/metro/governance/bean/Integrity.java

@@ -0,0 +1,37 @@
+package com.sunwin.metro.governance.bean;
+
+import com.alibaba.fastjson.JSONArray;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @program: data_governance
+ * @description: 完整性
+ * @author: xuYJ
+ * @create: 2022-02-17 13:18
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class Integrity {
+    private String ruleId;
+    private String type;
+    private List<String> fields;
+    private boolean flag;
+    private String appType;
+
+    @Override
+    public String toString() {
+        return "Integrity{" +
+                "ruleId='" + ruleId + '\'' +
+                ", type='" + type + '\'' +
+                ", appType='" + appType + '\'' +
+                ", fields=" + fields +
+                '}';
+    }
+}

+ 34 - 0
src/main/java/com/sunwin/metro/governance/bean/Timeliness.java

@@ -0,0 +1,34 @@
+package com.sunwin.metro.governance.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @program: data_governance
+ * @description: 及时性
+ * @author: xuYJ
+ * @create: 2022-02-15 13:31
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class Timeliness {
+    private String ruleId;
+    private String type;
+    private int collectTime;
+    private boolean flag;
+    private String appType;
+
+    @Override
+    public String toString() {
+        return "Timeliness{" +
+                "ruleId='" + ruleId + '\'' +
+                ", type='" + type + '\'' +
+                ", appType='" + appType + '\'' +
+                ", collectTime=" + collectTime +
+                '}';
+    }
+}

+ 36 - 0
src/main/java/com/sunwin/metro/governance/bean/Uniformity.java

@@ -0,0 +1,36 @@
+package com.sunwin.metro.governance.bean;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * @program: data_governance
+ * @description: 一致性
+ * @author: xuYJ
+ * @create: 2022-02-18 09:49
+ **/
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class Uniformity {
+    private String ruleId;
+    private String type;
+    private List<JSONObject> fields;
+    private boolean flag;
+    private String appType;
+    @Override
+    public String toString() {
+        return "Uniformity{" +
+                "ruleId='" + ruleId + '\'' +
+                ", type='" + type + '\'' +
+                ", appType='" + appType + '\'' +
+                ", fields=" + fields +
+                '}';
+    }
+}

+ 65 - 0
src/main/java/com/sunwin/metro/process/BroadcastMeterMes.java

@@ -0,0 +1,65 @@
+package com.sunwin.metro.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.sunwin.metro.utils.StringUtils;
+import org.apache.flink.api.java.tuple.Tuple2;
+import org.apache.flink.streaming.api.functions.co.BroadcastProcessFunction;
+import org.apache.flink.util.Collector;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @program: boryou-flink
+ * @description: 处理不同关键词匹配
+ * @author: xuYJ
+ * @create: 2020-10-19 16:23
+ **/
+public class BroadcastMeterMes extends BroadcastProcessFunction<String, Map<String, List<String>>, Tuple2<String,String>> {
+
+    private List<String> keyWords;
+
+    @Override
+    public void processElement(String value, ReadOnlyContext ctx, Collector<Tuple2<String,String>> collector) throws Exception {
+        JSONObject jsonObject = JSONObject.parseObject(value);
+        try {
+                if (!StringUtils.isNullOrEmpty(keyWords)) {
+                    for (String tuple2 : keyWords) {
+                        String[] split = tuple2.split("_");
+                        String num = split[0];
+                        String station = split[1].trim();
+                        String name = split[2].trim();
+                        String appType = split[3].trim();
+                        if(jsonObject.containsKey(name.split("-")[0].trim())){
+                            JSONObject json = JSONObject.parseObject(jsonObject.getString(name.split("-")[0].trim()));
+                            json.put("num",num);
+                            json.put("station",station);
+                            json.put("name",name);
+                            json.put("appType",appType);
+                            collector.collect(new Tuple2<>((num+"_"+station+"_"+name+"_"+appType),json.toString()));
+                        }else {
+                            System.out.println("没有该设备数据:" + tuple2);
+                        }
+                    }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.out.println("解析该设备数据失败");
+        }
+    }
+
+    @Override
+    public void processBroadcastElement(Map<String, List<String>> map, Context ctx, Collector<Tuple2<String,String>> out) throws Exception {
+        try {
+            if (!StringUtils.isNullOrEmpty(map)) {
+                List<String> keyWords = map.get("keyWords");
+                if (!StringUtils.isNullOrEmpty(keyWords)) {
+                    this.keyWords = keyWords;
+                } else {
+                    System.out.println("查询数据库为空");
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 35 - 0
src/main/java/com/sunwin/metro/process/ErrorMetersProcess.java

@@ -0,0 +1,35 @@
+package com.sunwin.metro.process;
+
+import org.apache.flink.api.java.tuple.Tuple2;
+import org.apache.flink.streaming.api.functions.ProcessFunction;
+import org.apache.flink.util.Collector;
+import org.apache.flink.util.OutputTag;
+
+/**
+ * @program: sunwin_metro
+ * @description: 过滤异常仪表号 (DI属性值异常)
+ * @author: xuYJ
+ * @create: 2021-04-25 15:43
+ **/
+public class ErrorMetersProcess extends ProcessFunction<Tuple2<String, String>, Tuple2<String, String>> {
+    private final OutputTag<Tuple2<String, String>> errorMeter;
+
+    public ErrorMetersProcess(OutputTag<Tuple2<String, String>> errorMeter) {
+        this.errorMeter = errorMeter;
+    }
+
+    @Override
+    public void processElement(Tuple2<String, String> tuple4, Context context, Collector<Tuple2<String, String>> collector) throws Exception {
+        try {
+            if (tuple4.f1.contains("true")) {
+                context.output(errorMeter, tuple4);
+            } else {
+                String[] s = tuple4.f0.split("_");
+                String[] split = s[s.length - 2].split("-");
+                collector.collect(new Tuple2<>(split[0],tuple4.f1));
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+    }

+ 139 - 0
src/main/java/com/sunwin/metro/process/PrometheusProcess.java

@@ -0,0 +1,139 @@
+package com.sunwin.metro.process;
+
+import com.alibaba.fastjson.JSONObject;
+import com.sunwin.metro.bean.*;
+import io.prometheus.client.CollectorRegistry;
+import io.prometheus.client.Gauge;
+import io.prometheus.client.exporter.PushGateway;
+import org.apache.flink.api.java.tuple.Tuple2;
+import org.apache.flink.configuration.Configuration;
+import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
+import org.apache.flink.util.Collector;
+
+import java.io.IOException;
+
+/**
+ * @program: sunwin_metro
+ * @description: 数据发送到Prometheus
+ * @author: xuYJ
+ * @create: 2021-12-01 15:48
+ **/
+public class PrometheusProcess extends KeyedProcessFunction<String, Tuple2<String, String>, String> {
+    private PushGateway gateway;
+
+    @Override
+    public void open(Configuration parameters) throws Exception {
+        super.open(parameters);
+        gateway = new PushGateway("192.168.20.65:9091");
+        System.out.println("开启发送Prometheus客户端");
+    }
+
+    @Override
+    public void close() throws Exception {
+        super.close();
+    }
+
+    @Override
+    public void processElement(Tuple2<String, String> value, Context ctx, Collector<String> out) throws Exception {
+        String[] result = value.f0.split("_");
+        try {
+            CollectorRegistry pushRegistry = new CollectorRegistry();
+            if (value.f1.contains("隧道风机")) {
+                BasTefMes basTefMes = JSONObject.parseObject(value.f1, BasTefMes.class);
+                Gauge valueToExpose = Gauge.build()
+                        .name("BAS_TEF_AI_COMM_WORD")
+                        .help("电池总电压")
+                        .register(pushRegistry);
+                Gauge valueToExpose2 = Gauge.build()
+                        .name("BAS_TEF_AI_FAXLET")
+                        .help("前轴温度反馈")
+                        .register(pushRegistry);
+                Gauge valueToExpose3 = Gauge.build()
+                        .name("BAS_TEF_AI_Y_VIBR")
+                        .help("Y轴振动值")
+                        .register(pushRegistry);
+                valueToExpose.set(basTefMes.getAi_comm_word());
+                valueToExpose2.set(basTefMes.getAi_faxlet());
+                valueToExpose3.set(basTefMes.getAi_y_vibr());
+            }
+            if (value.f1.contains("排热风机")) {
+                BasTvfMes basTvfMes = JSONObject.parseObject(value.f1, BasTvfMes.class);
+                Gauge valueToExpose = Gauge.build()
+                        .name("BAS_TVF_AI_X_VIBR")
+                        .help("X轴振动值")
+                        .register(pushRegistry);
+                Gauge valueToExpose2 = Gauge.build()
+                        .name("BAS_TEF_Ai_FAXLET")
+                        .help("前轴温度反馈")
+                        .register(pushRegistry);
+                Gauge valueToExpose3 = Gauge.build()
+                        .name("BAS_TVF_AI_Y_VIBR")
+                        .help("Y轴振动值")
+                        .register(pushRegistry);
+                valueToExpose.set(basTvfMes.getAi_x_vibr());
+                valueToExpose2.set(basTvfMes.getAi_faxlet());
+                valueToExpose3.set(basTvfMes.getAi_y_vibr());
+            }
+            if (value.f1.contains("不间断电源")) {
+                UpsMes ups = JSONObject.parseObject(value.f1, UpsMes.class);
+                Gauge valueToExpose = Gauge.build()
+                        .name("UPS_AI_DP29")
+                        .help("电池电压")
+                        .register(pushRegistry);
+                Gauge valueToExpose2 = Gauge.build()
+                        .name("UPS_AI_DP32")
+                        .help("充放电电流")
+                        .register(pushRegistry);
+                Gauge valueToExpose3 = Gauge.build()
+                        .name("UPS_AI_DP36")
+                        .help("输出频率")
+                        .register(pushRegistry);
+                valueToExpose.set(ups.getDp29());
+                valueToExpose2.set(ups.getDp32());
+                valueToExpose3.set(ups.getDp36());
+            }
+            if (value.f1.contains("ups巡检仪")) {
+                UpsXjyMes upsXyj = JSONObject.parseObject(value.f1, UpsXjyMes.class);
+                Gauge valueToExpose = Gauge.build()
+                        .name("UPS_XJY_AI_WD")
+                        .help("环境温度")
+                        .register(pushRegistry);
+                Gauge valueToExpose2 = Gauge.build()
+                        .name("UPS_XJY_AI_ZDL")
+                        .help("组电流")
+                        .register(pushRegistry);
+                Gauge valueToExpose3 = Gauge.build()
+                        .name("UPS_XJY_AI_ZDY")
+                        .help("组电压")
+                        .register(pushRegistry);
+                valueToExpose.set(upsXyj.getWd());
+                valueToExpose2.set(upsXyj.getZdl());
+                valueToExpose3.set(upsXyj.getZdy());
+            }
+            if (value.f1.contains("雨水泵")) {
+                BasAtMes basAt = JSONObject.parseObject(value.f1, BasAtMes.class);
+                Gauge valueToExpose = Gauge.build()
+                        .name("BAS_AT_AI_LR")
+                        .help("实时水位测量")
+                        .register(pushRegistry);
+                Gauge valueToExpose2 = Gauge.build()
+                        .name("BAS_AT_AI_FLTNO")
+                        .help("故障次数")
+                        .register(pushRegistry);
+                valueToExpose.set(basAt.getAi_lr());
+                valueToExpose2.set(basAt.getAi_fltno());
+            }
+            //利用网关采集数据
+            gateway.pushAdd(pushRegistry, result[0] +"_"+  result[1] + "站台_" + result[2] + "设备监控数据");
+            out.collect(result[0] +"_"+  result[1] + "站台_" + result[2] + "设备监控数据发送到Prometheus");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    public static void main(String[] args) throws IOException {
+        PushGateway pushGateway = new PushGateway("192.168.20.65:9091");
+        pushGateway.delete("2号线_高铁站站台");
+    }
+}

+ 289 - 0
src/main/java/com/sunwin/metro/source/CreateMetroMes.java

@@ -0,0 +1,289 @@
+package com.sunwin.metro.source;
+
+import com.alibaba.fastjson.JSONObject;
+import com.sunwin.metro.bean.*;
+import com.sunwin.metro.utils.DateUtils;
+import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import static com.sunwin.metro.utils.StringUtils.m2;
+
+/**
+ * @program: sunwin_metro
+ * @description: 模拟生成设备数据源
+ * @author: xuYJ
+ * @create: 2021-12-01 15:32
+ **/
+public class CreateMetroMes extends RichSourceFunction<String> {
+    public static int getMinute(Date date) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        return calendar.get(Calendar.MINUTE);
+    }
+
+    @Override
+    public void run(SourceContext<String> ctx) throws Exception {
+
+        //生成固定变化值
+        BasTefMes basTefMes = new BasTefMes();
+        basTefMes.setAi_comm_word(m2(220 + Math.random() * 10));
+        basTefMes.setAi_faxlet(m2(80 + Math.random() * 10));
+        basTefMes.setAi_y_vibr(m2(20 + Math.random() * 5));
+        basTefMes.setDi_commokst(false);
+        basTefMes.setDi_vfflt(false);
+
+        BasTvfMes basTvfMes = new BasTvfMes();
+        basTvfMes.setAi_x_vibr(m2(20 + Math.random() * 5));
+        basTvfMes.setAi_faxlet(m2(80 + Math.random() * 10));
+        basTvfMes.setAi_y_vibr(m2(20 + Math.random() * 5));
+        basTvfMes.setDi_vfflt(false);
+        basTvfMes.setDi_commokst(false);
+
+        UpsMes upsMes = new UpsMes();
+        upsMes.setDp36(m2(100 + Math.random() * 5));
+        upsMes.setDp32(m2(20 + Math.random() * 3));
+        upsMes.setDp29(m2(380 + Math.random() * 10));
+        upsMes.setDp23(false);
+        upsMes.setDp30(false);
+
+
+        UpsXjyMes upsMesXyj = new UpsXjyMes();
+        upsMesXyj.setWd(m2(60 + Math.random() * 2));
+        upsMesXyj.setZdl(m2(20 + Math.random() * 2));
+        upsMesXyj.setZdy(m2(380 + Math.random() * 2));
+
+
+        BasAtMes basAtMes = new BasAtMes();
+        basAtMes.setAi_fltno(10 + (int) (Math.random() * 2));
+        basAtMes.setAi_lr(m2(1000 + Math.random() * 5));
+        basAtMes.setDi_commokst(false);
+        basAtMes.setDi_m0vl1(false);
+
+        int one = 0;
+        int two = 0;
+        int three = 0;
+        int four = 0;
+
+        while (true) {
+            int minute = getMinute(new Date());
+            //生成6/9个点 随机 向上/向下
+            if (minute % 5 == 0) {
+                if (one < 6) {
+                    //6点连续向上
+                    System.out.println("6点连续向上");
+                    JSONObject jsonObject = new JSONObject();
+                    basTefMes.setAi_comm_word(m2(basTefMes.getAi_comm_word() + Math.random() * 10));
+                    basTefMes.setAi_faxlet(m2(basTefMes.getAi_faxlet() + Math.random() * 10));
+                    basTefMes.setAi_y_vibr(m2(basTefMes.getAi_y_vibr() + Math.random() * 5));
+                    basTefMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    basTefMes.setEventTime(new Date());
+                    jsonObject.put("隧道风机", JSONObject.toJSONString(basTefMes));
+                    basTvfMes.setAi_x_vibr(m2(basTvfMes.getAi_x_vibr() + Math.random() * 5));
+                    basTvfMes.setAi_faxlet(m2(basTvfMes.getAi_faxlet() + Math.random() * 10));
+                    basTvfMes.setAi_y_vibr(m2(basTvfMes.getAi_y_vibr() + Math.random() * 5));
+                    basTvfMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    basTvfMes.setEventTime(new Date());
+                    jsonObject.put("排热风机", JSONObject.toJSONString(basTvfMes));
+                    upsMes.setDp36(m2(upsMes.getDp36() + Math.random() * 5));
+                    upsMes.setDp32(m2(upsMes.getDp32() + Math.random() * 3));
+                    upsMes.setDp29(m2(upsMes.getDp29() + Math.random() * 10));
+                    upsMes.setEventTime(new Date());
+                    upsMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("不间断电源", JSONObject.toJSONString(upsMes));
+                    upsMesXyj.setWd(m2(upsMesXyj.getWd() + Math.random() * 5));
+                    upsMesXyj.setZdl(m2(upsMesXyj.getZdl() + Math.random() * 3));
+                    upsMesXyj.setZdy(m2(upsMesXyj.getZdy() + Math.random() * 10));
+                    upsMesXyj.setEventTime(new Date());
+                    upsMesXyj.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("ups巡检仪", JSONObject.toJSONString(upsMesXyj));
+                    basAtMes.setAi_fltno(basAtMes.getAi_fltno() + (int) (Math.random() * 10));
+                    basAtMes.setAi_lr(m2(basAtMes.getAi_lr() + Math.random() * 10));
+                    basAtMes.setEventTime(new Date());
+                    basAtMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("雨水泵", JSONObject.toJSONString(basAtMes));
+                    ctx.collect(jsonObject.toString());
+                    one++;
+                }
+                Thread.sleep(20000L);
+            } else if (minute % 6 == 0) {
+                if (two < 9) {
+                    //9点连续向下
+                    System.out.println("9点连续向下");
+                    JSONObject jsonObject = new JSONObject();
+                    basTefMes.setAi_comm_word(m2(basTefMes.getAi_comm_word() - Math.random() * 10));
+                    basTefMes.setAi_faxlet(m2(basTefMes.getAi_faxlet() - Math.random() * 10));
+                    basTefMes.setAi_y_vibr(m2(basTefMes.getAi_y_vibr() - Math.random() * 5));
+                    basTefMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    basTefMes.setEventTime(new Date());
+                    jsonObject.put("隧道风机", JSONObject.toJSONString(basTefMes));
+                    basTvfMes.setAi_x_vibr(m2(basTvfMes.getAi_x_vibr() - Math.random() * 5));
+                    basTvfMes.setAi_faxlet(m2(basTvfMes.getAi_faxlet() - Math.random() * 10));
+                    basTvfMes.setAi_y_vibr(m2(basTvfMes.getAi_y_vibr() - Math.random() * 5));
+                    basTvfMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    basTvfMes.setEventTime(new Date());
+                    jsonObject.put("排热风机", JSONObject.toJSONString(basTvfMes));
+                    upsMes.setDp36(m2(upsMes.getDp36() - Math.random() * 5));
+                    upsMes.setDp32(m2(upsMes.getDp32() - Math.random() * 3));
+                    upsMes.setDp29(m2(upsMes.getDp29() - Math.random() * 10));
+                    upsMes.setEventTime(new Date());
+                    upsMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("不间断电源", JSONObject.toJSONString(upsMes));
+                    upsMesXyj.setWd(m2(upsMesXyj.getWd() - Math.random() * 5));
+                    upsMesXyj.setZdl(m2(upsMesXyj.getZdl() - Math.random() * 3));
+                    upsMesXyj.setZdy(m2(upsMesXyj.getZdy() - Math.random() * 10));
+                    upsMesXyj.setEventTime(new Date());
+                    upsMesXyj.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("ups巡检仪", JSONObject.toJSONString(upsMesXyj));
+                    basAtMes.setAi_fltno(basAtMes.getAi_fltno() - (int) (Math.random() * 10));
+                    basAtMes.setAi_lr(m2(basAtMes.getAi_lr() - Math.random() * 10));
+                    basAtMes.setEventTime(new Date());
+                    basAtMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("雨水泵", JSONObject.toJSONString(basAtMes));
+                    two++;
+                    ctx.collect(jsonObject.toString());
+                }
+                Thread.sleep(20000L);
+            } else if (minute % 7 == 0) {
+                if (three < 9) {
+                    //9点连续向上
+                    System.out.println("9点连续向上");
+                    JSONObject jsonObject = new JSONObject();
+                    basTefMes.setAi_comm_word(m2(basTefMes.getAi_comm_word() + Math.random() * 10));
+                    basTefMes.setAi_faxlet(m2(basTefMes.getAi_faxlet() + Math.random() * 10));
+                    basTefMes.setAi_y_vibr(m2(basTefMes.getAi_y_vibr() + Math.random() * 5));
+                    basTefMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    basTefMes.setEventTime(new Date());
+                    jsonObject.put("隧道风机", JSONObject.toJSONString(basTefMes));
+                    basTvfMes.setAi_x_vibr(m2(basTvfMes.getAi_x_vibr() + Math.random() * 5));
+                    basTvfMes.setAi_faxlet(m2(basTvfMes.getAi_faxlet() + Math.random() * 10));
+                    basTvfMes.setAi_y_vibr(m2(basTvfMes.getAi_y_vibr() + Math.random() * 5));
+                    basTvfMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    basTvfMes.setEventTime(new Date());
+                    jsonObject.put("排热风机", JSONObject.toJSONString(basTvfMes));
+                    upsMes.setDp36(m2(upsMes.getDp36() + Math.random() * 5));
+                    upsMes.setDp32(m2(upsMes.getDp32() + Math.random() * 3));
+                    upsMes.setDp29(m2(upsMes.getDp29() + Math.random() * 10));
+                    upsMes.setEventTime(new Date());
+                    upsMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("不间断电源", JSONObject.toJSONString(upsMes));
+                    upsMesXyj.setWd(m2(upsMesXyj.getWd() + Math.random() * 5));
+                    upsMesXyj.setZdl(m2(upsMesXyj.getZdl() + Math.random() * 3));
+                    upsMesXyj.setZdy(m2(upsMesXyj.getZdy() + Math.random() * 10));
+                    upsMesXyj.setEventTime(new Date());
+                    upsMesXyj.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("ups巡检仪", JSONObject.toJSONString(upsMesXyj));
+                    basAtMes.setAi_fltno(basAtMes.getAi_fltno() + (int) (Math.random() * 10));
+                    basAtMes.setAi_lr(m2(basAtMes.getAi_lr() + Math.random() * 10));
+                    basAtMes.setEventTime(new Date());
+                    basAtMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("雨水泵", JSONObject.toJSONString(basAtMes));
+                    ctx.collect(jsonObject.toString());
+                    three++;
+                }
+                Thread.sleep(20000L);
+            } else if (minute % 8 == 0) {
+                if (four < 6) {
+                    //6点连续向下
+                    System.out.println("6点连续向下");
+                    JSONObject jsonObject = new JSONObject();
+                    basTefMes.setAi_comm_word(m2(basTefMes.getAi_comm_word() - Math.random() * 10));
+                    basTefMes.setAi_faxlet(m2(basTefMes.getAi_faxlet() - Math.random() * 10));
+                    basTefMes.setAi_y_vibr(m2(basTefMes.getAi_y_vibr() - Math.random() * 5));
+                    basTefMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    basTefMes.setEventTime(new Date());
+                    jsonObject.put("隧道风机", JSONObject.toJSONString(basTefMes));
+                    basTvfMes.setAi_x_vibr(m2(basTvfMes.getAi_x_vibr() - Math.random() * 5));
+                    basTvfMes.setAi_faxlet(m2(basTvfMes.getAi_faxlet() - Math.random() * 10));
+                    basTvfMes.setAi_y_vibr(m2(basTvfMes.getAi_y_vibr() - Math.random() * 5));
+                    basTvfMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    basTvfMes.setEventTime(new Date());
+                    jsonObject.put("排热风机", JSONObject.toJSONString(basTvfMes));
+                    upsMes.setDp36(m2(upsMes.getDp36() - Math.random() * 5));
+                    upsMes.setDp32(m2(upsMes.getDp32() - Math.random() * 3));
+                    upsMes.setDp29(m2(upsMes.getDp29() - Math.random() * 10));
+                    upsMes.setEventTime(new Date());
+                    upsMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("不间断电源", JSONObject.toJSONString(upsMes));
+                    upsMesXyj.setWd(m2(upsMesXyj.getWd() - Math.random() * 5));
+                    upsMesXyj.setZdl(m2(upsMesXyj.getZdl() - Math.random() * 3));
+                    upsMesXyj.setZdy(m2(upsMesXyj.getZdy() - Math.random() * 10));
+                    upsMesXyj.setEventTime(new Date());
+                    upsMesXyj.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("ups巡检仪", JSONObject.toJSONString(upsMesXyj));
+                    basAtMes.setAi_fltno(basAtMes.getAi_fltno() - (int) (Math.random() * 10));
+                    basAtMes.setAi_lr(m2(basAtMes.getAi_lr() - Math.random() * 10));
+                    basAtMes.setEventTime(new Date());
+                    basAtMes.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                    jsonObject.put("雨水泵", JSONObject.toJSONString(basAtMes));
+                    four++;
+                    ctx.collect(jsonObject.toString());
+                }
+                Thread.sleep(20000L);
+            } else {
+                //System.out.println("生成随机值");
+                //生成随机值
+                JSONObject jsonObject = new JSONObject();
+                //生成区间隧道风机
+                BasTefMes basTefMes2 = new BasTefMes();
+                basTefMes2.setAi_comm_word(m2(220 + Math.random() * 10));
+                basTefMes2.setAi_faxlet(m2(80 + Math.random() * 10));
+                basTefMes2.setAi_y_vibr(m2(20 + Math.random() * 5));
+                basTefMes2.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                basTefMes2.setDi_commokst(Math.random() * 100 > 98);
+                basTefMes2.setDi_vfflt(Math.random() * 100 > 98);
+                basTefMes2.setEventTime(new Date());
+                jsonObject.put("隧道风机", JSONObject.toJSONString(basTefMes2));
+                //生成排热风机
+                BasTvfMes basTvfMes2 = new BasTvfMes();
+                basTvfMes2.setAi_x_vibr(m2(20 + Math.random() * 5));
+                basTvfMes2.setAi_faxlet(m2(80 + Math.random() * 10));
+                basTvfMes2.setAi_y_vibr(m2(20 + Math.random() * 5));
+                basTvfMes2.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                basTvfMes2.setDi_vfflt(Math.random() * 100 > 98);
+                basTvfMes2.setDi_commokst(Math.random() * 100 > 98);
+                basTvfMes2.setEventTime(new Date());
+                jsonObject.put("排热风机", JSONObject.toJSONString(basTvfMes2));
+                //生成ups
+                UpsMes upsMes2 = new UpsMes();
+                upsMes2.setDp36(m2(100 + Math.random() * 5));
+                upsMes2.setDp32(m2(20 + Math.random() * 3));
+                upsMes2.setDp29(m2(380 + Math.random() * 10));
+                upsMes2.setDp23(Math.random() * 100 > 98);
+                upsMes2.setDp30(Math.random() * 100 > 98);
+                upsMes2.setEventTime(new Date());
+                upsMes2.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                jsonObject.put("不间断电源", JSONObject.toJSONString(upsMes2));
+                //生成ups巡检仪
+                UpsXjyMes upsMesXyj2 = new UpsXjyMes();
+                upsMesXyj2.setWd(m2(60 + Math.random() * 5));
+                upsMesXyj2.setZdl(m2(20 + Math.random() * 3));
+                upsMesXyj2.setZdy(m2(380 + Math.random() * 10));
+                upsMesXyj2.setEventTime(new Date());
+                upsMesXyj2.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                jsonObject.put("ups巡检仪", JSONObject.toJSONString(upsMesXyj2));
+                //生成雨水泵
+                BasAtMes basAtMes2 = new BasAtMes();
+                basAtMes2.setAi_fltno(10 + (int) (Math.random() * 10));
+                basAtMes2.setAi_lr(m2(1000 + Math.random() * 10));
+                basAtMes2.setDi_commokst(Math.random() * 100 > 98);
+                basAtMes2.setDi_m0vl1(Math.random() * 100 > 98);
+                basAtMes2.setEventTime(new Date());
+                basAtMes2.setTime(DateUtils.dateToLongStringNoSep(new Date()));
+                jsonObject.put("雨水泵", JSONObject.toJSONString(basAtMes2));
+                ctx.collect(jsonObject.toString());
+                one = 0;
+                two = 0;
+                three = 0;
+                four = 0;
+                Thread.sleep(20000L);
+            }
+        }
+    }
+
+    @Override
+    public void cancel() {
+
+    }
+}

+ 95 - 0
src/main/java/com/sunwin/metro/source/MetroSubSource.java

@@ -0,0 +1,95 @@
+package com.sunwin.metro.source;
+
+import com.sunwin.metro.utils.MysqlUtil;
+import com.sunwin.metro.utils.StringUtils;
+import lombok.SneakyThrows;
+import org.apache.flink.configuration.Configuration;
+import org.apache.flink.streaming.api.functions.source.RichSourceFunction;
+import pro.husk.mysql.MySQL;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+/**
+ * @program: sunwin_metro
+ * @description: 从mysql读取设备名,用来模拟设备数据
+ * @author: xuYJ
+ * @create: 2021-12-01 15:26
+ **/
+public class MetroSubSource extends RichSourceFunction<Map<String, List<String>>> {
+    private volatile boolean isRunning = true;
+    private MySQL sql;
+
+    @Override
+    public void open(Configuration parameters) throws Exception {
+        super.open(parameters);
+        sql = MysqlUtil.getProMeter();
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (null != sql) {
+            sql.closeConnection();
+        }
+        super.close();
+    }
+
+    @Override
+    public void run(SourceContext<Map<String, List<String>>> ctx) throws Exception {
+        while (isRunning) {
+            Map<String, List<String>> keyWords = new HashMap<>(16);
+            try {
+                //从Mysql数据库获取配置
+                List<String> list = new ArrayList<>();
+                // Execute query
+                try (ResultSet results = sql.query("select tl.line_name as sub_name,  \n" +
+                        "                       ts.station_name as sub_station, \n" +
+                        "                         concat(te.name,'-',t.equipment_id) as sub_metro,  \n" +
+                        "                       ta.id as app_code \n" +
+                        "                       from t_equipment t \n" +
+                        "                      LEFT JOIN t_equipment_type te on t.equipment_type = te.id \n" +
+                        "                        LEFT JOIN t_station ts on t.station_id = ts.id\n" +
+                        "                       LEFT JOIN t_line tl on tl.id = ts.line_id\n" +
+                        "                      LEFT JOIN t_application ta on ta.id = t.app_id")) {
+                    while (results.next()) {
+                        String numSource = results.getString("sub_name");
+                        String station = results.getString("sub_station");
+                        String metro = results.getString("sub_metro");
+                        String appType = results.getString("app_code");
+                        list.add(numSource + "_" + station + "_" + metro+"_"+appType);
+                    }
+                    results.getStatement().close();
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                }
+                //解析规则与业务逻辑相关请忽略
+                if (!StringUtils.isNullOrEmpty(list)) {
+                    keyWords.put("keyWords", list);
+                    //输出规则流
+                    ctx.collect(keyWords);
+                }
+            } catch (Exception e) {
+                System.out.println("连接mysql模拟设备库异常");
+                e.printStackTrace();
+                sql = MysqlUtil.getProMeter2();
+            }
+            //线程睡眠(半个小时刷新一次mysql)
+            Thread.sleep(5000L);
+        }
+    }
+
+    @SneakyThrows
+    @Override
+    public void cancel() {
+        isRunning = false;
+        if (null != sql) {
+            sql.closeConnection();
+        }
+    }
+}

+ 79 - 0
src/main/java/com/sunwin/metro/utils/DataType.java

@@ -0,0 +1,79 @@
+package com.sunwin.metro.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @program: data_governance
+ * @description: 判断某个值的基本类型
+ * @author: xuYJ
+ * @create: 2022-02-18 15:14
+ **/
+public class DataType {
+    public static Map<String, String> getType(Object o) {
+        Map<String, String> typeInfo = new HashMap<String, String>();
+        typeInfo.put("类型", o.getClass().getSimpleName());
+        typeInfo.put("描述", "引用类型");
+        return typeInfo;
+    }
+
+    public static Map<String, String> getType(int i) {
+        Map<String, String> typeInfo = new HashMap<String, String>();
+        typeInfo.put("类型", "int");
+        typeInfo.put("描述", "整形");
+        return typeInfo;
+    }
+
+    public static Map<String, String> getType(long l) {
+        Map<String, String> typeInfo = new HashMap<String, String>();
+        typeInfo.put("类型", "long");
+        typeInfo.put("描述", "长整型");
+        return typeInfo;
+    }
+
+    public static Map<String, String> getType(boolean b) {
+        Map<String, String> typeInfo = new HashMap<String, String>();
+        typeInfo.put("类型", "boolean");
+        typeInfo.put("描述", "布尔类型");
+        return typeInfo;
+    }
+
+    public static Map<String, String> getType(char b) {
+        Map<String, String> typeInfo = new HashMap<String, String>();
+        typeInfo.put("类型", "char");
+        typeInfo.put("描述", "字符");
+        return typeInfo;
+    }
+
+    public static Map<String, String> getType(float f) {
+        Map<String, String> typeInfo = new HashMap<String, String>();
+        typeInfo.put("类型", "float");
+        typeInfo.put("描述", "单精度浮点型");
+        return typeInfo;
+    }
+
+    public static Map<String, String> getType(double d) {
+        Map<String, String> typeInfo = new HashMap<String, String>();
+        typeInfo.put("类型", "double");
+        typeInfo.put("描述", "双精度浮点型");
+        return typeInfo;
+    }
+
+    public static Map<String, String> getType(String s) {
+        Map<String, String> typeInfo = new HashMap<String, String>();
+        typeInfo.put("类型", "String");
+        typeInfo.put("描述", "字符串类型");
+        return typeInfo;
+    }
+
+    public static void main(String[] args) {
+
+        JSONObject jsonObject = new JSONObject();
+
+        Map<String, String> type = getType(jsonObject.get("1"));
+        System.out.println("type = " + type);
+    }
+}

+ 54 - 0
src/main/java/com/sunwin/metro/utils/DateUtils.java

@@ -0,0 +1,54 @@
+package com.sunwin.metro.utils;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+
+/**
+ * jdk要求最低1.8
+ * @author kane
+ * @date 2019/12/4 18:02
+ */
+public class DateUtils {
+
+
+    /**
+     * 将date转化成yyyyMMddHHmmss的字符串
+     * @param date 日期
+     * @return String
+     * @author kane
+     * @date 2017-4-13 下午4:37:03
+     */
+    public static String dateToLongStringNoSep(Date date) {
+        return dateToStringWithFormat(date, "yyyyMMddHHmmss");
+    }
+
+
+    /**
+     * 将Date转换成指定日期格式的字符串
+     * @param date   日期
+     * @param format 日期格式
+     * @return 字符串
+     * @author kane
+     * @date 2017-4-6 下午2:47:48
+     */
+    public static String dateToStringWithFormat(Date date, String format) {
+        String str = "";
+        if (date == null || format == null || format.length() == 0) {
+            return str;
+        }
+        try {
+            str = new SimpleDateFormat(format).format(date);
+        } catch (Exception ignored) {
+        }
+        return str;
+    }
+
+
+
+
+
+
+}

+ 64 - 0
src/main/java/com/sunwin/metro/utils/DeletePush.java

@@ -0,0 +1,64 @@
+package com.sunwin.metro.utils;
+
+import io.prometheus.client.exporter.PushGateway;
+import org.apache.flink.api.common.state.MapState;
+import org.apache.flink.api.common.state.MapStateDescriptor;
+import org.apache.flink.api.common.typeinfo.TypeInformation;
+import org.apache.flink.configuration.Configuration;
+import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
+import org.apache.flink.util.Collector;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+/**
+ * @program: test_prometheus
+ * @description: 删除pushaway节点
+ * @author: xuYJ
+ * @create: 2022-01-25 09:30
+ **/
+public class DeletePush extends KeyedProcessFunction<String, Map<String, List<String>>, String> {
+    private transient MapState<String, String> mapState;
+    private PushGateway gateway;
+    @Override
+    public void open(Configuration parameters) throws Exception {
+        MapStateDescriptor<String, String> descriptor = new MapStateDescriptor<>("mapState", TypeInformation.of(String.class), TypeInformation.of(String.class));
+        mapState = getRuntimeContext().getMapState(descriptor);
+        gateway = new PushGateway("192.168.20.65:9091");
+        System.out.println("生成 gateway 客户端 ");
+        super.open(parameters);
+        super.open(parameters);
+    }
+
+    @Override
+    public void close() throws Exception {
+        super.close();
+    }
+
+    @Override
+    public void processElement(Map<String, List<String>> value, Context ctx, Collector<String> out) throws Exception {
+        ArrayList<String> list = new ArrayList<>();
+        mapState.keys().forEach(new Consumer<String>() {
+            @Override
+            public void accept(String s) {
+                list.add(s);
+            }
+        });
+        List<String> keyWords = value.get("keyWords");
+        for (String keywords : value.get("keyWords")) {
+            if(!list.contains(keywords)){
+                mapState.put(keywords,"1");
+            }
+        }
+        List<String> collect = list.stream().filter(item -> !keyWords.contains(item)).collect(Collectors.toList());
+        for (String s : collect) {
+            String[] result = s.split("_");
+            gateway.delete(result[0] + "_" + result[1] + "站台_" + result[2] + "设备监控数据");
+            mapState.remove(s);
+            out.collect("删除job :" + result[0] + "_" + result[1] + "站台_" + result[2] + "设备监控数据");
+        }
+    }
+}

+ 55 - 0
src/main/java/com/sunwin/metro/utils/Md5Util.java

@@ -0,0 +1,55 @@
+package com.sunwin.metro.utils;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+
+/**
+ * @author kane
+ */
+public class Md5Util {
+    private static MessageDigest md5 = null;
+
+    static {
+        try {
+            md5 = MessageDigest.getInstance("MD5");
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+    }
+
+    public static String getMd5(String str) {
+        byte[] bs = null;
+        synchronized (md5) {
+            bs = md5.digest(str.getBytes());
+        }
+        StringBuilder sb = new StringBuilder();
+        for (byte x : bs) {
+            if ((x & 0xff) >> 4 == 0) {
+                sb.append("0").append(Integer.toHexString(x & 0xff));
+            } else {
+                sb.append(Integer.toHexString(x & 0xff));
+            }
+        }
+        return sb.toString();
+    }
+
+    public static String MD5(String str) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] array = md.digest(str.getBytes(StandardCharsets.UTF_8));
+            StringBuilder sb = new StringBuilder();
+            for (byte b : array) {
+                sb.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);
+            }
+            return sb.toString();
+        } catch (java.security.NoSuchAlgorithmException ignored) {
+        }
+        return null;
+    }
+
+    public static void main(String[] args) {
+        System.out.println(getMd5("aaaa"));
+        System.out.println(MD5("aaaa"));
+        System.out.println(MD5("1234"));
+    }
+}

+ 19 - 0
src/main/java/com/sunwin/metro/utils/MeterKey.java

@@ -0,0 +1,19 @@
+package com.sunwin.metro.utils;
+
+import org.apache.flink.api.java.functions.KeySelector;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @program: test_prometheus
+ * @description: 根据keyword分组
+ * @author: xuYJ
+ * @create: 2022-01-25 09:28
+ **/
+public class MeterKey implements KeySelector<Map<String, List<String>>, String> {
+    @Override
+    public String getKey(Map<String, List<String>> value) throws Exception {
+        return value.keySet().toString();
+    }
+}

+ 104 - 0
src/main/java/com/sunwin/metro/utils/MysqlUtil.java

@@ -0,0 +1,104 @@
+package com.sunwin.metro.utils;
+
+import org.apache.commons.dbcp2.BasicDataSource;
+import pro.husk.mysql.MySQL;
+
+import java.sql.Connection;
+
+/**
+ * @program: sunwin_metro
+ * @description: mysql工具类
+ * @author: xuYJ
+ * @create: 2022-01-14 08:42
+ **/
+public class MysqlUtil {
+
+    private static Connection con;
+    private static MySQL sql3;
+
+    static {
+        BasicDataSource dataSource = new BasicDataSource();
+        dataSource.setDriverClassName("org.postgresql.Driver");
+        dataSource.setUrl("jdbc:postgresql://192.168.20.72:5432/urtmpdb?characterEncoding=utf-8&serverTimezone=UTC");
+        dataSource.setUsername("postgres");
+        dataSource.setPassword("sw12345");
+        dataSource.setMaxWaitMillis(1000 * 60 * 10);
+        dataSource.setInitialSize(10);
+        dataSource.setMaxTotal(50);
+        dataSource.setMinIdle(2);
+        try {
+            con = dataSource.getConnection();
+            System.out.println("创建连接池:" + con);
+            con.setAutoCommit(false);
+        } catch (Exception e) {
+            System.out.println("-----------mysql get connection has exception , msg = " + e.getMessage());
+        }
+        sql3 = new MySQL("jdbc:postgresql://192.168.20.72:5432/urtmpdb?characterEncoding=utf-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=UTC&rewriteBatchedStatements=true",
+                "postgres",
+                "sw12345");
+
+
+    }
+
+    /**
+     * 获取postgres数据库链接
+     */
+    public static Connection getCon() {
+        if (null == con) {
+            BasicDataSource dataSource = new BasicDataSource();
+            dataSource.setDriverClassName("org.postgresql.Driver");
+            dataSource.setUrl("jdbc:postgresql://192.168.20.72:5432/urtmpdb?characterEncoding=utf-8&serverTimezone=UTC");
+            dataSource.setUsername("postgres");
+            dataSource.setPassword("sw12345");
+            dataSource.setMaxWaitMillis(1000 * 60 * 10);
+            dataSource.setInitialSize(10);
+            dataSource.setMaxTotal(50);
+            dataSource.setMinIdle(2);
+            try {
+                con = dataSource.getConnection();
+                System.out.println("异常后重新创建连接池:" + con);
+                con.setAutoCommit(false);
+            } catch (Exception e) {
+                System.out.println("-----------mysql get connection has exception , msg = " + e.getMessage());
+            }
+        }
+        return con;
+    }
+
+    public static Connection getCon2() {
+        BasicDataSource dataSource = new BasicDataSource();
+        dataSource.setDriverClassName("org.postgresql.Driver");
+        dataSource.setUrl("jdbc:postgresql://192.168.20.72:5432/urtmpdb?characterEncoding=utf-8&serverTimezone=UTC");
+        dataSource.setUsername("postgres");
+        dataSource.setPassword("sw12345");
+        dataSource.setMaxWaitMillis(1000 * 60 * 10);
+        dataSource.setInitialSize(10);
+        dataSource.setMaxTotal(50);
+        dataSource.setMinIdle(2);
+        try {
+            con = dataSource.getConnection();
+            System.out.println("异常后重新创建连接池:" + con);
+            con.setAutoCommit(false);
+        } catch (Exception e) {
+            System.out.println("-----------mysql get connection has exception , msg = " + e.getMessage());
+        }
+        return con;
+    }
+
+
+    public static MySQL getProMeter() {
+        if (null == sql3) {
+            sql3 = new MySQL("jdbc:postgresql://192.168.20.72:5432/urtmpdb?characterEncoding=utf-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=UTC&rewriteBatchedStatements=true",
+                    "postgres",
+                    "sw12345");
+        }
+        return sql3;
+    }
+
+    public static MySQL getProMeter2() {
+        sql3 = new MySQL("jdbc:postgresql://192.168.20.72:5432/urtmpdb?characterEncoding=utf-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=UTC&rewriteBatchedStatements=true",
+                "postgres",
+                "sw12345");
+        return sql3;
+    }
+}

+ 53 - 0
src/main/java/com/sunwin/metro/utils/StringUtils.java

@@ -0,0 +1,53 @@
+package com.sunwin.metro.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.text.DecimalFormat;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 字符串工具类
+ *
+ * @author tanghui
+ * @date 2019/12/4 17:52
+ */
+public class StringUtils {
+
+
+    /**
+     * 判断object是否为空,或者转换成字符串( String.valueOf(object))是否为空字符串
+     *
+     * @param object Object对象
+     * @author tanghui
+     * @date 2019-08-28 14:52
+     **/
+    public static boolean isNullOrEmpty(Object object) {
+        return object == null || String.valueOf(object).trim().length() == 0;
+    }
+
+    /**
+     * 判断集合是否是null值或没有元素
+     *
+     * @param collection 继承collection的类
+     * @return boolean
+     */
+    public static boolean isNullOrEmpty(Collection<?> collection) {
+        return collection == null || collection.size() == 0;
+    }
+
+
+    /**
+     * DecimalFormat转换最简便
+     */
+    public static Double m2(Double input) {
+        DecimalFormat df = new DecimalFormat("#.00");
+        return Double.parseDouble(df.format(input));
+    }
+
+
+    public static void main(String[] args) {
+    }
+
+
+}

+ 12 - 0
src/main/resources/rule.stg

@@ -0,0 +1,12 @@
+sqlTemplate(ruleId,expression,class,level)
+::= <<
+package rule_10001
+import com.sunwin.metro.bean.<class>
+rule "<ruleId>"
+     when
+           $pAlarm : <class>( <expression> )
+     then
+            //用insert返回值
+            $pAlarm.setFlag($pAlarm.getFlag()+"<ruleId>"+"/");
+end
+>>

+ 52 - 0
src/test/java/test/Test.java

@@ -0,0 +1,52 @@
+package test;
+
+import com.alibaba.fastjson.JSONObject;
+import com.sunwin.metro.utils.MysqlUtil;
+import org.apache.flink.api.java.tuple.Tuple2;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * @program: data_governance-no-cdc
+ * @description:
+ * @author: xuYJ
+ * @create: 2022-03-24 16:00
+ **/
+public class Test {
+    public static void main(String[] args) throws InterruptedException, SQLException {
+        Connection connection = MysqlUtil.getCon();
+        PreparedStatement pStatement;
+        while (true) {
+            pStatement = connection.prepareStatement("SELECT * FROM t_data_rule ;");
+            try {
+                ResultSet results = pStatement.executeQuery();
+                while (results.next()) {
+                    JSONObject jsonObject = new JSONObject();
+                    String ruleId = String.valueOf(results.getInt("id"));
+                    jsonObject.put("rule_id", ruleId);
+                    jsonObject.put("model", results.getString("target_name"));
+                    jsonObject.put("type", results.getString("equipment_type_code"));
+                    jsonObject.put("mes", results.getString("expr"));
+                    jsonObject.put("create_time", results.getDate("update_time"));
+                    jsonObject.put("flag", results.getInt("flag"));
+                    System.out.println("jsonObject = " + jsonObject);
+                }
+            } catch (SQLException e) {
+                System.out.println("mysql连接异常1: " + e);
+                e.printStackTrace();
+                if (pStatement != null) {
+                    pStatement.close();
+                }
+                if (connection != null) {
+                    connection.close();
+                }
+                connection = MysqlUtil.getCon();
+            }
+            Thread.sleep(5000L);
+
+        }
+    }
+}