Qt——xml文件生成DBus接口

1. 如何根据xml文件生成Dbus接口

         要使用 XML 文件生成 D-Bus 接口,你可以按照以下步骤操作:

        步骤 1: 准备 XML 文件

                确保你的 XML 文件遵循 D-Bus 的接口描述规范。这通常包括定义接口、方法、信号和属性。一个基本的例子如下:

<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN""http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node><interface name="com.example.SampleInterface"><method name="TestMethod"><arg direction="in" type="s" name="input"/><arg direction="out" type="s" name="output"/></method><signal name="TestSignal"><arg type="s" name="signalData"/></signal></interface>
</node>

        步骤 2: 使用工具生成代码

                在 Linux 系统上,你可以使用 `gdbus-codegen` 工具来根据 XML 文件生成代码。这个工具是 Glib 库的一部分,能够生成服务端和客户端代码。

1. 安装工具(如果尚未安装):sudo apt-get install libglib2.0-dev2. 生成代码:gdbus-codegen --generate-c-code my_interface_gen --c-namespace My --interface-prefix com.example. my_interface.xml
这里,`my_interface_gen` 是生成的源文件的前缀,`com.example.` 是接口名称的前缀,`my_interface.xml` 是你的 XML 文件。生成的文件通常包括:
- `my_interface_gen.h`:头文件,包含接口定义。
- `my_interface_gen.c`:源文件,包含接口实现的框架。

        当你使用工具如 `qdbusxml2cpp`(这是 Qt 提供的一个工具,用来从 D-Bus XML 描述文件生成 D-Bus 适配器代码),你会得到两个主要的文件:

        1. Header (.h) 文件 - 包含了从 XML 文件定义的 D-Bus 接口生成的 C++ 类的声明。这个类通常继承自 `QDBusAbstractAdaptor`。
        2. Source (.cpp) 文件 - 包含了实现文件,实现了 XML 文件中定义的接口。

        使用 `qdbusxml2cpp` 生成的适配器代码可能会看起来像这样:

// Generated Adaptor Code (SampleAdaptor.h)
#include <QDBusAbstractAdaptor>
#include <QDBusConnection>
#include <QObject>class SampleAdaptor : public QDBusAbstractAdaptor {Q_OBJECTQ_CLASSINFO("D-Bus Interface", "com.example.SampleInterface")
public:SampleAdaptor(QObject *parent) : QDBusAbstractAdaptor(parent) {// Constructor code here}public slots:QString TestMethod(const QString &input) {// Implementation herereturn "Received: " + input;}
signals:void TestSignal(const QString &signalData);
};

2. QDBusAbstractAdaptor QDBusAbstractInter区别是什么?

        在 Qt 的 D-Bus 模块中,`QDBusAbstractAdaptor` 和 `QDBusAbstractInterface` 是两个核心类,它们在 D-Bus 系统中扮演不同的角色,分别用于实现服务端适配器和客户端接口。下面是这两个类的主要区别和用途:

QDBusAbstractAdaptor

1. 定义与用途:
   - `QDBusAbstractAdaptor` 类用于创建 D-Bus 适配器。这个适配器充当了 Qt 对象和 D-Bus 之间的桥梁。
   - 它通常用于将现有的 Qt 对象的功能公开为 D-Bus 服务,允许其他应用程序通过 D-Bus 调用这些功能。

2. 工作方式:
   - 适配器类从 `QDBusAbstractAdaptor` 派生,并将其关联到一个 QObject。这个适配器为 QObject 定义的公开方法、信号和属性提供 D-Bus 访问。

3. 特点:
   - 适配器通过注册到 D-Bus 系统来使得其他应用可以通过 D-Bus 通信机制调用其方法、接收信号或访问属性。

QDBusAbstractInterface

1. 定义与用途:
   - `QDBusAbstractInterface` 类用于创建能与 D-Bus 服务进行交互的客户端接口。
   - 它通常用于编写客户端应用程序,这些应用程序需要与 D-Bus 服务通信,调用服务提供的方法或访问服务的属性。

2. 工作方式:
   - 从 `QDBusAbstractInterface` 派生的类可以用来表示 D-Bus 上的远程接口。这个类处理所有的低级 D-Bus 通信细节,如方法调用、信号订阅和属性访问。

