Skip to content

架构图

IBOOT系统除了可以部署在云服务器作为软网关也可以嵌入到硬件(工控机)里面作为边缘网关。 架构图

多环境说明

  • 本地开发环境:dev, 本地开发时需要修改application-dev.properties文件中的信息
  • 测试环境:test, 测试环境安装部署时修改application-test.properties文件中的信息
  • 生产环境:prod, 正式环境安装部署时修改application-prod.properties文件中的信息

通过修改application.properties文件中的spring.profiles.active的值来切换环境,默认是dev环境。

properties
# 修改application.properties文件,将配置spring.profiles.active的值改成dev|test|prod
spring.profiles.active=dev|test|prod

注意: 由于线上环境使用nginx做反向代理, 所以test、prod环境的server.servlet.context-path属性设置为/api, 开发环境的server.servlet.context-path属性设置为/,然后前端则由vite3的http服务做代理。

js
// vite.config.js文件中的server配置, 此配置只有在本地开发时才需要修改, 线上环境不需要修改
// 线上环境需要修改docs/nginx/iot.conf或iot-https.conf文件中的反向代理等配置参数
server: {
    proxy: {
        '^/api/*': {
            changeOrigin: true,
            target: 'http://localhost:8085',
            rewrite: (path) => {
                return path.replace(/^\/api/, '')
            }
        },
    },
},

如果需要修改server.servlet.context-path属性的值, 请修改docs/nginx/iot.conf或iot-https.conf文件中的反向代理等配置参数。

项目结构

iboot项目由maven的多模块组成, 主要分为以下几个模块:

java
iboot
├── bootstrap                # 项目启动模块,包含启动类和核心配置
├── framework                # 框架核心模块,包含通用工具和基础组件
├── iboot-plugin             # 插件模块集合
│    ├── iboot-code          # 代码生成器插件
│    ├── iboot-protocol      # 协议驱动支持
│    │    ├── protocol-mqtt  # MQTT协议支持
│    │    ├── protocol-dtu   # DTU协议支持
│    │    ├── protocol-modbus # Modbus协议支持
│    ├── iboot-SaToken       # SaToken权限认证插件
│    ├── iboot-shiro         # Shiro权限认证插件
│    ├── iboot-knife4j       # API文档插件
│    ├── iboot-amqp          # 消息队列插件(商业)
│    ├── iboot-datasource    # 多数据源插件(商业)
│    ├── iboot-gb28181       # GB28181插件(商业)
│    ├── iboot-le5le         # 乐吾乐大屏插件(商业)
│    ├── iboot-message       # 消息通知插件(商业)
│    ├── iboot-open          # 开放接口插件(商业)
│    ├── iboot-script        # 脚本引擎插件(商业)
│    ├── iboot-oauth2        # OAuth2认证插件(商业)
  • bootstrap: 项目启动模块, 包含项目的启动类和配置文件以及业务模块等. 包含的业务模块有:
    1. core包: 项目的核心模块, 包含系统的基础功能 如: 登录、菜单、授权、角色、用户、部门、字典、文件、日志、系统配置等
    2. iot包: 项目的物联网相关模块, 包含物联网功能 如: 设备管理、数据采集、规则引擎、告警等
  • framework: 整个项目的框架层, 包含项目的通用工具类、常量类、枚举类、spring自动配置、api接口等
  • iboot-plugin: 项目的插件模块, 包含项目的插件类、插件接口等(通过在bootstrap模块的pom.xml文件引入插件来实现插件的功能)
    1. iboot-code: 此插件下面包含代码生成器的支持, 目前支持mybatis-plus代码生成器
    2. iboot-protocol: 此插件提供对协议驱动的支持, 目前开源版支持mqtt、dtu(modbus)、modbus等协议
    3. iboot-SaToken: 此插件提供系统的权限、认证支持(和iboot-shiro插件二选一)
    4. iboot-shiro: 此插件提供系统的权限、认证支持(和iboot-SaToken插件二选一)
    5. iboot-knife4j: 此插件下面包含knife4j的api文档支持, 主要是对openapi的支持
    6. iboot-amqp(商业): 此插件下面包含消息队列的支持, 目前支持rabbitmq消息队列
    7. iboot-datasource(商业): 此插件下面包含多数据源的支持, 主要是采集数据的存储支持, 目前支持mysql和TDengine时序数据库
    8. iboot-gb28181(商业): 此插件下面包含gb28181的支持, 主要是gb28181设备的接入支持, 目前支持gb28181设备的接入和管理
    9. iboot-le5le(商业): 此插件提供对乐吾乐大屏和组态的支持
    10. iboot-message(商业): 此插件提供对告警消息的支持, 目前支持邮件、短信等消息发送
    11. iboot-open(商业): 此插件提供对外接口的支持, 通过此插件提供北向接口实现, 目前支持mqtt数据转发
    12. iboot-script(商业): 此插件提供对脚本的支持, 目前支持javascript脚本并提供模型数据的数据转换以及数据过滤(数据存储和mqtt转发)
    13. iboot-oauth2(商业): 此插件提供北向http协议接口的认证支持, 可以调用系统的任何接口

