当前位置: 首页 > news >正文

Harmony Ble蓝牙App(四)描述符

Harmony Ble蓝牙App(四)描述符

  • 前言
  • 正文
    • 一、优化
    • 二、描述
      • ① 概念
      • ② 描述提供者
      • ③ 显示描述符
    • 三、源码

前言

  上一篇中了解了特性和属性,同时显示设备蓝牙服务下的特性和属性,本文中就需要来使用这些特性和属性来完成一些功能。

正文

  上一篇完成了特性,这一篇中我们增加描述符的处理,以及一些简单的优化。

一、优化

  这样看起来主页面在没有设备信息的时候不会显得单调,那么还有一个小细节就是,当设备的蓝牙服务和特性不属于SIG定义的,是厂商自定义时,我们最好就显示完整的UUID,为了方便使用,在BleUtils类中增加如下代码:

	public static final String APP_NAME = "GoodBle";public static final String UNKNOWN_DEVICE = "Unknown device";public static final String UNKNOWN_SERVICE = "Unknown Service";public static final String UNKNOWN_CHARACTERISTICS = "Unknown Characteristics";public static final String UNKNOWN_DESCRIPTOR = "Unknown Descriptor";public static final String BROADCAST = "Broadcast";public static final String READ = "Read";public static final String WRITE_NO_RESPONSE = "Write No Response";public static final String WRITE = "Write";public static final String NOTIFY = "Notify";public static final String INDICATE = "Indicate";public static final String AUTHENTICATED_SIGNED_WRITES = "Authenticated Signed Writes";public static final String EXTENDED_PROPERTIES = "Extended Properties";

  这里定义了一些常量,包括未知服务、未知特性,和一些其他的属性,这样做在修改的时候修改一个常量就可以了。下面我们分别修改一下BleUtils中的getServiceName()getCharacteristicsName()方法的else的值为UNKNOWN_SERVICEUNKNOWN_CHARACTERISTICS,剩下的就可以在服务适配器和特性适配器中去修改了,首先是服务适配器,修改

    @Overridepublic Component getComponent(int position, Component component, ComponentContainer componentContainer) {...String serviceName = BleUtils.getServiceName(service.getUuid());holder.txServiceName.setText(serviceName);holder.txUuid.setText(serviceName.equals(BleUtils.UNKNOWN_SERVICE) ? service.getUuid().toString() : BleUtils.getShortUUID(service.getUuid()));return cpt;}

在设置uuid的时候根据服务的名称进行判断,如果是标准的SIG服务则使用短UUID,不是则使用完整的UUID。默认是小写的,你也可以改成大写。

那么同样特性适配器也改一下:

    @Overridepublic Component getComponent(int position, Component component, ComponentContainer componentContainer) {...String characteristicsName = BleUtils.getCharacteristicsName(characteristic.getUuid());holder.txCharacterName.setText(characteristicsName);holder.txUuid.setText(BleUtils.getShortUUID(characteristic.getUuid()));holder.txUuid.setText(characteristicsName.equals(BleUtils.UNKNOWN_CHARACTERISTICS) ? characteristic.getUuid().toString() : BleUtils.getShortUUID(characteristic.getUuid()));return cpt;}

再运行一下,对于未知设备服务和特性的UUID就会显示完整的值。

二、描述

  在上一篇中提到了特性和属性,特性有那些功能是属性决定的,那么描述又是做什么的呢?

① 概念

在蓝牙低功耗(BLE)中,Descriptor(描述符)是用于提供有关特征值的额外信息的数据结构。Descriptor 提供了特定特征的更详细描述和配置选项。Descriptor 是特征(Characteristics)的子项,用于描述特征的特定属性或行为。每个特征可以有一个或多个 Descriptor。