3. 特点:
   - 客户端接口对象提供了一个高级的抽象,使得开发者可以像调用本地对象一样调用远程 D-Bus 服务的方法。

        `QDBusAbstractAdaptor` 适用于需要将应用的一部分功能通过 D-Bus 公开给其他应用调用的场景(服务端),`QDBusAbstractAdaptor` 是为了将本地对象的功能“导出”到 D-Bus 上。

         `QDBusAbstractInterface` 适用于需要从应用中访问其他应用公开的 D-Bus 服务的场景(客户端),`QDBusAbstractInterface` 是为了从 D-Bus 上“导入”远程服务的接口。

        2.1 举例

                接下来通过一个简单的例子来展示如何使用 `QDBusAbstractAdaptor` 和 `QDBusAbstractInterface` 来在 Qt 应用程序中实现 D-Bus 服务端和客户端。

                假设我们有一个简单的系统服务,它提供了一个方法来获取系统的当前时间。我们将首先创建一个服务端应用程序,它使用 `QDBusAbstractAdaptor` 将这个功能公开为一个 D-Bus 服务。然后,我们将创建一个客户端应用程序,使用 `QDBusAbstractInterface` 来访问这个服务

服务端:使用 QDBusAbstractAdaptor

1. 定义服务接口 (`TimeService.h`):#include <QObject>#include <QDBusAbstractAdaptor>#include <QDateTime>class TimeService : public QObject{Q_OBJECTQ_CLASSINFO("D-Bus Interface", "com.example.timeservice")public:explicit TimeService(QObject *parent = nullptr) : QObject(parent) {}public slots:QString getCurrentTime() {return QDateTime::currentDateTime().toString();}};class TimeServiceAdaptor : public QDBusAbstractAdaptor{Q_OBJECTQ_CLASSINFO("D-Bus Interface", "com.example.timeservice")public:explicit TimeServiceAdaptor(TimeService *service): QDBusAbstractAdaptor(service), m_service(service) {setAutoRelaySignals(true);}public slots:QString getCurrentTime() {return m_service->getCurrentTime();}private:TimeService *m_service;};2. 实现主函数 (`main.cpp`):#include <QCoreApplication>#include <QDBusConnection>#include "TimeService.h"int main(int argc, char *argv[]){QCoreApplication app(argc, argv);TimeService service;TimeServiceAdaptor adaptor(&service);QDBusConnection connection = QDBusConnection::sessionBus();connection.registerObject("/timeservice", &service);connection.registerService("com.example.timeservice");return app.exec();}

        仔细看代码会发现 `TimeServiceAdaptor`构造函数中,有一个方法`setAutoRelaySignals(true)`,这个函数的作用可参见setAutoRelaySignals(true)-CSDN博客

客户端:使用 QDBusAbstractInterface

1. 定义客户端接口 (`TimeClient.h`):#include <QDBusAbstractInterface>#include <QDBusConnection>class TimeClient : public QDBusAbstractInterface{Q_OBJECTpublic:explicit TimeClient(QObject *parent = nullptr): QDBusAbstractInterface("com.example.timeservice","/timeservice","com.example.timeservice",QDBusConnection::sessionBus(),parent) {}QDBusPendingCall asyncGetCurrentTime() {return asyncCall("getCurrentTime");}};2. 实现客户端主函数 (`main.cpp`):#include <QCoreApplication>#include <QDebug>#include "TimeClient.h"int main(int argc, char *argv[]){QCoreApplication app(argc, argv);TimeClient client;QDBusPendingReply<QString> reply = client.asyncGetCurrentTime();reply.waitForFinished();if (reply.isValid()) {qDebug() << "Current Time:" << reply.value();} else {qDebug() << "Error:" << reply.error().message();}return app.exec();}

        在这个示例中:
        - 服务端应用程序创建了一个 `TimeService` 对象和一个 `TimeServiceAdaptor` 适配器,通过 D-Bus 在 `com.example.timeservice` 服务下公开了一个方法 `getCurrentTime`。
        - 客户端应用程序使用 `TimeClient`(派生自 `QDBusAbstractInterface`)来异步调用这个方法,并在接收到结果后打印当前时间或错误信息。