多模块

iboot是多maven模块的架构, 新增模块是有两种方式:

  1. 直接在bootstrap项目的module包下面新增一个业务模块包(目前已包含core和iot), 然后在新的模块中编写代码即可
  2. 通过在iboot-plugin项目的下面新增一个插件(maven模块), 然后在新的模块中编写代码, 然后在bootstrap项目的pom.xml文件中引入插件即可

新增模块

在bootstrap项目的module包下面新增模块, 例如新增一个demo模块

java
//1. 在bootstrap项目下面的module包新增一个demo包, 项目结构如下:
bootstrap
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com.iteaj.iboot.module.demo
│   │   │       ├── service
│   │   │       │   ├── impl
│   │   │       │   │   └── DemoServiceImpl.java // 模块的服务实现类
│   │   │       │   └── IDemoService.java // 模块的服务接口类
│   │   │       ├── controller
│   │   │       │   └── DemoController.java // 模块的控制器类
│   │   │       ├── mapper
│   │   │       │   └── IDemoMapper.java // 模块的mapper类
│   │   │       ├── entity
│   │   │       │   └── DemoEntity.java // 模块的实体类
│   │   │       ├── DemoAutoConfiguration.java // 模块的自动配置类

// 2. 然后在demo模块包下面新增一个spring的自动配置类
package com.iteaj.iboot.module.demo;
import com.iteaj.framework.spi.admin.Module;
@AutoConfiguration
@MapperScan({"com.iteaj.iboot.module.demo.mapper"})
@ComponentScan(basePackages = "com.iteaj.iboot.module.demo")
public class DemoAutoConfiguration {
    // 根据需要创建一个module类用来声明此模块
    // 此module声明可以在菜单中显示, 用于控制模块的菜单权限
    @Bean
    public Module demoModule() {
        return new Module("demo", "demo模块");
    }
}
// 3. 然后在bootstrap项目的启动类{@code IBootApplication}上面导入配置类
@ImportAutoConfiguration(value = {
        IotAutoConfiguration.class, // 物联网模块
        DemoAutoConfiguration.class, // 新增的demo模块
        // 以下是IBoot的核心配置(必须启用)
        CoreAutoConfiguration.class, // 系统管理模块
})
@SpringBootApplication
public class IBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(IBootApplication.class, args);
    } 
}

新增插件

  1. 在iboot-plugin项目的下面新增一个插件(maven项目), 例如新增一个demo插件, 项目结构如下:
java
// 注:包名最好以com.iteaj.iboot.plugin开头
iboot-plugin
├── iboot-demo
│   ├── src
│   │   ├── main
│   │   │   ├── java
│   │   │   │   └── com.iteaj.iboot.plugin.demo
│   │   │   │       ├── service
│   │   │   │       │   ├── IDemoService.java  // 服务接口定义
│   │   │   │       │   └── impl
│   │   │   │       │       └── DemoServiceImpl.java  // 服务接口实现
│   │   │   │       ├── controller
│   │   │   │       │   └── DemoController.java // 插件的控制器类
│   │   │   │       ├── mapper
│   │   │   │       │   └── IDemoMapper.java // 插件的mapper类
│   │   │   │       ├── entity
│   │   │   │       │   └── DemoEntity.java // 插件的实体类
│   │   │   │       ├── DemoAutoConfiguration.java // 插件的自动配置类
│   │   │   └── resources
│   │   │       └── META-INF
│   │   │           └── spring
│   │   │               ├── org.springframework.boot.autoconfigure.AutoConfiguration.imports
// 2. 为了告诉spring自动导入插件的自动配置类则需要在src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中添加插件的自动配置类
com.iteaj.iboot.plugin.demo.DemoAutoConfiguration
// 3. 编写DemoAutoConfiguration类
package com.iteaj.iboot.plugin.demo;
import com.iteaj.framework.spi.admin.Module;
import com.iteaj.framework.security.OrderFilterChainDefinition;

@MapperScan({"com.iteaj.iboot.plugin.demo.mapper"})
@ComponentScan(basePackages = "com.iteaj.iboot.plugin.demo")
public class DemoAutoConfiguration {
    // 根据需要创建一个module类用来声明此模块
    // 此module声明可以在菜单中显示, 用于控制模块的菜单权限 
    @Bean
    public Module demoModule() {
        return new Module("demo", "demo模块");
    }

    // 如果此插件需要添加匿名访问的接口
    @Bean
    @Order(value = 58)
    public OrderFilterChainDefinition demoFilterChainDefinition() {
        return new OrderFilterChainDefinition()
                .addAnon("/demo/a", "/demo/b/**");
    }
}
// 4. 然后在bootstrap项目的pom.xml文件中引入依赖
<dependency>
    <groupId>com.iteaj.iboot</groupId>
    <artifactId>iboot-demo</artifactId>
    <version>${project.version}</version>
