吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7816|回复: 99
收起左侧

[Java 原创] 【个人开源项目】第二弹#基于物联网终端DTU设备的企业级物联网系统#求star

    [复制链接]
AflyExeed 发表于 2024-5-23 11:22
本帖最后由 AflyExeed 于 2024-5-23 11:24 编辑

上次开源的是一个扫码点餐系统,这个是毕业之前做的一个毕设,稍微整理一下就开源出来供大家学习了,有吾友说要拿去开饭店,但其实这个项目只能用来学习而已,并不能商业化,毕竟没有对接支付
然后本次是开源一个物联网系统,上班之后业余时间写了这个,基于大名鼎鼎的若依框架二开的,可以拿来学习一下Netty通信、动态大屏等开发。项目写完也就写完了,不如开源出来大家互相学习,也为论坛做出点贡献
各位师哥师姐可以给小的点个star吗

源码仓库:https://gitee.com/ah-f/AflyExceedIot-backend

项目介绍


本项目是用于企业工厂设备监控,统计设备稼动率、监控设备实时运行状况等。 通过物联网终端设备(DTU)接入平台,配置好设备参数将设备添加到平台即可对设备运行状态监控。


项目分为这四部分

项目模块仓库地址
前端https://gitee.com/ah-f/AflyExceedIot-front
后端https://gitee.com/ah-f/AflyExceedIot-backend
设备网关服务https://gitee.com/ah-f/AflyExceedIot-gateway
wx小程序https://gitee.com/ah-f/AflyExceedIot-miniprogram

项目整体架构
1.jpg
物联网终端(DUT): 是一种专为物联网(Internet of Things, IoT)应用设计的无线数据传输设备。其核心功能在于实现现场设备(如传感器、控制器、仪表等)与远程服务器之间的数据透明传输,即在不同通信协议和网络架构之间建立起可靠的桥接,确保数据能够在不同的网络环境中高效、稳定地交换。 本项目对接的终端设备是一种携带四个继电器的设备,通过4G无线网络实时发送当前四位继电器的状态发送到设备网关服务,可以将继电器的状态规定为运行、关机、报警、待机四种状态,这样就可以在后端知道当前设备状态进行监控,计算获取当前设备稼动率。系统介绍
  • 基于若依管理后台进行二次开发。
  • 基于Netty框架实现物联网设备网关服务
  • 基于Echarts实现动态实时大屏
  • 前端采用Vue3、Element UI。
  • 后端采用Spring Boot、Spring Security、Redis & Jwt。
  • 权限认证使用Jwt,支持多终端认证系统。
  • 支持加载动态权限菜单,多方式轻松权限控制。
  • 封装异步任务管理,提高系统并发。
功能介绍
  • 设备管理:对DTU设备进行管理。
  • 动态大屏:实时显示设备当前状态、设备位置、设备监控、设备稼动率统计。
  • 设备地图:展示设备地理位置分布等信息。
  • 数据记录:对设备数据进行统计、查看、分析。
  • 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
  • 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
  • 登录日志:系统登录日志记录查询包含登录异常。
  • 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
  • 缓存监控:对系统的缓存信息查询,命令统计等。
  • 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
Netty核心代码
[Java] 纯文本查看 复制代码
@Slf4j
@Component("nettyServer")
public class NettyServer {

    @Resource
    private CustomerChannelInitializer channelInitializer;

    //配置服务端NIO线程组
    private final EventLoopGroup parentGroup = new NioEventLoopGroup(); //NioEventLoopGroup extends MultithreadEventLoopGroup Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
    private final EventLoopGroup childGroup = new NioEventLoopGroup();
    private Channel channel;

