JetLinks设备接入的认识与理解【woodwhales.cn】
为了更好的阅读体验,建议移步至笔者的博客阅读:JetLinks设备接入的认识与理解
1、认识 JetLinks
1.1、官网文档
官网:https://www.jetlinks.cn/
JetLinks 有两个产品:JetLinks-lot和JetLinks-view
官方文档:
-
JetLinks 物联网基础平台
-
JetLinks 物联网平台开发手册
1.2、JetLinks
JetLinks 是可支持多种方式接入设备的物联网设备管理平台
https://hanta.yuque.com/px7kg1/yfac2l/fwqriw24lp3cy2lw
JetLinks IOT 是一个开源的、企业级的物联网平台,它集成了设备管理、数据安全通信、消息订阅、规则引擎等一系列物联网核心能力,支持以平台适配设备的方式连接海量设备,采集设备数据上云,提供云端API,通过调用云端API实现远程控制。JetLinks物联网平台还支持多种设备接入协议,并提供了丰富的协议库。
支持:多协议(MQTT、HTTP、CoAP、UDP、TCP、WebSocket)自定义编解码插件接入;
支持:云平台对接接入;
支持: ModBus/TCP、OPC UA通道接入;
支持:基于GB/T 28181国标协议视频接入;
支持:自研边缘计算网关接入。
1.3、产品架构的理解
https://hanta.yuque.com/px7kg1/yfac2l/tvlxz93cht8zyl94
1.3.1、理解1
通过不同层级功能职责的封装、组合,以支持多设备、多协议接入平台
-
设备连接层:支持MQTT、TCP、UDP、CoAP、HTTP、WebSocket协议,提供统一设备接入的能力。
-
设备管理层:提供设备注册、配置、维护和监控的功能,支持设备属性、状态实时展示和历史属性、设备日志记录查询等。
-
业务逻辑层:提供规则引擎、数据转发和数据解析等功能,支持多种业务场景下的数据处理和交互操作。
-
应用开发层:提供RESTAPI和WebSocket接口,支持前端对接和自定义应用开发。同时还提供了可视化的数据展示和操作页面,方便用户快速搭建物联网应用系统。
1.3.2、理解2
设备接入JetLinks物联网平台后,可实现:设备通讯、数据的采集、认证、流转、存储、分析和实时监控
13.3、理解3
开发者需要自行实现编解码器逻辑,才可以让平台对设备数据进行全面管理
1.4、基本概念
https://hanta.yuque.com/px7kg1/yfac2l/dagxgfzc3vnul0sn
1.4.1、产品
产品是指一组具有相同功能和规格的设备集合,通常由同一家生产厂家制造。
设备可能是传感器、执行器、控制器等各种不同类型的物联网设备,它们可以通过网络连接到物联网平台。通过将这些设备组合到一个产品中,企业可以对这些设备进行统一管理和监控,以便更有效地控制其行为和状态。
1.4.2、设备
设备是指物理存在的、可通过网络连接的单个物联网设备。
设备可以是各种类型的物品,例如传感器、执行器、控制器等。这些设备通过物联网连接到平台,以便与其他设备或应用程序进行通信、交换数据和接收命令。
1.4.3、物模型
物模型说明:http://doc.jetlinks.cn/function-description/metadata_description.html
物模型是物理空间中的实体在云端的数字化表示,有 4 个纬度:属性、功能、事件、标签。
-
属性:用于描述设备运行时具体信息和状态。例如温湿度传感器包含“温度”、“湿度”两个属性。
-
功能:设备可被外部调用的能力或方法,可设置输入参数和输出参数。相比于属性,服务可通过一条指令实现更复杂的业务逻辑
-
事件:用于描述设备上报云端的多个参数,多用于复杂报文结构或设备本身在某个阈值触发的报文。
-
标签:统一为设备添加拓展字段,添加后将在设备信息页显示。
2、开发手册
社区版后端工程:
- github 仓库:https://github.com/jetlinks/jetlinks-community
- gitee 仓库:https://gitee.com/jetlinks/jetlinks-community
2.1、模块说明
社区版系统模块说明:https://hanta.yuque.com/px7kg1/nn1gdr/gfqb3xmxg8fsvyxf#lR7Pd
- jetlinks-components # 组件库
- common-component # 通用组件、工具类等
- configure-component # 统一配置模块
- dashboard-component # 仪表盘模块
- elasticsearch-component # ElasticSearch集成
- gateway-component # 网关模块,统一定义网关接口等信息
- io-component # IO模块,文件管理等
- logging-component # 日志模块
- network-component # 网络组件模块,统一定义网络组件规范以及默认实现
- http-component # http模块
- mqtt-component # mqtt模块
- network-core # 网络组件核心模块
- tcp-component # tcp模块
- notify-component # 通知模块,统一定义通知规范以及默认实现
- notify-core # 通知模块核心
- notify-dingtalk # 钉钉通知模块
- notify-email # 邮件通知模块
- notify-sms # 短信通知模块
- notify-voice # 语音通知模块
- notify-webhook # webhook通知模块
- notify-wechat # 微信通知模块
- protocol-component # 协议模块
- relation-component # 关系模块,用于描述物与物之间的关系
- rule-engine-component # 规则引擎模块,集成规则引擎通用功能
- script-component # 脚本模块,封装脚本引擎
- tdengine-component # 对tdengine的支持
- things-component # 物管理模块
- timeseries-component # 时序数据组件
- jetlinks-manager # 管理功能
- authentication-manager # 用户,权限管理模块
- device-manager # 设备管理模块
- logging-manager # 日志管理模块
- network-manager # 网络组件管理模块
- notify-manager # 通知管理模块
- rule-engine-manager # 规则引擎管理模块
- jetlinks-standalone #单例模块,启动JetLinks平台
2.2、技术选型
技术栈 | 描述 |
---|---|
Java8 | 编程语言 |
hsweb Framework | 业务基础框架 |
Spring Boot 2.7.x | 响应式web支持 |
vert.x,netty | 高性能网络框架 |
R2DBC | 关系型数据库响应式驱动 |
Postgresql | 关系型数据库,可更换为mysql、sqlserver |
ElasticSearch | 设备数据与日志存储,可更换为其他中间件 |
Redis | 用户信息与权限缓存、设备注册中心缓存 |
scalecube | 基于JVM的分布式服务框架,支持响应式 |
micrometer | 监控指标框架 |
2.3、必要的开发知识
响应式编程:http://doc.jetlinks.cn/dev-guide/reactor.html
事件驱动:http://doc.jetlinks.cn/dev-guide/event-driver.html
添加自定义模块:https://hanta.yuque.com/px7kg1/dev/wdymp6flcfa1vwh5
3、设备接入流程
设备接入流程:http://doc.jetlinks.cn/function-description/device_message_description.html#%E8%AE%BE%E5%A4%87%E6%8E%A5%E5%85%A5%E6%B5%81%E7%A8%8B
HTTP协议设备接入:https://hanta.yuque.com/px7kg1/yfac2l/qlr6nz5btr5rwrgk
3.1、流程图
3.2、开发:协议包
开发者自行实现自定义协议,官方教程:http://doc.jetlinks.cn/dev-guide/custom-message-protocol.html
官方提供了协议开发示例工程:https://github.com/jetlinks/jetlinks-official-protocol
JetLinks 官方协议 jar 包:https://github.com/jetlinks/jetlinks-official-protocol/blob/v3/package/jetlinks-official-protocol-3.0.0.jar
-
编写
自定义编解码器
:创建
org.jetlinks.core.message.codec.DeviceMessageCodec
接口实现类,重写encode()
、decode()
、getSupportTransport()
方法 -
编写
协议的元信息
创建
org.jetlinks.core.metadata.DefaultConfigMetadata
对象并设置对应属性 -
编写
自定义设备协议支持提供商
:创建
org.jetlinks.core.spi.ProtocolSupportProvider
接口实现类,并重写create()
方法,在
create()
方法中将:将自定义编解码器
注册到协议中 -
配置路由配置:
在
org.jetlinks.core.spi.ProtocolSupportProvider
接口实现类的create()
方法中创建org.jetlinks.core.defaults.CompositeProtocolSupport
对象,在其中配置路由配置、身份认证(可选)
3.3、添加:协议包
将协议包上传到协议管理中
3.4、添加:网络组件
- 配置:本地和公网的接口地址、端口号
- 配置:接口处理的服务类型
3.5、添加:设备接入网关
将上述的协议包和网络组件进行绑定
3.6、添加:产品
-
配置:产品信息
-
绑定:上述的自定义网络组件(官方定义:设备接入)
-
配置:认证信息
-
配置存储策略
-
配置:物模型
- 属性定义
- 功能定义
- 事件定义
- 标签定义
-
启用:产品
行式存储
ElasticSearch-行式存储是系统默认情况下使用的存储方案。每一个属性值都保存为一条索引记录。
典型应用场景:设备每次只会上报一部分属性, 以及支持读取部分属性数据的时候。
列式存储
一个属性作为一列,一条属性消息作为一条索引记录进行存储。
典型应用场景:适合设备每次都上报所有的属性值的场景。
3.7、添加:设备
- 配置:设备ID、名称
- 绑定:上述配置好的产品(只能配置状态是正常的产品,即已启用的产品)
- 启动:设备
- (可选)默认继承了所属产品的物模型。可以配置专属当前设备的物模型
4、理解协议包
关于协议包:https://hanta.yuque.com/px7kg1/nn1gdr/kcqv8dn8y6778t2a
协议包主要包含 4 个部分
-
数据传输协议:协议包约定了常见的网络通信协议,例如MQTT、HTTP、TCP、CoAP等,来实现物联网设备与JetLinks平台之间的数据传输。开发者可根据设备实际情况选择对应的通信协议。
-
数据解析标准:协议包定义了一套设备数据解析标准,使得各种类型的物联网设备通过网络协议传输至JetLinks后,根据协议包内的数据解析标准将不同类型的报文转换成平台统一的消息。
-
设备管理功能:协议包内可以获取平台内定义的设备数据,包括设备信息、设备配置、设备状态等,方便开发者在接入设备时获取设备相关数据进行自定义的业务逻辑处理。
-
身份认证:协议包支持物联网设备的身份认证,用户可以在协议包内编写身份认证逻辑来验证连接的客户端身份,以保护设备和数据的安全。
5、理解自定义编解码器开发流程
5.1、步骤1
自定义 DeviceMessageCodec 接口实现类,重写 encode()、decode() 方法
5.1.1、消息编码
重写 DeviceMessageCodec 接口中的encode()
方法
5.1.2、消息解码
重写 DeviceMessageCodec 接口中的decode()
方法
5.2、步骤2
自定义 ProtocolSupportProvider 接口实现类,配置元数据信息
5.3、步骤3
配置路由与 DeviceMessage 的绑定关系
5.4、步骤4
自定义 Authenticator 接口实现并配置
6、理解编解码涉及的核心类关系
协议加载设计:https://hanta.yuque.com/px7kg1/nn1gdr/gascdx49ia6u4lsf
平台统一设备消息定义:http://doc.jetlinks.cn/function-description/device_message_description.html
7、协议包上传逻辑分析
7.1、步骤1:上传协议 jar
后端接口
POST
/api/file/upload
请求报文
表单请求,接收参数名为:file 的文件数据对象
Content-Disposition: form-data; name="file"; filename="jetlinks-official-protocol-3.0.0.jar"
Content-Type: application/octet-stream
接口类:org.jetlinks.community.io.file.web.FileManagerController#upload
处理逻辑
-
获取文件信息,并将文件数据保存到本地指定目录
-
默认文件目录为:./data/files/yyyyMMdd/
-
重命名 jar 文件名,生成规则:md5(uuid())
-
计算当前文件的 md5 和 sha256 值
-
-
将文件相关信息保存到数据库中,数据对象:
org.jetlinks.community.io.file.FileEntity
-
保存成功的文件数据记录主键和文件信息一起通过接口返回
响应报文
返回文件数据相关记录信息,核心信息:
{ "message": "success", "result": { "id": "9c9ce661a1fadb8019ca50145b33a074", "name": "jetlinks-official-protocol-3.0.0.jar", "extension": "jar", "length": 102512, "md5": "24504ceb0d6570b84b86e6180d9fca9f", "sha256": "fb0c6144ad056326e26eb829c13759b5080da095c7bb02386c7f064ac059f24e", "createTime": 1699859432789, "creatorId": "1199596756811550720", "options": [], "others": { "accessKey": "c24b19b0c91119c6673fa1a06a4d2ae0" } }, "status": 200, "timestamp": 1699859454032 }
7.2、步骤2:确定协议
7.2.1、后端接口
PATCH
/api/protocol
接口类:org.jetlinks.community.device.web.ProtocolSupportController
7.2.2、请求报文
{"id": "1722876422724329472","name": "官方协议v3.0","description": "","type": "jar","state": 1,"creatorId": "1199596756811550720","createTime": 1699600723328,"configuration": {"location": "http://localhost:5173/api/file/9c9ce661a1fadb8019ca50145b33a074?accessKey=c24b19b0c91119c6673fa1a06a4d2ae0"}
}
7.2.3、处理逻辑
- 将前端请求的文件信息保存到数据库中,数据对象:
org.jetlinks.community.device.entity.ProtocolSupportEntity
前端逻辑:将步骤1 的响应结果拼接成:文件地址(用户不可编辑)+ 用户填写的协议包基本信息(名称、类型、说明)
org.jetlinks.community.device.web.ProtocolSupportController
实现了org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController
接口。
org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController
接口又继承了三个接口:org.hswebframework.web.crud.web.reactive.ReactiveServiceSaveController
、org.hswebframework.web.crud.web.reactive.ReactiveServiceQueryController
、org.hswebframework.web.crud.web.reactive.ReactiveServiceDeleteController
ProtocolSupportController
package org.jetlinks.community.device.web;import org.hswebframework.web.crud.web.reactive.ReactiveServiceCrudController;
import org.jetlinks.community.device.service.LocalProtocolSupportService;@RestController
@RequestMapping("/protocol")
public class ProtocolSupportControllerimplements ReactiveServiceCrudController<ProtocolSupportEntity, String> {@Autowired@Getterprivate LocalProtocolSupportService service;}
ReactiveServiceCrudController
package org.hswebframework.web.crud.web.reactive;public interface ReactiveServiceCrudController<E, K> extendsReactiveServiceSaveController<E, K>,ReactiveServiceQueryController<E, K>,ReactiveServiceDeleteController<E, K> {
}
PATH /api/protocol
接口实际由:ReactiveServiceSaveController
接口提供的默认 save()
方法处理数据,最终调用getService()
方法进行save()
操作。
package org.hswebframework.web.crud.web.reactive;import org.hswebframework.web.authorization.annotation.Authorize;public interface ReactiveServiceSaveController<E, K> {@Authorize(ignore = true)ReactiveCrudService<E, K> getService();@PatchMapping@Operation(summary = "保存数据", description = "如果传入了id,并且对应数据存在,则尝试覆盖,不存在则新增.")default Mono<SaveResult> save(@RequestBody Flux<E> payload) {return Authentication.currentReactive().flatMapMany(auth -> payload.map(entity -> applyAuthentication(entity, auth))).switchIfEmpty(payload).as(getService()::save);}}
由于ProtocolSupportController
注入了org.jetlinks.community.device.service.LocalProtocolSupportService
,并且属性名为:service,因此ProtocolSupportController
的getService()
就是ReactiveServiceSaveController
接口的getService()
方法实现。显而易见,确定协议的核心逻辑就在:LocalProtocolSupportService
的save()
方法。
org.jetlinks.community.device.service.LocalProtocolSupportService
类继承了org.hswebframework.web.crud.service.GenericReactiveCrudService
抽象类,而GenericReactiveCrudService
抽象类又实现了org.hswebframework.web.crud.service.ReactiveCrudService
接口,在ReactiveCrudService
中有save()
方法
ProtocolSupportController
package org.jetlinks.community.device.service;import org.jetlinks.community.reference.DataReferenceManager;
import org.jetlinks.supports.protocol.management.ProtocolSupportManager;@Service
public class LocalProtocolSupportService extends GenericReactiveCrudService<ProtocolSupportEntity, String> {@Autowiredprivate ProtocolSupportManager supportManager;@Autowiredprivate DataReferenceManager referenceManager;}
GenericReactiveCrudService
package org.hswebframework.web.crud.service;import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
import org.springframework.beans.factory.annotation.Autowired;public abstract class GenericReactiveCrudService<E, K> implements ReactiveCrudService<E, K> {@Autowiredprivate ReactiveRepository<E, K> repository;@Overridepublic ReactiveRepository<E, K> getRepository() {return repository;}}
GenericReactiveCrudService 注入了 ReactiveRepository 接口,该接口的实现类为:org.hswebframework.ezorm.rdb.mapping.defaults.DefaultReactiveRepository
,里面实现了save()
方法:
package org.hswebframework.ezorm.rdb.mapping.defaults;import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;public class DefaultReactiveRepository<E, K> extends DefaultRepository<E> implements ReactiveRepository<E, K> {@Overridepublic Mono<SaveResult> save(Publisher<E> data) {return Flux.from(data).collectList().filter(CollectionUtils::isNotEmpty).flatMap(list -> doSave(list).reactive().as(this::setupLogger)).defaultIfEmpty(SaveResult.of(0, 0));}
}
上述doSave()
方法是org.hswebframework.ezorm.rdb.mapping.defaults.DefaultRepository
抽象类提供的默认方法:
package org.hswebframework.ezorm.rdb.mapping.defaults;import org.hswebframework.ezorm.rdb.mapping.events.EventResultOperator;public abstract class DefaultRepository<E> {protected SaveResultOperator doSave(Collection<E> data) {RDBTableMetadata table = getTable();UpsertOperator upsert = operator.dml().upsert(table.getFullName());return EventResultOperator.create(() -> {upsert.columns(getProperties());List<String> ignore = new ArrayList<>();for (E e : data) {upsert.values(Stream.of(getProperties()).map(property -> getInsertColumnValue(e, property, (prop, val) -> ignore.add(prop))).toArray());}upsert.ignoreUpdate(ignore.toArray(new String[0]));return upsert.execute();},SaveResultOperator.class,table,MappingEventTypes.save_before,MappingEventTypes.save_after,getDefaultContextKeyValue(instance(data),type("batch"),tableMetadata(table),upsert(upsert)));}
}
上述EventResultOperator
的create()
方法中,发布了EntitySavedEvent<E>
事件(通过 Spring的ApplicationEventPublisher 发送事件)。
在org.jetlinks.community.device.service.ProtocolSupportHandler
中订阅了EntitySavedEvent<ProtocolSupportEntity>
事件:
package org.jetlinks.community.device.service;import lombok.AllArgsConstructor;
import org.jetlinks.core.ProtocolSupport;
import org.jetlinks.community.reference.DataReferenceManager;
import org.jetlinks.supports.protocol.management.ProtocolSupportLoader;
import org.jetlinks.supports.protocol.management.ProtocolSupportManager;@Component
@AllArgsConstructor
public class ProtocolSupportHandler {private final DataReferenceManager referenceManager;private ProtocolSupportLoader loader;private ProtocolSupportManager supportManager;@EventListenerpublic void handleCreated(EntityCreatedEvent<ProtocolSupportEntity> event) {event.async(reloadProtocol(event.getEntity()));}@EventListenerpublic void handleSaved(EntitySavedEvent<ProtocolSupportEntity> event) {event.async(reloadProtocol(event.getEntity()));}@EventListenerpublic void handleModify(EntityModifyEvent<ProtocolSupportEntity> event) {event.async(reloadProtocol(event.getAfter()));}// 重新加载协议private Mono<Void> reloadProtocol(Collection<ProtocolSupportEntity> protocol) {return Flux.fromIterable(protocol).filter(entity -> entity.getState() != null).map(entity -> entity.getState() == 1 ? entity.toDeployDefinition() : entity.toUnDeployDefinition()).flatMap(def -> loader//加载一下检验是否正确,然后就卸载.load(def).doOnNext(ProtocolSupport::dispose).thenReturn(def)).onErrorMap(err -> new BusinessException("error.unable_to_load_protocol", 500, err.getMessage())).flatMap(supportManager::save).then();}}
上述ProtocolSupportLoader
接口的实现类为org.jetlinks.community.protocol.SpringProtocolSupportLoader
,其中load()
方法会动态加载 jar 包为org.jetlinks.core.spi.ProtocolSupportProvider
接口实现,并执行create()
方法。
7.2.4、响应报文
{"message": "success","result": {"added": 0,"updated": 1,"total": 1},"status": 200,"timestamp": 1699859463951
}
8、加载协议包时机
8.1、加载协议包时机1
通过org.jetlinks.community.device.service.ProtocolSupportHandler
监听EntityCreatedEvent<ProtocolSupportEntity>
、EntitySavedEvent<ProtocolSupportEntity>
、EntityModifyEvent<ProtocolSupportEntity>
事件,调用ProtocolSupportLoader
的load()
方法加载协议
在 ProtocolSupportLoader 的 load() 方法中:会调用 org.jetlinks.core.spi.ProtocolSupportProvider 接口实现,并执行 create() 方法
8.2、加载协议包时机2
通过org.jetlinks.community.protocol.LazyInitManagementProtocolSupports
实现org.springframework.boot.CommandLineRunner
接口,在项目启动时执行init()
方法,调用ProtocolSupportLoader
的load()
方法加载协议
在 ProtocolSupportLoader 的 load() 方法中:会调用 org.jetlinks.core.spi.ProtocolSupportProvider 接口实现,并执行 create() 方法
9、设备网关加载机制
- 通过 DeviceGatewayEventHandler 实现 CommandLineRunner 接口,在项目启动时执行 init() 方法
- 通过 DeviceGatewayEventHandler 监听 DeviceGatewayEntity 的保存、创建、更新事件
为了更好的阅读体验,建议移步至笔者的博客阅读:JetLinks设备接入的认识与理解
相关文章:

JetLinks设备接入的认识与理解【woodwhales.cn】
为了更好的阅读体验,建议移步至笔者的博客阅读:JetLinks设备接入的认识与理解 1、认识 JetLinks 1.1、官网文档 官网:https://www.jetlinks.cn/ JetLinks 有两个产品:JetLinks-lot和JetLinks-view 官方文档: JetLi…...

机器人开发的选择
喷涂机器人 码垛机器人 纸箱码垛机器人 焊接机器人 跳舞机器人 管道清理机器人 工地巡检机器人 点餐机器人 化工巡检机器人 装箱机器人 安防巡检机器人 迎宾机器人好像有点像软银那个 污水管道检测机器人 大酒店用扫地机器人 家用扫地机器人 工厂用(…...

LeetCode Hot100 102.二叉树的层序遍历
题目: 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 方法:迭代 class Solution {public List<List<Integer>> levelOrder(TreeNode root) {if …...

【Kotlin】类与接口
文章目录 类的定义创建类的实例构造函数主构造函数次构造函数init语句块 数据类的定义数据类定义了componentN方法 继承AnyAny:非空类型的根类型Any?:所有类型的根类型 覆盖方法覆盖属性覆盖 抽象类接口:使用interface关键字函数:funUnit:让…...

Wagtail-基于Python Django的内容管理系统CMS如何实现公网访问
Wagtail-基于Python Django的内容管理系统CMS实现公网访问 文章目录 Wagtail-基于Python Django的内容管理系统CMS实现公网访问前言1. 安装并运行Wagtail1.1 创建并激活虚拟环境 2. 安装cpolar内网穿透工具3. 实现Wagtail公网访问4. 固定的Wagtail公网地址 前言 Wagtail是一个…...

什么是LASSO回归,怎么看懂LASSO回归的结果
随着机器学习的发展,越来越多SCI文章都使用了更多有趣、高效的统计方法来进行分析,LASSO回归就是其中之一。很多小伙伴听说过LASSO,但是对于LASSO是什么,有什么用,怎么才能实现,大家可能一头雾水。今天的文…...

python树长子兄弟链存储结构(孩子兄弟链存储结构)
长子兄弟链存储结构(孩子兄弟链存储结构)解释: 长子兄弟链存储结构是一种树的存储结构,它使用孩子兄弟表示法(也称作左孩子右兄弟表示法)来表示树的结构。这种表示方法主要用于存储一般的树,而不…...
开源和闭源软件对开发的影响
开源软件的优势: 开源性:开源软件允许任何人查看、修改和发布源代码,这促进了代码的共享和集体学习。透明性:开源软件提高了软件的透明度,使用户可以更好地理解软件的工作原理,增加对软件的信任。社区支持…...

centos无法进入系统之原因解决办法集合
前言 可爱的小伙伴们,由于精力有限,暂时整理了两类。如果没有你遇到的问题也没有关系,欢迎底下留言评论或私信,小编看到后第一时间帮助解决 一. Centos 7 LVM xfs文件系统修复 情况1: [sda] Assuming drive cache:…...
【Linux】系统初始化配置
CentOS 7 的虚拟机安装后必须要做的几个操作,记录以下,网络配置修改、yum源安装、基础工具安装: 1、先修改权限,新建普通用户,并授权普通用户apps 的sudo权限; useradd apps password apps visudo apps A…...

使用VC++设计程序对一幅256级灰度图像进行全局固定阈值分割、自适应阈值分割
图像分割–全局固定阈值分割、自适应阈值分割 获取源工程可访问gitee可在此工程的基础上进行学习。 该工程的其他文章: 01- 一元熵值、二维熵值 02- 图像平移变换,图像缩放、图像裁剪、图像对角线镜像以及图像的旋转 03-邻域平均平滑算法、中值滤波算法、…...

【ArcGIS Pro微课1000例】0035:栅格影像拼接(dem高程数据)
本实验讲解在ArcGIS Pro中,栅格数据的两种拼接(镶嵌)方法,适用于遥感影像、DOM、DEM、DSM等常见栅格数据。 文章目录 一、加载实验数据二、栅格拼接工具1. 镶嵌2. 镶嵌至新栅格三、注意事项四、拓展阅读一、加载实验数据 加载配套实验数据中的0035.rar中的两个dem数据,如…...

Zynq-7000系列FPGA使用 Video Processing Subsystem 实现图像缩放,提供工程源码和技术支持
目录 1、前言免责声明 2、相关方案推荐FPGA图像处理方案FPGA图像缩放方案自己写的HLS图像缩放方案 3、设计思路详解Video Processing Subsystem 介绍 4、工程代码详解PL 端 FPGA 逻辑设计PS 端 SDK 软件设计 5、工程移植说明vivado版本不一致处理FPGA型号不一致处理其他注意事项…...

【C】内存函数
目录 1. memcpy 使用和模拟实现 2. memmove 使⽤和模拟实现 3. memset 函数的使用 4. memcmp 函数的使用 1. memcpy 使用和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); • 函数memcpy从source的位置开始向后复制num个字节的数据到d…...

windows系统玩游戏找不到d3dx9_35.dll缺失的解决方法
分享一个我们在打开游戏或许软件过程中遇到的问题——“由于找不到d3dx9_35.dll,无法继续执行代码”的五个修复方案。这个问题可能会影响到我们的工作和娱乐效率,甚至可能导致工作的延期。因此,我希望通过今天的文章,能够帮助大家更好地解决这…...

webshell之内置函数免杀
原始webshell 查杀的点在于Runtime.getRuntime().exec非常明显的特征 利用ProcessBuilder替换Runtime.getRuntime().exec(cmd) Runtime.getRuntime().exec(cmd)其实最终调用的是ProcessBuilder这个函数,因此我们可以直接利用ProcessBuilder来替换Runtime.getRunti…...
react高阶成分(HOC)
使用React函数式组件写了一个身份验证的一个功能,示例通过高阶组件实现的一个效果展示: import React, { useState, useEffect } from react;// 定义一个高阶组件,它接受一个组件作为输入,并返回一个新的包装组件 const withAuth…...

<JavaEE> Thread线程类 和 Thread的常用方法
目录 一、Thread概述 二、构造方法 三、常用方法 1.1 getId()、getName()、getState()、getPririty() 1.2 start() 1.3 isDaemon()、setDaemon() 1.4 isAlive() 1.5 currentThread() 1.6 Interrupt()、interrupted()、isInterrupted() 1.6.1 方法一:添加共…...

Linux加强篇004-Vim编辑器与Shell命令脚本
目录 前言 1. Vim文本编辑器 1.1 编写简单文档 1.2 配置主机名称 1.3 配置网卡信息 1.4 配置软件仓库 2. 编写Shell脚本 2.1 编写简单的脚本 2.2 接收用户的参数 2.3 判断用户的参数 3. 流程控制语句 3.1 if条件测试语句 3.2 for条件循环语句 3.3 while条件循环语…...
【shell脚本】常见的shell脚本面试题目
1、请用shell脚本for,while,until这三种方式写出输出1到100的所有偶数的方法。 sum=0;for((i=0;i<=100;i+=2));do let sum+=i;done;echo $sum sum=0;i=0;while [ $i -le 100 ];do let sum+=i;let i+=2;done;echo $sum sum=0;i=0;until [ $i -gt 100 ];do let sum+=i;let i+…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...