3. xml生成的QDBusAbstractAdaptor函数 直接就生成dbus服务了吗?

        使用 XML 文件生成 `QDBusAbstractAdaptor` 类的代码并不会直接创建一个运行的 D-Bus 服务。这个过程只是自动化了在 Qt 中为 D-Bus 服务编写适配器代码的部分工作,生成的适配器代码需要在一个 Qt 应用程序中被编译和运行,才能实际形成一个可用的 D-Bus 服务。

        看过刚刚服务端的例子,可以了解到尽管 XML 到 `QDBusAbstractAdaptor` 的代码生成是自动的,但是要让这个适配器成为一个活跃的 D-Bus 服务,还需要手动编写一些胶水代码来实例化和注册到 D-Bus 系统。这包括设置 Qt 应用程序基础设施、实例化适配器类、并且确保它被注册为一个 D-Bus 服务。

4. QDBusAbstractAdaptor如何绑定的接口

        在 Qt 的 D-Bus 系统中,`QDBusAbstractAdaptor` 类用于将一个 QObject 或其子类的方法、属性和信号绑定到 D-Bus 接口。这个绑定过程是通过几个关键步骤实现的,使得当远程 D-Bus 调用发生时,相应的本地 QObject 的方法能够被触发。下面详细介绍这个过程。

创建 QObject 子类

        首先,你需要有一个 QObject 子类,这个类实现了你想要通过 D-Bus 公开的功能。例如:

class MyService : public QObject {Q_OBJECT
public:explicit MyService(QObject *parent = nullptr) : QObject(parent) {}public slots:QString performAction(const QString &param) {// 实现具体的功能return "Action performed with: " + param;}
};

创建和配置 QDBusAbstractAdaptor 子类

        接着,你创建一个从 `QDBusAbstractAdaptor` 派生的类,这个类将作为中间人,把 D-Bus 调用转发到你的 QObject 子类。你需要在这个适配器类中声明你想通过 D-Bus 公开的所有方法、信号和属性。

class MyServiceAdaptor : public QDBusAbstractAdaptor {Q_OBJECTQ_CLASSINFO("D-Bus Interface", "com.example.MyService")
public:explicit MyServiceAdaptor(MyService *service): QDBusAbstractAdaptor(service), myService(service) {// 自动将所有信号关联到 D-BussetAutoRelaySignals(true);}public slots:QString performAction(const QString &param) {return myService->performAction(param);}private:MyService *myService;
};

注册 QObject 和适配器到 D-Bus 系统

        在你的应用程序的主函数中或在适当的初始化代码中,你需要创建你的服务和适配器的实例,并将它们注册到 D-Bus 系统中。

int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);MyService service;MyServiceAdaptor adaptor(&service);QDBusConnection dbus = QDBusConnection::sessionBus();bool success = dbus.registerObject("/MyService", &service);success &= dbus.registerService("com.example.MyService");return success ? app.exec() : -1;
}

绑定和调用流程

1. D-Bus 请求到达:当其他应用通过 D-Bus 发送请求调用 `performAction` 方法时,请求首先到达 D-Bus 守护进程。
2. 适配器接收请求:D-Bus 守护进程将调用转发到注册的对象(在本例中是 `/MyService`)和其适配器。
3. 适配器调用 QObject 方法:`MyServiceAdaptor` 的 `performAction` 方法被触发,该方法内部再调用 `MyService` 实例的 `performAction` 方法。
4. 结果返回给调用者:方法执行完成后的返回值被发送回调用者。

        这种方式通过 `QDBusAbstractAdaptor` 类来封装 QObject 的实现细节,使得 D-Bus 服务的创建和管理更加模块化和清晰。这样,你就能够在 Qt 应用程序中方便地实现和使用基于 D-Bus 的 IPC (进程间通信) 功能。