    public ChannelFuture bing(InetSocketAddress address) {
        ChannelFuture channelFuture = null;
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(parentGroup, childGroup)
                    .channel(NioServerSocketChannel.class)    //非阻塞模式
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childHandler(channelInitializer);

            channelFuture = b.bind(address).syncUninterruptibly();
            channel = channelFuture.channel();
        } catch (Exception e) {
            log.error(e.getMessage());
        } finally {
            if (null != channelFuture && channelFuture.isSuccess()) {
                log.info("device netty server start done. ");
            } else {
                log.error("device netty server start error. ");
            }
        }
        return channelFuture;
    }

    public void destroy() {
        if (null == channel) return;
        channel.close();
        parentGroup.shutdownGracefully();
        childGroup.shutdownGracefully();
    }

    public Channel getChannel() {
        return channel;
    }

}


处理设备消息核心逻辑:

[Java] 纯文本查看 复制代码
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //接收msg消息
        log.info(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 服务端接收到消息:" + msg);
        long currentTimeMillis = System.currentTimeMillis();
        //通知客户端链消息发送成功
        String str = "服务端收到:" + new Date() + " " + msg + "\r\n";
        SocketChannel channel = (SocketChannel) ctx.channel();
        String channelId = channel.id().toString();
        //处理发送注册码
        if (msg.toString().charAt(0) != 'D') {
            // 设备上线
            poolTaskExecutor.execute(() -> {
                Device dev = deviceService.getOne(new QueryWrapper<Device>().lambda()
                        .eq(Device::getNumber, msg.toString()));
                if (dev == null){
                    //设备不存在不处理
                    log.info("该设备还未添加或者其他数据不做处理");
                    return;
                }
                CacheUtil.cacheClientChannel.put(channelId, channel);
                CacheUtil.deviceChannelMap.put(channelId, msg.toString());
                Device device = Device.builder().number(msg.toString())
                        .status(1)
                        .lastOnline(LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault()))
                        .build();
                Boolean result = deviceService.updateDeviceStatus(device);
                if (result) {
                    log.info("修改设备{}在线成功,时间{}", msg, new Date().toInstant());
                } else {
                    log.info("修改设备{}在线失败,时间{}", msg, new Date().toInstant());
                }
                //判断当前设备是否是波动下线 是的话进行数据补偿
                if (CacheUtil.deviceOfflineMap.containsKey(msg.toString())) {
                    Long lastTime = CacheUtil.deviceOfflineMap.get(msg.toString());
                    if (currentTimeMillis - lastTime < 1000 * 60 * 15) { //间隔小于15分钟进行数据补偿
                        Transaction one = transactionMapper.selectOne(new QueryWrapper<Transaction>().lambda()
                                .eq(Transaction::getDeviceNo, msg.toString())
                                .eq(Transaction::getFromType, "1")
                                .orderByDesc(Transaction::getId)
                                .last("limit 1")); //获取上一次数据内容
                        long times = (currentTimeMillis - lastTime) / (1000 * 60 * 3);
                        List<Transaction> transactions = new ArrayList<>();
                        for (long i = 0; i < times; i++) {
                            one.setTime(one.getTime().plusMinutes(3 * (i + 1))); //时间增加三分钟
                            transactions.add(one);
                        }
                        if (transactionService.saveBatch(transactions)) {//批量添加
                            //删除缓存中波动设备
                            CacheUtil.deviceOfflineMap.remove(msg.toString());
                        }
                    }
                }

            });

        } else {
            //获取设备号
            String deviceNo = CacheUtil.deviceChannelMap.get(channelId);

            poolTaskExecutor.execute(() -> { //数据保存到数据库
                transactionService.save(Transaction.builder().deviceNo(deviceNo)
                        .data(msg.toString().substring(1))
                        .fromType("1")
                        .time(LocalDateTime.ofInstant(new Date().toInstant(), ZoneId.systemDefault())).build());
            });
        }

        ctx.writeAndFlush(str);
    }

[size=1.25em]

