【案例+1】HarmonyOS官方模板优秀案例

(第7期:金融理财 · 记账应用)

鸿蒙生态为开发者提供海量的HarmonyOS模板/组件,助力开发效率原地起飞

★ 一键直达生态市场组件&模板市场 , 快速应用DevEco Studio插件市场集成组件&模板

实战分享:如何基于模板快速开发一款记账应用?本期案例为您解答。

覆盖20+行业,点击查看往期案例汇总贴,持续更新,点击收藏!一键三连!常看常新!

【第7期】金融理财 · 记账应用

  1. 概述
  2. 行业洞察
  3. 行业诉求:
  • 功能冗余:普通用户刚需功能简单分类、预算管理、账单总结;部分 APP 堆砌 “投资分析”“信贷推荐” 等功能。
  • 用户习惯培养难,留存率低:部分APP页面简陋、广告过多、分类复杂导致用户放弃使用。
  • 盈利模式与用户体验博弈: 运营及开发成本依赖广告收益,用户付费意愿弱。
  • 数据安全与合规风险凸显。
  1. 行业常用三方SDK

分类

三方库名称

功能

支持情况

SDK链接

媒体

阿里云视频播放器SDK

音视频

已支持

支付宝SDK

微信支付SDK

银联SDK

腾讯QQ SDK

新浪微博SDK

极光PUSH SDK

友盟移动统计SDK

腾讯微信SDK

个推

Bugly

ShareSDK

听云SDK

七牛云存储SDK

登录认证

中国移动一键登录SDK/易盾一键登录SDK/创蓝闪验/极光安全认证/阿里云号码认证SDK/中国电信一键登录SDK

登录

已支持

分享

友盟/ShareSDK/微信分享/QQ分享/新浪微博SDK/MobTech ShareSDK

统计/推送/分享

已支持

支付

支付宝支付/微信支付/银联支付

支付

已支持

数据分析

友盟移动统计SD/神策数据SDK

数据收集、处理、分析、运用

已支持

性能监控

腾讯Bugly SDK/听云SDK/岳鹰全景监控SDK/友盟应用性能监控SDK/

异常上报和运营统计

已支持

推送

个推/华为推送/极光PUSH/阿里推送SDK

消息推送

已支持

存储

七牛云存储-SDK/腾讯MMKV组件

音视频

已支持

安全

火山设备安全SDK/Utdid SDK/

安全风控

已支持

广告

穿山甲广告SDK

广告

已支持

休闲娱乐

ThinkingSDK

游戏

已支持