</dependency>

设备状态事件

iboot平台支持监听设备上线/离线事件, 设备状态事件是由netty框架或者平台自动触发

java
/**
 * 设备状态监听器
 * @see CombinedEventListener 用于监听netty的tcp事件
 * @see IotListener 用于监听非netty事件的设备状态, 如网关子设备的上线/离线事件等(有平台实现)
 * @see ApplicationReadyListener 用于监听系统启动就绪事件, 做一些初始化操作
 * @author iteaj  
 */
@Component
public class DeviceStatusListener implements CombinedEventListener, ApplicationReadyListener, IotListener<RealtimeStatus> {

    private final IotCacheManager cacheManager;
    private final IDeviceService deviceService;
    private final FrameworkProperties properties;
    private Logger logger = LoggerFactory.getLogger(getClass());

    public DeviceStatusListener(IotCacheManager cacheManager, IDeviceService deviceService, FrameworkProperties properties) {
        this.cacheManager = cacheManager;
        this.deviceService = deviceService;
        this.properties = properties;
    }

    @Override
    public void online(String source, FrameworkComponent component) {
        // 设备上线事件
        DeviceProtocolSupplier supplier = ProtocolSupplierManager.get(component.getMessageClass());
        if(supplier != null) {
            RealtimeStatus device = cacheManager.get(supplier.getProtocol().getCode(), source);
            if(device != null) {
                device.setStatus(DeviceStatus.online);
                deviceService.updateDeviceStatus(device);
            } else {
                logger.warn("更新设备状态失败 设备不存在 - 设备编号: {} - 协议/驱动: {}", source, supplier.getDesc());
            }
        } else {
            logger.warn("更新设备状态失败 协议不存在 - 设备编号: {} - 协议类: {}", source, component.getMessageClass().getSimpleName());
        }
    }

    @Override
    public void offline(String source, FrameworkComponent component) {
        // 设备掉线事件
        DeviceProtocolSupplier supplier = ProtocolSupplierManager.get(component.getMessageClass());
        if(supplier != null) {
            RealtimeStatus device = cacheManager.get(supplier.getProtocol().getCode(), source);
            if(device != null) {
                device.setStatus(DeviceStatus.offline);
                deviceService.updateDeviceStatus(device);
            } else {
                logger.warn("更新设备状态失败 设备不存在 - 设备编号: {} - 协议码: {}", source, supplier.getProtocol().getCode());
            }
        } else {
            logger.warn("更新设备状态失败 协议不存在 - 设备编号: {} - 协议类: {}", source, component.getMessageClass().getSimpleName());
        }
    }

    @Override
    public void started(ApplicationContext context) {
        if(!properties.isCluster()) {
            // 系统重启时 更新所有的设备状态到离线
            deviceService.update(Wrappers.<Device>lambdaUpdate()
                    .set(Device::getStatus, DeviceStatus.offline)
                    .set(Device::getSwitchTime, new Date()));
        }
    }

    @Override
    public boolean isEventMatcher(IotEventType eventType) {
        return IotEventType.DeviceStatus == eventType;
    }

    @Override
    public void onIotEvent(IotEventType eventType, RealtimeStatus value) {
        deviceService.updateDeviceStatus(value);
    }

    @Override
    public int getOrder() {
        return Integer.MIN_VALUE + 1000;
    }
}

平台启动就绪事件

平台启动就绪事件是由spring框架触发的, 当spring容器启动完毕后会触发此事件, 可以在此事件中做一些初始化操作, 如初始化设备状态等, 可以通过实现{@code ApplicationReadyListener}接口来监听平台启动就绪事件

java
/**
 * 应用启动就绪监听
 */
@FunctionalInterface
public interface ApplicationReadyListener extends EventListener, Ordered {

    /**
     * 启动完成处理
     * @param context
     */
    void started(ApplicationContext context);

    @Override
    default int getOrder() {
        return Integer.MIN_VALUE + 100000;
    }
}
// 平台以实现如下:
/**
 * iot模块监听应用重启时的初始化监听
 */
@Component
public class IotRestartListener implements ApplicationReadyListener {}
/**
 * 系统采集任务(事件源)初始化监听
 */
@Service
public class CollectTaskListenerService implements ApplicationReadyListener {}
@Component
public class EventSourceCollectService implements ApplicationReadyListener {}
/**
 * 网关子设备的在线状态触发任务
 */
public class DeviceStatusModelApiManager implements Runnable, ApplicationReadyListener {}

websocket推送事件

此事件用于给前端推送实时采集数据、设备状态、告警事件

java
/**
 * 将采集的数据实时推送到前端
 */
public class RealtimePushListener implements WebSocketServerListener, EventGroupCollectListener
        , SignalCollectListener, DeviceStatusListener, ModelAttrListener {
    // 省略具体代码, 具体实现可以参考源码
}