5. 为了调用能联通 MyServiceAdaptor 和MyService的方法名需一致吗?

        在使用 `QDBusAbstractAdaptor` 时,确保 D-Bus 接口能够正确地调用到后端 `MyService` 的方法,并不严格要求适配器和服务中的方法名完全一致。但是,使它们一致通常会使代码更易于理解和维护。关键在于适配器方法中如何调用服务方法,以及如何映射 D-Bus 接口到具体的实现。
        `QDBusAbstractAdaptor` 的工作是为一个或多个 QObject 方法提供 D-Bus 访问。当你创建适配器类的时候,你定义了哪些方法应该通过 D-Bus 被暴露出去。这包括在适配器中定义方法,这些方法将会在 D-Bus 调用时被触发。在这些方法内部,你可以调用实际的服务对象(例如 `MyService` 类)的任何方法。
        以下示例展示了即使方法名不一致,适配器如何将调用正确地转发给服务对象:

        服务器的类如上,就不举例了,下面是修改后的适配器类
 

 class MyServiceAdaptor : public QDBusAbstractAdaptor {Q_OBJECTQ_CLASSINFO("D-Bus Interface", "com.example.MyService")public:explicit MyServiceAdaptor(MyService *service): QDBusAbstractAdaptor(service), myService(service) {setAutoRelaySignals(true);}public slots:QString performAction(const QString &param) {return myService->serviceAction(param);//注意这里函数名不一致,主要还是看绑定的对象}private:MyService *myService;};

        在这个例子中,适配器的 `performAction` 方法调用了服务对象 `MyService` 的 `serviceAction` 方法。这样的设计允许你在 D-Bus 接口中公开一个逻辑上的接口,而无需关心服务实现的内部方法名,增加了灵活性。

6. xml 生成的`QDBusAbstractInterface`,客户端是怎么使用的?

        在 Qt 中使用 `QDBusAbstractInterface` 创建 D-Bus 客户端是与 D-Bus 服务进行交互的一种方式。`QDBusAbstractInterface` 提供了一个便捷的方法来调用 D-Bus 服务上的方法、订阅信号和访问属性,而无需手写大量的 D-Bus 通信代码。下面详细介绍如何使用 `QDBusAbstractInterface` 创建和使用一个 D-Bus 客户端。

### 步骤 1: 创建客户端接口

假设你已经有一个 D-Bus 服务在运行,比如前面服务端的例子,你可以手动定义接口或使用 `qdbusxml2cpp` 工具生成接口类。这里我们手动定义一个:

   #include <QDBusAbstractInterface>#include <QDBusReply>class TestClient : public QDBusAbstractInterface {public:TestClient (QObject *parent = nullptr): QDBusAbstractInterface("com.test","/test,"com.test",QDBusConnection::sessionBus(),parent) {}QDBusReply<void> test(const QString &name, const QString &testname) {return call("test", name, testname);}};

        这个类定义了如何连接到 D-Bus 服务 (`com.test`) 和调用 `test` 方法。

        使用客户端接口,在你的 Qt 应用程序中,你可以创建 `TestClient` 的实例并使用它来调用 D-Bus 服务。

#include <QCoreApplication>
#include <QDebug>int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);TestClient client;QDBusReply<void> reply = client.test("test", "test");if (reply.isValid()) {qDebug() << "Call succeeded";} else {qDebug() << "Call failed:" << reply.error().message();}return app.exec();
}

7. QDBusAbstractAdaptor 和QDBusAbstractInterface之间是怎么绑定的呢?

        在 Qt 的 D-Bus 系统中,`QDBusAbstractInterface` 和对应的 `QDBusAbstractAdaptor` 之间的“绑定”是通过 D-Bus 服务的接口定义实现的。具体来说,这种绑定不是在代码层面上直接操作的,而是通过 D-Bus 的服务注册和接口调用机制来实现相互操作的。下面详细解释这个过程。

        这种“绑定”实际上是通过 D-Bus 的消息传递系统在服务端和客户端之间进行的。下面是绑定过程的简化描述:

1. 服务注册:
   - 在服务端,`QDBusAbstractAdaptor` 将 QObject 的某些功能注册为 D-Bus 服务。
   - 服务通过在 D-Bus 系统中注册一个唯一的服务名称和对象路径来完成。
   - 这些信息(服务名称、对象路径、接口名)都需要在客户端知晓,以便能正确地定位和调用服务。

2. 服务发现:
   - 客户端使用 `QDBusAbstractInterface` 来创建一个代表远程服务的对象。
   - 客户端在创建这个接口对象时,需要指定服务名称、对象路径和接口名称。
   - 一旦指定,`QDBusAbstractInterface` 就可以使用这些信息通过 D-Bus 发送调用请求。

3. 方法调用和响应
   - 当客户端通过 `QDBusAbstractInterface` 调用一个方法时,D-Bus 守护进程将这个调用转发到服务端。
   - 服务端的 `QDBusAbstractAdaptor` 接收到调用后,会将其转化为本地的 QObject 方法调用。
   - 执行结果(如果方法调用有返回值)或状态(成功或失败)将通过 D-Bus 返回给客户端。

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

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

相关文章

Axure如何实现限制选择项数量的交互

大家经常会看到这样的功能设计&#xff1a;可以多选&#xff0c;但是限制多选。比如某招聘网站城市的选择只能选择5个。再选择第6个的时候会提示最多只能选择5项。 这个效果是我们经常会遇到的&#xff0c;在工作中也经常会遇到需要制作这样的效果。今天我们一起来看看&#xf…

RabbitMQ-交换机

文章目录 交换机fanoutDirecttopicHeadersRPC 交换机 **交换机 **是消息队列中的一个组件&#xff0c;其作用类似于网络路由器。它负责将我们发送的消息转发到相应的目标&#xff0c;就像快递站将快递发送到对应的站点&#xff0c;或者网络路由器将网络请求转发到相应的服务器…

从二本调剂到上海互联网公司算法工程师:我的成长故事

探讨选择成为一名程序员的原因&#xff0c;是出于兴趣还是职业发展&#xff1f; 在这个科技飞速发展的时代&#xff0c;程序员这一职业无疑成为了许多人眼中的香饽饽。那么&#xff0c;是什么驱使着越来越多的人选择投身于这一行业呢&#xff1f;是出于对编程的热爱&#xff0…

SFusion论文速读

SFusion: Self-attention Based N-to-One Multimodal Fusion Block 摘要 人们用不同的感官感知世界&#xff0c;例如视觉、听觉、嗅觉和触觉。处理和融合来自多种模式的信息使人工智能能够更轻松地理解我们周围的世界。然而&#xff0c;当缺少模态时&#xff0c;可用模态的数…

使用Canal同步MySQL 8到ES中小白配置教程

&#x1f680; 使用Canal同步MySQL 8到ES中小白配置教程 &#x1f680; 文章目录 &#x1f680; 使用Canal同步MySQL 8到ES中小白配置教程 &#x1f680;**摘要****引言****正文**&#x1f4d8; 第1章&#xff1a;初识Canal1.1 Canal概述1.2 工作原理解析 &#x1f4d8; 第2章&…

Python多态

1.多态 多态定义&#xff1a;多态&#xff08;polymorphism&#xff09;是指同一个方法调用由于对象不同可能会产生不同的行为 注意以下2点&#xff1a; 1.多态是方法的多态&#xff0c;属性没有多态。 2.多态的存在有2个必要条件&#xff1a;继承、方法重写 class Animal:de…

DRF过滤类

DRF过滤类 目录 DRF过滤类OrderingFilter排序SearchFilter过滤第三方过滤django-filter自定义过滤类使用 OrderingFilter排序 DRF自带的排序类OrderingFilter 必须是继承 GenericAPIView 的视图类才能调用&#xff0c;继承APIView时不能这么配置 # views.py from rest_frame…

Hadoop中的MapReduce流程(图解)

一、MapReduce流程图&#xff1a; 二、MapReduce流程步骤&#xff1a; 1.文件上传到HDFS中&#xff0c;默认以128M切分为一个block块 2.每个block块对数据进行逻辑上的切片&#xff0c;切片大小为128M,与block块大小一致 3.之后根据切片产生Map任务 4.Map任务会进入环形缓冲区&…

【Go语言快速上手(二)】 分支与循环函数讲解

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Go语言专栏⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Go语言知识   &#x1f51d;&#x1f51d; Go快速上手 1. 前言2. 分支与循环2.1…

PLGA-PEG-PLGA温敏水凝胶 相变温度下是溶液 相变温度上是凝胶

PLGA-PEG-PLGA温敏水凝胶 相变温度下是溶液 相变温度上是凝胶 【中文名称】 温敏水凝胶 【英文名称】 PLGA-PEG-PLGA 【结 构】 【品 牌】 碳水科技&#xff08;Tanshtech&#xff09; 【纯 度】 95%以上 【保 存】 -20 【规 格】 10g/袋 【产品特性】…

Web端Webrtc,SIP,RTSP/RTMP,硬件端,MCU/SFU融合视频会议系统方案分析

Web端视频融合&#xff0c;会议互通已经是视频会议应用的大趋势&#xff0c;一是目前企业有大量的老视频会议硬件设&#xff0c;二新业务又需要Web端支持视频会议监控直播需求&#xff0c;迫切需要一个融合对接的方案&#xff0c;即能把老的设备用起来&#xff0c;又能对接新的…

浅析LED节能原理

随着全球对节能环保意识的增强&#xff0c;LED显示屏行业也在积极探索更加节能的生产和使用方式。作为显示屏制造厂家&#xff0c;了解和应用LED节能原理不仅是市场的需求&#xff0c;也是企业履行社会责任的表现。本文将浅析LED节能原理及其在显示屏制造中的应用。 LED节能的基…

【R语言】动画图:散点图

绘制成如下的散点图&#xff1a; 如果数据量大&#xff0c;有多个年份&#xff0c;就会生成多张图&#xff0c;例如&#xff1a; 具体代码如下&#xff1a; library(gapminder)#加载 gapminder 包&#xff0c;其中包含了从 1952 年至 2007 年各个国家的 GDP、预期寿命和人口数据…

Activity 的生命周期

进入应用&#xff0c;点击 Home 键退出&#xff0c;再次回到应用&#xff1a; 横竖屏切换时&#xff0c;Activity 的生命周期&#xff08;没有配置 configChanges 属性时&#xff09;&#xff1a; 横竖屏切换时&#xff0c;Activity 的生命周期&#xff08;在清单文件中配置 a…

单链表的实现(单链表的增删查改)

在顺序表中实现数据的增删的操作时&#xff0c;都要把操作位置之后的数据全部移动一遍&#xff0c;操作效率低下。其次是容量固定&#xff08;静态顺序表&#xff09;&#xff0c;虽然在动态顺序表中容量可变&#xff0c;但也会造成空间上的浪费。 单链表就完美解决了上述缺点…

为什么很多人说考研数学不要用张宇?你要警惕的是老学长!

先看看说的是不是老学长&#xff0c;他们不了解24考情。 25考研er&#xff0c;都是用脚投票&#xff01; 一、最新数据 1. 中等基础&#xff08; “答案都懂&#xff0c;题型一变就不会做了”&#xff09; 2024年&#xff0c;67%选择武忠祥&#xff0c;23%选择张宇&#xff…

150个 HTML5 成体系的网站模版 量大慢选 持续更新中

目录 HTML5 网站模版 No.1HTML5 网站模版 No.2HTML5 网站模版 No.3HTML5 网站模版 No.4HTML5 网站模版 No.5 HTML5 网站模版 No.1 HTML5 网站模版 No.1 HTML5 网站模版 No.2 HTML5 网站模版 No.2 HTML5 网站模版 No.3 HTML5 成体系网站模版 No.3 HTML5 网站模版…

SpringCloud(一)

微服务框架 一、分布式架构 分布式架构︰根据业务功能对系统进行拆分&#xff0c;每个业务模块作为独立项目开发&#xff0c;称为一个服务。 优点: 降低服务耦合有利于服务升级拓展 微服务是一种经过良好架构设计的分布式架构方案&#xff0c;微服务架构特征: 单一职责:微…

OWASP发布大语言模型网络安全与治理清单

当前人工智能技术面临的最大风险是大语言模型&#xff08;LLM&#xff09;和生成式人工智能技术的发展和应用速度已经远远超过了安全和治理的速度。 OpenAI、Anthropic、谷歌和微软等公司的生成式人工智能和大语言模型产品的使用正呈指数级增长。与此同时&#xff0c;开源大语…

js微博发布案例

思路&#xff1a; 需求1&#xff1a;检测用户输入的字数 注册input事件 将输入文本长度赋值给对应的数值 需求2&#xff1a;输入不能为空 点击按钮之后判断 如果输入为空&#xff0c;则提示不能输入为空&#xff0c;并直接return 为了防止无意义的一些输入&#xff0c;利用字符…