├── .gitignore ├── LICENSE ├── README.md ├── iot-dc-beans ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── theembers │ └── iot │ ├── GlobalInfo.java │ ├── IotInfo.java │ ├── ItemInfo.java │ ├── ModbusInfo.java │ ├── RTUChannelInfo.java │ ├── RTUCommandInfo.java │ ├── RTUInfo.java │ ├── config │ ├── RabbitMQConfig.java │ └── RedisConfig.java │ └── enums │ ├── EMqExchange.java │ └── ERTUChannelFlag.java ├── iot-dc-netty-server ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── theembers │ │ └── iot │ │ ├── Application.java │ │ ├── NettyCollectorRunner.java │ │ ├── TheEmbersBanner.java │ │ ├── collector │ │ └── NettyCollector.java │ │ ├── config │ │ └── NettyConfig.java │ │ ├── kafka │ │ ├── Consumer.java │ │ └── Producer.java │ │ ├── mq │ │ ├── MQSender.java │ │ └── MqListener.java │ │ ├── netty │ │ ├── PortListenerAbstract.java │ │ ├── RTUPortListener.java │ │ ├── channelhandler │ │ │ ├── ChannelManagerHandler.java │ │ │ ├── CommandHandler.java │ │ │ ├── ExceptionHandler.java │ │ │ ├── HeartBeatHandler.java │ │ │ ├── KafkaHandler.java │ │ │ ├── MqHandler.java │ │ │ └── ProcessorHandler.java │ │ └── processor │ │ │ ├── DisplayDataProcessor.java │ │ │ ├── IDataProcessor.java │ │ │ ├── IR485DataProcessor.java │ │ │ ├── ProcessorAbstract.java │ │ │ ├── R485DataProcessor.java │ │ │ ├── SimDataProcessor.java │ │ │ └── SysDataProcessor.java │ │ ├── redis │ │ ├── IoTService.java │ │ └── RedisService.java │ │ └── utils │ │ ├── ByteUtils.java │ │ ├── CRCUtils.java │ │ ├── JsonUtils.java │ │ └── KeyUtils.java │ └── resources │ └── application.yml ├── iot-example ├── pom.xml └── src │ └── main │ └── java │ └── me │ └── theembers │ └── iot │ ├── TestCollector.java │ ├── TestRouter.java │ ├── bean │ ├── IotMsgData.java │ ├── TestAppData.java │ └── TestIotData.java │ ├── bizprocessor │ ├── Test2Processor.java │ └── TestProcessor.java │ ├── rule │ └── CacheRule.java │ └── shadow │ ├── Device.java │ ├── IotShadow.java │ └── Product.java ├── iot-framework-dc ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── theembers │ └── iot │ ├── collector │ ├── AbstractCollectorRunner.java │ ├── CollectorRunner.java │ ├── DataCollector.java │ ├── DataCollectorConfig.java │ └── SourceData.java │ ├── processor │ ├── AbstractProcessor.java │ ├── Input.java │ ├── InputData.java │ ├── Output.java │ ├── OutputData.java │ ├── Processor.java │ ├── Slot.java │ ├── SlotData.java │ ├── SortData.java │ └── ThingData.java │ ├── router │ ├── AbstractRouter.java │ ├── DefaultRouter.java │ ├── Router.java │ ├── route │ │ ├── AbstractRoute.java │ │ ├── Dispatcher.java │ │ ├── LinkedRoute.java │ │ ├── MultipleRoute.java │ │ ├── Route.java │ │ └── SimpleRoute.java │ ├── rule │ │ ├── LinkedRule.java │ │ ├── MultipleRule.java │ │ ├── Rule.java │ │ └── SimpleRule.java │ └── selector │ │ ├── AbstractSelector.java │ │ ├── AutoSelector.java │ │ ├── DefaultSelector.java │ │ └── Selector.java │ └── shadow │ ├── DeviceShadow.java │ ├── DeviceShadowSnapshot.java │ ├── ProductShadow.java │ └── Shadow.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ 26 | 27 | .gitkeep -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://img.shields.io/github/license/Theembers/iot-dc) 2 | ![](https://img.shields.io/badge/%E4%B8%AD%E5%9B%BD%E5%8A%A0%E6%B2%B9%20%E6%AD%A6%E6%B1%89%E5%8A%A0%E6%B2%B9-%E4%B8%BA%E6%B0%91%E8%80%8C%E7%94%9F%E4%B8%8E%E6%B0%91%E5%85%B1%E7%94%9F%20%E4%BC%97%E5%BF%97%E6%88%90%E5%9F%8E%E5%85%B1%E5%85%8B%E6%97%B6%E8%89%B0%20-red) 3 | ## IoT-DC framework 4 | 5 | > a IoT data collector framework and power by springboot+netty+rabbitmq/kafka 6 | > 7 | > 一个基于 springboot+netty+rabbitmq 实现的 物联网设备(IoT) 数据接入的项目 8 | 9 | > **src**: https://github.com/Theembers/iot-dc 10 | > 11 | > **thanks for star! :) ⭐⭐⭐⭐⭐** 12 | 13 | the obsolete version (branch:s-0.1) will be not update yet (except bug fix), the master will be rebuild as new one. thanks follow! 14 | 15 | 旧版本以封版(分支s-0.1)不再更新(除了bug修改),master 分支将启用新的设计,敬请期待! 16 | 17 | [branch:s-0.1](https://github.com/Theembers/iot-dc/tree/s-0.1) 18 | 19 | 🎉 new framework had be done! you can running with `iot-example`-`me.theembers.iot.TestCollector` to debug it. 20 | 21 | 🎉 新版本框架已基本完成!可以通过 `iot-example`-`me.theembers.iot.TestCollector` 运行调试。 22 | 23 | ## IoT platform framework (IoT平台总体架构设计) 24 | 25 | ![设备总体接入架构](https://image-1257148187.cos.ap-chengdu.myqcloud.com/picgo_img/20190926173357.jpg) 26 | 27 | ## about the new IoT-DC Framework (关于新版 IoT-DC Framework) 28 | 29 | 抽离了netty的实现逻辑,保留了基础框架 30 | 31 | - iot-framework-dc 抽象了基础的接入逻辑模型。如下图: 32 | 33 | ![iot-framework-dc 模型](https://image-1257148187.cos.ap-chengdu.myqcloud.com/picgo_img/20191111134357.jpg) 34 | 35 | - router 模型 & device shadow 模型 36 | 37 | 路由器 (router),把接入的数据分发到符合规则 (rule) 的处理器 (processor) 中进行处理。 38 | 39 | ![router 模型](https://image-1257148187.cos.ap-chengdu.myqcloud.com/picgo_img/20191111131757.jpg) 40 | 41 | - processor-link 模型 42 | 43 | router 通过选择器 (Selector) 选择出的导航 (Route) 维护了一个调度者 (Dispatcher) 调度者负责管理被使用的 processor链 以及 processor 的调用 规则: 44 | 45 | ![processor-link 模型](https://image-1257148187.cos.ap-chengdu.myqcloud.com/picgo_img/processor-link-1.jpg) 46 | 47 | ```java 48 | /** 49 | * 执行 50 | * 如果 当前processor是头节点,调用 headIn ( 调用 beforeTransform & transForm) 51 | * 否则 (中间节点 或者 尾节点) 调用 receive(接收) 52 | * 最终 如果 是尾结点 则 调用 tailOut (调用 afterTransform) 并 退出循环 53 | * 到 //1 则 调用 buildSlotData (构建插槽) 54 | * 55 | * @param shadow 56 | * @param sourceData 57 | */ 58 | void run(Shadow shadow, SourceData sourceData) { 59 | Output output = null; 60 | SlotData slotData = null; 61 | Iterator processors = this.link.iterator(); 62 | while (processors.hasNext()) { 63 | Processor p = processors.next(); 64 | if (p == getFirst()) { 65 | output = p.headIn(shadow, sourceData); 66 | } else { 67 | output = p.receive(shadow, slotData); 68 | } 69 | if (p == getLast()) { 70 | output = p.tailOut(shadow, output); 71 | return; 72 | } 73 | slotData = p.passOn(shadow, output); // 1 74 | } 75 | } 76 | ``` 77 | 78 | - iot-dc-netty-server 是之前的netty实现,目前(2019-11-07)只是迁移了老模块的代码,后期会修改结构,所以暂不做架构说明。新分支侧着架构设计,所以具体实现可能要延后实现。 79 | 80 | -------------------------------------------------------------------------------- /iot-dc-beans/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | iot-dc 7 | com.theembers.iot 8 | 1.0-SNAPSHOT 9 | ../pom.xml 10 | 11 | 4.0.0 12 | 13 | iot-dc-beans 14 | 15 | 16 | -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/GlobalInfo.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot; 2 | 3 | import io.netty.channel.ChannelId; 4 | 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | /** 9 | * @author TheEmbers Guo 10 | * @version 1.0 11 | * createTime 2018-11-08 14:19 12 | */ 13 | public class GlobalInfo { 14 | 15 | public static String Global_Iot_Redis_Key; 16 | 17 | /** 18 | * 全局 物联网设备映射 19 | */ 20 | public static Map iotMapper; 21 | /** 22 | * 全局 netty channel 管理器 23 | * map{channelId, channelinfo} 24 | */ 25 | public static final Map CHANNEL_INFO_MAP = new ConcurrentHashMap<>(); 26 | 27 | /** 28 | * 全局 netty channel 管理器 29 | * map{sn, channelinfo} 30 | */ 31 | public static final Map SN_CHANNEL_INFO_MAP = new ConcurrentHashMap<>(); 32 | } 33 | -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/IotInfo.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * @author TheEmbers Guo 7 | * @version 1.0 8 | * createTime 2018-10-29 10:29 9 | */ 10 | public class IotInfo { 11 | private String id; 12 | private Map data; 13 | 14 | public String getId() { 15 | return id; 16 | } 17 | 18 | public void setId(String id) { 19 | this.id = id; 20 | } 21 | 22 | public Map getData() { 23 | return data; 24 | } 25 | 26 | public void setData(Map data) { 27 | this.data = data; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "IotInfo{" + 33 | "id='" + id + '\'' + 34 | ", data=" + data + 35 | '}'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/ItemInfo.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot; 2 | 3 | /** 4 | * 指标信息 5 | * 6 | * @author TheEmbers Guo 7 | * @version 1.0 8 | * createTime 2018-10-22 10:54 9 | */ 10 | public class ItemInfo { 11 | /** 12 | * 指标 id 13 | */ 14 | private String id; 15 | /** 16 | * 值 17 | */ 18 | private String val; 19 | /** 20 | * 时间戳 21 | */ 22 | private Long time; 23 | 24 | 25 | 26 | public ItemInfo(String id, String val) { 27 | this(id, val, System.currentTimeMillis()); 28 | } 29 | 30 | public ItemInfo(String id, String val, Long time) { 31 | this.id = id; 32 | this.val = val; 33 | this.time = time; 34 | } 35 | 36 | 37 | public String getId() { 38 | return id; 39 | } 40 | 41 | public void setId(String id) { 42 | this.id = id; 43 | } 44 | 45 | public String getVal() { 46 | return val; 47 | } 48 | 49 | public void setVal(String val) { 50 | this.val = val; 51 | } 52 | 53 | public Long getTime() { 54 | return time; 55 | } 56 | 57 | public void setTime(Long time) { 58 | this.time = time; 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return "ItemInfo{" + 64 | "id='" + id + '\'' + 65 | ", val='" + val + '\'' + 66 | ", time=" + time + 67 | '}'; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/ModbusInfo.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * modbus 数据模型 9 | * 10 | * @author TheEmbers Guo 11 | * @version 1.0 12 | * createTime 2018-10-23 14:16 13 | */ 14 | public class ModbusInfo { 15 | private byte[] address; 16 | private byte[] command; 17 | private byte[] length; 18 | private byte[] data; 19 | private byte[] crc; 20 | private byte[] fullData; 21 | 22 | private ByteBuf source; 23 | 24 | { 25 | address = new byte[ModBusModel.ADDRESS_LEN.len]; 26 | command = new byte[ModBusModel.COMMAND_LEN.len]; 27 | length = new byte[ModBusModel.LENGTH_LEN.len]; 28 | crc = new byte[ModBusModel.CRC_LEN.len]; 29 | } 30 | 31 | public ModbusInfo(ByteBuf source) { 32 | this.source = source; 33 | this.data = new byte[source.readableBytes() - address.length - command.length - length.length - crc.length]; 34 | this.fullData = new byte[source.readableBytes() - crc.length]; 35 | 36 | this.source.readBytes(address) 37 | // command 38 | .readBytes(command) 39 | // length 40 | .readBytes(length) 41 | // data 42 | .readBytes(data) 43 | // crc 44 | .readBytes(crc); 45 | // fullData 46 | this.source.resetReaderIndex(); 47 | this.source.readBytes(fullData); 48 | 49 | } 50 | 51 | private enum ModBusModel { 52 | ADDRESS_LEN(1), 53 | COMMAND_LEN(1), 54 | LENGTH_LEN(1), 55 | CRC_LEN(2); 56 | 57 | int len; 58 | 59 | ModBusModel(int len) { 60 | this.len = len; 61 | } 62 | } 63 | 64 | public byte[] getAddress() { 65 | return address; 66 | } 67 | 68 | public byte[] getCommand() { 69 | return command; 70 | } 71 | 72 | public byte[] getLength() { 73 | return length; 74 | } 75 | 76 | public byte[] getData() { 77 | return data; 78 | } 79 | 80 | public byte[] getCrc() { 81 | return crc; 82 | } 83 | 84 | public byte[] getFullData() { 85 | return fullData; 86 | } 87 | 88 | @Override 89 | public String toString() { 90 | return "ModbusInfo{" + 91 | "address=" + Arrays.toString(address) + 92 | ", command=" + Arrays.toString(command) + 93 | ", length=" + Arrays.toString(length) + 94 | ", data=" + Arrays.toString(data) + 95 | ", crc=" + Arrays.toString(crc) + 96 | '}'; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/RTUChannelInfo.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot; 2 | 3 | import io.netty.channel.Channel; 4 | import io.netty.channel.ChannelId; 5 | 6 | /** 7 | * @author TheEmbers Guo 8 | * @version 1.0 9 | * createTime 2018-10-25 16:10 10 | */ 11 | public class RTUChannelInfo { 12 | private ChannelId channelId; 13 | private String sn; 14 | private IotInfo iotInfo; 15 | private Channel channel; 16 | 17 | public static RTUChannelInfo build(String sn, ChannelId channelId) { 18 | return new RTUChannelInfo(sn, channelId); 19 | } 20 | 21 | private RTUChannelInfo(String sn, ChannelId channelId) { 22 | this.channelId = channelId; 23 | this.sn = sn; 24 | } 25 | 26 | public ChannelId getChannelId() { 27 | return channelId; 28 | } 29 | 30 | public RTUChannelInfo setChannelId(ChannelId channelId) { 31 | this.channelId = channelId; 32 | return this; 33 | } 34 | 35 | public String getSn() { 36 | return sn; 37 | } 38 | 39 | public RTUChannelInfo setSn(String sn) { 40 | this.sn = sn; 41 | return this; 42 | } 43 | 44 | public Channel getChannel() { 45 | return channel; 46 | } 47 | 48 | public RTUChannelInfo setChannel(Channel channel) { 49 | this.channel = channel; 50 | return this; 51 | } 52 | 53 | public IotInfo getIotInfo() { 54 | return iotInfo; 55 | } 56 | 57 | public RTUChannelInfo setIotInfo(IotInfo iotInfo) { 58 | this.iotInfo = iotInfo; 59 | return this; 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return "RTUChannelInfo{" + 65 | "channelId=" + channelId + 66 | ", sn='" + sn + '\'' + 67 | ", iotInfo=" + iotInfo + 68 | ", channel=" + channel + 69 | '}'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/RTUCommandInfo.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * @version 1.0 6 | * createTime 2018-11-09 14:41 7 | */ 8 | public class RTUCommandInfo { 9 | private String id; 10 | private String sn; 11 | private String instruction; 12 | private int instructionType; 13 | private String tid; 14 | 15 | public String getId() { 16 | return id; 17 | } 18 | 19 | public void setId(String id) { 20 | this.id = id; 21 | } 22 | 23 | public String getSn() { 24 | return sn; 25 | } 26 | 27 | public void setSn(String sn) { 28 | this.sn = sn; 29 | } 30 | 31 | public String getInstruction() { 32 | return instruction; 33 | } 34 | 35 | public void setInstruction(String instruction) { 36 | this.instruction = instruction; 37 | } 38 | 39 | public int getInstructionType() { 40 | return instructionType; 41 | } 42 | 43 | public void setInstructionType(int instructionType) { 44 | this.instructionType = instructionType; 45 | } 46 | 47 | public String getTid() { 48 | return tid; 49 | } 50 | 51 | public void setTid(String tid) { 52 | this.tid = tid; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "RTUCommandInfo{" + 58 | "id='" + id + '\'' + 59 | ", sn='" + sn + '\'' + 60 | ", instruction='" + instruction + '\'' + 61 | ", instructionType=" + instructionType + 62 | ", tid='" + tid + '\'' + 63 | '}'; 64 | } 65 | 66 | public enum EInstructionType { 67 | JSON(1), 68 | HEX(2); 69 | 70 | int type; 71 | 72 | EInstructionType(int type) { 73 | this.type = type; 74 | } 75 | 76 | public int getType() { 77 | return type; 78 | } 79 | 80 | public void setType(int type) { 81 | this.type = type; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/RTUInfo.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnore; 4 | import com.theembers.iot.enums.EMqExchange; 5 | 6 | import java.util.Arrays; 7 | 8 | /** 9 | * netty 对象 10 | * 11 | * @author TheEmbers Guo 12 | * @version 1.0 13 | * createTime 2018-10-22 10:53 14 | */ 15 | public class RTUInfo { 16 | /** 17 | * 物联网id 18 | */ 19 | private String id; 20 | 21 | @JsonIgnore 22 | private String sn; 23 | /** 24 | * 指标信息 25 | */ 26 | private T data; 27 | 28 | /** 29 | * 是否发布 30 | */ 31 | @JsonIgnore 32 | private boolean publish; 33 | /** 34 | * 消息队列标示 35 | */ 36 | @JsonIgnore 37 | private EMqExchange[] mqExchange; 38 | 39 | 40 | public RTUInfo(String id) { 41 | this.id = id; 42 | this.publish = true; 43 | } 44 | 45 | public String getId() { 46 | return id; 47 | } 48 | 49 | public void setId(String id) { 50 | this.id = id; 51 | } 52 | 53 | public String getSn() { 54 | return sn; 55 | } 56 | 57 | public void setSn(String sn) { 58 | this.sn = sn; 59 | } 60 | 61 | public T getData() { 62 | return data; 63 | } 64 | 65 | public void setData(T data) { 66 | this.data = data; 67 | } 68 | 69 | public boolean isPublish() { 70 | return publish; 71 | } 72 | 73 | public void setPublish(boolean publish) { 74 | this.publish = publish; 75 | } 76 | 77 | public EMqExchange[] getMqExchange() { 78 | return mqExchange; 79 | } 80 | 81 | public void setMqExchange(EMqExchange[] mqExchange) { 82 | this.mqExchange = mqExchange; 83 | } 84 | 85 | @Override 86 | public String toString() { 87 | return "RTUInfo{" + 88 | "id='" + id + '\'' + 89 | ", sn='" + sn + '\'' + 90 | ", data=" + data + 91 | ", publish=" + publish + 92 | ", mqExchange=" + Arrays.toString(mqExchange) + 93 | '}'; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/config/RabbitMQConfig.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.config; 2 | 3 | import com.theembers.iot.enums.EMqExchange; 4 | import org.springframework.amqp.core.FanoutExchange; 5 | import org.springframework.amqp.core.Queue; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | /** 10 | * @author TheEmbers Guo 11 | * @version 1.0 12 | * createTime 2018-11-05 16:29 13 | */ 14 | @Configuration 15 | public class RabbitMQConfig { 16 | @Bean 17 | FanoutExchange fanoutExchange() { 18 | return new FanoutExchange(EMqExchange.RTU_DATA.getMqFanoutExchange()); 19 | } 20 | 21 | @Bean 22 | FanoutExchange fanoutExchange1() { 23 | return new FanoutExchange(EMqExchange.RTU_HEART.getMqFanoutExchange()); 24 | } 25 | 26 | @Bean 27 | FanoutExchange fanoutExchange2() { 28 | return new FanoutExchange(EMqExchange.RTU_SIGNAL.getMqFanoutExchange()); 29 | } 30 | 31 | @Bean 32 | FanoutExchange fanoutExchange3() { 33 | return new FanoutExchange(EMqExchange.RTU_UNREGISTERED.getMqFanoutExchange()); 34 | } 35 | 36 | @Bean 37 | public Queue instQueue() { 38 | return new Queue("rtu_inst_queue", true); 39 | } 40 | @Bean 41 | public Queue refreshQueue() { 42 | return new Queue("rtu_refresh_queue", true); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/config/RedisConfig.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.config; 2 | 3 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 4 | import com.fasterxml.jackson.annotation.PropertyAccessor; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.data.redis.connection.RedisConnectionFactory; 9 | import org.springframework.data.redis.core.RedisTemplate; 10 | import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 11 | import org.springframework.data.redis.serializer.StringRedisSerializer; 12 | 13 | @Configuration 14 | public class RedisConfig { 15 | 16 | @Bean 17 | public RedisTemplate redisTemplate(RedisConnectionFactory factory) { 18 | 19 | RedisTemplate redisTemplate = new RedisTemplate<>(); 20 | redisTemplate.setConnectionFactory(factory); 21 | 22 | Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class); 23 | 24 | ObjectMapper om = new ObjectMapper(); 25 | om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 26 | om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 27 | jacksonSeial.setObjectMapper(om); 28 | 29 | StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); 30 | redisTemplate.setValueSerializer(jacksonSeial); 31 | redisTemplate.setKeySerializer(stringRedisSerializer); 32 | 33 | redisTemplate.setHashKeySerializer(stringRedisSerializer); 34 | redisTemplate.setHashValueSerializer(jacksonSeial); 35 | 36 | redisTemplate.afterPropertiesSet(); 37 | return redisTemplate; 38 | } 39 | 40 | 41 | 42 | 43 | } -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/enums/EMqExchange.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.enums; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * @version 1.0 6 | * createTime 2018-11-05 16:04 7 | */ 8 | public enum EMqExchange { 9 | RTU_SIGNAL("rtu_signal_fx"), 10 | RTU_HEART("rtu_heart_fx"), 11 | RTU_DATA("rtu_data_fx"), 12 | RTU_UNREGISTERED("rtu_unregistered_fx"), 13 | RTU_INSTRUCTION_EXCHANGE("rtu-instruction-exchange"); 14 | private String mqFanoutExchange; 15 | 16 | EMqExchange(String mqFanoutExchange) { 17 | this.mqFanoutExchange = mqFanoutExchange; 18 | } 19 | 20 | public String getMqFanoutExchange() { 21 | return mqFanoutExchange; 22 | } 23 | 24 | public void setMqFanoutExchange(String mqFanoutExchange) { 25 | this.mqFanoutExchange = mqFanoutExchange; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /iot-dc-beans/src/main/java/com/theembers/iot/enums/ERTUChannelFlag.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.enums; 2 | 3 | /** 4 | * RTU 通道标记 5 | * 6 | * @author TheEmbers Guo 7 | * @version 1.0 8 | * createTime 2018-10-22 13:14 9 | */ 10 | public enum ERTUChannelFlag { 11 | SYS("0#".getBytes()), 12 | DISPLAY("1#".getBytes()), 13 | R485("2#".getBytes()), 14 | R232("3#".getBytes()), 15 | SIM("4#".getBytes()); 16 | 17 | 18 | private byte[] flag; 19 | 20 | ERTUChannelFlag(byte[] flag) { 21 | this.flag = flag; 22 | } 23 | 24 | public byte[] getFlag() { 25 | return flag; 26 | } 27 | 28 | public void setFlag(byte[] flag) { 29 | this.flag = flag; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /iot-dc-netty-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | iot-dc 7 | com.theembers.iot 8 | 1.0-SNAPSHOT 9 | ../pom.xml 10 | 11 | 4.0.0 12 | 13 | iot-dc-netty-server 14 | 15 | 16 | 17 | com.theembers.iot 18 | iot-framework-dc 19 | 20 | 21 | com.theembers.iot 22 | iot-dc-beans 23 | 24 | 25 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/Application.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot; 2 | 3 | import org.springframework.boot.Banner; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | 7 | /** 8 | * @author TheEmbers Guo 9 | * createTime 2019-11-07 13:45 10 | */ 11 | @SpringBootApplication(scanBasePackages = "com.theembers.iot") 12 | public class Application { 13 | public static void main(String[] args) { 14 | new SpringApplicationBuilder() 15 | .banner(new TheEmbersBanner()) 16 | .bannerMode(Banner.Mode.LOG) 17 | .sources(Application.class) 18 | .run(args); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/NettyCollectorRunner.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot; 2 | 3 | import com.theembers.iot.collector.AbstractCollectorRunner; 4 | import com.theembers.iot.collector.DataCollector; 5 | import com.theembers.iot.config.NettyConfig; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * 基于 netty 实现的采集器执行者 11 | * 也就是之前s-0.1这的netty实现方案 12 | * 13 | * @author TheEmbers Guo 14 | * createTime 2019-11-06 14:46 15 | */ 16 | @Component 17 | public class NettyCollectorRunner extends AbstractCollectorRunner { 18 | @Autowired 19 | private NettyConfig nettyConfig; 20 | @Autowired 21 | private DataCollector collector; 22 | 23 | @Override 24 | public NettyConfig setCollectorConfig() { 25 | return nettyConfig; 26 | } 27 | 28 | @Override 29 | public DataCollector setDataCollector() { 30 | return collector; 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/TheEmbersBanner.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot; 2 | 3 | import org.springframework.boot.Banner; 4 | import org.springframework.boot.ansi.AnsiOutput; 5 | import org.springframework.core.env.Environment; 6 | 7 | import java.io.PrintStream; 8 | 9 | import static org.springframework.boot.ansi.AnsiColor.BRIGHT_BLUE; 10 | import static org.springframework.boot.ansi.AnsiColor.BRIGHT_YELLOW; 11 | 12 | /** 13 | * @author TheEmbers Guo 14 | * createTime 2019-08-01 13:59 15 | */ 16 | public class TheEmbersBanner implements Banner { 17 | @Override 18 | public void printBanner(Environment environment, Class sourceClass, PrintStream out) { 19 | for (String line : BANNER) { 20 | out.println(AnsiOutput.toString(BRIGHT_BLUE, line)); 21 | } 22 | 23 | String version = Banner.class.getPackage().getImplementationVersion(); 24 | version = (version == null ? "" : " (v" + version + ")..."); 25 | out.println(AnsiOutput.toString(BRIGHT_YELLOW, SPRING_BOOT, version)); 26 | out.println(); 27 | } 28 | private static final String SPRING_BOOT = " :: Spring Boot Version :: "; 29 | private static final String[] BANNER = { 30 | "\n" + 31 | " _______ _ ______ _ \n" + 32 | " |__ __| | | ____| | | \n" + 33 | " | | | |__ ___| |__ _ __ ___ | |__ ___ _ __ ___ \n" + 34 | " | | | '_ \\ / _ \\ __| | '_ ` _ \\| '_ \\ / _ \\ '__/ __|\n" + 35 | " | | | | | | __/ |____| | | | | | |_) | __/ | \\__ \\\n" + 36 | " |_| |_| |_|\\___|______|_| |_| |_|_.__/ \\___|_| |___/\n" + 37 | " \n" 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/collector/NettyCollector.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.collector; 2 | 3 | import com.theembers.iot.config.NettyConfig; 4 | import com.theembers.iot.netty.RTUPortListener; 5 | import com.theembers.iot.redis.IoTService; 6 | import io.netty.channel.EventLoopGroup; 7 | import io.netty.channel.nio.NioEventLoopGroup; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.net.InetAddress; 14 | 15 | /** 16 | * netty实现的执行器 17 | * 18 | * @author TheEmbers Guo 19 | * createTime 2019-11-06 17:52 20 | */ 21 | @Component 22 | public class NettyCollector implements DataCollector { 23 | private static final Logger LOGGER = LoggerFactory.getLogger(NettyCollector.class); 24 | private static EventLoopGroup bossGroup = new NioEventLoopGroup(); 25 | private static EventLoopGroup workerGroup = new NioEventLoopGroup(); 26 | 27 | @Autowired 28 | private IoTService ioTService; 29 | 30 | @Override 31 | public void init() { 32 | 33 | } 34 | 35 | @Override 36 | public void executor(NettyConfig nettyConfig) { 37 | LOGGER.info("Netty Start.."); 38 | Integer port = nettyConfig.getPort(); 39 | if (port == null) { 40 | LOGGER.warn("port is empty."); 41 | return; 42 | } 43 | // 获取配置 44 | try { 45 | ioTService.loadIotMapper2Global(InetAddress.getLocalHost().getHostAddress(), port); 46 | new RTUPortListener(port, bossGroup, workerGroup); 47 | } catch (Exception e) { 48 | e.printStackTrace(); 49 | } 50 | 51 | } 52 | 53 | @Override 54 | public void dispatch() { 55 | 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/config/NettyConfig.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.config; 2 | 3 | 4 | import com.theembers.iot.collector.DataCollectorConfig; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | @ConfigurationProperties(prefix = "theembers.iot.netty") 10 | public class NettyConfig extends DataCollectorConfig { 11 | private Integer port; 12 | 13 | public Integer getPort() { 14 | return port; 15 | } 16 | 17 | public void setPort(Integer port) { 18 | this.port = port; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/kafka/Consumer.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.kafka; 2 | 3 | import com.theembers.iot.GlobalInfo; 4 | import com.theembers.iot.RTUCommandInfo; 5 | import com.theembers.iot.netty.channelhandler.ChannelManagerHandler; 6 | import com.theembers.iot.netty.channelhandler.CommandHandler; 7 | import com.theembers.iot.redis.IoTService; 8 | import com.theembers.iot.utils.JsonUtils; 9 | import org.apache.kafka.clients.consumer.ConsumerRecord; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.kafka.annotation.KafkaListener; 14 | import org.springframework.stereotype.Component; 15 | import org.springframework.util.StringUtils; 16 | 17 | /** 18 | * kafka 消费者 19 | * 20 | * @author TheEmbers Guo 21 | * createTime 2019-08-01 11:06 22 | */ 23 | //@Component 24 | public class Consumer { 25 | private static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class); 26 | 27 | @Autowired 28 | private IoTService ioTService; 29 | /** 30 | * 指令队列 31 | * 32 | * @param record 33 | * @throws Exception 34 | */ 35 | @KafkaListener(topics = "rtu_inst_topic") 36 | public void listen(ConsumerRecord record) throws Exception { 37 | String msg = new String(record.value()); 38 | LOGGER.info("rtu-command: {}", msg); 39 | RTUCommandInfo commandInfo = JsonUtils.jsonStr2Obj(msg, RTUCommandInfo.class); 40 | if (commandInfo == null || 41 | StringUtils.isEmpty(commandInfo.getSn()) || 42 | StringUtils.isEmpty(commandInfo.getInstruction()) || 43 | StringUtils.isEmpty(commandInfo.getInstructionType())) { 44 | LOGGER.warn("bad command: {}", commandInfo); 45 | return; 46 | } 47 | CommandHandler.writeCommand(commandInfo.getSn(), commandInfo.getInstruction(), commandInfo.getInstructionType()); 48 | } 49 | 50 | /** 51 | * 刷新 iot信息 52 | * 53 | * @param record 54 | * @throws Exception 55 | */ 56 | @KafkaListener(topics = "rtu_refresh_topic") 57 | public void refreshIotInfo(ConsumerRecord record) throws Exception { 58 | String msg = new String(record.value()); 59 | if (GlobalInfo.Global_Iot_Redis_Key.equals(msg)) { 60 | LOGGER.info("start refresh GlobalInfo, rtu_refresh key is : {}", msg); 61 | boolean flag = ioTService.refreshIotMapper2Global(); 62 | if (flag) { 63 | ChannelManagerHandler.refreshRTUChannelInfo(); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/kafka/Producer.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.kafka; 2 | 3 | import com.theembers.iot.enums.EMqExchange; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.kafka.core.KafkaTemplate; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.util.Arrays; 11 | 12 | /** 13 | * kafka 生产者 14 | * 15 | * @author TheEmbers Guo 16 | * createTime 2019-08-01 10:59 17 | */ 18 | //@Component 19 | public class Producer { 20 | private static final Logger LOGGER = LoggerFactory.getLogger(Producer.class); 21 | 22 | @Autowired 23 | private KafkaTemplate kafkaTemplate; 24 | 25 | public void send(EMqExchange[] mqExchange, String message) { 26 | if (mqExchange == null || mqExchange.length == 0) { 27 | return; 28 | } 29 | Arrays.asList(mqExchange).stream().forEach(eMqExchange -> { 30 | LOGGER.info("send -> {} -> {}", eMqExchange.name(), message); 31 | kafkaTemplate.send(eMqExchange.getMqFanoutExchange(), "", message.getBytes()); 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/mq/MQSender.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.mq; 2 | 3 | import com.theembers.iot.enums.EMqExchange; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.amqp.core.AmqpTemplate; 7 | import org.springframework.amqp.core.Message; 8 | import org.springframework.amqp.core.MessageBuilder; 9 | import org.springframework.amqp.core.MessageProperties; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.Arrays; 14 | 15 | /** 16 | * mq 17 | * 18 | * @author TheEmbers Guo 19 | * @version 1.0 20 | * createTime 2018-10-22 14:37 21 | */ 22 | //@Component 23 | public class MQSender { 24 | private static final Logger LOGGER = LoggerFactory.getLogger(MQSender.class); 25 | 26 | @Autowired 27 | private AmqpTemplate rabbitTemplate; 28 | 29 | public void send(EMqExchange[] mqExchange, String content) { 30 | Message message = MessageBuilder.withBody(content.getBytes()) 31 | .setContentType(MessageProperties.CONTENT_TYPE_JSON) 32 | .setContentEncoding("utf-8") 33 | .build(); 34 | if (mqExchange == null || mqExchange.length == 0) { 35 | return; 36 | } 37 | Arrays.asList(mqExchange).stream().forEach(eMqExchange -> { 38 | LOGGER.info("send -> {} -> {}", eMqExchange.name(), message); 39 | this.rabbitTemplate.convertAndSend(eMqExchange.getMqFanoutExchange(), "", message); 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/mq/MqListener.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.mq; 2 | 3 | import com.theembers.iot.GlobalInfo; 4 | import com.theembers.iot.RTUCommandInfo; 5 | import com.theembers.iot.netty.channelhandler.ChannelManagerHandler; 6 | import com.theembers.iot.netty.channelhandler.CommandHandler; 7 | import com.theembers.iot.redis.IoTService; 8 | import com.theembers.iot.utils.JsonUtils; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.amqp.core.Message; 12 | import org.springframework.amqp.rabbit.annotation.RabbitHandler; 13 | import org.springframework.amqp.rabbit.annotation.RabbitListener; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.stereotype.Component; 16 | import org.springframework.util.StringUtils; 17 | 18 | import java.io.IOException; 19 | 20 | /** 21 | * @author TheEmbers Guo 22 | * @version 1.0 23 | * createTime 2018-11-09 11:09 24 | */ 25 | //@Component 26 | public class MqListener { 27 | private static final Logger LOGGER = LoggerFactory.getLogger(MqListener.class); 28 | 29 | @Autowired 30 | private IoTService ioTService; 31 | 32 | /** 33 | * 指令队列 34 | * 35 | * @param message 36 | */ 37 | @RabbitListener(queues = "rtu_inst_queue") 38 | @RabbitHandler 39 | public void command(Message message) throws IOException { 40 | String msg = new String(message.getBody()); 41 | LOGGER.info("rtu-command: {}", msg); 42 | RTUCommandInfo commandInfo = JsonUtils.jsonStr2Obj(msg, RTUCommandInfo.class); 43 | if (commandInfo == null || 44 | StringUtils.isEmpty(commandInfo.getSn()) || 45 | StringUtils.isEmpty(commandInfo.getInstruction()) || 46 | StringUtils.isEmpty(commandInfo.getInstructionType())) { 47 | LOGGER.warn("bad command: {}", commandInfo); 48 | return; 49 | } 50 | CommandHandler.writeCommand(commandInfo.getSn(), commandInfo.getInstruction(), commandInfo.getInstructionType()); 51 | } 52 | 53 | /** 54 | * 刷新 iot信息 55 | * 56 | * @param message 57 | * @throws Exception 58 | */ 59 | @RabbitListener(queues = "rtu_refresh_queue") 60 | @RabbitHandler 61 | public void refreshIotInfo(Message message) throws Exception { 62 | String msg = new String(message.getBody()); 63 | if (GlobalInfo.Global_Iot_Redis_Key.equals(msg)) { 64 | LOGGER.info("start refresh GlobalInfo, rtu_refresh key is : {}", msg); 65 | boolean flag = ioTService.refreshIotMapper2Global(); 66 | if (flag) { 67 | ChannelManagerHandler.refreshRTUChannelInfo(); 68 | } 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/PortListenerAbstract.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty; 2 | 3 | 4 | import com.theembers.iot.netty.channelhandler.ChannelManagerHandler; 5 | import com.theembers.iot.netty.channelhandler.ExceptionHandler; 6 | import com.theembers.iot.netty.channelhandler.MqHandler; 7 | import io.netty.bootstrap.ServerBootstrap; 8 | import io.netty.channel.*; 9 | import io.netty.channel.socket.SocketChannel; 10 | import io.netty.channel.socket.nio.NioServerSocketChannel; 11 | import io.netty.handler.logging.LogLevel; 12 | import io.netty.handler.logging.LoggingHandler; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | /** 17 | * 端口监听 18 | * 19 | * @author TheEmbers Guo 20 | * @version 1.0 21 | * createTime 2018-09-30 1:54 PM 22 | */ 23 | abstract class PortListenerAbstract { 24 | private static final Logger LOGGER = LoggerFactory.getLogger(PortListenerAbstract.class); 25 | /** 26 | * 端口 27 | */ 28 | private int port; 29 | private EventLoopGroup bossGroup; 30 | private EventLoopGroup workerGroup; 31 | 32 | PortListenerAbstract(int port, EventLoopGroup bossGroup, EventLoopGroup workerGroup) { 33 | this.port = port; 34 | this.bossGroup = bossGroup; 35 | this.workerGroup = workerGroup; 36 | } 37 | 38 | /** 39 | * channelhandler 设置 抽象方法 40 | * 41 | * @return 42 | */ 43 | abstract ChannelHandler settingChannelInitializerHandler(); 44 | 45 | /** 46 | * 接口绑定 47 | */ 48 | void bind() { 49 | if (port == 0 || this.workerGroup == null || this.bossGroup == null) { 50 | throw new RuntimeException("'port','bossGroup' and 'workerGroup' had to be initialized before bind."); 51 | } 52 | 53 | try { 54 | ServerBootstrap bootstrap = new ServerBootstrap(); 55 | bootstrap.group(this.bossGroup, this.workerGroup) 56 | .channel(NioServerSocketChannel.class) 57 | .childHandler(this.settingChannelInitializerHandler()); 58 | ChannelFuture channelFuture = bootstrap.bind(this.port).sync(); 59 | LOGGER.info("port:{} bind successful.", port); 60 | channelFuture.channel().closeFuture().sync(); 61 | } catch (InterruptedException e) { 62 | e.printStackTrace(); 63 | } finally { 64 | bossGroup.shutdownGracefully(); 65 | workerGroup.shutdownGracefully(); 66 | } 67 | } 68 | 69 | /** 70 | * 基础 71 | */ 72 | abstract class BaseHandler extends ChannelInitializer { 73 | /** 74 | * 拓展 75 | * 76 | * @param pipeline 77 | * @return 78 | */ 79 | abstract ChannelPipeline extHandler(ChannelPipeline pipeline); 80 | 81 | @Override 82 | protected void initChannel(SocketChannel socketChannel) { 83 | ChannelPipeline pipeline = socketChannel.pipeline(); 84 | pipeline 85 | // log 86 | .addLast("logging", new LoggingHandler(LogLevel.INFO)) 87 | // 心跳检测 88 | // .addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS)) 89 | // .addLast(new HeartBeatHandler()) 90 | // 链路管理 91 | .addLast(new ChannelManagerHandler()) 92 | ; 93 | // 拓展 94 | extHandler(socketChannel.pipeline()); 95 | pipeline.addLast(new MqHandler()) 96 | // 异常管理 97 | .addLast(new ExceptionHandler()) 98 | ; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/RTUPortListener.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty; 2 | 3 | import com.theembers.iot.netty.channelhandler.CommandHandler; 4 | import com.theembers.iot.netty.channelhandler.ProcessorHandler; 5 | import io.netty.channel.ChannelHandler; 6 | import io.netty.channel.ChannelPipeline; 7 | import io.netty.channel.EventLoopGroup; 8 | import io.netty.handler.codec.LengthFieldBasedFrameDecoder; 9 | 10 | /** 11 | * RTU 接口监听器 12 | * 13 | * @author TheEmbers Guo 14 | * @version 1.0 15 | * createTime 2018-09-30 2:29 PM 16 | */ 17 | public class RTUPortListener extends PortListenerAbstract { 18 | public RTUPortListener(int port, EventLoopGroup bossGroup, EventLoopGroup workerGroup) { 19 | super(port, bossGroup, workerGroup); 20 | super.bind(); 21 | } 22 | 23 | @Override 24 | ChannelHandler settingChannelInitializerHandler() { 25 | return new ChildChannelHandler(); 26 | } 27 | 28 | private class ChildChannelHandler extends BaseHandler { 29 | @Override 30 | ChannelPipeline extHandler(ChannelPipeline pipeline) { 31 | pipeline 32 | // 数据拆帧 & 头信息过滤 33 | .addLast(new LengthFieldBasedFrameDecoder(10240, 2, 2, -4, 4, true)) 34 | // 数据封装 35 | .addLast(new ProcessorHandler()) 36 | // 指令下发 37 | .addFirst(new CommandHandler()) 38 | ; 39 | return pipeline; 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/channelhandler/ChannelManagerHandler.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.channelhandler; 2 | 3 | import com.theembers.iot.GlobalInfo; 4 | import com.theembers.iot.IotInfo; 5 | import com.theembers.iot.RTUChannelInfo; 6 | import io.netty.channel.ChannelHandler.Sharable; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.ChannelId; 9 | import io.netty.channel.ChannelInboundHandlerAdapter; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | /** 14 | * 链路管理 handler 15 | * 16 | * @author TheEmbers Guo 17 | * @version 1.0 18 | * createTime 2018-10-25 15:18 19 | */ 20 | @Sharable 21 | public class ChannelManagerHandler extends ChannelInboundHandlerAdapter { 22 | private static final Logger LOGGER = LoggerFactory.getLogger(ChannelManagerHandler.class); 23 | 24 | @Override 25 | public void channelRegistered(ChannelHandlerContext ctx) throws Exception { 26 | LOGGER.info("new channel coming! ----> {}", ctx.channel()); 27 | ChannelId channelId = ctx.channel().id(); 28 | RTUChannelInfo channelInfo = GlobalInfo.CHANNEL_INFO_MAP.getOrDefault(channelId, RTUChannelInfo.build("unknownSN", channelId)); 29 | GlobalInfo.CHANNEL_INFO_MAP.put(channelId, channelInfo); 30 | ctx.fireChannelRegistered(); 31 | } 32 | 33 | @Override 34 | public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { 35 | LOGGER.info("channel out! ----> {}", ctx.channel()); 36 | ChannelId channelId = ctx.channel().id(); 37 | RTUChannelInfo channelInfo = GlobalInfo.CHANNEL_INFO_MAP.remove(channelId); 38 | GlobalInfo.SN_CHANNEL_INFO_MAP.remove(channelInfo.getSn()); 39 | LOGGER.info("remove channel: {}", channelInfo); 40 | ctx.fireChannelUnregistered(); 41 | } 42 | 43 | /** 44 | * 补全 链路信息:根据 channelId 获取 channelInfo 并写入 sn 和 物联网信息 45 | * 46 | * @param ctx 47 | * @param sn 48 | * @return 49 | */ 50 | public static void setRTUChannelInfo(ChannelHandlerContext ctx, String sn) { 51 | ChannelId channelId = ctx.channel().id(); 52 | IotInfo iot = GlobalInfo.iotMapper.get(sn); 53 | GlobalInfo.CHANNEL_INFO_MAP.get(channelId) 54 | .setSn(sn).setIotInfo(iot).setChannel(ctx.channel()); 55 | 56 | RTUChannelInfo channelInfo = GlobalInfo.SN_CHANNEL_INFO_MAP.getOrDefault(sn, RTUChannelInfo.build(sn, channelId)); 57 | channelInfo.setIotInfo(iot).setChannel(ctx.channel()); 58 | GlobalInfo.SN_CHANNEL_INFO_MAP.put(sn, channelInfo); 59 | LOGGER.info("sn: {} in the house.", sn); 60 | } 61 | 62 | /** 63 | * 刷新 链路信息 64 | */ 65 | public static void refreshRTUChannelInfo() { 66 | LOGGER.info("refresh GlobalInfo..."); 67 | GlobalInfo.CHANNEL_INFO_MAP.forEach((channelId, channelInfo) -> { 68 | String sn = channelInfo.getSn(); 69 | channelInfo.setIotInfo(GlobalInfo.iotMapper.get(sn)); 70 | }); 71 | GlobalInfo.SN_CHANNEL_INFO_MAP.forEach((sn, channelInfo) -> channelInfo.setIotInfo(GlobalInfo.iotMapper.get(sn))); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/channelhandler/CommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.channelhandler; 2 | 3 | import com.theembers.iot.GlobalInfo; 4 | import com.theembers.iot.RTUCommandInfo; 5 | import com.theembers.iot.utils.ByteUtils; 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.buffer.Unpooled; 8 | import io.netty.channel.Channel; 9 | import io.netty.channel.ChannelFutureListener; 10 | import io.netty.channel.ChannelHandler.Sharable; 11 | import io.netty.channel.ChannelHandlerContext; 12 | import io.netty.handler.codec.MessageToByteEncoder; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | import org.springframework.util.CollectionUtils; 16 | 17 | /** 18 | * 指令下发 19 | * 20 | * @author TheEmbers Guo 21 | * @version 1.0 22 | * createTime 2018-11-09 13:35 23 | */ 24 | @Sharable 25 | public class CommandHandler extends MessageToByteEncoder { 26 | private static final Logger LOGGER = LoggerFactory.getLogger(CommandHandler.class); 27 | 28 | @Override 29 | protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception { 30 | out.writeBytes(msg); 31 | } 32 | 33 | public static void writeCommand(String sn, String command, int commandType) { 34 | if (CollectionUtils.isEmpty(GlobalInfo.SN_CHANNEL_INFO_MAP)) { 35 | LOGGER.warn("global snChannelInfo is empty."); 36 | return; 37 | } 38 | if (GlobalInfo.SN_CHANNEL_INFO_MAP.containsKey(sn)) { 39 | Channel channel = GlobalInfo.SN_CHANNEL_INFO_MAP.get(sn).getChannel(); 40 | LOGGER.info("\n command: ({}) \n type: ({}) \n sn: ({})", command, commandType, sn); 41 | 42 | ByteBuf byteBuf = Unpooled.buffer(); 43 | if (commandType == RTUCommandInfo.EInstructionType.JSON.getType()) { 44 | byteBuf.writeBytes(command.getBytes()); 45 | } else if (commandType == RTUCommandInfo.EInstructionType.HEX.getType()) { 46 | try { 47 | byteBuf.writeBytes(ByteUtils.hex2byte(command)); 48 | } catch (Exception e) { 49 | LOGGER.error("bad command to hex: {} ", command,e); 50 | return; 51 | } 52 | } 53 | 54 | channel.writeAndFlush(byteBuf).addListener((ChannelFutureListener) future -> { 55 | if (future.isSuccess()) { 56 | LOGGER.info("ok"); 57 | } else { 58 | LOGGER.error("send data to client exception occur: {}", future.cause()); 59 | } 60 | }); 61 | } else { 62 | LOGGER.warn("no channel in global channelInfo by this sn:{}", sn); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/channelhandler/ExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.channelhandler; 2 | 3 | import io.netty.channel.ChannelHandler.Sharable; 4 | import io.netty.channel.ChannelHandlerContext; 5 | import io.netty.channel.ChannelInboundHandlerAdapter; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * 异常控制器 11 | * 12 | * @author TheEmbers Guo 13 | * @version 1.0 14 | * createTime 2018-11-15 09:26 15 | */ 16 | @Sharable 17 | public class ExceptionHandler extends ChannelInboundHandlerAdapter { 18 | private static final Logger LOGGER = LoggerFactory.getLogger(ExceptionHandler.class); 19 | @Override 20 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 21 | LOGGER.error("Error: ", cause); 22 | ctx.channel().close(); 23 | ctx.fireExceptionCaught(cause); 24 | } 25 | } -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/channelhandler/HeartBeatHandler.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.channelhandler; 2 | 3 | import io.netty.channel.ChannelHandlerContext; 4 | import io.netty.channel.ChannelInboundHandlerAdapter; 5 | import io.netty.handler.timeout.IdleState; 6 | import io.netty.handler.timeout.IdleStateEvent; 7 | 8 | /** 9 | * 心跳检测 headler 10 | * 11 | * @author TheEmbers Guo 12 | * @version 1.0 13 | * createTime 2018-10-26 11:48 14 | */ 15 | public class HeartBeatHandler extends ChannelInboundHandlerAdapter { 16 | private int loss_connect_time = 0; 17 | @Override 18 | public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { 19 | if (evt instanceof IdleStateEvent) { 20 | IdleStateEvent event = (IdleStateEvent) evt; 21 | if (event.state() == IdleState.READER_IDLE) { 22 | loss_connect_time++; 23 | if (loss_connect_time > 2) { 24 | ctx.channel().close(); 25 | } 26 | } else { 27 | super.userEventTriggered(ctx, evt); 28 | } 29 | } 30 | } 31 | 32 | @Override 33 | public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 34 | ctx.close(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/channelhandler/KafkaHandler.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.channelhandler; 2 | 3 | import com.theembers.iot.RTUInfo; 4 | import com.theembers.iot.kafka.Producer; 5 | import com.theembers.iot.utils.JsonUtils; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | import javax.annotation.PostConstruct; 14 | 15 | /** 16 | * @author TheEmbers Guo 17 | * createTime 2019-08-01 11:17 18 | */ 19 | //@Component 20 | public class KafkaHandler extends ChannelInboundHandlerAdapter { 21 | 22 | private static final Logger LOGGER = LoggerFactory.getLogger(MqHandler.class); 23 | 24 | public KafkaHandler() { 25 | } 26 | 27 | @Autowired 28 | private Producer producer; 29 | 30 | private static KafkaHandler kafkaHandler; 31 | 32 | @PostConstruct 33 | public void init() { 34 | kafkaHandler = this; 35 | } 36 | 37 | @Override 38 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 39 | if (!(msg instanceof RTUInfo)) { 40 | return; 41 | } 42 | RTUInfo rtuInfo = (RTUInfo) msg; 43 | if (!rtuInfo.isPublish()) { 44 | LOGGER.info("unpublished sendMsg: {}", rtuInfo); 45 | return; 46 | } 47 | String dataStr = JsonUtils.str2Json(msg); 48 | LOGGER.info("sn: {} send..", rtuInfo.getSn()); 49 | kafkaHandler.producer.send(rtuInfo.getMqExchange(), dataStr); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/channelhandler/MqHandler.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.channelhandler; 2 | 3 | import com.theembers.iot.RTUInfo; 4 | import com.theembers.iot.mq.MQSender; 5 | import com.theembers.iot.utils.JsonUtils; 6 | import io.netty.channel.ChannelHandlerContext; 7 | import io.netty.channel.ChannelInboundHandlerAdapter; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Component; 12 | 13 | import javax.annotation.PostConstruct; 14 | 15 | /** 16 | * 消息队列 17 | * 18 | * @author TheEmbers Guo 19 | * @version 1.0 20 | * createTime 2018-10-19 16:37 21 | */ 22 | //@Component 23 | public class MqHandler extends ChannelInboundHandlerAdapter { 24 | private static final Logger LOGGER = LoggerFactory.getLogger(MqHandler.class); 25 | 26 | public MqHandler() { 27 | } 28 | 29 | @Autowired 30 | private MQSender mqSender; 31 | 32 | private static MqHandler mqHandler; 33 | 34 | @PostConstruct 35 | public void init() { 36 | mqHandler = this; 37 | } 38 | 39 | @Override 40 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 41 | if (!(msg instanceof RTUInfo)) { 42 | return; 43 | } 44 | RTUInfo rtuInfo = (RTUInfo) msg; 45 | if (!rtuInfo.isPublish()) { 46 | LOGGER.info("unpublished sendMsg: {}", rtuInfo); 47 | return; 48 | } 49 | String dataStr = JsonUtils.str2Json(msg); 50 | LOGGER.info("sn: {} send..", rtuInfo.getSn()); 51 | mqHandler.mqSender.send(rtuInfo.getMqExchange(), dataStr); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/channelhandler/ProcessorHandler.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.channelhandler; 2 | 3 | import com.theembers.iot.*; 4 | import com.theembers.iot.enums.EMqExchange; 5 | import com.theembers.iot.netty.processor.*; 6 | import io.netty.buffer.ByteBuf; 7 | import io.netty.channel.ChannelHandlerContext; 8 | import io.netty.channel.ChannelInboundHandlerAdapter; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.stereotype.Component; 12 | import org.springframework.util.CollectionUtils; 13 | 14 | import java.util.Collection; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | /** 20 | * RTU 设备 解码 21 | * 22 | * @author TheEmbers Guo 23 | * @version 1.0 24 | * createTime 2018-10-19 15:59 25 | */ 26 | @Component 27 | public class ProcessorHandler extends ChannelInboundHandlerAdapter { 28 | private static final Logger LOGGER = LoggerFactory.getLogger(ProcessorHandler.class); 29 | private final IDataProcessor sysDataProcessor = new SysDataProcessor(); 30 | private final IDataProcessor simDataProcessor = new SimDataProcessor(); 31 | private final IDataProcessor displayDataProcessor = new DisplayDataProcessor(); 32 | private final IDataProcessor r485DataProcessor = new R485DataProcessor(); 33 | 34 | 35 | public ProcessorHandler() { 36 | sysDataProcessor.setNextProcessor(simDataProcessor); 37 | simDataProcessor.setNextProcessor(r485DataProcessor); 38 | r485DataProcessor.setNextProcessor(displayDataProcessor); 39 | } 40 | 41 | @Override 42 | public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 43 | if (msg instanceof ByteBuf) { 44 | ByteBuf byteBuf = (ByteBuf) msg; 45 | RTUInfo rtuInfo = new RTUInfo(null); 46 | sysDataProcessor.translate(ctx, byteBuf, rtuInfo); 47 | buildRtuInfo(ctx, rtuInfo); 48 | ctx.fireChannelRead(rtuInfo); 49 | } else { 50 | ctx.fireChannelRead(msg); 51 | } 52 | 53 | } 54 | 55 | private void buildRtuInfo(ChannelHandlerContext ctx, RTUInfo rtuInfo) { 56 | RTUChannelInfo rtuChannelInfo = GlobalInfo.CHANNEL_INFO_MAP.get(ctx.channel().id()); 57 | IotInfo iotInfo = rtuChannelInfo.getIotInfo(); 58 | // 如果不存在物联网信息则使用sn号并添加未注册队列标记,否则使用物联网id 59 | rtuInfo.setSn(rtuChannelInfo.getSn()); 60 | Map iotInfoDataMap; 61 | if (iotInfo == null) { 62 | rtuInfo.setId(rtuChannelInfo.getSn()); 63 | EMqExchange[] eMqExchanges = {EMqExchange.RTU_UNREGISTERED}; 64 | rtuInfo.setMqExchange(eMqExchanges); 65 | iotInfoDataMap = new HashMap<>(); 66 | } else { 67 | rtuInfo.setId(iotInfo.getId()); 68 | iotInfoDataMap = iotInfo.getData(); 69 | } 70 | 71 | // 替换 rtuInfo 的 item id 72 | if (rtuInfo.getData() instanceof Collection) { 73 | List itemInfoList = (List) rtuInfo.getData(); 74 | if (CollectionUtils.isEmpty(itemInfoList)) { 75 | return; 76 | } 77 | itemInfoList.forEach(item -> { 78 | String itemId = rtuInfo.getSn() + "-" + item.getId(); 79 | item.setId(iotInfoDataMap.getOrDefault(itemId, itemId)); 80 | }); 81 | } else if (rtuInfo.getData() instanceof ItemInfo) { 82 | ItemInfo itemInfo = ((ItemInfo) rtuInfo.getData()); 83 | String itemId = rtuInfo.getSn() + "-" + itemInfo.getId(); 84 | itemInfo.setId(iotInfoDataMap.getOrDefault(itemId, itemId)); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/processor/DisplayDataProcessor.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.processor; 2 | 3 | import com.theembers.iot.ItemInfo; 4 | import com.theembers.iot.RTUInfo; 5 | import com.theembers.iot.enums.EMqExchange; 6 | import com.theembers.iot.enums.ERTUChannelFlag; 7 | import io.netty.buffer.ByteBuf; 8 | import io.netty.channel.ChannelHandlerContext; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * 显示器 15 | * 16 | * @author TheEmbers Guo 17 | * @version 1.0 18 | * createTime 2018-11-19 16:18 19 | */ 20 | public class DisplayDataProcessor extends ProcessorAbstract implements IDataProcessor { 21 | public DisplayDataProcessor() { 22 | super(ERTUChannelFlag.DISPLAY); 23 | } 24 | 25 | @Override 26 | public void translate(ChannelHandlerContext ctx, ByteBuf source, RTUInfo rtuInfo) throws Exception { 27 | if (checkAndGetAvailable(source)) { 28 | // byte[] dataBytes = new byte[source.readableBytes()]; 29 | // source.readBytes(dataBytes); 30 | // String dataStr = new String(dataBytes); 31 | List itemInfoList = new ArrayList<>(1); 32 | itemInfoList.add(new ItemInfo("DISPLAY-WORK", "ok")); 33 | EMqExchange[] eMqExchanges = {EMqExchange.RTU_DATA, EMqExchange.RTU_HEART}; 34 | rtuInfo.setMqExchange(eMqExchanges); 35 | rtuInfo.setData(itemInfoList); 36 | } else { 37 | if (super.getNextProcessor() != null) 38 | super.getNextProcessor().translate(ctx, source, rtuInfo); 39 | } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/processor/IDataProcessor.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.processor; 2 | 3 | import com.theembers.iot.RTUInfo; 4 | import io.netty.buffer.ByteBuf; 5 | import io.netty.channel.ChannelHandlerContext; 6 | 7 | /** 8 | * 数据处理器 9 | * 10 | * @author TheEmbers Guo 11 | * @version 1.0 12 | * createTime 2018-10-19 15:45 13 | */ 14 | public interface IDataProcessor { 15 | IDataProcessor getNextProcessor(); 16 | 17 | void setNextProcessor(IDataProcessor nextProcessor); 18 | 19 | void translate(ChannelHandlerContext ctx, ByteBuf source, RTUInfo rtuInfo) throws Exception; 20 | } 21 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/processor/IR485DataProcessor.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.processor; 2 | 3 | import io.netty.buffer.ByteBuf; 4 | import io.netty.buffer.Unpooled; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * @author TheEmbers Guo 11 | * @version 1.0 12 | * createTime 2018-11-15 17:10 13 | */ 14 | public interface IR485DataProcessor { 15 | /** 16 | * 获取子数据段 17 | * 18 | * @param data 19 | * @return 20 | */ 21 | static List subData(byte[] data) { 22 | int count = data.length / 4; 23 | List dataItemList = new ArrayList<>(count); 24 | ByteBuf byteBuf = Unpooled.wrappedBuffer(data); 25 | for (int i = 1; i <= count; i++) { 26 | byte[] bytes = new byte[4]; 27 | byteBuf.readBytes(bytes); 28 | dataItemList.add(bytes); 29 | } 30 | return dataItemList; 31 | } 32 | 33 | /** 34 | * 高低位转换 35 | * 36 | * @param src 37 | * @return 38 | */ 39 | static Float exchangeHL(byte[] src) { 40 | int value = ((src[0] & 0xFF) << 8) 41 | | (src[1] & 0xFF) 42 | | ((src[2] & 0xFF) << 24) 43 | | ((src[3] & 0xFF) << 16); 44 | return Float.intBitsToFloat(value); 45 | } 46 | 47 | static Float toFloat(byte[] b) { 48 | return Float.intBitsToFloat(getInt(b, 0)); 49 | } 50 | 51 | static int getInt(byte[] memory, int index) { 52 | return (memory[index] & 0xff) << 24 | 53 | (memory[index + 1] & 0xff) << 16 | 54 | (memory[index + 2] & 0xff) << 8 | 55 | memory[index + 3] & 0xff; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/processor/ProcessorAbstract.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.processor; 2 | 3 | import com.theembers.iot.enums.ERTUChannelFlag; 4 | import io.netty.buffer.ByteBuf; 5 | 6 | /** 7 | * 数据解码器 抽象类 8 | * 9 | * @author TheEmbers Guo 10 | * @version 1.0 11 | * createTime 2018-10-19 15:52 12 | */ 13 | public abstract class ProcessorAbstract implements IDataProcessor { 14 | private IDataProcessor nextProcessor; 15 | private ERTUChannelFlag flag; 16 | 17 | @Override 18 | public IDataProcessor getNextProcessor() { 19 | return nextProcessor; 20 | } 21 | 22 | @Override 23 | public void setNextProcessor(IDataProcessor nextProcessor) { 24 | this.nextProcessor = nextProcessor; 25 | } 26 | 27 | ProcessorAbstract(ERTUChannelFlag flag) { 28 | this.flag = flag; 29 | } 30 | 31 | /** 32 | * 通道检测:前两个字节比较 33 | * 34 | * @param source 35 | * @return 36 | */ 37 | boolean checkAndGetAvailable(ByteBuf source) { 38 | int length = source.readableBytes(); 39 | if (length <= 2 && flag == null) { 40 | return false; 41 | } 42 | byte[] sourceFlag = new byte[2]; 43 | source.readBytes(sourceFlag); 44 | int i = 0; 45 | int n = sourceFlag.length; 46 | byte[] checkFlag = flag.getFlag(); 47 | while (n-- != 0) { 48 | if (sourceFlag[i] != checkFlag[i]) { 49 | // 未监测到 重置读标记位 50 | source.resetReaderIndex(); 51 | return false; 52 | } 53 | i++; 54 | } 55 | // mark 读取标记位 56 | source.markReaderIndex(); 57 | return true; 58 | } 59 | 60 | String buildDataKey(String littleKey) { 61 | return this.flag + "-" + littleKey; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/processor/R485DataProcessor.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.processor; 2 | 3 | import com.theembers.iot.ItemInfo; 4 | import com.theembers.iot.ModbusInfo; 5 | import com.theembers.iot.RTUInfo; 6 | import com.theembers.iot.enums.EMqExchange; 7 | import com.theembers.iot.enums.ERTUChannelFlag; 8 | import com.theembers.iot.utils.CRCUtils; 9 | import io.netty.buffer.ByteBuf; 10 | import io.netty.channel.ChannelHandlerContext; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * 485串口 处理器 19 | * 20 | * @author TheEmbers Guo 21 | * @version 1.0 22 | * createTime 2018-10-22 15:51 23 | */ 24 | public class R485DataProcessor extends ProcessorAbstract implements IDataProcessor, IR485DataProcessor { 25 | private static final Logger LOGGER = LoggerFactory.getLogger(R485DataProcessor.class); 26 | 27 | public R485DataProcessor() { 28 | super(ERTUChannelFlag.R485); 29 | } 30 | 31 | @Override 32 | public void translate(ChannelHandlerContext ctx, ByteBuf source, RTUInfo rtuInfo) throws Exception { 33 | if (checkAndGetAvailable(source)) { 34 | // 截取数据 35 | ModbusInfo modbusInfo = new ModbusInfo(source); 36 | // 校验数据 37 | if (!CRCUtils.checkCRC(modbusInfo.getFullData(), modbusInfo.getCrc())) { 38 | LOGGER.warn("R485 bad data: {}", String.valueOf(source)); 39 | } 40 | // 数据转换 41 | List dataItemList = IR485DataProcessor.subData(modbusInfo.getData()); 42 | 43 | // 构建 rtuInfo 信息 44 | List itemInfoList = new ArrayList<>(2); 45 | byte[] SSLL = dataItemList.get(0); 46 | String itemKeySSLL = buildDataKey("SSLL"); 47 | itemInfoList.add(new ItemInfo(itemKeySSLL, String.valueOf(IR485DataProcessor.exchangeHL(SSLL)))); 48 | byte[] LJLL = dataItemList.get(1); 49 | String itemKeyLJLL = buildDataKey("LJLL"); 50 | itemInfoList.add(new ItemInfo(itemKeyLJLL, String.valueOf(IR485DataProcessor.exchangeHL(LJLL)))); 51 | if (dataItemList.size() == 3) { 52 | byte[] YL = dataItemList.get(2); 53 | String itemKeyYL = buildDataKey("YL"); 54 | itemInfoList.add(new ItemInfo(itemKeyYL, String.valueOf(IR485DataProcessor.toFloat(YL)))); 55 | } 56 | rtuInfo.setData(itemInfoList); 57 | 58 | // 设置 mq 交换器 59 | EMqExchange[] eMqExchanges = {EMqExchange.RTU_DATA, EMqExchange.RTU_HEART}; 60 | rtuInfo.setMqExchange(eMqExchanges); 61 | } else { 62 | if (super.getNextProcessor() != null) 63 | super.getNextProcessor().translate(ctx, source, rtuInfo); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/processor/SimDataProcessor.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.processor; 2 | 3 | import com.theembers.iot.ItemInfo; 4 | import com.theembers.iot.RTUInfo; 5 | import com.theembers.iot.enums.EMqExchange; 6 | import com.theembers.iot.enums.ERTUChannelFlag; 7 | import com.theembers.iot.utils.JsonUtils; 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.util.CollectionUtils; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | /** 19 | * 模拟信号 处理器 20 | * 21 | * @author TheEmbers Guo 22 | * @version 1.0 23 | * createTime 2018-10-19 16:04 24 | */ 25 | public class SimDataProcessor extends ProcessorAbstract implements IDataProcessor { 26 | private static final Logger LOGGER = LoggerFactory.getLogger(SimDataProcessor.class); 27 | 28 | public SimDataProcessor() { 29 | super(ERTUChannelFlag.SIM); 30 | } 31 | 32 | @Override 33 | public void translate(ChannelHandlerContext ctx, ByteBuf source, RTUInfo rtuInfo) throws Exception { 34 | if (checkAndGetAvailable(source)) { 35 | byte[] dataBytes = new byte[source.readableBytes()]; 36 | source.readBytes(dataBytes); 37 | String dataJsonStr = new String(dataBytes); 38 | Map>> dataMap = JsonUtils.jsonStr2Obj(dataJsonStr, Map.class); 39 | if (!CollectionUtils.isEmpty(dataMap) && dataMap.containsKey("data")) { 40 | List> dataItems = dataMap.get("data"); 41 | if (CollectionUtils.isEmpty(dataItems)) { 42 | return; 43 | } 44 | List itemInfos = new ArrayList<>(dataItems.size()); 45 | dataItems.forEach(data -> { 46 | if (CollectionUtils.isEmpty(data)) { 47 | return; 48 | } 49 | data.forEach((key, val) -> { 50 | String itemKey = buildDataKey(key); 51 | if ("ch1".equals(key)) { 52 | val = String.valueOf((Float.valueOf(val) - 4) / 16); 53 | } 54 | itemInfos.add(new ItemInfo(itemKey, val)); 55 | }); 56 | EMqExchange[] eMqExchanges = {EMqExchange.RTU_DATA, EMqExchange.RTU_HEART}; 57 | rtuInfo.setMqExchange(eMqExchanges); 58 | rtuInfo.setData(itemInfos); 59 | }); 60 | } 61 | } else { 62 | if (super.getNextProcessor() != null) 63 | super.getNextProcessor().translate(ctx, source, rtuInfo); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/netty/processor/SysDataProcessor.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.netty.processor; 2 | 3 | import com.theembers.iot.ItemInfo; 4 | import com.theembers.iot.RTUInfo; 5 | import com.theembers.iot.enums.EMqExchange; 6 | import com.theembers.iot.enums.ERTUChannelFlag; 7 | import com.theembers.iot.netty.channelhandler.ChannelManagerHandler; 8 | import io.netty.buffer.ByteBuf; 9 | import io.netty.channel.ChannelHandlerContext; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | /** 14 | * 系统信息 处理器 15 | * 16 | * @author TheEmbers Guo 17 | * @version 1.0 18 | * createTime 2018-10-19 15:50 19 | */ 20 | public class SysDataProcessor extends ProcessorAbstract implements IDataProcessor { 21 | private static final Logger LOGGER = LoggerFactory.getLogger(SysDataProcessor.class); 22 | 23 | private static final String SIGNAL = "Signal"; 24 | private static final String VERSION = "version"; 25 | private static final String PING = "ping"; 26 | private static final String SN = "sn"; 27 | 28 | public SysDataProcessor() { 29 | super(ERTUChannelFlag.SYS); 30 | } 31 | 32 | @Override 33 | public void translate(ChannelHandlerContext ctx, ByteBuf source, RTUInfo rtuInfo) throws Exception { 34 | if (checkAndGetAvailable(source)) { 35 | byte[] dataBytes = new byte[source.readableBytes()]; 36 | source.readBytes(dataBytes); 37 | String sourceStr = new String(dataBytes); 38 | if (sourceStr.contains(SIGNAL)) { 39 | // 信号强度 40 | String signal = sourceStr.split(":")[1].trim(); 41 | rtuInfo.setData(new ItemInfo(SIGNAL, signal)); 42 | EMqExchange[] eMqExchanges = {EMqExchange.RTU_SIGNAL, EMqExchange.RTU_HEART}; 43 | rtuInfo.setMqExchange(eMqExchanges); 44 | } else if (sourceStr.contains(VERSION)) { 45 | // 版本信息 46 | String version = sourceStr.split(":")[1].trim(); 47 | rtuInfo.setData(new ItemInfo(VERSION, version)); 48 | } else if (sourceStr.contains(PING)) { 49 | // ping 50 | rtuInfo.setData(new ItemInfo(PING, "ok")); 51 | EMqExchange[] eMqExchanges = {EMqExchange.RTU_HEART}; 52 | rtuInfo.setMqExchange(eMqExchanges); 53 | } else if (sourceStr.contains(SN)) { 54 | // sn 55 | String sn = sourceStr.split(":")[1].trim(); 56 | // 补全 channelInfo信息 57 | ChannelManagerHandler.setRTUChannelInfo(ctx, sn); 58 | } else { 59 | LOGGER.warn("unchecked system source: \"{}\"", sourceStr); 60 | } 61 | } else { 62 | if (super.getNextProcessor() != null) 63 | super.getNextProcessor().translate(ctx, source, rtuInfo); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/redis/IoTService.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.redis; 2 | 3 | import com.theembers.iot.GlobalInfo; 4 | import com.theembers.iot.IotInfo; 5 | import com.theembers.iot.utils.JsonUtils; 6 | import com.theembers.iot.utils.KeyUtils; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.util.CollectionUtils; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | import java.util.Set; 16 | 17 | import static com.theembers.iot.GlobalInfo.Global_Iot_Redis_Key; 18 | 19 | /** 20 | * 物联网 service 21 | * 22 | * @author TheEmbers Guo 23 | * @version 1.0 24 | * createTime 2018-10-26 16:36 25 | */ 26 | @Service 27 | public class IoTService { 28 | private static final Logger LOGGER = LoggerFactory.getLogger(IoTService.class); 29 | 30 | @Autowired 31 | private RedisService redisService; 32 | 33 | /** 34 | * 加载 IoT 映射信息到 全局 35 | * 36 | * @param host 37 | * @param port 38 | * @return 39 | */ 40 | public boolean loadIotMapper2Global(String host, Integer port) throws Exception { 41 | if (GlobalInfo.iotMapper == null) { 42 | Global_Iot_Redis_Key = KeyUtils.buildKey(host, port); 43 | GlobalInfo.iotMapper = this.getIoTSnIdMapper(Global_Iot_Redis_Key); 44 | } 45 | if (CollectionUtils.isEmpty(GlobalInfo.iotMapper)) { 46 | return false; 47 | } 48 | return true; 49 | } 50 | 51 | /** 52 | * 刷新 全局 IoT 映射信息 53 | * 54 | * @return 55 | * @throws Exception 56 | */ 57 | public boolean refreshIotMapper2Global() throws Exception { 58 | GlobalInfo.iotMapper = this.getIoTSnIdMapper(Global_Iot_Redis_Key); 59 | if (CollectionUtils.isEmpty(GlobalInfo.iotMapper)) { 60 | return false; 61 | } 62 | return true; 63 | } 64 | 65 | /** 66 | * 获取 IoT 映射信息 67 | */ 68 | private Map getIoTSnIdMapper(String key) throws Exception { 69 | LOGGER.info("get IoT SnId Mapper... key is [{}]", key); 70 | Map mapperMap = redisService.hGetAll(key); 71 | if (CollectionUtils.isEmpty(mapperMap)) { 72 | LOGGER.warn("the IoTSnIdMapper is empty!"); 73 | return new HashMap<>(0); 74 | } 75 | 76 | Map mapperStrMap = new HashMap<>(mapperMap.size()); 77 | Set keySet = mapperMap.keySet(); 78 | for (Object sn : keySet) { 79 | Object data = mapperMap.get(sn); 80 | IotInfo dataMap = JsonUtils.jsonStr2Obj(String.valueOf(data), IotInfo.class); 81 | mapperStrMap.put(String.valueOf(sn), dataMap); 82 | } 83 | return mapperStrMap; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/redis/RedisService.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.redis; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.data.redis.connection.DataType; 5 | import org.springframework.data.redis.core.Cursor; 6 | import org.springframework.data.redis.core.RedisTemplate; 7 | import org.springframework.data.redis.core.ScanOptions; 8 | import org.springframework.data.redis.core.ZSetOperations.TypedTuple; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.util.*; 12 | import java.util.Map.Entry; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | /** 16 | * @author TheEmbers 17 | * @version 1.0 18 | * createTime 2018-08-09 16:36 19 | */ 20 | @Component 21 | public class RedisService { 22 | @Autowired 23 | private RedisTemplate redisTemplate; 24 | 25 | public void setRedisTemplate(RedisTemplate redisTemplate) { 26 | this.redisTemplate = redisTemplate; 27 | } 28 | 29 | public RedisTemplate getRedisTemplate() { 30 | return this.redisTemplate; 31 | } 32 | 33 | /** -------------------key相关操作--------------------- */ 34 | 35 | /** 36 | * 删除key 37 | * 38 | * @param key 39 | */ 40 | public void delete(String key) { 41 | redisTemplate.delete(key); 42 | } 43 | 44 | /** 45 | * 批量删除key 46 | * 47 | * @param keys 48 | */ 49 | public void delete(Collection keys) { 50 | redisTemplate.delete(keys); 51 | } 52 | 53 | /** 54 | * 序列化key 55 | * 56 | * @param key 57 | * @return 58 | */ 59 | public byte[] dump(String key) { 60 | return redisTemplate.dump(key); 61 | } 62 | 63 | /** 64 | * 是否存在key 65 | * 66 | * @param key 67 | * @return 68 | */ 69 | public Boolean hasKey(String key) { 70 | return redisTemplate.hasKey(key); 71 | } 72 | 73 | /** 74 | * 设置过期时间 75 | * 76 | * @param key 77 | * @param timeout 78 | * @param unit 79 | * @return 80 | */ 81 | public Boolean expire(String key, long timeout, TimeUnit unit) { 82 | return redisTemplate.expire(key, timeout, unit); 83 | } 84 | 85 | /** 86 | * 设置过期时间 87 | * 88 | * @param key 89 | * @param date 90 | * @return 91 | */ 92 | public Boolean expireAt(String key, Date date) { 93 | return redisTemplate.expireAt(key, date); 94 | } 95 | 96 | /** 97 | * 查找匹配的key 98 | * 99 | * @param pattern 100 | * @return 101 | */ 102 | public Set keys(String pattern) { 103 | return redisTemplate.keys(pattern); 104 | } 105 | 106 | /** 107 | * 将当前数据库的 key 移动到给定的数据库 db 当中 108 | * 109 | * @param key 110 | * @param dbIndex 111 | * @return 112 | */ 113 | public Boolean move(String key, int dbIndex) { 114 | return redisTemplate.move(key, dbIndex); 115 | } 116 | 117 | /** 118 | * 移除 key 的过期时间,key 将持久保持 119 | * 120 | * @param key 121 | * @return 122 | */ 123 | public Boolean persist(String key) { 124 | return redisTemplate.persist(key); 125 | } 126 | 127 | /** 128 | * 返回 key 的剩余的过期时间 129 | * 130 | * @param key 131 | * @param unit 132 | * @return 133 | */ 134 | public Long getExpire(String key, TimeUnit unit) { 135 | return redisTemplate.getExpire(key, unit); 136 | } 137 | 138 | /** 139 | * 返回 key 的剩余的过期时间 140 | * 141 | * @param key 142 | * @return 143 | */ 144 | public Long getExpire(String key) { 145 | return redisTemplate.getExpire(key); 146 | } 147 | 148 | /** 149 | * 从当前数据库中随机返回一个 key 150 | * 151 | * @return 152 | */ 153 | public Object randomKey() { 154 | return redisTemplate.randomKey(); 155 | } 156 | 157 | /** 158 | * 修改 key 的名称 159 | * 160 | * @param oldKey 161 | * @param newKey 162 | */ 163 | public void rename(String oldKey, String newKey) { 164 | redisTemplate.rename(oldKey, newKey); 165 | } 166 | 167 | /** 168 | * 仅当 newkey 不存在时,将 oldKey 改名为 newkey 169 | * 170 | * @param oldKey 171 | * @param newKey 172 | * @return 173 | */ 174 | public Boolean renameIfAbsent(String oldKey, String newKey) { 175 | return redisTemplate.renameIfAbsent(oldKey, newKey); 176 | } 177 | 178 | /** 179 | * 返回 key 所储存的值的类型 180 | * 181 | * @param key 182 | * @return 183 | */ 184 | public DataType type(String key) { 185 | return redisTemplate.type(key); 186 | } 187 | 188 | /** -------------------string相关操作--------------------- */ 189 | 190 | /** 191 | * 设置指定 key 的值 192 | * 193 | * @param key 194 | * @param value 195 | */ 196 | public void set(String key, String value) { 197 | redisTemplate.opsForValue().set(key, value); 198 | } 199 | 200 | /** 201 | * 获取指定 key 的值 202 | * 203 | * @param key 204 | * @return 205 | */ 206 | public Object get(String key) { 207 | return redisTemplate.opsForValue().get(key); 208 | } 209 | 210 | /** 211 | * 返回 key 中字符串值的子字符 212 | * 213 | * @param key 214 | * @param start 215 | * @param end 216 | * @return 217 | */ 218 | public String getRange(String key, long start, long end) { 219 | return redisTemplate.opsForValue().get(key, start, end); 220 | } 221 | 222 | /** 223 | * 将给定 key 的值设为 value ,并返回 key 的旧值(old value) 224 | * 225 | * @param key 226 | * @param value 227 | * @return 228 | */ 229 | public Object getAndSet(String key, String value) { 230 | return redisTemplate.opsForValue().getAndSet(key, value); 231 | } 232 | 233 | /** 234 | * 对 key 所储存的字符串值,获取指定偏移量上的位(bit) 235 | * 236 | * @param key 237 | * @param offset 238 | * @return 239 | */ 240 | public Boolean getBit(String key, long offset) { 241 | return redisTemplate.opsForValue().getBit(key, offset); 242 | } 243 | 244 | /** 245 | * 批量获取 246 | * 247 | * @param keys 248 | * @return 249 | */ 250 | public List multiGet(Collection keys) { 251 | return redisTemplate.opsForValue().multiGet(keys); 252 | } 253 | 254 | /** 255 | * 设置ASCII码, 字符串'a'的ASCII码是97, 转为二进制是'01100001', 此方法是将二进制第offset位值变为value 256 | * 257 | * @param key 258 | * @param postion 位置 259 | * @param value 值,true为1, false为0 260 | * @return 261 | */ 262 | public boolean setBit(String key, long offset, boolean value) { 263 | return redisTemplate.opsForValue().setBit(key, offset, value); 264 | } 265 | 266 | /** 267 | * 将值 value 关联到 key ,并将 key 的过期时间设为 timeout 268 | * 269 | * @param key 270 | * @param value 271 | * @param timeout 过期时间 272 | * @param unit 时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES 273 | * 秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS 274 | */ 275 | public void setEx(String key, String value, long timeout, TimeUnit unit) { 276 | redisTemplate.opsForValue().set(key, value, timeout, unit); 277 | } 278 | 279 | /** 280 | * 只有在 key 不存在时设置 key 的值 281 | * 282 | * @param key 283 | * @param value 284 | * @return 之前已经存在返回false, 不存在返回true 285 | */ 286 | public boolean setIfAbsent(String key, String value) { 287 | return redisTemplate.opsForValue().setIfAbsent(key, value); 288 | } 289 | 290 | /** 291 | * 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始 292 | * 293 | * @param key 294 | * @param value 295 | * @param offset 从指定位置开始覆写 296 | */ 297 | public void setRange(String key, String value, long offset) { 298 | redisTemplate.opsForValue().set(key, value, offset); 299 | } 300 | 301 | /** 302 | * 获取字符串的长度 303 | * 304 | * @param key 305 | * @return 306 | */ 307 | public Long size(String key) { 308 | return redisTemplate.opsForValue().size(key); 309 | } 310 | 311 | /** 312 | * 批量添加 313 | * 314 | * @param maps 315 | */ 316 | public void multiSet(Map maps) { 317 | redisTemplate.opsForValue().multiSet(maps); 318 | } 319 | 320 | /** 321 | * 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在 322 | * 323 | * @param maps 324 | * @return 之前已经存在返回false, 不存在返回true 325 | */ 326 | public boolean multiSetIfAbsent(Map maps) { 327 | return redisTemplate.opsForValue().multiSetIfAbsent(maps); 328 | } 329 | 330 | /** 331 | * 增加(自增长), 负数则为自减 332 | * 333 | * @param key 334 | * @param value 335 | * @return 336 | */ 337 | public Long incrBy(String key, long increment) { 338 | return redisTemplate.opsForValue().increment(key, increment); 339 | } 340 | 341 | /** 342 | * @param key 343 | * @param value 344 | * @return 345 | */ 346 | public Double incrByFloat(String key, double increment) { 347 | return redisTemplate.opsForValue().increment(key, increment); 348 | } 349 | 350 | /** 351 | * 追加到末尾 352 | * 353 | * @param key 354 | * @param value 355 | * @return 356 | */ 357 | public Integer append(String key, String value) { 358 | return redisTemplate.opsForValue().append(key, value); 359 | } 360 | 361 | /** -------------------hash相关操作------------------------- */ 362 | 363 | /** 364 | * 获取存储在哈希表中指定字段的值 365 | * 366 | * @param key 367 | * @param field 368 | * @return 369 | */ 370 | public Object hGet(String key, String field) { 371 | return redisTemplate.opsForHash().get(key, field); 372 | } 373 | 374 | /** 375 | * 获取所有给定字段的值 376 | * 377 | * @param key 378 | * @return 379 | */ 380 | public Map hGetAll(String key) { 381 | return redisTemplate.opsForHash().entries(key); 382 | } 383 | 384 | /** 385 | * 获取所有给定字段的值 386 | * 387 | * @param key 388 | * @param fields 389 | * @return 390 | */ 391 | public List hMultiGet(String key, Collection fields) { 392 | return redisTemplate.opsForHash().multiGet(key, fields); 393 | } 394 | 395 | public void hPut(String key, String hashKey, String value) { 396 | redisTemplate.opsForHash().put(key, hashKey, value); 397 | } 398 | 399 | public void hPutAll(String key, Map maps) { 400 | redisTemplate.opsForHash().putAll(key, maps); 401 | } 402 | 403 | /** 404 | * 仅当hashKey不存在时才设置 405 | * 406 | * @param key 407 | * @param hashKey 408 | * @param value 409 | * @return 410 | */ 411 | public Boolean hPutIfAbsent(String key, String hashKey, String value) { 412 | return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value); 413 | } 414 | 415 | /** 416 | * 删除一个或多个哈希表字段 417 | * 418 | * @param key 419 | * @param fields 420 | * @return 421 | */ 422 | public Long hDelete(String key, Object... fields) { 423 | return redisTemplate.opsForHash().delete(key, fields); 424 | } 425 | 426 | /** 427 | * 查看哈希表 key 中,指定的字段是否存在 428 | * 429 | * @param key 430 | * @param field 431 | * @return 432 | */ 433 | public boolean hExists(String key, String field) { 434 | return redisTemplate.opsForHash().hasKey(key, field); 435 | } 436 | 437 | /** 438 | * 为哈希表 key 中的指定字段的整数值加上增量 increment 439 | * 440 | * @param key 441 | * @param field 442 | * @param increment 443 | * @return 444 | */ 445 | public Long hIncrBy(String key, Object field, long increment) { 446 | return redisTemplate.opsForHash().increment(key, field, increment); 447 | } 448 | 449 | /** 450 | * 为哈希表 key 中的指定字段的整数值加上增量 increment 451 | * 452 | * @param key 453 | * @param field 454 | * @param delta 455 | * @return 456 | */ 457 | public Double hIncrByFloat(String key, Object field, double delta) { 458 | return redisTemplate.opsForHash().increment(key, field, delta); 459 | } 460 | 461 | /** 462 | * 获取所有哈希表中的字段 463 | * 464 | * @param key 465 | * @return 466 | */ 467 | public Set hKeys(String key) { 468 | return redisTemplate.opsForHash().keys(key); 469 | } 470 | 471 | /** 472 | * 获取哈希表中字段的数量 473 | * 474 | * @param key 475 | * @return 476 | */ 477 | public Long hSize(String key) { 478 | return redisTemplate.opsForHash().size(key); 479 | } 480 | 481 | /** 482 | * 获取哈希表中所有值 483 | * 484 | * @param key 485 | * @return 486 | */ 487 | public List hValues(String key) { 488 | return redisTemplate.opsForHash().values(key); 489 | } 490 | 491 | /** 492 | * 迭代哈希表中的键值对 493 | * 494 | * @param key 495 | * @param options 496 | * @return 497 | */ 498 | public Cursor> hScan(String key, ScanOptions options) { 499 | return redisTemplate.opsForHash().scan(key, options); 500 | } 501 | 502 | /** ------------------------list相关操作---------------------------- */ 503 | 504 | /** 505 | * 通过索引获取列表中的元素 506 | * 507 | * @param key 508 | * @param index 509 | * @return 510 | */ 511 | public Object lIndex(String key, long index) { 512 | return redisTemplate.opsForList().index(key, index); 513 | } 514 | 515 | /** 516 | * 获取列表指定范围内的元素 517 | * 518 | * @param key 519 | * @param start 开始位置, 0是开始位置 520 | * @param end 结束位置, -1返回所有 521 | * @return 522 | */ 523 | public List lRange(String key, long start, long end) { 524 | return redisTemplate.opsForList().range(key, start, end); 525 | } 526 | 527 | /** 528 | * 存储在list头部 529 | * 530 | * @param key 531 | * @param value 532 | * @return 533 | */ 534 | public Long lLeftPush(String key, String value) { 535 | return redisTemplate.opsForList().leftPush(key, value); 536 | } 537 | 538 | /** 539 | * @param key 540 | * @param value 541 | * @return 542 | */ 543 | public Long lLeftPushAll(String key, String... value) { 544 | return redisTemplate.opsForList().leftPushAll(key, value); 545 | } 546 | 547 | /** 548 | * @param key 549 | * @param value 550 | * @return 551 | */ 552 | public Long lLeftPushAll(String key, Collection value) { 553 | return redisTemplate.opsForList().leftPushAll(key, value); 554 | } 555 | 556 | /** 557 | * 当list存在的时候才加入 558 | * 559 | * @param key 560 | * @param value 561 | * @return 562 | */ 563 | public Long lLeftPushIfPresent(String key, String value) { 564 | return redisTemplate.opsForList().leftPushIfPresent(key, value); 565 | } 566 | 567 | /** 568 | * 如果pivot存在,再pivot前面添加 569 | * 570 | * @param key 571 | * @param pivot 572 | * @param value 573 | * @return 574 | */ 575 | public Long lLeftPush(String key, String pivot, String value) { 576 | return redisTemplate.opsForList().leftPush(key, pivot, value); 577 | } 578 | 579 | /** 580 | * @param key 581 | * @param value 582 | * @return 583 | */ 584 | public Long lRightPush(String key, String value) { 585 | return redisTemplate.opsForList().rightPush(key, value); 586 | } 587 | 588 | /** 589 | * @param key 590 | * @param value 591 | * @return 592 | */ 593 | public Long lRightPushAll(String key, String... value) { 594 | return redisTemplate.opsForList().rightPushAll(key, value); 595 | } 596 | 597 | /** 598 | * @param key 599 | * @param value 600 | * @return 601 | */ 602 | public Long lRightPushAll(String key, Collection value) { 603 | return redisTemplate.opsForList().rightPushAll(key, value); 604 | } 605 | 606 | /** 607 | * 为已存在的列表添加值 608 | * 609 | * @param key 610 | * @param value 611 | * @return 612 | */ 613 | public Long lRightPushIfPresent(String key, String value) { 614 | return redisTemplate.opsForList().rightPushIfPresent(key, value); 615 | } 616 | 617 | /** 618 | * 在pivot元素的右边添加值 619 | * 620 | * @param key 621 | * @param pivot 622 | * @param value 623 | * @return 624 | */ 625 | public Long lRightPush(String key, String pivot, String value) { 626 | return redisTemplate.opsForList().rightPush(key, pivot, value); 627 | } 628 | 629 | /** 630 | * 通过索引设置列表元素的值 631 | * 632 | * @param key 633 | * @param index 位置 634 | * @param value 635 | */ 636 | public void lSet(String key, long index, String value) { 637 | redisTemplate.opsForList().set(key, index, value); 638 | } 639 | 640 | /** 641 | * 移出并获取列表的第一个元素 642 | * 643 | * @param key 644 | * @return 删除的元素 645 | */ 646 | public Object lLeftPop(String key) { 647 | return redisTemplate.opsForList().leftPop(key); 648 | } 649 | 650 | /** 651 | * 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 652 | * 653 | * @param key 654 | * @param timeout 等待时间 655 | * @param unit 时间单位 656 | * @return 657 | */ 658 | public Object lBLeftPop(String key, long timeout, TimeUnit unit) { 659 | return redisTemplate.opsForList().leftPop(key, timeout, unit); 660 | } 661 | 662 | /** 663 | * 移除并获取列表最后一个元素 664 | * 665 | * @param key 666 | * @return 删除的元素 667 | */ 668 | public Object lRightPop(String key) { 669 | return redisTemplate.opsForList().rightPop(key); 670 | } 671 | 672 | /** 673 | * 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 674 | * 675 | * @param key 676 | * @param timeout 等待时间 677 | * @param unit 时间单位 678 | * @return 679 | */ 680 | public Object lBRightPop(String key, long timeout, TimeUnit unit) { 681 | return redisTemplate.opsForList().rightPop(key, timeout, unit); 682 | } 683 | 684 | /** 685 | * 移除列表的最后一个元素,并将该元素添加到另一个列表并返回 686 | * 687 | * @param sourceKey 688 | * @param destinationKey 689 | * @return 690 | */ 691 | public Object lRightPopAndLeftPush(String sourceKey, String destinationKey) { 692 | return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, 693 | destinationKey); 694 | } 695 | 696 | /** 697 | * 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 698 | * 699 | * @param sourceKey 700 | * @param destinationKey 701 | * @param timeout 702 | * @param unit 703 | * @return 704 | */ 705 | public Object lBRightPopAndLeftPush(String sourceKey, String destinationKey, 706 | long timeout, TimeUnit unit) { 707 | return redisTemplate.opsForList().rightPopAndLeftPush(sourceKey, 708 | destinationKey, timeout, unit); 709 | } 710 | 711 | /** 712 | * 删除集合中值等于value得元素 713 | * 714 | * @param key 715 | * @param index index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素; 716 | * index<0, 从尾部开始删除第一个值等于value的元素; 717 | * @param value 718 | * @return 719 | */ 720 | public Long lRemove(String key, long index, String value) { 721 | return redisTemplate.opsForList().remove(key, index, value); 722 | } 723 | 724 | /** 725 | * 裁剪list 726 | * 727 | * @param key 728 | * @param start 729 | * @param end 730 | */ 731 | public void lTrim(String key, long start, long end) { 732 | redisTemplate.opsForList().trim(key, start, end); 733 | } 734 | 735 | /** 736 | * 获取列表长度 737 | * 738 | * @param key 739 | * @return 740 | */ 741 | public Long lLen(String key) { 742 | return redisTemplate.opsForList().size(key); 743 | } 744 | 745 | /** --------------------set相关操作-------------------------- */ 746 | 747 | /** 748 | * set添加元素 749 | * 750 | * @param key 751 | * @param values 752 | * @return 753 | */ 754 | public Long sAdd(String key, String... values) { 755 | return redisTemplate.opsForSet().add(key, values); 756 | } 757 | 758 | /** 759 | * set移除元素 760 | * 761 | * @param key 762 | * @param values 763 | * @return 764 | */ 765 | public Long sRemove(String key, Object... values) { 766 | return redisTemplate.opsForSet().remove(key, values); 767 | } 768 | 769 | /** 770 | * 移除并返回集合的一个随机元素 771 | * 772 | * @param key 773 | * @return 774 | */ 775 | public Object sPop(String key) { 776 | return redisTemplate.opsForSet().pop(key); 777 | } 778 | 779 | /** 780 | * 将元素value从一个集合移到另一个集合 781 | * 782 | * @param key 783 | * @param value 784 | * @param destKey 785 | * @return 786 | */ 787 | public Boolean sMove(String key, String value, String destKey) { 788 | return redisTemplate.opsForSet().move(key, value, destKey); 789 | } 790 | 791 | /** 792 | * 获取集合的大小 793 | * 794 | * @param key 795 | * @return 796 | */ 797 | public Long sSize(String key) { 798 | return redisTemplate.opsForSet().size(key); 799 | } 800 | 801 | /** 802 | * 判断集合是否包含value 803 | * 804 | * @param key 805 | * @param value 806 | * @return 807 | */ 808 | public Boolean sIsMember(String key, Object value) { 809 | return redisTemplate.opsForSet().isMember(key, value); 810 | } 811 | 812 | /** 813 | * 获取两个集合的交集 814 | * 815 | * @param key 816 | * @param otherKey 817 | * @return 818 | */ 819 | public Set sIntersect(String key, String otherKey) { 820 | return redisTemplate.opsForSet().intersect(key, otherKey); 821 | } 822 | 823 | /** 824 | * 获取key集合与多个集合的交集 825 | * 826 | * @param key 827 | * @param otherKeys 828 | * @return 829 | */ 830 | public Set sIntersect(String key, Collection otherKeys) { 831 | return redisTemplate.opsForSet().intersect(key, otherKeys); 832 | } 833 | 834 | /** 835 | * key集合与otherKey集合的交集存储到destKey集合中 836 | * 837 | * @param key 838 | * @param otherKey 839 | * @param destKey 840 | * @return 841 | */ 842 | public Long sIntersectAndStore(String key, String otherKey, String destKey) { 843 | return redisTemplate.opsForSet().intersectAndStore(key, otherKey, 844 | destKey); 845 | } 846 | 847 | /** 848 | * key集合与多个集合的交集存储到destKey集合中 849 | * 850 | * @param key 851 | * @param otherKeys 852 | * @param destKey 853 | * @return 854 | */ 855 | public Long sIntersectAndStore(String key, Collection otherKeys, 856 | String destKey) { 857 | return redisTemplate.opsForSet().intersectAndStore(key, otherKeys, 858 | destKey); 859 | } 860 | 861 | /** 862 | * 获取两个集合的并集 863 | * 864 | * @param key 865 | * @param otherKeys 866 | * @return 867 | */ 868 | public Set sUnion(String key, String otherKeys) { 869 | return redisTemplate.opsForSet().union(key, otherKeys); 870 | } 871 | 872 | /** 873 | * 获取key集合与多个集合的并集 874 | * 875 | * @param key 876 | * @param otherKeys 877 | * @return 878 | */ 879 | public Set sUnion(String key, Collection otherKeys) { 880 | return redisTemplate.opsForSet().union(key, otherKeys); 881 | } 882 | 883 | /** 884 | * key集合与otherKey集合的并集存储到destKey中 885 | * 886 | * @param key 887 | * @param otherKey 888 | * @param destKey 889 | * @return 890 | */ 891 | public Long sUnionAndStore(String key, String otherKey, String destKey) { 892 | return redisTemplate.opsForSet().unionAndStore(key, otherKey, destKey); 893 | } 894 | 895 | /** 896 | * key集合与多个集合的并集存储到destKey中 897 | * 898 | * @param key 899 | * @param otherKeys 900 | * @param destKey 901 | * @return 902 | */ 903 | public Long sUnionAndStore(String key, Collection otherKeys, 904 | String destKey) { 905 | return redisTemplate.opsForSet().unionAndStore(key, otherKeys, destKey); 906 | } 907 | 908 | /** 909 | * 获取两个集合的差集 910 | * 911 | * @param key 912 | * @param otherKey 913 | * @return 914 | */ 915 | public Set sDifference(String key, String otherKey) { 916 | return redisTemplate.opsForSet().difference(key, otherKey); 917 | } 918 | 919 | /** 920 | * 获取key集合与多个集合的差集 921 | * 922 | * @param key 923 | * @param otherKeys 924 | * @return 925 | */ 926 | public Set sDifference(String key, Collection otherKeys) { 927 | return redisTemplate.opsForSet().difference(key, otherKeys); 928 | } 929 | 930 | /** 931 | * key集合与otherKey集合的差集存储到destKey中 932 | * 933 | * @param key 934 | * @param otherKey 935 | * @param destKey 936 | * @return 937 | */ 938 | public Long sDifference(String key, String otherKey, String destKey) { 939 | return redisTemplate.opsForSet().differenceAndStore(key, otherKey, 940 | destKey); 941 | } 942 | 943 | /** 944 | * key集合与多个集合的差集存储到destKey中 945 | * 946 | * @param key 947 | * @param otherKeys 948 | * @param destKey 949 | * @return 950 | */ 951 | public Long sDifference(String key, Collection otherKeys, 952 | String destKey) { 953 | return redisTemplate.opsForSet().differenceAndStore(key, otherKeys, 954 | destKey); 955 | } 956 | 957 | /** 958 | * 获取集合所有元素 959 | * 960 | * @param key 961 | * @return 962 | */ 963 | public Set setMembers(String key) { 964 | return redisTemplate.opsForSet().members(key); 965 | } 966 | 967 | /** 968 | * 随机获取集合中的一个元素 969 | * 970 | * @param key 971 | * @return 972 | */ 973 | public Object sRandomMember(String key) { 974 | return redisTemplate.opsForSet().randomMember(key); 975 | } 976 | 977 | /** 978 | * 随机获取集合中count个元素 979 | * 980 | * @param key 981 | * @param count 982 | * @return 983 | */ 984 | public List sRandomMembers(String key, long count) { 985 | return redisTemplate.opsForSet().randomMembers(key, count); 986 | } 987 | 988 | /** 989 | * 随机获取集合中count个元素并且去除重复的 990 | * 991 | * @param key 992 | * @param count 993 | * @return 994 | */ 995 | public Set sDistinctRandomMembers(String key, long count) { 996 | return redisTemplate.opsForSet().distinctRandomMembers(key, count); 997 | } 998 | 999 | /** 1000 | * @param key 1001 | * @param options 1002 | * @return 1003 | */ 1004 | public Cursor sScan(String key, ScanOptions options) { 1005 | return redisTemplate.opsForSet().scan(key, options); 1006 | } 1007 | 1008 | /**------------------zSet相关操作--------------------------------*/ 1009 | 1010 | /** 1011 | * 添加元素,有序集合是按照元素的score值由小到大排列 1012 | * 1013 | * @param key 1014 | * @param value 1015 | * @param score 1016 | * @return 1017 | */ 1018 | public Boolean zAdd(String key, String value, double score) { 1019 | return redisTemplate.opsForZSet().add(key, value, score); 1020 | } 1021 | 1022 | /** 1023 | * @param key 1024 | * @param values 1025 | * @return 1026 | */ 1027 | public Long zAdd(String key, Set> values) { 1028 | return redisTemplate.opsForZSet().add(key, values); 1029 | } 1030 | 1031 | /** 1032 | * @param key 1033 | * @param values 1034 | * @return 1035 | */ 1036 | public Long zRemove(String key, Object... values) { 1037 | return redisTemplate.opsForZSet().remove(key, values); 1038 | } 1039 | 1040 | /** 1041 | * 增加元素的score值,并返回增加后的值 1042 | * 1043 | * @param key 1044 | * @param value 1045 | * @param delta 1046 | * @return 1047 | */ 1048 | public Double zIncrementScore(String key, String value, double delta) { 1049 | return redisTemplate.opsForZSet().incrementScore(key, value, delta); 1050 | } 1051 | 1052 | /** 1053 | * 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列 1054 | * 1055 | * @param key 1056 | * @param value 1057 | * @return 0表示第一位 1058 | */ 1059 | public Long zRank(String key, Object value) { 1060 | return redisTemplate.opsForZSet().rank(key, value); 1061 | } 1062 | 1063 | /** 1064 | * 返回元素在集合的排名,按元素的score值由大到小排列 1065 | * 1066 | * @param key 1067 | * @param value 1068 | * @return 1069 | */ 1070 | public Long zReverseRank(String key, Object value) { 1071 | return redisTemplate.opsForZSet().reverseRank(key, value); 1072 | } 1073 | 1074 | /** 1075 | * 获取集合的元素, 从小到大排序 1076 | * 1077 | * @param key 1078 | * @param start 开始位置 1079 | * @param end 结束位置, -1查询所有 1080 | * @return 1081 | */ 1082 | public Set zRange(String key, long start, long end) { 1083 | return redisTemplate.opsForZSet().range(key, start, end); 1084 | } 1085 | 1086 | /** 1087 | * 获取集合元素, 并且把score值也获取 1088 | * 1089 | * @param key 1090 | * @param start 1091 | * @param end 1092 | * @return 1093 | */ 1094 | public Set> zRangeWithScores(String key, long start, 1095 | long end) { 1096 | return redisTemplate.opsForZSet().rangeWithScores(key, start, end); 1097 | } 1098 | 1099 | /** 1100 | * 根据Score值查询集合元素 1101 | * 1102 | * @param key 1103 | * @param min 最小值 1104 | * @param max 最大值 1105 | * @return 1106 | */ 1107 | public Set zRangeByScore(String key, double min, double max) { 1108 | return redisTemplate.opsForZSet().rangeByScore(key, min, max); 1109 | } 1110 | 1111 | /** 1112 | * 根据Score值查询集合元素, 从小到大排序 1113 | * 1114 | * @param key 1115 | * @param min 最小值 1116 | * @param max 最大值 1117 | * @return 1118 | */ 1119 | public Set> zRangeByScoreWithScores(String key, 1120 | double min, double max) { 1121 | return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max); 1122 | } 1123 | 1124 | /** 1125 | * @param key 1126 | * @param min 1127 | * @param max 1128 | * @param start 1129 | * @param end 1130 | * @return 1131 | */ 1132 | public Set> zRangeByScoreWithScores(String key, 1133 | double min, double max, long start, long end) { 1134 | return redisTemplate.opsForZSet().rangeByScoreWithScores(key, min, max, 1135 | start, end); 1136 | } 1137 | 1138 | /** 1139 | * 获取集合的元素, 从大到小排序 1140 | * 1141 | * @param key 1142 | * @param start 1143 | * @param end 1144 | * @return 1145 | */ 1146 | public Set zReverseRange(String key, long start, long end) { 1147 | return redisTemplate.opsForZSet().reverseRange(key, start, end); 1148 | } 1149 | 1150 | /** 1151 | * 获取集合的元素, 从大到小排序, 并返回score值 1152 | * 1153 | * @param key 1154 | * @param start 1155 | * @param end 1156 | * @return 1157 | */ 1158 | public Set> zReverseRangeWithScores(String key, 1159 | long start, long end) { 1160 | return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, 1161 | end); 1162 | } 1163 | 1164 | /** 1165 | * 根据Score值查询集合元素, 从大到小排序 1166 | * 1167 | * @param key 1168 | * @param min 1169 | * @param max 1170 | * @return 1171 | */ 1172 | public Set zReverseRangeByScore(String key, double min, 1173 | double max) { 1174 | return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max); 1175 | } 1176 | 1177 | /** 1178 | * 根据Score值查询集合元素, 从大到小排序 1179 | * 1180 | * @param key 1181 | * @param min 1182 | * @param max 1183 | * @return 1184 | */ 1185 | public Set> zReverseRangeByScoreWithScores( 1186 | String key, double min, double max) { 1187 | return redisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, 1188 | min, max); 1189 | } 1190 | 1191 | /** 1192 | * @param key 1193 | * @param min 1194 | * @param max 1195 | * @param start 1196 | * @param end 1197 | * @return 1198 | */ 1199 | public Set zReverseRangeByScore(String key, double min, 1200 | double max, long start, long end) { 1201 | return redisTemplate.opsForZSet().reverseRangeByScore(key, min, max, 1202 | start, end); 1203 | } 1204 | 1205 | /** 1206 | * 根据score值获取集合元素数量 1207 | * 1208 | * @param key 1209 | * @param min 1210 | * @param max 1211 | * @return 1212 | */ 1213 | public Long zCount(String key, double min, double max) { 1214 | return redisTemplate.opsForZSet().count(key, min, max); 1215 | } 1216 | 1217 | /** 1218 | * 获取集合大小 1219 | * 1220 | * @param key 1221 | * @return 1222 | */ 1223 | public Long zSize(String key) { 1224 | return redisTemplate.opsForZSet().size(key); 1225 | } 1226 | 1227 | /** 1228 | * 获取集合大小 1229 | * 1230 | * @param key 1231 | * @return 1232 | */ 1233 | public Long zZCard(String key) { 1234 | return redisTemplate.opsForZSet().zCard(key); 1235 | } 1236 | 1237 | /** 1238 | * 获取集合中value元素的score值 1239 | * 1240 | * @param key 1241 | * @param value 1242 | * @return 1243 | */ 1244 | public Double zScore(String key, Object value) { 1245 | return redisTemplate.opsForZSet().score(key, value); 1246 | } 1247 | 1248 | /** 1249 | * 移除指定索引位置的成员 1250 | * 1251 | * @param key 1252 | * @param start 1253 | * @param end 1254 | * @return 1255 | */ 1256 | public Long zRemoveRange(String key, long start, long end) { 1257 | return redisTemplate.opsForZSet().removeRange(key, start, end); 1258 | } 1259 | 1260 | /** 1261 | * 根据指定的score值的范围来移除成员 1262 | * 1263 | * @param key 1264 | * @param min 1265 | * @param max 1266 | * @return 1267 | */ 1268 | public Long zRemoveRangeByScore(String key, double min, double max) { 1269 | return redisTemplate.opsForZSet().removeRangeByScore(key, min, max); 1270 | } 1271 | 1272 | /** 1273 | * 获取key和otherKey的并集并存储在destKey中 1274 | * 1275 | * @param key 1276 | * @param otherKey 1277 | * @param destKey 1278 | * @return 1279 | */ 1280 | public Long zUnionAndStore(String key, String otherKey, String destKey) { 1281 | return redisTemplate.opsForZSet().unionAndStore(key, otherKey, destKey); 1282 | } 1283 | 1284 | /** 1285 | * @param key 1286 | * @param otherKeys 1287 | * @param destKey 1288 | * @return 1289 | */ 1290 | public Long zUnionAndStore(String key, Collection otherKeys, 1291 | String destKey) { 1292 | return redisTemplate.opsForZSet() 1293 | .unionAndStore(key, otherKeys, destKey); 1294 | } 1295 | 1296 | /** 1297 | * 交集 1298 | * 1299 | * @param key 1300 | * @param otherKey 1301 | * @param destKey 1302 | * @return 1303 | */ 1304 | public Long zIntersectAndStore(String key, String otherKey, 1305 | String destKey) { 1306 | return redisTemplate.opsForZSet().intersectAndStore(key, otherKey, 1307 | destKey); 1308 | } 1309 | 1310 | /** 1311 | * 交集 1312 | * 1313 | * @param key 1314 | * @param otherKeys 1315 | * @param destKey 1316 | * @return 1317 | */ 1318 | public Long zIntersectAndStore(String key, Collection otherKeys, 1319 | String destKey) { 1320 | return redisTemplate.opsForZSet().intersectAndStore(key, otherKeys, 1321 | destKey); 1322 | } 1323 | 1324 | /** 1325 | * @param key 1326 | * @param options 1327 | * @return 1328 | */ 1329 | public Cursor> zScan(String key, ScanOptions options) { 1330 | return redisTemplate.opsForZSet().scan(key, options); 1331 | } 1332 | } -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/utils/ByteUtils.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.utils; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * @version 1.0 6 | * createTime 2018-10-09 09:58 7 | */ 8 | public class ByteUtils { 9 | 10 | public static String bytesToHexString(byte[] src) { 11 | StringBuffer sb = new StringBuffer(""); 12 | if (src == null || src.length <= 0) { 13 | return null; 14 | } 15 | for (int i = 0; i < src.length; i++) { 16 | int v = src[i] & 0xFF; 17 | String hv = Integer.toHexString(v).toUpperCase(); 18 | if (hv.length() < 2) { 19 | sb.append(0); 20 | } 21 | sb.append(hv); 22 | } 23 | return sb.toString(); 24 | } 25 | 26 | public static byte[] hex2byte(String inHex){ 27 | int hexlen = inHex.length(); 28 | byte[] result; 29 | if (hexlen % 2 == 1){ 30 | //奇数 31 | hexlen++; 32 | result = new byte[(hexlen/2)]; 33 | inHex="0"+inHex; 34 | }else { 35 | //偶数 36 | result = new byte[(hexlen/2)]; 37 | } 38 | int j=0; 39 | for (int i = 0; i < hexlen; i+=2){ 40 | result[j]=hexToByte(inHex.substring(i,i+2)); 41 | j++; 42 | } 43 | return result; 44 | } 45 | 46 | public static byte hexToByte(String inHex){ 47 | return (byte)Integer.parseInt(inHex,16); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/utils/CRCUtils.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.utils; 2 | /** 3 | * @author TheEmbers Guo 4 | * @version 1.0 5 | * createTime 2018-10-23 11:35 6 | */ 7 | public class CRCUtils { 8 | /** 9 | * 计算CRC16校验码 10 | * 11 | * @param bytes 字节数组 12 | * @return {@link String} 校验码 13 | * @since 1.0 14 | */ 15 | public static String getCRC(byte[] bytes) { 16 | byte[] buf = new byte[bytes.length]; 17 | for (int i = 0; i < bytes.length; i++) { 18 | buf[i] = bytes[i]; 19 | } 20 | int len = buf.length; 21 | int crc = 0xFFFF; 22 | for (int pos = 0; pos < len; pos++) { 23 | if (buf[pos] < 0) { 24 | crc ^= (int) buf[pos] + 256; 25 | } else { 26 | crc ^= (int) buf[pos]; 27 | } 28 | for (int i = 8; i != 0; i--) { 29 | if ((crc & 0x0001) != 0) { 30 | crc >>= 1; 31 | crc ^= 0xA001; 32 | } else 33 | crc >>= 1; 34 | } 35 | } 36 | String c = Integer.toHexString(crc).toUpperCase(); 37 | if (c.length() == 4) { 38 | c = c.substring(2, 4) + c.substring(0, 2); 39 | } else if (c.length() == 3) { 40 | c = "0" + c; 41 | c = c.substring(2, 4) + c.substring(0, 2); 42 | } else if (c.length() == 2) { 43 | c = "0" + c.substring(1, 2) + "0" + c.substring(0, 1); 44 | } 45 | return c; 46 | } 47 | 48 | public static boolean checkCRC(byte[] data, byte[] crc) { 49 | return ByteUtils.bytesToHexString(crc).equals(getCRC(data)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.utils; 2 | 3 | import com.fasterxml.jackson.annotation.JsonInclude; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.DeserializationFeature; 6 | import com.fasterxml.jackson.databind.JavaType; 7 | import com.fasterxml.jackson.databind.ObjectMapper; 8 | import org.springframework.util.StringUtils; 9 | 10 | import java.io.IOException; 11 | 12 | /** 13 | * json 工具类 14 | * 15 | * @author TheEmbers Guo 16 | * @version 1.0 17 | * createTime 2018-10-22 11:23 18 | */ 19 | public class JsonUtils { 20 | private static final ObjectMapper objectMapper; 21 | 22 | static { 23 | objectMapper = new ObjectMapper(); 24 | objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); 25 | objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 26 | } 27 | 28 | public static String str2Json(Object o) throws JsonProcessingException { 29 | return objectMapper.writeValueAsString(o); 30 | } 31 | 32 | public static T jsonStr2Obj(String jsonString, Class clazz) throws IOException { 33 | if (StringUtils.isEmpty(jsonString)) { 34 | return null; 35 | } 36 | return objectMapper.readValue(jsonString, clazz); 37 | } 38 | 39 | public static T jsonStr2Collection(String jsonString, Class collectionClass, Class... elementClasses) throws IOException { 40 | JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses); 41 | return objectMapper.readValue(jsonString, javaType); 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/java/com/theembers/iot/utils/KeyUtils.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.utils; 2 | 3 | /** 4 | * key 工具类 5 | * 6 | * @author TheEmbers Guo 7 | * @version 1.0 8 | * createTime 2018-10-26 17:01 9 | */ 10 | public class KeyUtils { 11 | public static String buildKey(String ip, Integer port) { 12 | return buildKey("com.theembers.iot-ms:collect_model_mapping", ip, port); 13 | } 14 | 15 | public static String buildKey(String platformName, String ip, Integer port) { 16 | return platformName + ":" + ip + ":" + port; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /iot-dc-netty-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | theembers: 2 | iot.netty.port: 12345 3 | 4 | #spring: 5 | # kafka: 6 | # bootstrap-servers: localhost:9092 7 | # consumer.group-id: 0 8 | # producer: 9 | # batch-size: 65536 10 | # buffer-memory: 524288 11 | # redis: 12 | # database: 10 13 | # host: localhost 14 | # port: 6379 15 | # timeout: 3000 16 | # rabbitmq: 17 | # addresses: localhost 18 | # port: 5672 19 | # username: guest 20 | # password: guest 21 | # host: localhost 22 | 23 | loggingpath: ./logs -------------------------------------------------------------------------------- /iot-example/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | iot-dc 7 | com.theembers.iot 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | iot-example 13 | 14 | 15 | 16 | com.theembers.iot 17 | iot-framework-dc 18 | 19 | 20 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/TestCollector.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.theembers.iot.router.Router; 5 | import me.theembers.iot.bean.IotMsgData; 6 | import me.theembers.iot.bean.TestIotData; 7 | import me.theembers.iot.rule.CacheRule; 8 | import me.theembers.iot.shadow.Device; 9 | import me.theembers.iot.shadow.IotShadow; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /** 15 | * @author TheEmbers Guo 16 | * createTime 2019-11-15 13:59 17 | */ 18 | public class TestCollector { 19 | 20 | 21 | private Router router = new TestRouter(); 22 | 23 | public void execute() { 24 | try { 25 | IotMsgData iotData = buildIotMsg(); 26 | IotShadow shadow = iotData.getShadow(); 27 | router.getSelector().selectRoute(shadow.getRule()).run(shadow, iotData); 28 | } catch (Exception e) { 29 | throw e; 30 | } 31 | } 32 | 33 | 34 | public static void main(String[] args) { 35 | TestCollector collector = new TestCollector(); 36 | collector.execute(); 37 | } 38 | 39 | 40 | private IotMsgData buildIotMsg() { 41 | // ================================================== 42 | // 构建 影子 43 | CacheRule rule = new CacheRule(); 44 | String[] pArr = {"TestProcessor", "Test2Processor"}; 45 | String[] pArr2 = {"Test2Processor", "TestProcessor"}; // -> 这边有个单例的bug 本例中 Test2Processor 只会执行一次,因为在Dispatcher#run中是内存地址比较 46 | Map keys = new HashMap<>(); 47 | keys.put("t1", pArr); 48 | keys.put("t2", pArr2); 49 | rule.setKeys(keys); 50 | 51 | 52 | IotShadow shadow = new IotShadow(); 53 | Device device = new Device(); 54 | device.setRule(rule); 55 | shadow.setDeviceShadow(device); 56 | 57 | // ======================================================= 58 | TestIotData testIotData = new TestIotData(); 59 | testIotData.setSn("sn12355211"); 60 | testIotData.setName("设备001"); 61 | 62 | 63 | IotMsgData iotData = new IotMsgData(); 64 | iotData.setDataJson(JSON.toJSONString(testIotData)); 65 | iotData.setShadow(shadow); 66 | 67 | return iotData; 68 | } 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/TestRouter.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot; 2 | 3 | import com.theembers.iot.processor.Processor; 4 | import com.theembers.iot.router.AbstractRouter; 5 | import com.theembers.iot.router.selector.AutoSelector; 6 | import me.theembers.iot.bizprocessor.Test2Processor; 7 | import me.theembers.iot.bizprocessor.TestProcessor; 8 | 9 | /** 10 | * @author TheEmbers Guo 11 | * createTime 2019-11-15 14:40 12 | */ 13 | public class TestRouter extends AbstractRouter { 14 | public TestRouter() { 15 | initRouter(new AutoSelector(this)); 16 | } 17 | 18 | @Override 19 | public void scanAndBuildMap() { 20 | PROCESSOR_MAP.put("TestProcessor", new TestProcessor()); 21 | PROCESSOR_MAP.put("Test2Processor", new Test2Processor()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/bean/IotMsgData.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot.bean; 2 | 3 | 4 | import com.theembers.iot.collector.SourceData; 5 | import me.theembers.iot.shadow.IotShadow; 6 | 7 | /** 8 | * @author TheEmbers Guo 9 | * createTime 2019-11-15 14:11 10 | */ 11 | public class IotMsgData implements SourceData { 12 | private IotShadow shadow; 13 | private String dataJson; 14 | 15 | public IotShadow getShadow() { 16 | return shadow; 17 | } 18 | 19 | public IotMsgData setShadow(IotShadow shadow) { 20 | this.shadow = shadow; 21 | return this; 22 | } 23 | 24 | public String getDataJson() { 25 | return dataJson; 26 | } 27 | 28 | public IotMsgData setDataJson(String dataJson) { 29 | this.dataJson = dataJson; 30 | return this; 31 | } 32 | 33 | @Override 34 | public String getData() { 35 | return dataJson; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/bean/TestAppData.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot.bean; 2 | 3 | import com.theembers.iot.processor.OutputData; 4 | import com.theembers.iot.processor.SlotData; 5 | 6 | /** 7 | * @author TheEmbers Guo 8 | * createTime 2019-11-14 15:02 9 | */ 10 | public class TestAppData extends OutputData implements SlotData { 11 | private String sn; 12 | 13 | public String getSn() { 14 | return sn; 15 | } 16 | 17 | public TestAppData setSn(String sn) { 18 | this.sn = sn; 19 | return this; 20 | } 21 | 22 | @Override 23 | public TestAppData get() { 24 | return this; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/bean/TestIotData.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot.bean; 2 | 3 | import com.theembers.iot.processor.InputData; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author TheEmbers Guo 9 | * createTime 2019-11-14 14:59 10 | */ 11 | public class TestIotData extends InputData { 12 | private String sn; 13 | private String name; 14 | private List list; 15 | 16 | public String getSn() { 17 | return sn; 18 | } 19 | 20 | public TestIotData setSn(String sn) { 21 | this.sn = sn; 22 | return this; 23 | } 24 | 25 | public String getName() { 26 | return name; 27 | } 28 | 29 | public TestIotData setName(String name) { 30 | this.name = name; 31 | return this; 32 | } 33 | 34 | public List getList() { 35 | return list; 36 | } 37 | 38 | public TestIotData setList(List list) { 39 | this.list = list; 40 | return this; 41 | } 42 | 43 | @Override 44 | public TestIotData get() { 45 | return this; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/bizprocessor/Test2Processor.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot.bizprocessor; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.theembers.iot.collector.SourceData; 5 | import com.theembers.iot.processor.AbstractProcessor; 6 | import com.theembers.iot.processor.Input; 7 | import com.theembers.iot.processor.Output; 8 | import com.theembers.iot.processor.SlotData; 9 | import me.theembers.iot.bean.TestAppData; 10 | import me.theembers.iot.bean.TestIotData; 11 | import me.theembers.iot.shadow.IotShadow; 12 | 13 | import java.util.Date; 14 | 15 | /** 16 | * @author TheEmbers Guo 17 | * createTime 2019-11-15 16:19 18 | */ 19 | public class Test2Processor extends AbstractProcessor { 20 | @Override 21 | public Input beforeTransform(IotShadow shadow, SourceData srcData) throws Exception { 22 | System.out.println(Thread.currentThread().getName() + " Test2Processor beforeTransform >> " + srcData.getData()); 23 | return JSON.parseObject((String) srcData.getData(), TestIotData.class); 24 | } 25 | 26 | @Override 27 | public Output transform(IotShadow shadow, Input input) throws Exception { 28 | System.out.println(Thread.currentThread().getName() + " Test2Processor transform >> ..."); 29 | TestIotData data = input.get(); 30 | TestAppData appData = new TestAppData(); 31 | appData.setSn(data.getSn() + "_2_" + new Date().getTime()); 32 | return appData; 33 | } 34 | 35 | @Override 36 | public Output afterTransform(IotShadow shadow, TestAppData output) throws Exception { 37 | System.out.println(Thread.currentThread().getName() + " Test2Processor afterTransform << " + output.getSn()); 38 | return null; 39 | } 40 | 41 | @Override 42 | public void except(Exception e, String... msg) { 43 | System.out.println(e); 44 | } 45 | 46 | @Override 47 | public Input relay(IotShadow shadow, SlotData slotData) { 48 | System.out.println(Thread.currentThread().getName() + " Test2Processor relay >> "); 49 | if (slotData instanceof TestAppData) { 50 | TestAppData testAppData = (TestAppData) slotData.get(); 51 | TestIotData iotData = new TestIotData(); 52 | 53 | iotData.setSn(testAppData.getSn()); 54 | return iotData; 55 | } 56 | except(new Exception("bad data type.")); 57 | return null; 58 | } 59 | 60 | @Override 61 | public SlotData passOn(IotShadow shadow, Output output) { 62 | System.out.println(Thread.currentThread().getName() + " Test2Processor passOn <<======"); 63 | return output.get(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/bizprocessor/TestProcessor.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot.bizprocessor; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.theembers.iot.collector.SourceData; 5 | import com.theembers.iot.processor.AbstractProcessor; 6 | import com.theembers.iot.processor.Input; 7 | import com.theembers.iot.processor.Output; 8 | import com.theembers.iot.processor.SlotData; 9 | import me.theembers.iot.bean.TestAppData; 10 | import me.theembers.iot.bean.TestIotData; 11 | import me.theembers.iot.shadow.IotShadow; 12 | 13 | import java.util.Date; 14 | 15 | /** 16 | * @author TheEmbers Guo 17 | * createTime 2019-11-14 15:01 18 | */ 19 | public class TestProcessor extends AbstractProcessor { 20 | 21 | 22 | @Override 23 | public Input beforeTransform(IotShadow shadow, SourceData srcData) throws Exception { 24 | System.out.println(Thread.currentThread().getName() + " beforeTransform >> " + srcData.getData()); 25 | return JSON.parseObject((String) srcData.getData(), TestIotData.class); 26 | } 27 | 28 | @Override 29 | public Output transform(IotShadow shadow, Input input) throws Exception { 30 | System.out.println(Thread.currentThread().getName() + " transform >> ..."); 31 | TestIotData data = input.get(); 32 | TestAppData appData = new TestAppData(); 33 | appData.setSn(data.getSn() + "_1_" + new Date().getTime()); 34 | return appData; 35 | } 36 | 37 | @Override 38 | public Output afterTransform(IotShadow shadow, TestAppData output) throws Exception { 39 | System.out.println(Thread.currentThread().getName() + " afterTransform << " + output.getSn()); 40 | return null; 41 | } 42 | 43 | @Override 44 | public void except(Exception e, String... msg) { 45 | System.out.println(e); 46 | } 47 | 48 | @Override 49 | public Input relay(IotShadow shadow, SlotData slotData) { 50 | System.out.println(Thread.currentThread().getName() + " relay >> "); 51 | if (slotData instanceof TestAppData) { 52 | TestAppData testAppData = (TestAppData) slotData.get(); 53 | TestIotData iotData = new TestIotData(); 54 | 55 | iotData.setSn(testAppData.getSn()); 56 | return iotData; 57 | } 58 | except(new Exception("bad data type.")); 59 | return null; 60 | } 61 | 62 | @Override 63 | public SlotData passOn(IotShadow shadow, Output output) { 64 | System.out.println(Thread.currentThread().getName() + " passOn <<======"); 65 | return output.get(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/rule/CacheRule.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot.rule; 2 | 3 | import com.theembers.iot.router.rule.MultipleRule; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * @author TheEmbers Guo 9 | * createTime 2019-11-15 15:32 10 | */ 11 | public class CacheRule implements MultipleRule { 12 | private Map keys; 13 | 14 | public Map getKeys() { 15 | return keys; 16 | } 17 | 18 | public CacheRule setKeys(Map keys) { 19 | this.keys = keys; 20 | return this; 21 | } 22 | 23 | @Override 24 | public Map key() { 25 | return keys; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/shadow/Device.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot.shadow; 2 | 3 | import com.theembers.iot.shadow.DeviceShadow; 4 | 5 | /** 6 | * @author TheEmbers Guo 7 | * createTime 2019-11-15 15:20 8 | */ 9 | public class Device extends DeviceShadow { 10 | private String sn; 11 | private Long time; 12 | 13 | public String getSn() { 14 | return sn; 15 | } 16 | 17 | public Device setSn(String sn) { 18 | this.sn = sn; 19 | return this; 20 | } 21 | 22 | public Long getTime() { 23 | return time; 24 | } 25 | 26 | public Device setTime(Long time) { 27 | this.time = time; 28 | return this; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/shadow/IotShadow.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot.shadow; 2 | 3 | import com.theembers.iot.shadow.DeviceShadowSnapshot; 4 | 5 | /** 6 | * @author TheEmbers Guo 7 | * createTime 2019-11-15 14:11 8 | */ 9 | public class IotShadow extends DeviceShadowSnapshot { 10 | } 11 | -------------------------------------------------------------------------------- /iot-example/src/main/java/me/theembers/iot/shadow/Product.java: -------------------------------------------------------------------------------- 1 | package me.theembers.iot.shadow; 2 | 3 | import com.theembers.iot.shadow.ProductShadow; 4 | 5 | /** 6 | * @author TheEmbers Guo 7 | * createTime 2019-11-15 15:21 8 | */ 9 | public class Product extends ProductShadow { 10 | } 11 | -------------------------------------------------------------------------------- /iot-framework-dc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | iot-dc 7 | com.theembers.iot 8 | 1.0-SNAPSHOT 9 | ../pom.xml 10 | 11 | 4.0.0 12 | 13 | iot-framework-dc 14 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/collector/AbstractCollectorRunner.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.collector; 2 | 3 | import org.springframework.beans.factory.InitializingBean; 4 | 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | 8 | /** 9 | * 抽象采集器执行者 10 | * 实现了CollectorRunner & InitializingBean接口 11 | *

