HarmonyOS4.0系统性深入开发08服务卡片架构

服务卡片概述

服务卡片(以下简称“卡片”)是一种界面展示形式,可以将应用的重要信息或操作前置到卡片,以达到服务直达、减少体验层级的目的。卡片常用于嵌入到其他应用(当前卡片使用方只支持系统应用,如桌面)中作为其界面显示的一部分,并支持拉起页面、发送消息等基础的交互功能。

服务卡片架构

图1 服务卡片架构
点击放大

卡片的基本概念:

  • 卡片使用方:如上图中的桌面,显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。
    • 应用图标:应用入口图标,点击后可拉起应用进程,图标内容不支持交互。
    • 卡片:具备不同规格大小的界面展示,卡片的内容可以进行交互,如实现按钮进行界面的刷新、应用的跳转等。
  • 卡片提供方:包含卡片的应用,提供卡片的显示内容、控件布局以及控件点击处理逻辑。
    • FormExtensionAbility:卡片业务逻辑模块,提供卡片创建、销毁、刷新等生命周期回调。
    • 卡片页面:卡片UI模块,包含页面控件、布局、事件等显示和交互信息。

卡片的常见使用步骤如下。

图2 卡片常见使用步骤
点击放大

  1. 长按“桌面图标”,弹出操作菜单。
  2. 点击“服务卡片”选项,进入卡片预览界面。
  3. 点击“添加到桌面”按钮,即可在桌面上看到新添加的卡片。

服务卡片UI页面开发方式

在Stage模型下,服务卡片的UI页面支持通过ArkTS和JS两种语言进行开发:

  • 基于声明式范式ArkTS UI开发的卡片,简称ArkTS卡片。
  • 基于类Web范式JS UI开发的卡片,简称JS卡片。

ArkTS卡片与JS卡片具备不同的实现原理及特征,在场景能力上的差异如下表所示。

类别JS卡片ArkTS卡片
开发范式类Web范式声明式范式
组件能力支持支持
布局能力支持支持
事件能力支持支持
自定义动效不支持支持
自定义绘制不支持支持
逻辑代码执行(不包含import能力)不支持支持

相比于JS卡片,ArkTS卡片在能力和场景方面更加丰富,因此无论开发何种用途的卡片,都推荐使用ArkTS卡片,因为它可以提高开发效率并实现动态化。但如果只需要做静态页面展示的卡片,可以考虑使用JS卡片。

开发基于JS UI的卡片

以下内容介绍基于类Web范式的JS UI卡片开发指南。

运作机制

卡片框架的运作机制如图1所示。

图1 卡片框架运作机制(Stage模型)

点击放大

卡片使用方包含以下模块:

  • 卡片使用:包含卡片的创建、删除、请求更新等操作。
  • 通信适配层:由OpenHarmony SDK提供,负责与卡片管理服务通信,用于将卡片的相关操作到卡片管理服务。

卡片管理服务包含以下模块:

  • 周期性刷新:在卡片添加后,根据卡片的刷新策略启动定时任务周期性触发卡片的刷新。
  • 卡片缓存管理:在卡片添加到卡片管理服务后,对卡片的视图信息进行缓存,以便下次获取卡片时可以直接返回缓存数据,降低时延。
  • 卡片生命周期管理:对于卡片切换到后台或者被遮挡时,暂停卡片的刷新;以及卡片的升级/卸载场景下对卡片数据的更新和清理。
  • 卡片使用方对象管理:对卡片使用方的RPC对象进行管理,用于使用方请求进行校验以及对卡片更新后的回调处理。
  • 通信适配层:负责与卡片使用方和提供方进行RPC通信。

卡片提供方包含以下模块:

  • 卡片服务:由卡片提供方开发者实现,开发者实现生命周期处理创建卡片、更新卡片以及删除卡片等请求,提供相应的卡片服务。
  • 卡片提供方实例管理模块:由卡片提供方开发者实现,负责对卡片管理服务分配的卡片实例进行持久化管理。
  • 通信适配层:由OpenHarmony SDK提供,负责与卡片管理服务通信,用于将卡片的更新数据主动推送到卡片管理服务。

说明

实际开发时只需要作为卡片提供方进行卡片内容的开发,卡片使用方和卡片管理服务由系统自动处理。

