Harmony Ble蓝牙App(四)描述符

news2024/11/28 12:31:55

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,剩下的就可以在服务适配器和特性适配器中去修改了,首先是服务适配器,修改

    @Override
    public 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。默认是小写的,你也可以改成大写。

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

    @Override
    public 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"?>
<DependentLayout
    xmlns: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">

    <Text
        ohos:id="$+id:tx_character_name"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:background_element="$color:black"
        ohos:text="服务"
        ohos:text_size="16fp"/>

    <Text
        ohos: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"/>

    <Text
        ohos: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"/>

    <Text
        ohos: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"/>

    <ListContainer
        ohos: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"/>

    <DirectionalLayout
        ohos:id="$+id:lay_descriptors"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:below="$id:tx_property_title"
        ohos:orientation="vertical">

        <Text
            ohos:height="match_content"
            ohos:width="match_content"
            ohos:text="Descriptors:"
            ohos:text_color="#000000"
            ohos:text_size="16fp"
            ohos:top_margin="2vp"/>

        <ListContainer
            ohos: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"?>
<DependentLayout
    xmlns: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">

    <Text
        ohos:id="$+id:tx_descriptor_name"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:background_element="$color:black"
        ohos:text="描述"
        ohos:text_size="16fp"/>

    <Text
        ohos: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"/>

    <Text
        ohos: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;
    }

    @Override
    public int getCount() {
        return descriptorList == null ? 0 : descriptorList.size();
    }

    @Override
    public Object getItem(int position) {
        if (descriptorList != null && position >= 0 && position < descriptorList.size()) {
            return descriptorList.get(position);
        }
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public 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;
    }

    @Override
    public int getCount() {
        return characteristicList == null ? 0 : characteristicList.size();
    }

    @Override
    public Object getItem(int position) {
        if (characteristicList != null && position >= 0 && position < characteristicList.size()) {
            return characteristicList.get(position);
        }
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public 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:

        <Text
            ohos: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:

    <Text
        ohos: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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1399231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VS+QT编译环境中字符乱码问题详解

字符乱码问题详解 1 编码字符集与字符编码方式2 字符乱码原因3 字符乱码解决方案 在解释字符乱码问题之前&#xff0c;我们需要先理清一些基本概念 1 编码字符集与字符编码方式 编码字符集 编码字符集是所有字符以及对应代码值的集合。编码字符集中的每个字符都对应一个唯一的…

一步一步写线程之五线程池的模型之一领导者追随者模型

一、线程池的模型 在学习过相关的多线程知识后&#xff0c;从更抽象的角度来看待多线程解决问题的方向&#xff0c;其实仍然是典型的生产和消费者的模型。无论是数据计算、存储、分发和任务处理等都是通过多线程这种手段来解决生产者和消费者不匹配的情况。所以&#xff0c;得…

MySQL主从集群

MySQL主从集群 主从模式、集群模式&#xff0c;都是在一个项目中使用多个mysql节点进行存储和读取数据。 当单机模式部署&#xff0c;不满足安全性、高可用、高并发等需求的时候&#xff0c;就需要考虑主从模式或者集群模式部署。 什么是主从模式&#xff1f; 主从模式&…

commvault学习(5):在linux上安装cv客户端

我的环境&#xff1a; 服务器&#xff08;同时装有CS、MA&#xff09;&#xff1a;windows server2008r2 客户端&#xff1a;两台centos7 1.为两台centos7配置静态ip 使得2者可以与服务器ping通 2.在两台centos7上预留出足够大的磁盘空间以存放安装文件 我是在/mnt下创建了…

十本你不容错过的Docker入门到精通书籍推荐

前言&#xff1a; 最近有许多小伙伴私信让我推荐几本关于Docker学习的书籍&#xff0c;今天花了一下午的时间在网上查阅了一些资料和结合自己平时工作中的一些学习参考资料书籍写下了这篇文章。注意以下书籍都是十分优秀的Docker学习书籍&#xff08;因此排名不分先后&#xff…

tritonserver学习之三:tritonserver运行流程

tritonserver学习之一&#xff1a;triton使用流程 tritonserver学习之二&#xff1a;tritonserver编译 tritonserver学习之四&#xff1a;命令行解析 1、triton启动运行流程 triton功能设计全面&#xff0c;而且复杂&#xff0c;下面是triton(2.41.0)启动的整个流程&#x…

从函数角度看品牌网络推广:短期与长期的博弈

在数字营销的世界里&#xff0c;品牌网络推广无疑是一个复杂而多维度的领域。它不仅仅是一个简单的“投入-产出”关系&#xff0c;而是一个涉及到多种因素、时间和空间的动态过程。当我们尝试从函数的角度去解读品牌网络推广时&#xff0c;会发现它其实是一个不断变化的函数关系…

我在人工智能技术方面的发展规划

人工智能(AI)是当今科技领域最具前景和影响力的技术之一,它已经渗透到各行各业,为社会和经济发展带来了巨大的机遇和挑战。作为一名从事人工智能研究和开发的专业人士,我有必要制定一个合理的人工智能技术发展规划,以指导我的学习和工作,提高我的专业水平和竞争力,为人…

009 Linux_文件系统 | 软硬链接

前言 本文将会向你介绍文件系统与软硬链接 文章重点 本文将会先向你介绍文件是如何在磁盘上进行管理的&#xff0c;关于文件的管理将会从管理属性和管理内容两方面来谈&#xff0c;最后会向你介绍软硬链接的概念 文件在磁盘中的管理 首先&#xff0c;假设一个磁盘200GB&#…

softmax回实战

1.数据集 MNIST数据集 (LeCun et al., 1998) 是图像分类中广泛使用的数据集之一&#xff0c;但作为基准数据集过于简单。 我们将使用类似但更复杂的Fashion-MNIST数据集 (Xiao et al., 2017)。 import torch import torchvision from torch.utils import data from torchvisi…

25计算机考研408专业课复习计划

点击蓝字&#xff0c;关注我们 今天要分享的是25计算机考研408专业课复习计划。 以下内容供大家参考&#xff0c;大家要根据自己的复习情况进行适当调整。 统考与自命题 统考科目是指计算机学科专业基础综合&#xff08;408&#xff09;&#xff0c;满分150分&#xff0c;试…

用MATLAB函数在图表中建立模型

本节介绍如何使用Stateflow图表创建模型&#xff0c;该图表调用两个MATLAB函数meanstats和stdevstats。meanstats计算平均值&#xff0c;stdevstats计算vals中值的标准偏差&#xff0c;并将它们分别输出到Stateflow数据平均值和stdev。 请遵循以下步骤&#xff1a; 1.使用以下…

医保移动支付加密解密请求工具封装【国密SM2SM4】

文章目录 医保移动支付加密解密请求工具封装一、项目背景二、使用方法三、接口调用四、源码介绍五、下载地址 医保移动支付加密解密请求工具封装 定点医药机构向地方移动支付中心发起费用明细上传、支付下单、医保退费等交易时需要发送密文&#xff0c;由于各大医疗机构厂商的开…

揭秘AI换脸技术:从原理到应用

随着人工智能技术的不断发展&#xff0c;AI换脸技术逐渐成为人们关注的焦点。这项神奇的技术能够将一张图像或视频中的人脸替换成另一张人脸&#xff0c;让人不禁惊叹科技的神奇。那么&#xff0c;AI换脸技术究竟是如何实现的呢&#xff1f;本文将带您深入了解AI换脸技术的原理…

python系列-输入输出关系运算符算术运算符

&#x1f308;个人主页: 会编程的果子君​&#x1f4ab;个人格言:“成为自己未来的主人~” 目录 注释的语法 注释的规范 输入输出 通过控制台输出 通过控制台输入 运算符 算术运算符 关系运算符 注释的语法 python中有两种注释风格&#xff1a; 1.注释行&#xff1a;…

无人机打击激光器

激光器的应用非常广泛&#xff0c;涵盖了多个领域。以下是一些主要的激光器应用&#xff1a; 医疗领域&#xff1a;激光器在医疗行业中有着重要应用&#xff0c;比如用于激光手术&#xff08;如眼科手术&#xff09;、皮肤治疗、牙科治疗、肿瘤治疗等。 工业制造&#xff1a;在…

(菜鸟自学)初学脚本编程

&#xff08;菜鸟自学&#xff09;初学脚本编程 Bash脚本概述编写一个测试在线主机的脚本程序 Python脚本概述编写一个与Netcat功能类似的脚本程序 C语言脚本概述编写C语言脚本程序&#xff08;Hello World&#xff09; Bash脚本概述 Bash脚本是一种基于Bash&#xff08;Bourn…

图片批量建码怎么用?每张图片快速生成二维码

当我们需要给每个人分别下发对应的个人证件类图片信息&#xff0c;比如制作工牌、荣誉展示或者负责人信息展示时&#xff0c;现在都开始使用二维码的方法来展示员工信息。那么如何快速将每个人员的信息图片分别制作成二维码图片呢&#xff0c;最简单的方法就是使用图片批量建码…

vue中内置指令v-model的作用和常见使用方法介绍以及在自定义组件上支持

文章目录 一、v-model是什么二、什么是语法糖三、v-model常见的用法1、对于输入框&#xff08;input&#xff09;&#xff1a;2、对于复选框&#xff08;checkbox&#xff09;&#xff1a;3、对于选择框&#xff08;select&#xff09;&#xff1a;4、对于组件&#xff08;comp…

群发邮件效果追踪:掌握数据,优化营销策略

我们在邮件群发结束后&#xff0c;如果想要了解到这次群发活动的效果怎么样&#xff0c;就需要通过一些数据。比如说邮件达到率、打开率、跳出率、退订率等。这些信息可以将收件人的行为数据化&#xff0c;让我们可以更清晰地对活动进行深入分析让我们及时地找出问题和优点&…