以下是一些常见的 BLE Descriptor 类型及其含义:

  1. 声明 Descriptor:这个 Descriptor 用于描述特征的声明信息,包括特征的唯一标识符、权限、值的格式和其他标志。它提供了特征的基本信息供其他设备了解。

  2. 用户描述(User Description)Descriptor:用于提供特征的人类可读描述信息。这个描述可以是特征的名称、标签或其他有关特征的说明性文字。

  3. 配置 Descriptor:用于描述特征的配置选项。这个 Descriptor 可以包含特征的可选设置,例如采样率、测量单位或阈值等。

  4. 通知 Descriptor:用于配置特征是否支持通知功能。这个 Descriptor 可以用于使设备可以接收特征值变化的通知。

  5. 线性区间 Descriptor:用于描述特征值的线性关系,例如数值范围和步长等。

  6. 客户端配置 Descriptor:用于允许远程设备(例如中心设备)订阅特征值的变化通知,这个很重要。
    这些只是一些常见的 BLE Descriptor 类型和其含义的示例,实际上可以根据应用需求定义自定义的 Descriptor。

    Descriptor 提供了对特征更详细的描述和配置,它们可以通过蓝牙协议进行传输和访问。在 BLE 应用中,Descriptor 充当了配置和元数据信息的重要角色,帮助设备之间准确地交换和理解数据。

那么现在你已经了解了描述符的作用了,而我们目前的特性下还没有描述符的,注意不是每一个特性都有描述符,下面我们就来把描述符写出来了。首先我们在item_characteristic.xml中增加一个描述的列表控件,代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<DependentLayoutxmlns:ohos="http://schemas.huawei.com/res/ohos"ohos:height="match_content"ohos:width="match_parent"ohos:background_element="#FFFFFF"ohos:bottom_margin="2vp"ohos:bottom_padding="8vp"ohos:end_padding="16vp"ohos:start_padding="16vp"ohos:top_padding="8vp"><Textohos:id="$+id:tx_character_name"ohos:height="match_content"ohos:width="match_content"ohos:background_element="$color:black"ohos:text="服务"ohos:text_size="16fp"/><Textohos:id="$+id:tx_uuid_title"ohos:height="match_content"ohos:width="match_content"ohos:below="$id:tx_character_name"ohos:text="UUID:"ohos:text_color="$color:gray"ohos:text_size="16fp"ohos:top_margin="2vp"/><Textohos:id="$+id:tx_uuid"ohos:height="match_content"ohos:width="match_content"ohos:background_element="$color:black"ohos:below="$id:tx_character_name"ohos:end_of="$id:tx_uuid_title"ohos:text="UUID"ohos:text_size="16fp"ohos:top_margin="2vp"/><Textohos:id="$+id:tx_property_title"ohos:height="match_content"ohos:width="match_content"ohos:below="$id:tx_uuid_title"ohos:text="Properties:"ohos:text_color="$color:gray"ohos:text_size="16fp"ohos:top_margin="2vp"/><ListContainerohos:id="$+id:lc_property"ohos:height="match_content"ohos:width="match_parent"ohos:align_bottom="$id:tx_property_title"ohos:align_top="$id:tx_property_title"ohos:end_of="$id:tx_property_title"ohos:orientation="horizontal"/><DirectionalLayoutohos:id="$+id:lay_descriptors"ohos:height="match_content"ohos:width="match_parent"ohos:below="$id:tx_property_title"ohos:orientation="vertical"><Textohos:height="match_content"ohos:width="match_content"ohos:text="Descriptors:"ohos:text_color="#000000"ohos:text_size="16fp"ohos:top_margin="2vp"/><ListContainerohos:id="$+id:lc_descriptor"ohos:height="match_content"ohos:width="match_parent"/></DirectionalLayout></DependentLayout>

下面我们就可以正式去写描述符的提供者了。

② 描述提供者

  首先在layout下增加一个item_descriptor.xml,代码如下所示:

<?xml version="1.0" encoding="utf-8"?>
<DependentLayoutxmlns:ohos="http://schemas.huawei.com/res/ohos"ohos:height="match_content"ohos:width="match_parent"ohos:background_element="#FFFFFF"ohos:bottom_margin="2vp"ohos:bottom_padding="4vp"ohos:top_padding="4vp"><Textohos:id="$+id:tx_descriptor_name"ohos:height="match_content"ohos:width="match_content"ohos:background_element="$color:black"ohos:text="描述"ohos:text_size="16fp"/><Textohos:id="$+id:tx_uuid_title"ohos:height="match_content"ohos:width="match_content"ohos:below="$id:tx_descriptor_name"ohos:text="UUID:"ohos:text_color="$color:gray"ohos:text_size="16fp"ohos:top_margin="2vp"/><Textohos:id="$+id:tx_uuid"ohos:height="match_content"ohos:width="match_content"ohos:background_element="$color:black"ohos:below="$id:tx_descriptor_name"ohos:end_of="$id:tx_uuid_title"ohos:text="UUID"ohos:text_size="16fp"ohos:top_margin="2vp"/></DependentLayout>

然后关于描述符的名称,我们可以在BleUtils中写一个函数,代码如下所示:

    public static String getDescriptorName(UUID uuid) {String targetUuid = getShortUUID(uuid);switch (targetUuid) {case "0x2900":return "Characteristic Extended Properties";case "0x2901":return "Characteristic User Description";case "0x2902":return "Client Characteristic Configuration";case "0x2903":return "Server Characteristic Configuration";case "0x2904":return "Characteristic Presentation Format";case "0x2905":return "Characteristic Aggregate Format";case "0x2906":return "Valid Range";case "0x2907":return "External Report Reference";case "0x2908":return "Report Reference";case "0x2909":return "Number of Digitals";case "0x290A":return "Value Trigger Setting";case "0x290B":return "Environmental Sensing Configuration";case "0x290C":return "Environmental Sensing Measurement";case "0x290D":return "Environmental Sensing Trigger Setting";case "0x290E":return "Time Trigger Setting";case "0x290F":return "Complete BR-EDR Transport Block Data";case "0x2910":return "Observation Schedule";case "0x2911":return "Valid Range and Accuracy";default:return UNKNOWN_DESCRIPTOR;}}

  下面我们写描述符适配器,在provider包下新建一个DescriptorProvider类,代码如下所示:

public class DescriptorProvider extends BaseItemProvider {private final List<GattDescriptor> descriptorList;private final AbilitySlice slice;public DescriptorProvider(List<GattDescriptor> list, AbilitySlice slice) {this.descriptorList = list;this.slice = slice;}@Overridepublic int getCount() {return descriptorList == null ? 0 : descriptorList.size();}@Overridepublic Object getItem(int position) {if (descriptorList != null && position >= 0 && position < descriptorList.size()) {return descriptorList.get(position);}return null;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic Component getComponent(int position, Component component, ComponentContainer componentContainer) {final Component cpt;DescriptorHolder holder;GattDescriptor descriptor = descriptorList.get(position);if (component == null) {cpt = LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_item_descriptor, null, false);holder = new DescriptorHolder(cpt);//将获取到的子组件信息绑定到列表项的实例中cpt.setTag(holder);} else {cpt = component;// 从缓存中获取到列表项实例后,直接使用绑定的子组件信息进行数据填充。holder = (DescriptorHolder) cpt.getTag();}String descriptorName = BleUtils.getDescriptorName(descriptor.getUuid());holder.txDescriptorName.setText(descriptorName);holder.txUuid.setText(descriptorName.equals(BleUtils.UNKNOWN_DESCRIPTOR) ? descriptor.getUuid().toString() : BleUtils.getShortUUID(descriptor.getUuid()));return cpt;}/*** 用于保存列表项的子组件信息*/public static class DescriptorHolder {Text txDescriptorName;Text txUuid;ListContainer lcProperty;public DescriptorHolder(Component component) {txDescriptorName = (Text) component.findComponentById(ResourceTable.Id_tx_descriptor_name);txUuid = (Text) component.findComponentById(ResourceTable.Id_tx_uuid);lcProperty = (ListContainer) component.findComponentById(ResourceTable.Id_lc_property);}}
}

可以看这里的代码同样对于自定义UUID展示完整数据,对于SIG的展示短UUID。

③ 显示描述符