说明:“以上三方库及链接仅为示例,三方库由三方开发者独立提供,以其官方内容为准”

  1. 案例概览(下载模板

基于以上行业分析,本期将介绍鸿蒙生态市场金融类行业模板——记账应用模板,为行业提供常用功能的开发案例,模板主要分首页、统计和资产三大模块。

  • Stage开发模型 + 声明式UI开发范式。
  • 分层架构设计 + 组件化拆分,支持开发者在开发时既可以选择完整使用模板,也可以根据需求单独选用其中的业务组件。

本模板主要页面及核心功能如下所示:

记账模板
|-- 首页
| |-- 账单查询
| |-- 新增账单
| |-- 账单类型管理
| |-- 编辑账单
| |-- 删除账单
| └-- 账单详情查看
|-- 统计
| |-- 账单报表查看
| |-- 账单分类查看
| └-- 日历视图
└-- 资产
|-- 资产查询
|-- 新增资产
|-- 编辑资产
|-- 删除资产
└-- 资产内记账
  1. 应用架构设计
  2. 分层模块化设计
  • 产品定制层:专注于满足不同设备或使用场景的个性化需求,作为应用的入口,是用户直接互动的界面。
  • 本实践暂时只支持直板机,为单HAP包形式,包含路由根节点、底部导航栏等。
  • 基础特性层:用于存放相对独立的功能UI和业务逻辑实现。
  • 本实践的基础特性层将应用底部导航栏的每个选项拆分成一个独立的业务功能模块。
  • 每个功能模块都具备高内聚、低耦合、可定制的特点,支持产品的灵活部署。
  • 公共能力层:存放公共能力,包括公共UI组件、数据管理、外部交互和工具库等共享功能。
  • 本实践的公共能力层分为公共基础能力和可分可合组件,均打包为HAR包被上层业务组件引用。
  • 公共基础能力包含日志、文件处理等工具类,公共类型定义,网络库,以及弹窗、加载等公共组件。
  • 可分可合组件将包含行业特点、可完全自闭环的能力抽出独立的组件模块,支持开发者在开发中单独集成使用,详见业务组件设计章节。

  1. 业务组件设计

为支持开发者单独获取特定场景的页面和功能,本模板将功能完全自闭环的部分能力抽离出独立的行业组件模块,不依赖公共基础能力包,开发者可以单独集成,开箱即用,降低使用难度。

  1. 行业场景技术方案
  2. 账单数据管理
  3. 场景说明
  • 支持账单、资产数据本地存储和管理。
  • 未对接云侧时实现应用数据不丢失,仅在卸载后清空本地数据。
  1. 技术方案
  1. 账单图表
  2. 场景说明
  • 通过饼图、排行榜、柱状图、报表的形式呈现当月账单的数据分析。
  • 通过日历视图呈现每日收支详情。

  1. 技术方案
  • 使用开源三方库@ohos/mpchart呈现多类型图表
  • 使用开源三方库lunar实现农历日期、节假日数据的获取,使用开源三方库dayjs实现日期数据格式化。
  • 使用Grid组件循环渲染实现日历视图的开发。
  1. 动态卡片
  2. 场景说明
  • 支持在桌面展示2\*2 和 2\*4大小的服务卡片,展示当前月的收支情况。
  • 点击记一笔拉起本模板应用主页面,新增账单后,在桌面同步刷新获取最新的收支数据。

  1. 技术方案
  1. 模板代码
  2. 工程结构(下载模板

详细代码结构如下所示:

MoneyTrack
|--commons // 公共能力层
| └--commonlib // 基础能力包
| └--src/main
| |--ets
| | |--components // 公共组件
| | | |-- CommonButton.ets // 公共按钮
| | | |-- CommonDivider.ets // 公共分割线
| | | |-- CommonHeader.ets // 公共标题栏
| | | |-- CommonMonthPicker.ets // 月份选择
| | | |-- ContainerColumn.ets // 垂直卡片容器
| | | └-- ContainerRow.ets // 水平卡片容器 | | |--constants // 公共静态变量
| | | |-- CommonConstants.ets // 公共常量
| | | └-- CommonEnums.ets // 公共枚举
| | |
| | |--dialogs // 公共弹窗
| | | └-- CommonConfirmDialog.ets // 二次确认弹窗
| | |
| | └--utils // 公共方法
| | |-- eventbus // 全局事件管理
| | |-- framework // 全局框架管理
| | |-- logger // 日志
| | |-- router // 路由
| | └-- window // 窗口
| |
| └-- resources/base/element
| |-- color.json // 全局颜色
| |-- font.json // 全局字号
| └-- style.json // 全局样式
|
|--components // 可分可合组件包
| |-- asset_base // 资产通用基础包
| |-- asset_card // 资产卡片
| |-- asset_manage // 资产管理
| |-- bill_base // 账单通用基础包
| |-- bill_card // 账单卡片
| |-- bill_chart // 账单图表
| |-- bill_data_processing // 账单数据处理
| └-- bill_manage // 账单管理
|
|--features // 基础特性层
| |-- assets // 资产
| | └--src/main/ets/views
| | |--AssetDetailPage.ets // 资产详情页
| | └--AssetsView.ets // 资产页
| |-- home // 首页明细
| | └--src/main/ets/views
| | |--BillDetailPage.ets // 账单详情页
| | └--HomeView.ets // 首页
| └-- statistics // 统计
| └--src/main/ets/views
| |--BillByResourceView.ets // 分类账单详情
| └--StatisticsView.ets // 统计页
└--products // 设备入口层
└-- entry
└--src/main/ets
|-- pages
| └-- MainEntry.ets // 主入口
└-- widgets
|-- MiddleCard.ets // 2*4中号卡片
└-- MiniCard.ets // 2*2小号卡片

2. 关键代码解读

本篇代码非应用的全量代码,只包括应用的部分能力的关键代码。

     1)账单数据管理

  • 封装通用数据库类
ts
// MoneyTrack/components/bill_data_processing/src/main/ets/utils/basedb/BaseDB.ets
const TAG = '[BaseDB]'; // 基础数据库操作类
export abstract class BaseDB {
protected rdbStore: relationalStore.RdbStore | null = null;
protected abstract dbConfig: relationalStore.StoreConfig;
protected abstract tableSchemas: TableSchema[]; // 初始化数据库
public async initialize(context: Context) {
try {
this.rdbStore = await relationalStore.getRdbStore(context, this.dbConfig);
await this._createTables();
Logger.info(TAG, `[${this.dbConfig.name}] database initialized success`);
} catch (err) {
Logger.error(
TAG,
`database initialized failed. error: ${JSON.stringify(err)}`,
);
}
} // 创建表结构
private async _createTables() {
if (!this.rdbStore) {
return;
}
try {
for (const schema of this.tableSchemas) {
await this.rdbStore.executeSql(schema.createSQL);
if (schema.indexes) {
for (const indexSQL of schema.indexes) {
await this.rdbStore.executeSql(indexSQL);
}
}
}
} catch (err) {
Logger.error(TAG, `create table failed. error: ${JSON.stringify(err)}`);
}
} // 通用插入方法
protected async insert<T>(tableName: string, values: T): Promise<number> {...} // 通用更新方法
protected async update<T>(
tableName: string,
values: T,
conditions: TablePredicateParams[],
): Promise<number> {...} // 通用删除方法
protected async delete(
tableName: string,
conditions: TablePredicateParams[],
): Promise<number> {...} // 通用查询方法
protected async query<T>(
tableName: string,
conditions: TablePredicateParams[],
orderBy?: TableOrderByParams,
limit?: number,
): Promise<T[]> {...}
}
  • 创建账单表
ts
// MoneyTrack/components/bill_data_processing/src/main/ets/utils/accountingdb/AccountingDB.ets
const TAG = '[AccountingDB]'; class AccountingDB extends BaseDB {
protected dbConfig: relationalStore.StoreConfig =
AccountingDBConstants.DB_CONFIG;
protected tableSchemas: TableSchema[] = [
{
tableName: AccountingDBConstants.ACCOUNT_TABLE_NAME,
createSQL: AccountingDBConstants.ACCOUNT_TABLE_SQL_CREATE,
indexes: AccountingDBConstants.ACCOUNT_TABLE_INDEXES_CREATE,
},
{
tableName: AccountingDBConstants.TRANSACTION_TABLE_NAME,
createSQL: AccountingDBConstants.TRANSACTION_TABLE_SQL_CREATE,
indexes: AccountingDBConstants.TRANSACTION_TABLE_INDEXES_CREATE,
},
{
tableName: AccountingDBConstants.ASSET_TABLE_NAME,
createSQL: AccountingDBConstants.ASSET_TABLE_SQL_CREATE,
indexes: AccountingDBConstants.ASSET_TABLE_INDEXES_CREATE,
},
]; public async initialize(context: Context) {
await super.initialize(context);
await this._initDefaultAccounts();
} // 初始化账本
private async _initDefaultAccounts() {
const accountTable: AccountTableBasis = {
accountId: AccountID.DEFAULT,
name: '默认账本',
type: 'default',
};
const existing = await this.query<Account>(
AccountingDBConstants.ACCOUNT_TABLE_NAME,
[
{
field: AccountTableFields.NAME,
operator: DBOperator.EQUAL,
value: accountTable.name,
},
{
field: AccountTableFields.TYPE,
operator: DBOperator.EQUAL,
value: accountTable.type,
},
],
); if (existing.length === 0) {
await this.insert(AccountingDBConstants.ACCOUNT_TABLE_NAME, accountTable);
Logger.info(TAG, 'create account table success');
}
} // 新增交易记录
public async addTransaction(userTx: UserTransaction): Promise<void> {
const tx: TransactionTableBasis = {
transactionId: new Date().getTime(),
accountId: userTx.accountId,
type: userTx.type,
resource: userTx.resource,
amount: userTx.amount,
date: userTx.date,
note: userTx.note,
excluded: userTx.excluded,
assetId: userTx.assetId,
};
return this.transaction(async () => {
try {
await this.insert(AccountingDBConstants.TRANSACTION_TABLE_NAME, tx);
promptAction.showToast({ message: '交易记录新增成功~' });
await this.updateAssetAccountFromTransaction(userTx);
Logger.info(TAG, 'insert transaction success.');
} catch (err) {
promptAction.showToast({ message: '交易记录新增失败,请稍后重试~' });
Logger.error(
TAG,
'insert transaction failed. error:' + JSON.stringify(err),
);
}
});
}
// ...
} const accountingDB = new AccountingDB(); export { accountingDB as AccountingDB };

     2)动态卡片

  • 封装卡片事件工具