启动
  • 环境要求:JDK 1.8+、Maven 3.3+、MySQL 5.7+、redis 6.0+(mysql、redis 自行安装)。
  • 导入项目:将项目导入到IDE中,需要在application.yml中配置好数据库连接。
  • 编译项目:执行mvn clean install命令,编译成功后会在target目录下生成.jar。
  • 启动项目: redis、mysql环境搭建好,配置文件配置好即可启动项目。 首先启动网关服务AflyExceedIot-gateway 然后启动管理后台后端项目,直接对admin模块启动即可 最后启动后台前端项目即可
  • 模拟设备: 找到后端模块afly-analog-device 打开Startup.java可以创建模拟设备
2.png


系统图片
3.png
7.png
4.png
6.png
5.png
8.png
10.png
11.png
9.png
12.png
系统管理员账号:admin/admin123

免费评分

参与人数 34吾爱币 +32 热心值 +31 收起 理由
likuaile + 1 我很赞同!
coderLzh + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
aronsion + 1 + 1 谢谢@Thanks!
qiuhao001 + 1 + 1 大佬强的。
中国好网友 + 1 + 1 谢谢@Thanks!
MiracleMaster + 1 鼓励转贴优秀软件安全工具和文档!
watking + 1 + 1 谢谢@Thanks!
jackies + 1 + 1 热心回复!
weidechan + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
大街上要饭的 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Leon3051 + 1 + 1 我很赞同!
solidajun + 1 + 1 谢谢@Thanks!
SAPLU + 1 + 1 谢谢@Thanks!
xyl52p + 1 用心讨论,共获提升!
smallmin + 1 热心回复!
难念的经 + 1 我很赞同!
hurric + 2 + 1 谢谢@Thanks!
alanamy + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
huhu9999 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
葱油拌面 + 1 + 1 star了
小可爱~ + 2 + 1 谢谢@Thanks!
xfsan + 1 + 1 用心讨论,共获提升!
唐小样儿 + 1 + 1 我很赞同!
ck6102 + 1 + 1 热心回复!
wangyp0506c + 1 + 1 我很赞同!
hbcto + 1 + 1 虽然不懂,但是感觉很厉害!
0120 + 1 + 1 热心回复!
evea + 1 + 1 谢谢@Thanks!
ogli324 + 1 + 1 听&amp;amp;#128066;我说,谢谢你&amp;amp;#128591;,因为有你,52才美丽。
fengbolee + 2 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
jin_song + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
独怜 + 1 + 1 我很赞同!
1045837055lucy + 1 膜拜大神
DJKS666 + 1 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| AflyExeed 发表于 2024-5-24 15:00
怎么没人捏

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
芥子空间 + 1 + 1 谢谢@Thanks!

查看全部评分

lining11151 发表于 2024-5-29 17:13
感谢楼主分享, 其实在数据采集这个架构中,我认为主要的问题点还是在于不同设备不同协议的整合,而且不同设备的关注点不同,相应的数据结构也不一样,在数据的分析计算方式上也不同,这一点感觉很难整合在一起
RoyPenn 发表于 2024-5-23 16:59
有技术就是强啊,我之前也想基于若依python版的 去做自己想要的系统,可惜盘不转
1045837055lucy 发表于 2024-5-24 07:57
目前还处在调试上一个扫码点餐……
hai163555 发表于 2024-5-24 08:41
DTU下面是不是还有什么设备需要连的啊。能不能画个机床设备上传数据服务器数据库的总架构,设备对接部分哪种接口?谢谢
独怜 发表于 2024-5-24 09:22
先收藏先,刚好公司也要做物联网这块的
ylixx 发表于 2024-5-24 21:31
真的很好,学习学习
kaikai2023 发表于 2024-5-25 11:15
非常有价值!!!!
WePojie 发表于 2024-5-25 14:50
谢谢原创分享,辛苦了,不过还是出个部署教程会更好咯,特别是上次点餐系统,现在还没摸明白哪里出问题,部署完就是空白转圈圈
苦禅 发表于 2024-5-27 14:39
非常有价值
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-21 20:15

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表