接口说明

FormExtensionAbility类拥有如下API接口,具体的API介绍详见接口文档。

接口名描述
onAddForm(want: Want): formBindingData.FormBindingData卡片提供方接收创建卡片的通知接口。
onCastToNormalForm(formId: string): void卡片提供方接收临时卡片转常态卡片的通知接口。
onUpdateForm(formId: string): void卡片提供方接收更新卡片的通知接口。
onChangeFormVisibility(newStatus: { [key: string]: number }): void卡片提供方接收修改可见性的通知接口。
onFormEvent(formId: string, message: string): void卡片提供方接收处理卡片事件的通知接口。
onRemoveForm(formId: string): void卡片提供方接收销毁卡片的通知接口。
onConfigurationUpdate(config: Configuration): void当系统配置更新时调用。
onShareForm?(formId: string): { [key: string]: any }卡片提供方接收卡片分享的通知接口。

formProvider类有如下API接口,具体的API介绍详见接口文档。

接口名描述
setFormNextRefreshTime(formId: string, minute: number, callback: AsyncCallback): void;设置指定卡片的下一次更新时间。
setFormNextRefreshTime(formId: string, minute: number): Promise;设置指定卡片的下一次更新时间,以promise方式返回。
updateForm(formId: string, formBindingData: FormBindingData, callback: AsyncCallback): void;更新指定的卡片。
updateForm(formId: string, formBindingData: FormBindingData): Promise;更新指定的卡片,以promise方式返回。

formBindingData类有如下API接口,具体的API介绍详见接口文档。

接口名描述
createFormBindingData(obj?: Object | string): FormBindingData创建一个FormBindingData对象。

开发步骤

Stage卡片开发,即基于Stage模型的卡片提供方开发,主要涉及如下关键步骤:

  • 创建卡片FormExtensionAbility:卡片生命周期回调函数FormExtensionAbility开发。
  • 配置卡片配置文件:配置应用配置文件module.json5和profile配置文件。
  • 卡片信息的持久化:对卡片信息进行持久化管理。
  • 卡片数据交互:通过updateForm更新卡片显示的信息。
  • 开发卡片页面:使用HML+CSS+JSON开发JS卡片页面。
  • 开发卡片事件:为卡片添加router事件和message事件。

创建卡片FormExtensionAbility