12 | * InitializingBean接口 13 | * 负责加载指定的 collectorConfig配置对象 和 dataProcessor数据处理器对象 14 | *

15 | * CollectorRunner接口 16 | * CollectorRunner接口继承了 CommandLineRunner接口 17 | * 模板模式 [final method] 调用处理器 18 | * 19 | * @author TheEmbers Guo 20 | * @version 1.0 21 | * createTime 2018-09-30 2:48 PM 22 | */ 23 | public abstract class AbstractCollectorRunner implements CollectorRunner, InitializingBean { 24 | private static ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); 25 | private C collectorConfig; 26 | private DataCollector collector; 27 | 28 | public abstract C setCollectorConfig(); 29 | 30 | public abstract DataCollector setDataCollector(); 31 | 32 | 33 | @Override 34 | public void afterPropertiesSet() throws Exception { 35 | collectorConfig = setCollectorConfig(); 36 | collector = setDataCollector(); 37 | } 38 | 39 | @Override 40 | public final void run(String... args) throws Exception { 41 | singleThreadExecutor.execute(() -> this.collector.executor(this.collectorConfig)); 42 | } 43 | } -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/collector/CollectorRunner.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.collector; 2 | 3 | import org.springframework.boot.CommandLineRunner; 4 | 5 | /** 6 | * 采集器 执行者 7 | * 8 | * @author TheEmbers Guo 9 | * createTime 2019-11-06 14:06 10 | */ 11 | public interface CollectorRunner extends CommandLineRunner { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/collector/DataCollector.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.collector; 2 | 3 | /** 4 | * 数据采集器 5 | * 6 | * @author TheEmbers Guo 7 | * createTime 2019-11-06 14:18 8 | */ 9 | public interface DataCollector { 10 | /** 11 | * 初始化 12 | */ 13 | default void init() { 14 | } 15 | 16 | /** 17 | * 执行 18 | * 19 | * @param c 20 | */ 21 | void executor(C c); 22 | 23 | /** 24 | * 卸载 25 | */ 26 | default void dispatch() { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/collector/DataCollectorConfig.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.collector; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-07 15:22 6 | */ 7 | public abstract class DataCollectorConfig { 8 | } 9 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/collector/SourceData.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.collector; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-15 14:19 6 | */ 7 | public interface SourceData { 8 | T getData(); 9 | } 10 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/processor/AbstractProcessor.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.processor; 2 | 3 | import com.theembers.iot.collector.SourceData; 4 | import com.theembers.iot.shadow.Shadow; 5 | 6 | /** 7 | * @author TheEmbers Guo 8 | * createTime 2019-11-11 17:57 9 | */ 10 | public abstract class AbstractProcessor implements Processor { 11 | 12 | @Override 13 | public final Output receive(S shadow, SlotData slotData) { 14 | try { 15 | Input iData = relay(shadow, slotData); 16 | return transform(shadow, iData); 17 | } catch (Exception e) { 18 | except(e); 19 | } 20 | return null; 21 | } 22 | 23 | @Override 24 | public final Output headIn(S shadow, SourceData srcData) { 25 | try { 26 | Input iData = beforeTransform(shadow, srcData); 27 | return transform(shadow, iData); 28 | } catch (Exception e) { 29 | except(e); 30 | } 31 | return null; 32 | } 33 | 34 | @Override 35 | public final Output tailOut(S shadow, O output) { 36 | try { 37 | return afterTransform(shadow, output); 38 | } catch (Exception e) { 39 | except(e); 40 | } 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/processor/Input.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.processor; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-14 10:01 6 | */ 7 | public interface Input { 8 | T get(); 9 | } 10 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/processor/InputData.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.processor; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-14 14:59 6 | */ 7 | public abstract class InputData implements Input { 8 | private T data; 9 | private Long time; 10 | 11 | 12 | public T getData() { 13 | return data; 14 | } 15 | 16 | public InputData setData(T data) { 17 | this.data = data; 18 | return this; 19 | } 20 | 21 | public Long getTime() { 22 | return time; 23 | } 24 | 25 | public InputData setTime(Long time) { 26 | this.time = time; 27 | return this; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/processor/Output.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.processor; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-14 10:01 6 | */ 7 | public interface Output { 8 | T get(); 9 | } 10 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/processor/OutputData.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.processor; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-07 17:01 6 | */ 7 | public abstract class OutputData implements Output { 8 | private T data; 9 | private Long time; 10 | 11 | public Long getTime() { 12 | return time; 13 | } 14 | 15 | public OutputData setTime(Long time) { 16 | this.time = time; 17 | return this; 18 | } 19 | 20 | public T getData() { 21 | return data; 22 | } 23 | 24 | public OutputData setData(T data) { 25 | this.data = data; 26 | return this; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/processor/Processor.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.processor; 2 | 3 | import com.theembers.iot.collector.SourceData; 4 | import com.theembers.iot.shadow.Shadow; 5 | 6 | /** 7 | * @author TheEmbers Guo 8 | * createTime 2019-11-11 17:54 9 | */ 10 | public interface Processor extends Slot { 11 | /** 12 | * 前置处理流程 13 | * 流数据转换、对象转换等... 14 | * 15 | * @param shadow 16 | * @param srcData 17 | * @return 18 | */ 19 | Input beforeTransform(S shadow, SourceData srcData) throws Exception; 20 | 21 | /** 22 | * 业务处理 23 | * 具体业务赋能 24 | * 25 | * @param shadow 26 | * @param input 27 | * @return 28 | */ 29 | Output transform(S shadow, Input input) throws Exception; 30 | 31 | /** 32 | * 后置处理流程 33 | * 只有在最后才会被调用的方法 34 | * 数据封装、业务数据封装等 35 | * 36 | * @param shadow 37 | * @param output 38 | * @return 39 | */ 40 | Output afterTransform(S shadow, O output) throws Exception; 41 | 42 | /** 43 | * 异常 44 | */ 45 | void except(Exception e, String... msg); 46 | } 47 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/processor/Slot.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.processor; 2 | 3 | 4 | import com.theembers.iot.collector.SourceData; 5 | import com.theembers.iot.shadow.Shadow; 6 | 7 | /** 8 | * @author TheEmbers Guo 9 | * createTime 2019-11-13 16:29 10 | */ 11 | public interface Slot { 12 | 13 | /** 14 | * 接收 15 | * 插槽数据接收 & 执行 16 | */ 17 | Output receive(S shadow, SlotData slotData); 18 | 19 | /** 20 | * 接力 21 | * 插槽数据转换 22 | */ 23 | Input relay(S shadow, SlotData slotData); 24 | 25 | /** 26 | * 传递 27 | * 将自己的数据转为插槽 28 | */ 29 | SlotData passOn(S shadow, Output output); 30 | 31 | Output headIn(S shadow, SourceData input); 32 | 33 | Output tailOut(S shadow, O output); 34 | } 35 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/processor/SlotData.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.processor; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-14 17:01 6 | */ 7 | public interface SlotData { 8 | default T get() { 9 | return (T) this; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/processor/SortData.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.processor; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-13 16:39 6 | */ 7 | public class SortData { 8 | public T data; 9 | } 10 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/processor/ThingData.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.processor; 2 | 3 | import java.util.Collections; 4 | import java.util.Date; 5 | import java.util.List; 6 | 7 | /** 8 | * @author TheEmbers Guo 9 | * createTime 2019-11-07 16:57 10 | */ 11 | public class ThingData implements Input, Output { 12 | private String pId; 13 | private Date time; 14 | private T data; 15 | 16 | 17 | public T getData() { 18 | return data; 19 | } 20 | 21 | public ThingData setData(T data) { 22 | this.data = data; 23 | return this; 24 | } 25 | 26 | List buildDataEntity(Class clazz) { 27 | return Collections.singletonList(data); 28 | } 29 | 30 | @Override 31 | public T get() { 32 | return data; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/AbstractRouter.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router; 2 | 3 | import com.theembers.iot.router.selector.Selector; 4 | 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | /** 9 | * 抽象 路由 10 | * @author TheEmbers Guo 11 | * createTime 2019-11-11 10:01 12 | */ 13 | public abstract class AbstractRouter

implements Router

{ 14 | private Selector selector; 15 | protected final Map PROCESSOR_MAP = new ConcurrentHashMap<>(); 16 | 17 | @Override 18 | public Router initRouter(Selector selector) { 19 | setSelector(selector); 20 | scanAndBuildMap(); 21 | return this; 22 | } 23 | 24 | @Override 25 | public abstract void scanAndBuildMap(); 26 | 27 | @Override 28 | public void setSelector(Selector selector) { 29 | this.selector = selector; 30 | } 31 | 32 | @Override 33 | public Selector getSelector() { 34 | return this.selector; 35 | } 36 | 37 | @Override 38 | public Map getMap() { 39 | return PROCESSOR_MAP; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/DefaultRouter.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router; 2 | 3 | 4 | import com.theembers.iot.processor.Processor; 5 | import com.theembers.iot.router.selector.DefaultSelector; 6 | import org.springframework.beans.factory.InitializingBean; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.Map; 10 | 11 | /** 12 | * @author TheEmbers Guo 13 | * createTime 2019-11-11 10:58 14 | */ 15 | @Component 16 | public class DefaultRouter extends AbstractRouter implements InitializingBean { 17 | 18 | 19 | @Override 20 | public void scanAndBuildMap() { 21 | init(); 22 | } 23 | 24 | @Override 25 | public DefaultSelector getSelector() { 26 | return (DefaultSelector) super.getSelector(); 27 | } 28 | 29 | @Override 30 | public Map getMap() { 31 | return PROCESSOR_MAP; 32 | } 33 | 34 | 35 | @Override 36 | public void afterPropertiesSet() { 37 | initRouter(new DefaultSelector(this)); 38 | } 39 | 40 | private void init() { 41 | // todo 初始化方法 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/Router.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router; 2 | 3 | import com.theembers.iot.router.selector.Selector; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * @author TheEmbers Guo 9 | * createTime 2019-11-11 10:11 10 | */ 11 | public interface Router

{ 12 | /** 13 | * 初始化 路由器 14 | * 15 | * @return 16 | */ 17 | Router initRouter(Selector selector); 18 | 19 | /** 20 | * 扫描并构建 map 21 | * 22 | * @return 23 | */ 24 | void scanAndBuildMap(); 25 | 26 | /** 27 | * 设置 选择器 28 | * 29 | * @param selector 30 | */ 31 | void setSelector(Selector selector); 32 | 33 | Selector getSelector(); 34 | 35 | Map getMap(); 36 | } 37 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/route/AbstractRoute.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.route; 2 | 3 | import com.theembers.iot.router.Router; 4 | import com.theembers.iot.router.rule.Rule; 5 | 6 | /** 7 | * 抽象 导航 8 | * R 规则 9 | * T 为 dispatcher 的数据结构形态 10 | * 11 | * @author TheEmbers Guo 12 | * createTime 2019-11-13 14:53 13 | */ 14 | public abstract class AbstractRoute implements Route { 15 | protected R rule; 16 | protected T dispatchers; 17 | 18 | 19 | public R getRule() { 20 | return rule; 21 | } 22 | 23 | public T getDispatchers() { 24 | return dispatchers; 25 | } 26 | 27 | @Override 28 | public Route buildRoute(Router router, R rule) { 29 | this.rule = rule; 30 | this.dispatchers = buildDispatcher(router, rule, this.dispatchers); 31 | return this; 32 | } 33 | 34 | abstract T buildDispatcher(Router router, R rule, T dispatchers); 35 | } 36 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/route/Dispatcher.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.route; 2 | 3 | 4 | import com.theembers.iot.collector.SourceData; 5 | import com.theembers.iot.processor.Output; 6 | import com.theembers.iot.processor.Processor; 7 | import com.theembers.iot.processor.SlotData; 8 | import com.theembers.iot.shadow.Shadow; 9 | 10 | import java.util.*; 11 | import java.util.function.Consumer; 12 | 13 | /** 14 | * 处理器调度员 15 | * 16 | * @author TheEmbers Guo 17 | * createTime 2019-11-14 10:43 18 | */ 19 | public class Dispatcher implements Iterable { 20 | 21 | private Processor first; 22 | private Processor last; 23 | private int mark; 24 | private List link; 25 | 26 | public Processor getFirst() { 27 | return first; 28 | } 29 | 30 | public Processor getLast() { 31 | return last; 32 | } 33 | 34 | public void setFirst(Processor processor) { 35 | this.first = processor; 36 | } 37 | 38 | public void setLast(Processor processor) { 39 | this.last = processor; 40 | } 41 | 42 | public void append(Processor processor) { 43 | if (first == null) { 44 | link = new LinkedList<>(); 45 | setFirst(processor); 46 | } 47 | link.add(processor); 48 | setLast(processor); 49 | mark++; 50 | } 51 | 52 | public Processor getMark() { 53 | if (link.size() == 0) { 54 | return null; 55 | } 56 | return link.get(mark); 57 | } 58 | 59 | @Override 60 | public Iterator iterator() { 61 | return link.listIterator(); 62 | } 63 | 64 | @Override 65 | public void forEach(Consumer action) { 66 | Objects.requireNonNull(action); 67 | for (Processor t : this) { 68 | action.accept(t); 69 | } 70 | } 71 | 72 | @Override 73 | public Spliterator spliterator() { 74 | return Spliterators.spliteratorUnknownSize(iterator(), 0); 75 | } 76 | 77 | /** 78 | * 执行 79 | * 如果 当前processor是头节点,调用 headIn ( 调用 beforeTransform & transForm) 80 | * 否则 (中间节点 或者 尾节点) 调用 receive(接收) 81 | * 最终 如果 是尾结点 则 调用 tailOut (调用 afterTransform) 并 退出循环 82 | * 到 //1 则 调用 buildSlotData (构建插槽) 83 | * 84 | * @param shadow 85 | * @param sourceData 86 | */ 87 | void run(Shadow shadow, SourceData sourceData) { 88 | Output output = null; 89 | SlotData slotData = null; 90 | Iterator processors = this.link.iterator(); 91 | while (processors.hasNext()) { 92 | Processor p = processors.next(); 93 | if (p == getFirst()) { 94 | output = p.headIn(shadow, sourceData); 95 | } else { 96 | output = p.receive(shadow, slotData); 97 | } 98 | if (p == getLast()) { 99 | output = p.tailOut(shadow, output); 100 | return; 101 | } 102 | slotData = p.passOn(shadow, output); // 1 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/route/LinkedRoute.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.route; 2 | 3 | import com.theembers.iot.collector.SourceData; 4 | import com.theembers.iot.processor.Processor; 5 | import com.theembers.iot.router.Router; 6 | import com.theembers.iot.router.rule.LinkedRule; 7 | import com.theembers.iot.shadow.Shadow; 8 | 9 | import java.util.Map; 10 | 11 | /** 12 | * @author TheEmbers Guo 13 | * createTime 2019-11-12 10:14 14 | */ 15 | public class LinkedRoute extends AbstractRoute { 16 | @Override 17 | public Dispatcher buildDispatcher(Router router, LinkedRule rule, Dispatcher dispatcher) { 18 | if (dispatcher == null) { 19 | dispatcher = new Dispatcher(); 20 | } 21 | Map processorMap = router.getMap(); 22 | String[] keyArr = this.rule.getKey(); 23 | 24 | if (keyArr.length > 0) { 25 | for (String key : keyArr) { 26 | Processor theProcessor = processorMap.get(key); 27 | dispatcher.append(theProcessor); 28 | } 29 | } 30 | return dispatcher; 31 | } 32 | 33 | 34 | @Override 35 | public void run(Shadow shadow, SourceData data) { 36 | run(shadow, data); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/route/MultipleRoute.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.route; 2 | 3 | import com.theembers.iot.collector.SourceData; 4 | import com.theembers.iot.processor.Processor; 5 | import com.theembers.iot.router.Router; 6 | import com.theembers.iot.router.rule.MultipleRule; 7 | import com.theembers.iot.shadow.Shadow; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.concurrent.*; 12 | 13 | /** 14 | * @author TheEmbers Guo 15 | * createTime 2019-11-13 15:53 16 | */ 17 | public class MultipleRoute extends AbstractRoute, MultipleRule> { 18 | private static final ExecutorService THREAD_POOL = new ThreadPoolExecutor(5, 10, 60, TimeUnit.MINUTES, 19 | new LinkedBlockingQueue<>(100), Executors.defaultThreadFactory(), 20 | new ThreadPoolExecutor.AbortPolicy()); 21 | 22 | 23 | @Override 24 | public Map buildDispatcher(Router router, MultipleRule rule, Map dispatchers) { 25 | if (dispatchers == null) { 26 | dispatchers = new HashMap<>(); 27 | } 28 | Map processorMap = router.getMap(); 29 | Map ruleKey = this.rule.key(); 30 | if (ruleKey == null || ruleKey.size() == 0) { 31 | return dispatchers; 32 | } 33 | 34 | for (String head : ruleKey.keySet()) { 35 | String[] keys = ruleKey.get(head); 36 | if (keys == null || keys.length == 0) { 37 | return dispatchers; 38 | } 39 | Dispatcher d = new Dispatcher(); 40 | for (String key : keys) { 41 | d.append(processorMap.get(key)); 42 | } 43 | dispatchers.put(keys, d); 44 | } 45 | return dispatchers; 46 | } 47 | 48 | 49 | @Override 50 | public void run(Shadow shadow, SourceData data) { 51 | Map dispatcherMap = this.dispatchers; 52 | dispatcherMap.forEach((keys, dispatcher) -> THREAD_POOL.execute(() -> dispatcher.run(shadow, data))); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/route/Route.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.route; 2 | 3 | import com.theembers.iot.collector.SourceData; 4 | import com.theembers.iot.router.Router; 5 | import com.theembers.iot.router.rule.Rule; 6 | import com.theembers.iot.shadow.Shadow; 7 | 8 | /** 9 | * 路线 10 | * 11 | * @author TheEmbers Guo 12 | * createTime 2019-11-11 10:16 13 | */ 14 | public interface Route { 15 | 16 | 17 | Route buildRoute(Router router, R rule); 18 | 19 | /** 20 | * 执行 21 | * 22 | * @param shadow 23 | * @param srcData 24 | */ 25 | void run(Shadow shadow, SourceData srcData); 26 | } 27 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/route/SimpleRoute.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.route; 2 | 3 | import com.theembers.iot.collector.SourceData; 4 | import com.theembers.iot.processor.Processor; 5 | import com.theembers.iot.router.Router; 6 | import com.theembers.iot.router.rule.SimpleRule; 7 | import com.theembers.iot.shadow.Shadow; 8 | 9 | import java.util.Map; 10 | 11 | /** 12 | * @author TheEmbers Guo 13 | * createTime 2019-11-11 10:47 14 | */ 15 | 16 | public class SimpleRoute extends AbstractRoute { 17 | 18 | @Override 19 | public Dispatcher buildDispatcher(Router router, SimpleRule rule, Dispatcher dispatchers) { 20 | Map processorMap = router.getMap(); 21 | if (dispatchers == null) { 22 | dispatchers = new Dispatcher(); 23 | } 24 | dispatchers.append(processorMap.get(this.rule.key())); 25 | return dispatchers; 26 | } 27 | 28 | @Override 29 | public void run(Shadow shadow, SourceData srcData) { 30 | run(shadow, srcData); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/rule/LinkedRule.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.rule; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-13 14:45 6 | */ 7 | public interface LinkedRule extends Rule { 8 | String[] getKey(); 9 | } 10 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/rule/MultipleRule.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.rule; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * @author TheEmbers Guo 7 | * createTime 2019-11-13 14:45 8 | */ 9 | public interface MultipleRule extends Rule> { 10 | } 11 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/rule/Rule.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.rule; 2 | 3 | /** 4 | * 路径选择 规则 5 | * 6 | * @author TheEmbers Guo 7 | * createTime 2019-11-11 10:18 8 | */ 9 | public interface Rule { 10 | K key(); 11 | } 12 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/rule/SimpleRule.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.rule; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-13 14:45 6 | */ 7 | public interface SimpleRule extends Rule { 8 | } 9 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/selector/AbstractSelector.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.selector; 2 | 3 | 4 | import com.theembers.iot.router.Router; 5 | import com.theembers.iot.router.route.Route; 6 | import com.theembers.iot.router.rule.Rule; 7 | 8 | /** 9 | * @author TheEmbers Guo 10 | * createTime 2019-11-13 10:44 11 | */ 12 | public abstract class AbstractSelector implements Selector { 13 | protected Router router; 14 | 15 | 16 | protected AbstractSelector(Router router) { 17 | this.router = router; 18 | } 19 | 20 | @Override 21 | public Route selectRoute(Route route, Rule rule) { 22 | return route.buildRoute(router, rule); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/selector/AutoSelector.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.selector; 2 | 3 | import com.theembers.iot.router.Router; 4 | import com.theembers.iot.router.route.LinkedRoute; 5 | import com.theembers.iot.router.route.MultipleRoute; 6 | import com.theembers.iot.router.route.Route; 7 | import com.theembers.iot.router.route.SimpleRoute; 8 | import com.theembers.iot.router.rule.LinkedRule; 9 | import com.theembers.iot.router.rule.MultipleRule; 10 | import com.theembers.iot.router.rule.Rule; 11 | import com.theembers.iot.router.rule.SimpleRule; 12 | 13 | /** 14 | * @author TheEmbers Guo 15 | * createTime 2019-11-15 17:28 16 | */ 17 | public class AutoSelector extends AbstractSelector { 18 | 19 | public AutoSelector(Router router) { 20 | super(router); 21 | } 22 | 23 | public Route selectRoute(Rule rule) { 24 | Route route = getRoute(rule); 25 | return super.selectRoute(route, rule); 26 | } 27 | 28 | private Route getRoute(Rule rule) { 29 | 30 | if (rule instanceof SimpleRule) { 31 | return new SimpleRoute(); 32 | } else if (rule instanceof LinkedRule) { 33 | return new LinkedRoute(); 34 | } else if (rule instanceof MultipleRule) { 35 | return new MultipleRoute(); 36 | } else { 37 | return null; 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/selector/DefaultSelector.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.selector; 2 | 3 | import com.theembers.iot.router.Router; 4 | import com.theembers.iot.router.route.Route; 5 | import com.theembers.iot.router.rule.Rule; 6 | 7 | /** 8 | * @author TheEmbers Guo 9 | * createTime 2019-11-13 15:33 10 | */ 11 | public class DefaultSelector extends AbstractSelector { 12 | public DefaultSelector(Router router) { 13 | super(router); 14 | } 15 | 16 | @Override 17 | public Route selectRoute(Rule rule) { 18 | return null; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/router/selector/Selector.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.router.selector; 2 | 3 | import com.theembers.iot.router.route.Route; 4 | import com.theembers.iot.router.rule.Rule; 5 | 6 | /** 7 | * @author TheEmbers Guo 8 | * createTime 2019-11-11 10:14 9 | */ 10 | public interface Selector { 11 | Route selectRoute(Route route, Rule rule); 12 | 13 | Route selectRoute(Rule rule); 14 | } 15 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/shadow/DeviceShadow.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.shadow; 2 | 3 | 4 | import com.theembers.iot.router.rule.Rule; 5 | 6 | /** 7 | * @author TheEmbers Guo 8 | * createTime 2019-11-11 15:32 9 | */ 10 | public abstract class DeviceShadow implements Shadow { 11 | private Rule rule; 12 | private D device; 13 | private ProductShadow

productShadow; 14 | 15 | public Rule getRule() { 16 | if (null == rule) { 17 | return productShadow.getRule(); 18 | } 19 | return rule; 20 | } 21 | 22 | public DeviceShadow setRule(Rule rule) { 23 | this.rule = rule; 24 | return this; 25 | } 26 | 27 | public D getDevice() { 28 | return device; 29 | } 30 | 31 | public DeviceShadow setDevice(D device) { 32 | this.device = device; 33 | return this; 34 | } 35 | 36 | public ProductShadow

getProductShadow() { 37 | return productShadow; 38 | } 39 | 40 | public DeviceShadow setProductShadow(ProductShadow

productShadow) { 41 | this.productShadow = productShadow; 42 | return this; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/shadow/DeviceShadowSnapshot.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.shadow; 2 | 3 | 4 | import com.theembers.iot.router.rule.Rule; 5 | 6 | /** 7 | * @author TheEmbers Guo 8 | * createTime 2019-11-11 15:33 9 | */ 10 | public abstract class DeviceShadowSnapshot implements Shadow { 11 | private Rule rule; 12 | private DeviceShadow deviceShadow; 13 | 14 | public Rule getRule() { 15 | if (null == rule) { 16 | return deviceShadow.getRule(); 17 | } 18 | return rule; 19 | } 20 | 21 | public DeviceShadowSnapshot setRule(Rule rule) { 22 | this.rule = rule; 23 | return this; 24 | } 25 | 26 | public DeviceShadow getDeviceShadow() { 27 | return deviceShadow; 28 | } 29 | 30 | public DeviceShadowSnapshot setDeviceShadow(DeviceShadow deviceShadow) { 31 | this.deviceShadow = deviceShadow; 32 | return this; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/shadow/ProductShadow.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.shadow; 2 | 3 | 4 | import com.theembers.iot.router.rule.Rule; 5 | 6 | /** 7 | * @author TheEmbers Guo 8 | * createTime 2019-11-11 15:25 9 | */ 10 | public abstract class ProductShadow

implements Shadow { 11 | private Rule rule; 12 | private P product; 13 | private String[] topics; 14 | 15 | public String[] getTopics() { 16 | return topics; 17 | } 18 | 19 | public ProductShadow

setTopics(String[] topics) { 20 | this.topics = topics; 21 | return this; 22 | } 23 | 24 | public Rule getRule() { 25 | return rule; 26 | } 27 | 28 | public ProductShadow

setRule(Rule rule) { 29 | this.rule = rule; 30 | return this; 31 | } 32 | 33 | public P getProduct() { 34 | return product; 35 | } 36 | 37 | public ProductShadow

setProduct(P product) { 38 | this.product = product; 39 | return this; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /iot-framework-dc/src/main/java/com/theembers/iot/shadow/Shadow.java: -------------------------------------------------------------------------------- 1 | package com.theembers.iot.shadow; 2 | 3 | /** 4 | * @author TheEmbers Guo 5 | * createTime 2019-11-11 15:26 6 | */ 7 | public interface Shadow extends Cloneable { 8 | } 9 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.theembers.iot 8 | iot-dc 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | iot-dc-beans 13 | 14 | iot-framework-dc 15 | iot-dc-netty-server 16 | iot-example 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-parent 22 | 2.1.3.RELEASE 23 | 24 | 25 | 26 | UTF-8 27 | UTF-8 28 | 1.8 29 | 1.0-SNAPSHOT 30 | 31 | 32 | 33 | 34 | 35 | com.theembers.iot 36 | iot-dc-beans 37 | ${project-version} 38 | 39 | 40 | com.theembers.iot 41 | iot-framework-dc 42 | ${project-version} 43 | 44 | 45 | com.theembers.iot 46 | iot-dc-netty-server 47 | ${project-version} 48 | 49 | 50 | 51 | 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-starter 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-starter-test 60 | test 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-configuration-processor 65 | true 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | io.netty 76 | netty-all 77 | 4.1.42.Final 78 | 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-starter-amqp 83 | 84 | 85 | 86 | org.springframework.kafka 87 | spring-kafka 88 | 89 | 90 | 91 | org.springframework.boot 92 | spring-boot-starter-data-redis 93 | 94 | 95 | 96 | com.fasterxml.jackson.core 97 | jackson-databind 98 | [2.9.9,) 99 | 100 | 101 | com.alibaba 102 | fastjson 103 | 1.2.62 104 | 105 | 106 | 107 | --------------------------------------------------------------------------------