ts
// MoneyTrack/products/entry/src/main/ets/common/WidgetUtil.ets
import { preferences } from '@kit.ArkData';
import { BusinessError, commonEventManager } from '@kit.BasicServicesKit';
import { formBindingData, formProvider } from '@kit.FormKit';
import { AmountSummary, BillProcessingModel } from 'bill_data_processing';
import { Logger } from 'commonlib'; const TAG = '[WidgetUtil]'; export class WidgetUtil {
private static readonly _fileName: string = 'accounting_form_id_file';
private static readonly _formIdKey: string = 'accounting_form_id_key';
private static readonly _formIdEventName: string = 'form_id_event_name';
private static _billProcessing: BillProcessingModel =
new BillProcessingModel(); public static getFormIds(ctx: Context) {
const store = WidgetUtil._getStore(ctx);
return store.getSync(WidgetUtil._formIdKey, []) as string[];
} public static async addFormId(formId: string, cxt: Context) {
const list = WidgetUtil.getFormIds(cxt);
if (!list.some((id) => id === formId)) {
list.push(formId);
const store = WidgetUtil._getStore(cxt);
store.putSync(WidgetUtil._formIdKey, list);
await store.flush();
}
} public static async delFormId(formId: string, cxt: Context) {
const list = WidgetUtil.getFormIds(cxt);
const index = list.findIndex((id) => id === formId);
if (index !== -1) {
list.splice(index, 1);
const store = WidgetUtil._getStore(cxt);
store.putSync(WidgetUtil._formIdKey, list);
await store.flush();
}
} // 发布公共事件跨进程传递卡片id
public static publishFormId(formId: string, isDelete: boolean) {
commonEventManager.publish(
WidgetUtil._formIdEventName,
{ data: formId, parameters: { isDelete } },
(err: BusinessError) => {
if (err) {
Logger.error(
TAG,
`Failed to publish common event. Code is ${err.code}, message is ${err.message}`,
);
} else {
Logger.info(TAG, 'Succeeded in publishing common event.');
}
},
);
} // 订阅获取卡片id
public static async subscribeFormId(ctx: Context) {
let subscriber: commonEventManager.CommonEventSubscriber | undefined =
undefined;
let subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
events: [WidgetUtil._formIdEventName],
publisherPermission: '',
};
commonEventManager.createSubscriber(subscribeInfo, (err1, data1) => {
if (err1) {
Logger.error(
TAG,
`Failed to create subscriber. Code is ${err1.code}, message is ${err1.message}`,
);
return;
}
subscriber = data1;
// 订阅公共事件回调
commonEventManager.subscribe(subscriber, async (err2, data2) => {
if (err2) {
Logger.error(
TAG,
`Failed to subscribe common event. Code is ${err2.code}, message is ${err2.message}`,
);
return;
} else {
if (data2.parameters?.isDelete) {
WidgetUtil.delFormId(data2.data as string, ctx);
} else {
WidgetUtil.addFormId(data2.data as string, ctx);
WidgetUtil.updateWidgetsWhenChange();
}
Logger.info(TAG, 'Succeeded in creating subscriber1.');
}
});
});
} public static async updateWidgetsWhenChange() {
await WidgetUtil._billProcessing.getBillReport();
const summary: AmountSummary = {
totalExpense: Number(WidgetUtil._billProcessing.totalExpense),
totalIncome: Number(WidgetUtil._billProcessing.totalIncome),
};
WidgetUtil.getFormIds(getContext()).forEach((id) => {
const income = summary.totalIncome;
const expense = summary.totalExpense;
class TempForm {
date: Date = new Date();
income: number = 0;
expense: number = 0;
}
const formData: TempForm = {
date: new Date(),
income,
expense,
};
formProvider.updateForm(
id,
formBindingData.createFormBindingData(formData),
);
});
} private static _getStore(ctx: Context) {
return preferences.getPreferencesSync(ctx, { name: WidgetUtil._fileName });
}
}
  • 在EntryFormAbility中的生命周期进行事件管理