创建Stage模型的卡片,需实现FormExtensionAbility生命周期接口。先参考DevEco Studio服务卡片开发指南生成服务卡片模板。

  1. 在EntryFormAbility.ts中,导入相关模块。

    import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility';
    import formBindingData from '@ohos.app.form.formBindingData';
    import formInfo from '@ohos.app.form.formInfo';
    import formProvider from '@ohos.app.form.formProvider';
    import dataStorage from '@ohos.data.storage';
    
  2. 在EntryFormAbility.ts中,实现FormExtension生命周期接口。

    export default class EntryFormAbility extends FormExtensionAbility {onAddForm(want) {console.info('[EntryFormAbility] onAddForm');// 使用方创建卡片时触发,提供方需要返回卡片数据绑定类let obj = {"title": "titleOnCreate","detail": "detailOnCreate"};let formData = formBindingData.createFormBindingData(obj);return formData;}onCastToNormalForm(formId) {// 使用方将临时卡片转换为常态卡片触发,提供方需要做相应的处理console.info('[EntryFormAbility] onCastToNormalForm');}onUpdateForm(formId) {// 若卡片支持定时更新/定点更新/卡片使用方主动请求更新功能,则提供方需要重写该方法以支持数据更新console.info('[EntryFormAbility] onUpdateForm');let obj = {"title": "titleOnUpdate","detail": "detailOnUpdate"};let formData = formBindingData.createFormBindingData(obj);formProvider.updateForm(formId, formData).catch((error) => {console.info('[EntryFormAbility] updateForm, error:' + JSON.stringify(error));});}onChangeFormVisibility(newStatus) {// 使用方发起可见或者不可见通知触发,提供方需要做相应的处理,仅系统应用生效console.info('[EntryFormAbility] onChangeFormVisibility');}onFormEvent(formId, message) {// 若卡片支持触发事件,则需要重写该方法并实现对事件的触发console.info('[EntryFormAbility] onFormEvent');}onRemoveForm(formId) {// 删除卡片实例数据console.info('[EntryFormAbility] onRemoveForm');}onConfigurationUpdate(config) {console.info('[EntryFormAbility] nConfigurationUpdate, config:' + JSON.stringify(config));}onAcquireFormState(want) {return formInfo.FormState.READY;}
    }
    

说明

FormExtensionAbility不能常驻后台,即在卡片生命周期回调函数中无法处理长时间的任务。

配置卡片配置文件

  1. 卡片需要在module.json5配置文件中的extensionAbilities标签下,配置ExtensionAbility相关信息。FormExtensionAbility需要填写metadata元信息标签,其中键名称为固定字符串"ohos.extension.form",资源为卡片的具体配置信息的索引。

    配置示例如下:

    {"module": {..."extensionAbilities": [{"name": "EntryFormAbility","srcEntrance": "./ets/entryformability/EntryFormAbility.ts","label": "$string:EntryFormAbility_label","description": "$string:EntryFormAbility_desc","type": "form","metadata": [{"name": "ohos.extension.form","resource": "$profile:form_config"}]}]}
    }
    
  2. 卡片的具体配置信息。在上述FormExtensionAbility的元信息("metadata"配置项)中,可以指定卡片具体配置信息的资源索引。例如当resource指定为$profile:form_config时,会使用开发视图的resources/base/profile/目录下的form_config.json作为卡片profile配置文件。内部字段结构说明如下表所示。

    表1 卡片profile配置文件

    属性名称含义数据类型是否可缺省
    name表示卡片的类名,字符串最大长度为127字节。字符串
    description表示卡片的描述。取值可以是描述性内容,也可以是对描述性内容的资源索引,以支持多语言。字符串最大长度为255字节。字符串可缺省,缺省为空。
    src表示卡片对应的UI代码的完整路径。字符串
    window用于定义与显示窗口相关的配置。对象可缺省
    isDefault表示该卡片是否为默认卡片,每个UIAbility有且只有一个默认卡片。- true:默认卡片。- false:非默认卡片。布尔值
    colorMode表示卡片的主题样式,取值范围如下:- auto:自适应。- dark:深色主题。- light:浅色主题。字符串可缺省,缺省值为“auto”。
    supportDimensions表示卡片支持的外观规格,取值范围:- 1 * 2:表示1行2列的二宫格。- 2 * 2:表示2行2列的四宫格。- 2 * 4:表示2行4列的八宫格。- 4 * 4:表示4行4列的十六宫格。字符串数组
    defaultDimension表示卡片的默认外观规格,取值必须在该卡片supportDimensions配置的列表中。字符串
    updateEnabled表示卡片是否支持周期性刷新,取值范围:- true:表示支持周期性刷新,可以在定时刷新(updateDuration)和定点刷新(scheduledUpdateTime)两种方式任选其一,优先选择定时刷新。- false:表示不支持周期性刷新。布尔类型
    scheduledUpdateTime表示卡片的定点刷新的时刻,采用24小时制,精确到分钟。updateDuration参数优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration配置的刷新时间为准。字符串可缺省,缺省值为“0:0”。
    updateDuration表示卡片定时刷新的更新周期,单位为30分钟,取值为自然数。当取值为0时,表示该参数不生效。当取值为正整数N时,表示刷新周期为30*N分钟。updateDuration参数优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration配置的刷新时间为准。数值可缺省,缺省值为“0”。
    formConfigAbility表示卡片的配置跳转链接,采用URI格式。字符串可缺省,缺省值为空。
    formVisibleNotify标识是否允许卡片使用卡片可见性通知。字符串可缺省,缺省值为空。
    metaData表示卡片的自定义信息,包含customizeData数组标签。对象可缺省,缺省值为空。

    配置示例如下:

    {"forms": [{"name": "widget","description": "This is a service widget.","src": "./js/widget/pages/index/index","window": {"designWidth": 720,"autoDesignWidth": true},"colorMode": "auto","isDefault": true,"updateEnabled": true,"scheduledUpdateTime": "10:30","updateDuration": 1,"defaultDimension": "2*2","supportDimensions": ["2*2"]}]
    }
    

卡片信息的持久化

因大部分卡片提供方都不是常驻服务,只有在需要使用时才会被拉起获取卡片信息,且卡片管理服务支持对卡片进行多实例管理,卡片ID对应实例ID,因此若卡片提供方支持对卡片数据进行配置,则需要对卡片的业务数据按照卡片ID进行持久化管理,以便在后续获取、更新以及拉起时能获取到正确的卡片业务数据。

const DATA_STORAGE_PATH = "/data/storage/el2/base/haps/form_store";
async function storeFormInfo(formId: string, formName: string, tempFlag: boolean) {// 此处仅对卡片ID:formId,卡片名:formName和是否为临时卡片:tempFlag进行了持久化let formInfo = {"formName": formName,"tempFlag": tempFlag,"updateCount": 0};try {const storage = await dataStorage.getStorage(DATA_STORAGE_PATH);// put form infoawait storage.put(formId, JSON.stringify(formInfo));console.info(`[EntryFormAbility] storeFormInfo, put form info successfully, formId: ${formId}`);await storage.flush();} catch (err) {console.error(`[EntryFormAbility] failed to storeFormInfo, err: ${JSON.stringify(err)}`);}
}export default class EntryFormAbility extends FormExtension {...onAddForm(want) {console.info('[EntryFormAbility] onAddForm');let formId = want.parameters["ohos.extra.param.key.form_identity"];let formName = want.parameters["ohos.extra.param.key.form_name"];let tempFlag = want.parameters["ohos.extra.param.key.form_temporary"];// 将创建的卡片信息持久化,以便在下次获取/更新该卡片实例时进行使用// 此接口请根据实际情况实现,具体请参考:FormExtAbility Stage模型卡片实例storeFormInfo(formId, formName, tempFlag);let obj = {"title": "titleOnCreate","detail": "detailOnCreate"};let formData = formBindingData.createFormBindingData(obj);return formData;}
}

且需要适配onRemoveForm卡片删除通知接口,在其中实现卡片实例数据的删除。

const DATA_STORAGE_PATH = "/data/storage/el2/base/haps/form_store";
async function deleteFormInfo(formId: string) {try {const storage = await dataStorage.getStorage(DATA_STORAGE_PATH);// del form infoawait storage.delete(formId);console.info(`[EntryFormAbility] deleteFormInfo, del form info successfully, formId: ${formId}`);await storage.flush();} catch (err) {console.error(`[EntryFormAbility] failed to deleteFormInfo, err: ${JSON.stringify(err)}`);}
}...export default class EntryFormAbility extends FormExtension {...onRemoveForm(formId) {console.info('[EntryFormAbility] onRemoveForm');// 删除之前持久化的卡片实例数据// 此接口请根据实际情况实现,具体请参考:FormExtAbility Stage模型卡片实例deleteFormInfo(formId);}
}

具体的持久化方法可以参考应用数据持久化概述。

需要注意的是,卡片使用方在请求卡片时传递给提供方应用的Want数据中存在临时标记字段,表示此次请求的卡片是否为临时卡片:

  • 常态卡片:卡片使用方会持久化的卡片;
  • 临时卡片:卡片使用方不会持久化的卡片;

由于临时卡片的数据具有非持久化的特殊性,某些场景例如卡片服务框架死亡重启,此时临时卡片数据在卡片管理服务中已经删除,且对应的卡片ID不会通知到提供方,所以卡片提供方需要自己负责清理长时间未删除的临时卡片数据。同时对应的卡片使用方可能会将之前请求的临时卡片转换为常态卡片。如果转换成功,卡片提供方也需要对对应的临时卡片ID进行处理,把卡片提供方记录的临时卡片数据转换为常态卡片数据,防止提供方在清理长时间未删除的临时卡片时,把已经转换为常态卡片的临时卡片信息删除,导致卡片信息丢失。

卡片数据交互

当卡片应用需要更新数据时(如触发了定时更新或定点更新),卡片应用获取最新数据,并调用updateForm()接口主动触发卡片的更新。

onUpdateForm(formId) {// 若卡片支持定时更新/定点更新/卡片使用方主动请求更新功能,则提供方需要重写该方法以支持数据更新console.info('[EntryFormAbility] onUpdateForm');let obj = {"title": "titleOnUpdate","detail": "detailOnUpdate"};let formData = formBindingData.createFormBindingData(obj);// 调用updateForm接口去更新对应的卡片,仅更新入参中携带的数据信息,其他信息保持不变formProvider.updateForm(formId, formData).catch((error) => {console.info('[EntryFormAbility] updateForm, error:' + JSON.stringify(error));});
}

开发卡片页面

开发者可以使用类Web范式(HML+CSS+JSON)开发JS卡片页面。生成如下卡片页面,可以这样配置卡片页面文件:

img

说明

当前仅支持JS扩展的类Web开发范式来实现卡片的UI。

  • HML:使用类Web范式的组件描述卡片的页面信息。

    <div class="container"><stack><div class="container-img"><image src="/common/widget.png" class="bg-img"></image></div><div class="container-inner"><text class="title">{{title}}</text><text class="detail_text" onclick="routerEvent">{{detail}}</text></div></stack>
    </div>
    
  • CSS:HML中类Web范式组件的样式信息。

    .container {flex-direction: column;justify-content: center;align-items: center;
    }.bg-img {flex-shrink: 0;height: 100%;
    }.container-inner {flex-direction: column;justify-content: flex-end;align-items: flex-start;height: 100%;width: 100%;padding: 12px;
    }.title {font-size: 19px;font-weight: bold;color: white;text-overflow: ellipsis;max-lines: 1;
    }.detail_text {font-size: 16px;color: white;opacity: 0.66;text-overflow: ellipsis;max-lines: 1;margin-top: 6px;
    }
    
  • JSON:卡片页面中的数据和事件交互。

    {"data": {"title": "TitleDefault","detail": "TextDefault"},"actions": {"routerEvent": {"action": "router","abilityName": "EntryAbility","params": {"message": "add detail"}}}
    }
    

开发卡片事件

卡片支持为组件设置交互事件(action),包括router事件和message事件,其中router事件用于UIAbility跳转,message事件用于卡片开发人员自定义点击事件。

关键步骤说明如下:

  1. 在HML中为组件设置onclick属性,其值对应到JSON文件的actions字段中。
  2. 设置router事件:
    • action属性值为"router"。
    • abilityName为跳转目标的UIAbility名(支持跳转FA模型的PageAbility组件和Stage模型的UIAbility组件),如目前DevEco Studio创建的Stage模型的UIAbility默认名为EntryAbility。
    • params为传递给跳转目标UIAbility的自定义参数,可以按需填写。其值可以在目标UIAbility启动时的want中的parameters里获取。如Stage模型MainAbility的onCreate生命周期里的入参want的parameters字段下获取到配置的参数。
  3. 设置message事件:
    • action属性值为"message"。
    • params为message事件的用户自定义参数,可以按需填写。其值可以在卡片生命周期函数onFormEvent()中的message里获取。

示例如下。

  • HML文件

    <div class="container"><stack><div class="container-img"><image src="/common/widget.png" class="bg-img"></image></div><div class="container-inner"><text class="title" onclick="routerEvent">{{title}}</text><text class="detail_text" onclick="messageEvent">{{detail}}</text></div></stack>
    </div>
    
  • CSS文件

    .container {flex-direction: column;justify-content: center;align-items: center;
    }.bg-img {flex-shrink: 0;height: 100%;
    }.container-inner {flex-direction: column;justify-content: flex-end;align-items: flex-start;height: 100%;width: 100%;padding: 12px;
    }.title {font-size: 19px;font-weight: bold;color: white;text-overflow: ellipsis;max-lines: 1;
    }.detail_text {font-size: 16px;color: white;opacity: 0.66;text-overflow: ellipsis;max-lines: 1;margin-top: 6px;
    }
    
  • JSON文件

    {"data": {"title": "TitleDefault","detail": "TextDefault"},"actions": {"routerEvent": {"action": "router","abilityName": "EntryAbility","params": {"info": "router info","message": "router message"}},"messageEvent": {"action": "message","params": {"detail": "message detail"}}}
    }
    
  • 在UIAbility中接收router事件并获取参数

    import UIAbility from '@ohos.app.ability.UIAbility'export default class EntryAbility extends UIAbility {onCreate(want, launchParam) {let params = JSON.parse(want.parameters.params);// 获取router事件中传递的info参数if (params.info === "router info") {// do something// console.info("router info:" + params.info)}// 获取router事件中传递的message参数if (params.message === "router message") {// do something// console.info("router message:" + params.message)}}...
    };
    
  • 在FormExtensionAbility中接收message事件并获取参数

    import FormExtension from '@ohos.app.form.FormExtensionAbility';export default class FormAbility extends FormExtension {...onFormEvent(formId, message) {// 获取message事件中传递的detail参数let msg = JSON.parse(message)if (msg.detail === "message detail") {// do something// console.info("message info:" + msg.detail)}}...
    };
    

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

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

相关文章

鸿鹄电子招投标系统:基于Spring Boot、Mybatis、Redis和Layui的企业电子招采平台源码与立项流程

在数字化时代&#xff0c;企业需要借助先进的数字化技术来提高工程管理效率和质量。招投标管理系统作为企业内部业务项目管理的重要应用平台&#xff0c;涵盖了门户管理、立项管理、采购项目管理、采购公告管理、考核管理、报表管理、评审管理、企业管理、采购管理和系统管理等…

服务器被入侵后如何查询连接IP以及防护措施

目前越来越多的服务器被入侵&#xff0c;以及攻击事件频频的发生&#xff0c;像数据被窃取&#xff0c;数据库被篡改&#xff0c;网站被强制跳转到恶意网站上&#xff0c;网站在百度的快照被劫持等等的攻击症状层出不穷&#xff0c;在这些问题中&#xff0c;如何有效、准确地追…

使用Vscode远程debug报错找不到Module找不到File

1..报第一个错 提示我无法导入自己写的module 如图&#xff1a; 解决办法&#xff1a; stackoverflow上说的在launch.json中加了一条 env&#xff0c;就解决了。 "env": { "PYTHONPATH":"/home/zt/ge-sc-master/ge-sc-master"}, 2.解决完第一个…

软件测试/测试开发丨Python、pycharm 安装与环境配置

Python 安装与环境配置 1. Python 安装 版本推荐 3.10.0下载地址&#xff1a;www.python.org/downloads/w… 若需要安装旧版本&#xff0c;在页面下方选择对应版本即可&#xff0c;MacOS选择对应系统即可 图示下载windows 3.11.4版本 安装Python 执行安装程序&#xff0c;安…

numpy数组03-数组的计算

一.数组与数字之间进行计算 numpy中的数组与数字进行计算是广播形式&#xff0c;数组-*/数字&#xff0c;则数组中的每一个数字都会进行相应的四则运算。 1.1数组与数字之间的四则运算 示例代码如下&#xff1a; import numpy as npa np.arange(24) b a.reshape(4, 6) pr…

【Maven】<scope>provided</scope>

在Maven中&#xff0c;“provided”是一个常用的依赖范围&#xff0c;它表示某个依赖项在编译和测试阶段是必需的&#xff0c;但在运行时则由外部环境提供&#xff0c;不需要包含在最终的项目包中。下面是对Maven scope “provided”的详细解释&#xff1a; 编译和测试阶段可用…

帆软FineBi V6版本经验总结

帆软FineBi V6版本经验总结 BI分析出现背景 ​ 现在是一个大数据的时代&#xff0c;每时每刻都有海量的明细数据出现。这时大数据时代用户思维是&#xff1a;1、数据的爆炸式增长&#xff0c;人们比起明细数据&#xff0c;更在意样本的整体特征、相互关系。2、基于明细的“小…

数据结构之树 --- 二叉树

目录 定义二叉树的结构体 二叉树的遍历 递归遍历 非递归遍历 链式二叉树的实现 二叉树的功能接口 先序遍历创建二叉树 后序遍历销毁二叉树 先序遍历查找树中值为x的节点 层序遍历 上篇我们对二叉树的顺序存储堆进行了讲述&#xff0c;本文我们来看链式二叉树。 定…

SpringCloud(H版alibaba)框架开发教程之nacos做配置中心——附源码(2)

上篇主要讲了使用eureka&#xff0c;zk&#xff0c;nacos当注册中心 这篇内容是nacos配置中心 代码改动部分mysql驱动更新到8.0&#xff0c;数据库版本升级到了8.0&#xff0c;nacos版本更新到了2.x nacos2.x链接 链接&#xff1a;https://pan.baidu.com/s/11nObzgTjWisAfOp…

探秘交互设计:深入了解五大核心维度!

交互式设计是用户体验&#xff08;UX&#xff09;设计的重要组成部分。本文将解释什么是交互设计&#xff0c;并分享一些有用的交互设计模型&#xff0c;并简要描述交互设计师通常做什么。 如何解释交互设计 交互式设计可以用一个简单的术语来理解&#xff1a;它是用户和产品…

借贷协议 Tonka Finance:铭文资产流动性的新破局者

“Tonka Finance 是铭文赛道中首个借贷协议&#xff0c;它正在为铭文资产赋予捕获流动性的能力&#xff0c;并为其构建全新的金融场景。” 在 2023 年的 1 月&#xff0c;比特币 Ordinals 协议被推出后&#xff0c;包括 BRC20&#xff0c;Ordinals 等在内的系列铭文资产在包括比…

nginx源码分析-3

这一章内容讲述nginx中的事件是如何一步步添加到epoll实例中的。 在初始化http连接的函数ngx_http_init_connection中&#xff0c;nginx为http连接初始化了处理请求的回调函数&#xff0c;之后调用ngx_handle_read_event函数对可读数据进行处理。这里只为连接设置read而没有设…

Ubuntu22.04 安装教程

系统下载 Ubuntu官网下载 清华源镜像 安装流程 1. 选择安装语言 2. 选择是否在安装时更新 为了系统安装速度一般选择安装时不更新&#xff0c;安装后自行更新 3. 选择系统语言和键盘布局 4. 选择安装模式 5. 配置网络信息 6. 设置静态IP 7. 配置代理信息 8. 配置Ubuntu镜像…

在电脑上免费分区的 5 个有效磁盘分区软件工具

磁盘分区可能是一个脆弱而复杂的过程&#xff0c;磁盘崩溃或用户设备受到病毒攻击的风险很高。因此&#xff0c;它们很难由用户单独或手动管理。本文详细介绍了可以帮助简化磁盘分区过程的不同软件工具、它们的功能和优点。那么让我们开始吧。 什么是磁盘分区工具&#xff1f; …

在STM32中集成TSL2561光强传感器的开发和调试

在STM32中集成TSL2561光强传感器的开发和调试是一个常见的应用场景。TSL2561是一款数字光传感器&#xff0c;能够测量可见光和红外光的光强&#xff0c;并通过I2C接口将数据传输给微控制器。下面将为您介绍在STM32中集成TSL2561传感器的开发步骤&#xff0c;并附上相应的代码示…

【音视频 ffmpeg 学习】 RTMP推流 mp4文件

1.RTMP(实时消息传输协议)是Adobe 公司开发的一个基于TCP的应用层协议。 2.RTMP协议中基本的数据单元称为消息&#xff08;Message&#xff09;。 3.当RTMP协议在互联网中传输数据的时候&#xff0c;消息会被拆分成更小的单元&#xff0c;称为消息块&#xff08;Chunk&#xff…

Linux系统下隧道代理HTTP

在Linux系统下配置隧道代理HTTP是一个涉及网络技术的话题&#xff0c;主要目的是在客户端和服务器之间建立一个安全的通信通道。下面将详细解释如何进行配置。 一、了解基本概念 在开始之前&#xff0c;需要了解几个关键概念&#xff1a;代理服务器、隧道代理和HTTP协议。代理…

算法专题四:前缀和

前缀和 一.一维前缀和(模板)&#xff1a;1.思路一&#xff1a;暴力解法2.思路二&#xff1a;前缀和思路 二. 二维前缀和(模板)&#xff1a;1.思路一&#xff1a;构造前缀和数组 三.寻找数组的中心下标&#xff1a;1.思路一&#xff1a;前缀和 四.除自身以外数组的乘积&#xff…

3、Git分支操作与团队协作

Git分支操作 1.什么是分支2. 分支的好处3. 分支的操作3.1 查看分支3.2 创建分支3.3 切换分支3.4 修改分支3.5 合并分支3.6 产生和解决冲突 4. 创建分支和切换分支图解5. Git团队协作机制团队内协作跨团队协作 均在git bash中进行操作。事先建好本地工作库 1.什么是分支 在版本…

GLTF 编辑器实现逼真3D动物毛发效果

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 要实现逼真的3D动物毛发效果&#xff0c;可以采用以下技术和方法&…