  接下来就是在特性适配器中去加载显示描述符数据,修改CharacteristicProvider中代码,所示代码:

public class CharacteristicProvider extends BaseItemProvider {private final List<GattCharacteristic> characteristicList;private final AbilitySlice slice;private final OperateCallback operateCallback;public CharacteristicProvider(List<GattCharacteristic> list, AbilitySlice slice, OperateCallback operateCallback) {this.characteristicList = list;this.slice = slice;this.operateCallback = operateCallback;}@Overridepublic int getCount() {return characteristicList == null ? 0 : characteristicList.size();}@Overridepublic Object getItem(int position) {if (characteristicList != null && position >= 0 && position < characteristicList.size()) {return characteristicList.get(position);}return null;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic Component getComponent(int position, Component component, ComponentContainer componentContainer) {final Component cpt;CharacteristicHolder holder;GattCharacteristic characteristic = characteristicList.get(position);if (component == null) {cpt = LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_item_characteristic, null, false);holder = new CharacteristicHolder(cpt);//将获取到的子组件信息绑定到列表项的实例中cpt.setTag(holder);} else {cpt = component;// 从缓存中获取到列表项实例后,直接使用绑定的子组件信息进行数据填充。holder = (CharacteristicHolder) cpt.getTag();}String characteristicsName = BleUtils.getCharacteristicsName(characteristic.getUuid());holder.txCharacterName.setText(characteristicsName);holder.txUuid.setText(BleUtils.getShortUUID(characteristic.getUuid()));holder.txUuid.setText(characteristicsName.equals(BleUtils.UNKNOWN_CHARACTERISTICS) ? characteristic.getUuid().toString() : BleUtils.getShortUUID(characteristic.getUuid()));List<String> properties = BleUtils.getProperties(characteristic.getProperties());//加载属性holder.lcProperty.setItemProvider(new PropertyProvider(properties, slice));//属性列表点击holder.lcProperty.setItemClickedListener((listContainer, component1, propertyPosition, l) -> {if (operateCallback != null) {//属性操作回调operateCallback.onPropertyOperate(characteristic, properties.get(propertyPosition));}});//加载特性下的描述if (characteristic.getDescriptors().size() > 0) {holder.lcDescriptor.setItemProvider(new DescriptorProvider(characteristic.getDescriptors(), slice));} else {holder.layDescriptor.setVisibility(Component.HIDE);}return cpt;}/*** 用于保存列表项的子组件信息*/public static class CharacteristicHolder {Text txCharacterName;Text txUuid;ListContainer lcProperty;DirectionalLayout layDescriptor;ListContainer lcDescriptor;public CharacteristicHolder(Component component) {txCharacterName = (Text) component.findComponentById(ResourceTable.Id_tx_character_name);txUuid = (Text) component.findComponentById(ResourceTable.Id_tx_uuid);lcProperty = (ListContainer) component.findComponentById(ResourceTable.Id_lc_property);layDescriptor = (DirectionalLayout) component.findComponentById(ResourceTable.Id_lay_descriptors);lcDescriptor = (ListContainer) component.findComponentById(ResourceTable.Id_lc_descriptor);}}
}

请注意这一段代码:

        //加载特性下的描述if (characteristic.getDescriptors().size() > 0) {holder.lcDescriptor.setItemProvider(new DescriptorProvider(characteristic.getDescriptors(), slice));} else {holder.layDescriptor.setVisibility(Component.HIDE);}

  这个判断和重要,因为不是每一个特性都有描述符,这个前面已经说过了,没有的我们就直接隐藏对应的描述符布局,否则就加载描述符数据,同时我们还需要修改一下服务UUID和特性UUID的Text控件的属性,因为UUID过长的话可能一行无法显示出来。

改动如下:

服务uuid:

        <Textohos:id="$+id:tx_uuid"ohos:height="match_content"ohos:width="match_content"ohos:background_element="$color:black"ohos:below="$id:tx_service_name"ohos:truncation_mode="ellipsis_at_middle"ohos:end_margin="24vp"ohos:text="UUID"ohos:end_of="$id:tx_uuid_title"ohos:align_end="$id:iv_state"ohos:text_size="16fp"ohos:top_margin="2vp"/>

特性uuid:

    <Textohos:id="$+id:tx_uuid"ohos:height="match_content"ohos:width="match_content"ohos:background_element="$color:black"ohos:below="$id:tx_character_name"ohos:end_of="$id:tx_uuid_title"ohos:truncation_mode="ellipsis_at_middle"ohos:text="UUID"ohos:text_size="16fp"ohos:top_margin="2vp"/>

下面运行看一下。

在这里插入图片描述

通过这个图就可以清晰的的看到特性下的描述符,本文就到这里了。

三、源码

如果对你有所帮助的话,不妨 StarFork,山高水长,后会有期~

源码地址:HarmonyBle-Java

相关文章:

Harmony Ble蓝牙App(四)描述符

Harmony Ble蓝牙App&#xff08;四&#xff09;描述符 前言正文一、优化二、描述① 概念② 描述提供者③ 显示描述符 三、源码 前言 上一篇中了解了特性和属性&#xff0c;同时显示设备蓝牙服务下的特性和属性&#xff0c;本文中就需要来使用这些特性和属性来完成一些功能。 正…...

C# 实现单线程异步互斥锁

文章目录 前言一、异步互斥锁的作用是什么&#xff1f;示例一、创建和销毁 二、如何实现&#xff1f;1、标识&#xff08;1&#xff09;标识是否锁住&#xff08;2&#xff09;加锁&#xff08;3&#xff09;解锁 2、异步通知&#xff08;1&#xff09;创建对象&#xff08;2&a…...

Java设计模式中策略模式可以解决许多if-else的代码结构吗? 是否能满足开闭原则?

Java设计模式中策略模式可以解决许多if-else的代码结构吗&#xff1f; 是否能满足开闭原则&#xff1f; 是的&#xff0c;策略模式可以帮助解决许多if-else的代码结构。通过将不同的算法封装成不同的策略类&#xff0c;然后在需要的时候动态地切换策略&#xff0c;可以避免使…...

[C#]C# winform部署yolov8目标检测的openvino模型

【官方框架地址】 https://github.com/ultralytics/ultralytics 【openvino介绍】 OpenVINO&#xff08;Open Visual Inference & Neural Network Optimization&#xff09;是由Intel推出的&#xff0c;用于加速深度学习模型推理的工具套件。它旨在提高计算机视觉和深度学…...

力扣刷MySQL-第五弹(详细讲解)

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;力扣刷题讲解-MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出…...

用C语言实现简单的三子棋游戏

目录 1 -> 模块简介 2 -> test.c 3 -> game.c 4 -> game.h 1 -> 模块简介 test.c:测试游戏逻辑 game.c: 函数的实现 game.h:函数的声明 2 -> test.c #define _CRT_SECURE_NO_WARNINGS 1#include "game.h";void menu() {printf("****…...

Yaklang 中的类型和变量

Yaklang 的类型其实非常简单&#xff0c;我们仅需要记住如下类型即可 string 字符串类型&#xff0c;用以快速构建一个字符串int 整数类型&#xff1a;在 64 位机中&#xff0c;int 和 int64 是一样的float 浮点类型&#xff0c;用来定义和表示浮点数byte 本质上等同于 uint8u…...

C语言从入门到实战——编译和链接

编译和链接 前言一、 翻译环境和运行环境二、 翻译环境2.1 预处理&#xff08;预编译&#xff09;2.2 编译2.2.1 词法分析2.2.2 语法分析2.2.3 语义分析 2.3 汇编2.4 链接 三、 运行环境 前言 在C语言中&#xff0c;编译和链接是将源代码转换为可执行文件的两个主要步骤。 编…...

【实战教程】ThinkPHP6分页功能轻松实现,让你的网站更高效!

ThinkPHP是一款非常流行的PHP开发框架&#xff0c;其最新版本ThinkPHP6在性能和易用性方面都得到了很大的改善。分页功能是网页开发中非常常见的功能&#xff0c;而ThinkPHP6也提供了非常方便的分页方法。本文将介绍如何实现ThinkPHP6的分页功能。 一、了解分页功能 在Web应用…...

专业130+总分380+哈尔滨工程大学810信号与系统考研经验水声电子信息与通信

今年专业课810信号与系统130&#xff0c;总分380顺利考上哈尔滨工程大学&#xff0c;一年的努力终于换来最后的录取&#xff0c;期中复习有得有失&#xff0c;以下总结一下自己的复习经历&#xff0c;希望对大家有帮助&#xff0c;天道酬勤&#xff0c;加油&#xff01;专业课&…...

旅游项目day08

1. 旅游日记&#xff08;游记&#xff09; 后端&#xff1a;实体类&#xff0c;列表&#xff0c;查看&#xff0c;审核 前端&#xff1a;目的地明细中-游记->带范围条件查询&#xff0c;游记首页&#xff0c;【扩展】游记添加/编辑&#xff0c;【扩展】添加游记时间没登录时…...

蓝桥杯真题(Python)每日练Day2

题目 题目分析 对于本题首先确定其数据结构为优先队列&#xff0c;即邮费最小的衣服优先寄&#xff0c;算法符合贪心算法。可以直接使用queue库的PriorityQueue方法实现优先队列。关于PriorityQueue的使用方法主要有&#xff1a; import queue q queue.Queue()# 队列 pq qu…...

IntelliJ IDEA 拉取gitlab项目

一、准备好Gitlab服务器及项目 http://192.168.31.104/root/com.saas.swaggerdemogit 二、打开 IntelliJ IDEA安装插件 打开GitLab上的项目&#xff0c;输入项目地址 http://192.168.31.104/root/com.saas.swaggerdemogit 弹出输入登录用户名密码&#xff0c;完成。 操作Comm…...

RHCSA上课笔记(前半部分)

第一部分 网络服务 第一章 例行性工作 1.单一执行的例行性工作 单一执行的例行性工作&#xff08;就像某一个时间点 的闹钟&#xff09;&#xff1a;仅处理执行一次 1.1 at命令&#xff1a;定时任务信息 [rhellocalhost ~]$ rpm -qa |grep -w at at-spi2-core-2.40.3-1.el9.x…...

C++代码入门05 字符串容器

图源&#xff1a;文心一言 上机题目练习整理&#xff0c;本篇作为字符串容器的代码&#xff0c;提供了常规解法及其详细解释&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 第1版&#xff1a;在力扣新手村刷题的记录~&#x1f9e9;&#x1f9e9; 方法&#xff1a;常…...

vue3 项目中 arguments 对象获取失败问题

问题 在 vue3 项目中 获取到的 arguments 对象与传入实参不符&#xff0c;打印出函数中的 arguments 对象显示如下&#xff1a; 原因 作者仔细回看代码才发现&#xff0c;自己一直用的是 vue3 的组合式写法&#xff0c;函数都是箭头函数&#xff0c;而箭头函数不存在 argumen…...

12.线程同步

12.线程同步 1. 为什么需要线程同步2. 互斥锁2.1 互斥锁初始化2.1.1 PTHREAD_MUTEX_INITIALIZER 宏初始化2.1.2 使用函数初始化 2.2 加锁和解锁2.3 pthread_mutex_trylock()2.4 销毁互斥锁2.5 互斥锁死锁2.6 互斥锁的属性 3. 条件变量3.1 条件变量初始化3.2 通知和等待条件变量…...

开发安全之:System Information Leak: External

Overview 在调用 error_reporting() 过程中&#xff0c;程序可能会显示系统数据或调试信息。由 error_reporting() 揭示的信息有助于攻击者制定攻击计划。 Details 当系统数据或调试信息通过套接字或网络连接使程序流向远程机器时&#xff0c;就会发生外部信息泄露。 示例 1…...

burp靶场--文件上传

burp靶场–文件上传 https://portswigger.net/web-security/file-upload/lab-file-upload-remote-code-execution-via-web-shell-upload 1.文件上传 1、原理&#xff1a;文件上传漏洞是指Web服务器允许用户将文件上传到其文件系统&#xff0c;而不充分验证文件的名称、类型、…...

mac 中vscode设置root启动

1. 找到你的vscode app&#xff0c;点击鼠标右键------->选项----->在访达中显示 2. 终端中输入以下命令&#xff0c;不要点回车&#xff0c;不要点回车&#xff0c;输入一个空格 sudo chflags uchg 3. 然后将你的程序拖到终端&#xff0c;会自动…...

【MySQL数据库专项 一】一个例子讲清楚数据库三范式

好的&#xff0c;让我们以学校数据库中的一个表为例来说明第一范式&#xff08;1NF&#xff09;、第二范式&#xff08;2NF&#xff09;和第三范式&#xff08;3NF&#xff09;的概念。 什么是数据库三范式 数据库的范式&#xff08;Normalization&#xff09;是一组关于数据…...

【笔记】关于期刊

什么是统计源期刊 统计源期刊&#xff0c;全称为“中国科技论文统计源期刊”&#xff0c;也称作中国科技核心期刊&#xff0c;是由中国科技信息研究所&#xff08;ISTIC&#xff09;受国家科技部委托&#xff0c;选定的一系列在中国出版的高质量自然科学类学术期刊。这些期刊是…...

SpringMVC-.xml的配置

文章目录 一、对pom.xml的配置二、对web.xml1.第一种方式2. 第二种方式 三、对SpringMVC.xml的配置 一、对pom.xml的配置 <!-- 打包成war包--><packaging>war</packaging> <dependencies><!-- SpringMVC--><dependency><gro…...

Java找二叉树的公共祖先

描述&#xff1a; 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节…...

《Linux高性能服务器编程》笔记03

Linux高性能服务器编程 本文是读书笔记&#xff0c;如有侵权&#xff0c;请联系删除。 参考 Linux高性能服务器编程源码: https://github.com/raichen/LinuxServerCodes 豆瓣: Linux高性能服务器编程 文章目录 Linux高性能服务器编程第07章 Linux服务器程序规范7.1日志7.2用…...

Java毕业设计-基于ssm的网上求职招聘管理系统-第85期

获取源码资料&#xff0c;请移步从戎源码网&#xff1a;从戎源码网_专业的计算机毕业设计网站 项目介绍 基于ssm的网上求职招聘管理系统&#xff1a;前端 jsp、jquery&#xff0c;后端 springmvc、spring、mybatis&#xff0c;角色分为管理员、招聘人员、用户&#xff1b;集成…...

UDP和TCP

UDP协议是一种不可靠的、面向无连接的协议。在通信过程中&#xff0c;它并不像TCP那样需要先建立一个连接&#xff0c;只要&#xff08;目的地址&#xff0c;端口号&#xff0c;源地址&#xff0c;端口号&#xff09;确定了&#xff0c;就可以直接发送信息报文&#xff0c;并且…...

【C++】vector容器接口要点的补充

接口缩容 在VS编译器的模式下&#xff0c;类似于erase和insert接口的函数通常会进行缩容&#xff0c;因此&#xff0c;insert和erase行参中的迭代器可能会失效。下图中以erase为例&#xff1a; 代码如下&#xff1a; #include <iostream> #include <vector> #inclu…...

electron-vite中的ipc通信

1. 概述 再electron中&#xff0c;进程间的通信通过ipcMain和ipcRenderer模块&#xff0c;这些通道是任意和双向的 1.1. 什么是上下文隔离进程 ipc通道是通过预加载脚本绑定到window对象的electron对象属性上的 2. 通信方式 2.1. ipcMain&#xff08;也就是渲染进程向主进…...

探秘网络爬虫的基本原理与实例应用

1. 基本原理 网络爬虫是一种用于自动化获取互联网信息的程序&#xff0c;其基本原理包括URL获取、HTTP请求、HTML解析、数据提取和数据存储等步骤。 URL获取&#xff1a; 确定需要访问的目标网页&#xff0c;通过人工指定、站点地图或之前的抓取结果获取URL。 HTTP请求&#…...