ts
// MoneyTrack/products/entry/src/main/ets/entryformability/EntryFormAbility.ets
import { Want } from '@kit.AbilityKit';
import { emitter } from '@kit.BasicServicesKit';
import { formBindingData, FormExtensionAbility, formInfo } from '@kit.FormKit';
import { WidgetUtil } from '../common/WidgetUtil'; export default class EntryFormAbility extends FormExtensionAbility {
public onAddForm(want: Want) {
let formId = want.parameters?.[formInfo.FormParam.IDENTITY_KEY] as string | undefined;
if (formId) {
WidgetUtil.addFormId(formId, this.context);
WidgetUtil.publishFormId(formId, false);
}
return formBindingData.createFormBindingData('');
} public onUpdateForm() {
emitter.emit({ eventId: 1 });
} public onRemoveForm(formId: string) {
WidgetUtil.delFormId(formId, this.context);
WidgetUtil.publishFormId(formId, true);
}
}

以上代码展示了商务笔记应用的核心功能实现,包括多选管理、富文本编辑、分类管理和响应式布局等关键技术方案。

  1. 模板集成

本模板提供了两种代码集成方式,供开发者自由选用。

  1. 整体集成(下载模板

开发者可以选择直接基于模板工程开发自己的应用工程。

  • 模板代码获取:
  • 通过IDE插件创建模板工程,开发指导
  • 通过生态市场下载源码,下载模板
  • 通过开源仓访问源码,仓库地址
  • 打开模板工程,根据README说明中的快速入门章节,将自己的应用信息配置在模板工程内,即可运行并查看模板效果。

  • 对接开发者自己的服务器接口,转换数据结构,展示真实的云侧数据。

将commons/lib_common/src/main/ets/httprequest/HttpRequestApi.ets文件中的mock接口替换为真实的服务器接口。

在commons/lib_common/src/main/ets/httprequest/HttpRequest.ets文件中将云侧开发者自定义的数据结构转换为端侧数据结构。

根据自己的业务内容修改模板,进行定制化开发。

  1. 按需集成

若开发者已搭建好自己的应用工程,但暂未实现其中的部分场景能力,可以选择取用其中的业务组件,集成在自己的工程中。

  • 组件代码获取:
  • 通过IDE插件下载组件源码。开发指导
  • 通过生态市场下载组件源码。 下载地址
  • 下载组件源码,根据README中的说明,将组件包配置在自己的工程中。

  • 根据API参考和示例代码,将组件集成在自己的对应场景中。

以上是第7期“金融理财-记账应用”行业案例的内容,更多行业敬请期待~

欢迎下载使用行业模板“点击下载”,若您有体验和开发问题,或者迫不及待想了解XX行业的优秀案例,欢迎在评论区留言,小编会快马加鞭为您解答~

同时诚邀您添加下方二维码加入“组件模板开发者社群”,精彩上新&活动不错过!

HarmonyOS官方模板优秀案例系列持续更新, 点击查看往期案例汇总贴点击收藏方便查找!【互动有礼】邀请你成为HarmonyOS官方模板产品经理,优化方案由你制定!点击参加

【案例+1】HarmonyOS官方模板优秀案例 第7期:金融理财 · 记账应用的更多相关文章

  1. _00019 Storm架构介绍和Storm获取案例(简单的官方网站Java案例)

    博文作者:妳那伊抹微笑 itdog8 地址链接 : http://www.itdog8.com(个人链接) 博客地址:http://blog.csdn.net/u012185296 博文标题:_000 ...

  2. 12个学习 CSS3 网站布局设计的优秀案例

    网络上有很多的 CSS 画廊站点供大家对各类网站作品进行打分和评论,每天有数以百计的优秀网站被推荐上面,这对于网页设计师来说是很好的灵感来源.今天,我们选择了15赢得 CSS 设计大奖的优秀作品,帮助 ...

  3. 优秀案例:12个精美的设计工作室 & 设计公司网站

    如果你正在为自己的作品集网站设计寻找灵感,那么学习设计机构 & 设计公司的网站是如何制作的是一个良好的开端.在这篇稳重,我们已经聚集了一组设计机构的优秀作品集网站,你可以借鉴很多设计理念.当你 ...

  4. iOS界面设计,12个优秀案例激发你的灵感

    总所周知,iOS和Android是当今两大移动平台,前者采用Human Interface Design,后者采用Material Design.作为设计师,尤其是App设计师,总是会在这两者进行设计 ...

  5. 学习 Mobile App 网站制作的11个优秀案例

    我喜欢收集美丽的,精心设计的移动应用程序网站.在我看来,为 App 提供一个美丽的网站显示了设计者和开发者对它的用户和产品的关心,除了开发应用程序,他们去加倍努力去促进应用和传播关于它的 App. 我 ...

  6. 【iOS】7.4 定位服务->2.1.4 定位 - 官方框架CoreLocation 案例:指南针效果

    本文并非最终版本,如果想要关注更新或更正的内容请关注文集,联系方式详见文末,如有疏忽和遗漏,欢迎指正. 本文相关目录: ================== 所属文集:[iOS]07 设备工具 === ...

  7. Phoenix简介概述,Phoenix的Java API 相关操作优秀案例

    Phoenix简介概述,Phoenix的Java API 相关操作优秀案例 一.Phoenix概述简介 二.Phoenix实例一:Java API操作 2.1 phoenix.properties 2 ...

  8. 使用Zabbix官方模板监控Redis运行状况

    运行环境: OS:CentOS 6.8 / Python: 2.6.6 / Pip: 7.1.0 / Redis:3.0 / Zabbix:3.0.3 Zabbix官方提供的监控模板. 项目地址:ht ...

  9. 老李案例分享:Weblogic性能优化案例

    老李案例分享:Weblogic性能优化案例 POPTEST的测试技术交流qq群:450192312 网站应用首页大小在130K左右,在之前的测试过程中,其百用户并发的平均响应能力在6.5秒,性能优化后 ...

  10. ArcGIS案例学习笔记3_1_地理配准案例_目视找点

    ArcGIS案例学习笔记3_1_地理配准案例_目视找点 计划时间:第3天上午 方法:地理配准/添加链接点/左键/右键/输入坐标 数据:江苏省.zip 矢量:省界,市界,GPS WGS84 地理坐标系 ...

随机推荐

  1. 【攻防世界】Web | wife_wife 详细题解WP

    [攻防世界] | Web | wife_wife详细题解WP 进入题目环境,首先进入sign up创建一个admin用户,下方有勾选 is admin,打上勾 随便填写Invite Code,进行抓包 ...

  2. 【7】状态压缩DP学习笔记

    前言 状态压缩 DP 是一类常用的 DP 方式,思维难度不是很大,但需要一点卡常和实现技巧.比较容易掌握,是一个骗分的好东西. 状态压缩DP 状态压缩 DP 通常用来处理 DP 过程中与具体状态相关的 ...

  3. ARIMA 模型简单介绍

    简介 中文名字叫做 差分(I) 自相关回归(AR) 移动平均(MA) 模型 总而言之 根据以前的数据预测新数据 比较常用的模型 比较好的视频资料 https://www.bilibili.com/vi ...

  4. ERP系统是什么?ERP系统如何与数据库对接?

    ERP系统的定义 1.企业ERP系统标准的定义来自于其英文原意,即企业资源规划(Enterprise Resource Planning).企业资源计划系统是一种集成的软件系统,旨在帮助企业管理其资源 ...

  5. Linguistics-English-10级英语水平

    可以自我评估一下你的英语水平吗? 完全不会英文,无法听懂或说出任何英文内容. 仅能听懂或说出非常简单的单词或短语,如"Hello"."Thank you".&q ...

  6. 组织: 阶级: 组织+管理+授权+组织结构设计+ 角色 + 分工: individual类型: 体力+普工+文职+

    组织: 阶级: 组织+管理+ 授权+资源管理+ 组织结构设计+角色 社会:教育分科+分工: individual类型: 体力: 普工:砖头, 销售文职: 上传下达,文书 专业:一招鲜,专家 管理:人精 ...

  7. 【还在使用MyBatis-Plus?更强大的来了】MyBatis-Flex 完整使用指南

    MyBatis-Flex 完整使用指南 一.环境准备 1. Maven 依赖 <dependencies> <!-- MyBatis-Flex 核心依赖 --> <dep ...

  8. Linux CentOS 7系统固定网卡名称和MAC地址操作步骤

    以下是CentOS 7系统中固定网卡名称和MAC地址的详细操作流程,确保ip a或ifconfig显示修改后的结果: ​​一.固定网卡名称​​ ⚙️ ​​方法1:通过udev规则绑定(推荐)​​ ​​ ...

  9. 一步一步学习使用LiveBindings(2) 使用LiveBinding Designer进行控件到控件的绑定

    一步一步学习使用LiveBindings(2) 使用LiveBinding Designer进行控件到控件的绑定 接下来看一个组件属性间的绑定的例子,这个例子使用了几个非常有趣的FireMonkey控 ...

  10. Docker系列之Elasticsearch安装教程

    @ 目录 1.什么Elasticsearch? 2.安装elasticsearch 3.目录结构 4.常用命令 5.插件安装 6.elasticsearch-head 1.什么Elasticsearc ...