Flutter笔记:用于ORM的Floor框架简记
本文地址:https://blog.csdn.net/qq_28550263/article/details/133377191
floor 模块地址:https://pub.dev/packages/floor
【介绍】:最近想找用于Dart和Flutter的ORM框架,偶然间发现了Floor,觉得还不错,做一些记录。
- 1. Floor 框架概述
- 1.1 框架简介
- 1.2 框架的构成
- 1.3 安装
- 1.4 架构体系
- 2. 实体(Entity)
- 支持的类型
- 主键
- 外键
- 索引
- 忽略字段
- 继承
- 数据库视图(Database Views)
- 3. 数据访问对象(DAO - Data Access Object)
- 4. 创建数据库
- 5. 运行代码生成器
- 6. 使用生成的代码
1. Floor 框架概述
1.1 框架简介
Floor 框架是一个用于在 Flutter 应用程序中使用 SQLite 数据库的开源库。它允许开发者轻松地将本地数据库集成到其应用程序中,并提供了一种类型安全、高效和易于使用的方法来执行数据库操作。
1.2 框架的构成
Floor 框架由多个关键模块组成,每个模块都有特定的功能,协同工作以实现在 Flutter 应用程序中使用 SQLite 数据库的目标。以下是 Floor 框架的主要模块以及它们的作用:
-
floor(运行时库):
- 作用:
floor
是 Floor 框架的运行时库,包含用于运行时数据库操作的类和方法。 - 关键类和方法:
FloorDatabase
:抽象类,表示数据库的根类,生成的数据库类需要扩展它。@Database
:用于标记生成的数据库类,指定数据库版本号、实体列表和其他配置信息。databaseBuilder
:用于创建数据库实例的方法。- 数据库操作方法:生成的数据库类中包含与数据库表的交互方法,例如插入、查询、更新等。
- 作用:
-
floor_generator(代码生成器):
- 作用:
floor_generator
是 Floor 框架的代码生成器模块,它会根据实体和 DAO 的定义生成数据库访问代码。 - 生成的代码: 该模块生成包括数据库类、DAO 类以及其他与数据库交互相关的代码,使开发者能够轻松执行数据库操作,而无需手动编写大量的重复代码。
- 作用:
-
floor_annotation(Floor 框架中的注解)
- 作用: floor_annotation是Floor 框架中的注解。这些注解用于标记和配置数据库实体(Entities)、数据访问对象(DAOs)以及数据库操作,以便 Floor 框架的代码生成器 floor_generator 可以根据这些注解生成相应的数据库访问代码。
- floor_annotation 提供了一种类型安全的方式来配置和定义数据库操作,并允许开发者在 Dart 代码中使用注解来描述数据库模型和操作,而无需手动编写大量的重复代码。
- 例如:
- @entity:用于标记 Dart 类,表示它是一个数据库实体(Entity)。实体类通常与数据库表相对应,用于定义表的结构和字段。
- @dao:用于标记抽象类或接口,表示它是数据访问对象(DAO)。DAO 类包含了与数据库表相关的操作方法,如插入、查询、更新和删除。
等等
- sqflite(数据库驱动,由floor自动调用):
- 作用: Floor 框架依赖于
sqflite
插件,它提供了在 Flutter 中与 SQLite 数据库进行底层交互的功能。 sqflite
插件负责管理 SQLite 数据库文件、执行原始 SQL 查询和处理数据库事务。
- 作用: Floor 框架依赖于
这些模块协同工作,使开发者能够轻松地在 Flutter 应用程序中集成和操作 SQLite 数据库。通过定义实体、DAO 和数据库,然后运行代码生成器,开发者可以获得类型安全、高效和易于维护的数据库访问代码,从而实现数据持久化和本地数据存储的需求。
- build_runner:build_runner 通常与 floor_generator 一起使用,以自动生成与数据库操作相关的 Dart 代码。
1.3 安装
flutter pub add floor
flutter pub add floor_generator build_runner --dev
其中:
floor
: 包含了将在应用程序中使用的所有代码。floor_generator
: 包含了生成数据库类的代码。build_runner
: 允许以具体的方式生成源代码文件。
将在你的yaml中看到:
dependencies:flutter:sdk: flutterfloor: ^1.4.0dev_dependencies:floor_generator: ^1.4.0build_runner: ^2.1.2
版本可能随时间变化
1.4 架构体系
存储和访问数据的组件是 实体、数据访问对象(DAO) 和 数据库:
- 一个 实体 代表一个 持久类,也就是一个 数据库表;
- Dao管理对实体的访问,并负责内存中 对象 和表行 之间的 映射;
- 数据库是底层 SQLite 数据库的中心访问点。它 保存Dao,除此之外,还负责 初始化数据库及其 模式。
2. 实体(Entity)
一个实体是一个持久化类。Floor 自动创建内存中对象与数据库表行之间的映射。可以通过向 Entity 注释添加可选值来向 Floor 提供自定义元数据。它具有表名 tableName 的附加属性,该属性打开了为特定实体使用自定义名称的可能性,而不是使用类名。foreignKeys 允许向实体添加外键。有关如何使用这些内容的更多信息,请参阅外键部分。还支持索引。可以通过将索引添加到实体的 indices 值来使用它们。
@entity
注解用于标记了该类为持久类;@PrimaryKey
将类的属性标记为主键列。该属性必须是 int 类型。当启用autoGenerate
时,SQLite 可以自动生成该值;- 必须通过将
@primaryKey
注解添加到一个int
属性上为你的表添加一个主键,例如:// entity/person.dartimport 'package: floor/floor.dart'; class Person {final int id;final String name;Person(this.id, this.name); }
@ColumnInfo
使单个表列的自定义映射变得可能。使用该注释,可以为列指定自定义名称。如果要将表的列设置为可空,请将实体字段标记为可空;- Floor 自动使用实体类中定义的第一个构造函数来从数据库行创建内存中对象
支持的类型
Floor 实体可以保存以下 Dart 类型的值,这些类型与它们对应的 SQLite 类型相互映射。
int
- INTEGERdouble
- REALString
- TEXTbool
- INTEGER(0 = false,1 = true)Uint8List
- BLOBenum
- INTEGER(按索引 0…n 记录)
如果要存储可以由上述类型之一表示的复杂 Dart 对象,请查看类型转换器。
主键
每当需要复合主键(例如 n-m 关系)时,设置主键的语法与前面提到的设置主键的方式不同。不是使用 @PrimaryKey
注释字段,而是使用 @Entity
注释的 primaryKey 属性。它接受一个由列名组成的列表,这些列名组成复合主键。
(primaryKeys: ['id', 'name'])
class Person {final int id;final String name;Person(this.id, this.name);
}
外键
向引用实体的 Entity 注释添加 ForeignKeys 列表。childColumns 定义当前实体的列,而 parentColumns 定义父实体的列。在 onUpdate 和 onDelete 属性中定义外键操作后,可以触发外键操作。
// Dog 类,表示数据库中的狗实体
(tableName: 'dog', // 指定表名为 'dog'foreignKeys: [ForeignKey(childColumns: ['owner_id'], // 子列名为 'owner_id'parentColumns: ['id'], // 父列名为 'id'entity: Person, // 引用的实体为 Person 类)],
)
class Dog {() // PrimaryKey 注解,将 id 标记为主键列final int id;final String name; // 名称(name: 'owner_id') // ColumnInfo 注解,自定义列名为 'owner_id'final int ownerId; // 所有者的 ID// 构造函数,接受 id、name 和 ownerId 参数Dog(this.id, this.name, this.ownerId);
}
@Entity
注解标记了Dog
类,指定了表名为 ‘dog’,同时指定了一个外键(foreign key),该外键将在 ‘owner_id’ 列上创建,它引用了另一个实体Person
。这意味着在数据库中将创建名为 ‘dog’ 的表,并在 ‘owner_id’ 列上创建一个外键,以确保数据的完整性。@PrimaryKey
注解标记了id
字段作为主键列,这意味着它在数据库中将用作主键。@ColumnInfo
注解标记了ownerId
字段,并自定义了列名为 ‘owner_id’,这允许在数据库表中使用不同的列名,而不是默认的字段名。- 构造函数接受
id
、name
和ownerId
参数,并用于创建Dog
实例。
这些注释和注释说明了 Dog
类的结构,以及如何配置表名、外键和自定义列名。
索引
索引有助于加速查询、连接和分组操作。有关 SQLite 索引的更多信息,请参阅官方文档。要在 floor 中创建索引,请将索引列表添加到 @Entity 注释。下面的示例演示了如何在实体的 custom_name 列上创建索引。
此外,可以使用其 name 属性命名索引。要将索引设置为唯一索引,请使用 unique 属性。
// Person 类,表示数据库中的个人实体
(tableName: 'person', indices: [Index(value: ['custom_name'])])
class Person { // PrimaryKey 注解,将 id 标记为主键列final int id;(name: 'custom_name') // ColumnInfo 注解,自定义列名为 'custom_name'final String name; // 姓名// 构造函数,接受 id 和 name 参数Person(this.id, this.name);
}
@Entity
注解标记了 Person 类,指定了表名为 ‘person’,同时指定了一个索引,该索引将在 ‘custom_name’ 列上创建。这意味着在数据库中将创建名为 ‘person’ 的表,并在 ‘custom_name’ 列上创建一个索引,以提高查询性能。@primaryKey
注解标记了 id 字段作为主键列,这意味着它在数据库中将用作主键。@ColumnInfo
注解标记了 name 字段,并自定义了列名为 ‘custom_name’,这允许在数据库表中使用不同的列名,而不是默认的字段名。
构造函数接受 id 和 name 参数,并用于创建 Person 实例。
忽略字段
默认情况下,实体的 getter、setter 和所有静态字段都会被忽略,并因此从库的映射中排除。如果要进一步忽略字段,应使用 @ignore 注释,并按以下示例中所示应用它。
// 人员类,表示数据库中的人员实体
class Person { // PrimaryKey 注解,将 id 标记为主键列final int id;final String name; // 姓名 // Ignore 注解,指定 nickname 字段将被忽略String nickname; // 昵称// 默认情况下被忽略的字段,不会包含在库的映射中String get combinedName => "$name ($nickname)";// 构造函数,接受 id 和 name 参数Person(this.id, this.name);
}
继承
与 Dao 一样,实体(和数据库视图)可以从共同的基类继承并使用它们的字段。实体只需扩展基类。这个构造将被视为如果基类的所有字段都是实体的一部分,这意味着数据库表将包含实体和基类的所有列。
基类不必为类单独注释。它的字段可以像正常的实体列一样进行注释。外键和索引必须在实体中声明,不能在基类中定义。
// 基础对象类,用于继承到其他实体
class BaseObject {// 主键标记,指定 id 作为主键列()final int id;// ColumnInfo 注解,用于自定义列名 create_time(name: 'create_time')final String createTime;// ColumnInfo 注解,用于自定义列名 update_time(name: 'update_time')final String updateTime;// 构造函数,接受 id、updateTime 和可选的 createTime 参数BaseObject(this.id,this.updateTime, {String createTime,}) : this.createTime = createTime ?? DateTime.now().toString();// 重写父类的 props 方法,通常用于数据比较List<Object> get props => [];
}// Comment 类,继承自 BaseObject 类
(tableName: 'comments') // Entity 注解,指定表名为 'comments'
class Comment extends BaseObject {final String author; // 评论作者final String content; // 评论内容// 构造函数,接受 author、可选的 id、content、createTime 和 updateTime 参数Comment(this.author, {int id,this.content = '', // 默认为空字符串String createTime,String updateTime,}) : super(id, updateTime, createTime: createTime); // 调用父类构造函数,传递 id、updateTime 和 createTime 参数
}
数据库视图(Database Views)
如果希望定义返回与实体不同类型的静态 SELECT 语句,最佳选择是使用 @DatabaseView
。数据库视图可以被理解为虚拟表,可以像真实表一样进行查询。
在 Floor 中,数据库视图的定义和使用方式与实体类似,主要区别在于只读访问,这意味着无法执行更新、插入和删除操作。与实体类似,如果未设置 viewName,则使用类名。
('SELECT distinct(name) AS name FROM person', viewName: 'name')
class Name {final String name;Name(this.name);
}
数据库视图不具有任何外键、主键或索引。相反,您应该手动定义与您的语句匹配的索引,并将它们放入涉及实体的 @Entity
注释中。
与实体类似,setter、getter 和静态字段将自动被忽略(与实体类似),您可以使用 @ignore
注解来指定要忽略的附加字段。
在代码中定义数据库视图后,您需要将它添加到 @Database
注释的 views 字段中:
(version: 1, entities: [Person], views: [Name])
abstract class AppDatabase extends FloorDatabase {// DAO 获取器
}
然后,您可以通过 DAO 函数查询视图,就像查询实体一样。
数据库视图可以像实体一样从基类继承共同字段。
现在可以从 DAO 方法返回一个 Stream 对象,该方法查询数据库视图。但是,它将在整个数据库中的任何
@update
、@insert
、@delete
事件触发时发出,这可能会对运行时产生相当大的负担。请仅在明白自己在做什么时才添加它!这主要是因为检测哪些实体涉及到数据库视图的复杂性所致。
3. 数据访问对象(DAO - Data Access Object)
这个组件负责管理对底层的 SQLite 数据库的访问。抽象类包含了查询数据库的方法签名,这些方法必须返回 Future 或 Stream。
你可以通过将 @Query
注解添加到方法上来定义查询。SQL 语句必须放在括号中。方法必须返回你查询的实体的 Future 或 Stream。
@insert
标记了一个方法作为插入方法。
// dao/person_dao.dartimport 'package:floor/floor.dart';
abstract class PersonDao {// 查询并返回所有的 Person 实体对象列表('SELECT * FROM Person')Future<List<Person>> findAllPersons();// 根据提供的 id 查询并返回匹配的 Person 实体对象// 这是一个异步数据流,当数据发生变化时,会自动更新('SELECT * FROM Person WHERE id = :id')Stream<Person?> findPersonById(int id);// 将提供的 Person 对象插入到数据库中// 这是一个异步操作,不返回任何数据Future<void> insertPerson(Person person);
}
4. 创建数据库
它必须是一个继承自 FloorDatabase 的抽象类。此外,必须在类的签名中添加 @Database()
。确保将创建的实体添加到 @Database
注解的 entities 属性中。为了使生成的代码工作,还需要添加列出的导入项。
确保在这个文件的导入项下面添加 part ‘database.g.dart’;。重要的是要注意 ‘database’ 必须与数据库定义的文件名进行交换。在这种情况下,文件名命名为 database.dart。
// database.dartimport 'dart:async';
import 'package:floor/floor.dart';
import 'package:sqflite/sqflite.dart' as sqflite; import 'dao/person_dao.dart';
import 'entity/person.dart'; part 'database.g.dart'; // Floor代码生成器将在这里生成相关的代码(version: 1, entities: [Person]) // 声明数据库版本号和包含的实体类
abstract class AppDatabase extends FloorDatabase {PersonDao get personDao; // 获取PersonDao实例,用于执行数据库操作
}
5. 运行代码生成器
使用以下命令来运行生成器:
flutter packages pub run build_runner build
上面的命令用于在 Flutter 项目中运行代码生成工具以手动构建生成的代码。build命令 只会运行一次生成过程,然后退出。还可以在 Flutter 项目中使用 build_runner 模块的观察模式,以便在开发过程中自动更新生成的代码。如果想要在文件更改时自动运行它,请使用以下命令:
flutter packages pub run build_runner watch
6. 使用生成的代码
要获取数据库的实例,使用生成的 $FloorAppDatabase 类,它允许访问数据库生成器。名称由 $Floor 和数据库类名组成。传递给 databaseBuilder() 的字符串将是数据库文件的名称。要初始化数据库,调用 build() 并确保等待结果。
为了检索 PersonDao 实例,只需在数据库实例上调用 persoDao getter 即可。
可以参考下面的代码。
// 使用数据库生成器创建数据库实例,传递数据库文件的名称('app_database.db')
final database = await $FloorAppDatabase.databaseBuilder('app_database.db').build();// 从数据库实例中获取 PersonDao 实例
final personDao = database.personDao;// 创建一个 Person 对象
final person = Person(1, 'Frank');// 将新的 Person 对象插入到数据库中
await personDao.insertPerson(person);// 通过 ID 查找数据库中的 Person 记录
final result = await personDao.findPersonById(1);// 输出查找到的 Person 记录
print('Found Person: $result');
相关文章:

Flutter笔记:用于ORM的Floor框架简记
Flutter笔记 用于ORM的Floor框架简记 本文地址:https://blog.csdn.net/qq_28550263/article/details/133377191 floor 模块地址:https://pub.dev/packages/floor 【介绍】:最近想找用于Dart和Flutter的ORM框架,偶然间发现了Floor…...

Zabbix自定义脚本监控MySQL数据库
一、MySQL数据库配置 1.1 创建Mysql数据库用户 [rootmysql ~]# mysql -uroot -p create user zabbix127.0.0.1 identified by 123456; flush privileges; 1.2 添加用户密码到mysql client的配置文件中 [rootmysql ~]# vim /etc/my.cnf.d/client.cnf [client] host127.0.0.1 u…...

【Spatial-Temporal Action Localization(五)】论文阅读2020年
文章目录 1. Actions as Moving Points摘要和结论引言:针对痛点和贡献模型框架实验 1. Actions as Moving Points Actions as Moving Points (ECCV 2020) 摘要和结论 MovingCenter Detector (MOCdetector) 通过将动作实例视为移动点的轨迹。通过三个分支生成 tub…...

Linux基本指令(中)——“Linux”
各位CSDN的uu们好呀,今天,小雅兰的内容是Linux基本指令呀!!!下面,让我们进入Linux的世界吧!!! cp指令(重要) mv指令(重要)…...

OWASP Top 10漏洞解析(3)- A3:Injection 注入攻击
作者:gentle_zhou 原文链接:OWASP Top 10漏洞解析(3)- A3:Injection 注入攻击-云社区-华为云 Web应用程序安全一直是一个重要的话题,它不但关系到网络用户的隐私,财产,而且关系着用户对程序的新…...
Java自定义类加载器的详解与步骤
自定义类加载器的步骤 继承ClassLoader类:首先创建一个新的类,该类需要继承ClassLoader类。可以通过直接继承ClassLoader或是间接继承URLClassLoader等子类来实现。重写findClass()方法:在自定义类加载器中,最重要的是重写findCl…...

完美清晰,炫酷畅享——Perfectly Clear Video为你带来卓越的AI视频增强体验
在我们日常生活中,我们经常会拍摄和观看各种视频内容,无论是旅行记录、家庭聚会还是商务演示,我们都希望能够呈现出最清晰、最精彩的画面效果。而现在,有一个强大的工具可以帮助我们实现这一目标,那就是Perfectly Clea…...
如何让FileBeat支持http的output插件
目录 1 缘由2 编译filebeat3 配置虚拟机访问外网4 编译beats-output-http4.1 使用本地包4.2 发布在线包 5 测试6 beats-output-http的部分解释 1 缘由 官网的filebeat只有以下几种output插件: Elasticsearch ServiceElasticsearchLogstashKafkaRedisFileConsole …...

解密人工智能:决策树 | 随机森林 | 朴素贝叶斯
文章目录 一、机器学习算法简介1.1 机器学习算法包含的两个步骤1.2 机器学习算法的分类 二、决策树2.1 优点2.2 缺点 三、随机森林四、Naive Bayes(朴素贝叶斯)五、结语 一、机器学习算法简介 机器学习算法是一种基于数据和经验的算法,通过对…...

web:[极客大挑战 2019]BabySQL
题目 点进页面显示如下 查看源代码 先尝试一下万能密码 没用,or被过滤了 试着双写看看 回显一串,也不是flag 先查询列数尝试一下,把union select过滤了,使用双写 构造payload /check.php?usernameadmin&password1 %27 ununi…...

DRM全解析 —— plane详解(1)
本文参考以下博文: Linux内核4.14版本——drm框架分析(5)——plane分析 特此致谢! 1. 简介 一个plane代表一个image layer(硬件图层),最终的image由一个或者多个plane(s)组成。plane和 Framebuffer 一样是内存地址。…...
数据结构总结
数据结构 相关博文 单链表数组模拟单链表-CSDN博客双链表数组模拟双链表-CSDN博客栈及单调栈数组模拟栈以及单调栈-CSDN博客队列及单调队列数组模拟队列以及单调队列-CSDN博客KMPKMP详细算法思路-CSDN博客TrieTire树的理解-CSDN博客并查集并查集(面试常考ÿ…...

在SOLIDWORKS搭建一个简易的履带式机器人
文章目录 前言一、构建模型基本单元二、搭建车体模块三.插入轮子4.构建履带 前言 趁着十一假期,在solidworks中搭建了一个履带式机器人小车,计划将其应用在gazebo中完成多机器人编队的仿真。 一、构建模型基本单元 构建底板(a面)…...
C# 为什么要限制静态方法的使用
前言 在工作了一年多之后,我发现静态方法的耦合问题实在是头疼。如果可以尽量不要使用静态方法存储数据,如果要存储全局数据就把数据放在最顶层的主函数里面。 静态方法问题 耦合问题,不要用静态方法存储数据 我这里有两个静态方法&#…...

【已解决】Pyecharts折线图,只有坐标轴没有折线数据
【已解决】Pyecharts折线图,只有坐标轴没有折线数据 1、问题复现2、原因3、问题解决 1、问题复现 在做简单的数据通过 Pyecharts 生成折现图的时候,一直只有坐标轴没有折线数据,但是代码一直看不出问题,代码如下: im…...

win10搭建Selenium环境+java+IDEA(3)
这里主要对前面的maven和selenium做补充说明,以及更新一些pom文件下载依赖的问题。 IDEA里面,如果你创建的工程是maven工程文件,那么就会有一个pom.xml文件,可以在这个网站:https://mvnrepository.com/搜索依赖&#…...
String 、Stringbuffer、StringBuilder区别
上代码 public class Test {public static void main(String[] args) {//String 连接10000次消耗1127ms//StringBuffer 连接10000次消耗5ms//StringBuilder 连接10000次消耗3msStringTest(10000);StringBufferTest(10000);StringBuilderTest(10000);}public static void Strin…...

如何提升爬虫IP使用效率?精打细算的方法分享
在进行爬虫数据采集时,爬虫IP是不可或缺的工具。然而,爬虫IP的费用可能是一个爬虫项目的重要开支之一。为了帮助您节省爬虫IP经费,本文将分享一些经济高效的方法,让您在使用爬虫IP时更加节约成本,提高经济效益。 一、优…...
(高阶) Redis 7 第19讲 缓存过期淘汰策略 大厂篇
🌹 以下分享 Redis 缓存淘汰策略,如有问题请指教。🌹🌹 如你对技术也感兴趣,欢迎交流。🌹🌹🌹 如有对阁下帮助,请👍点赞💖收藏🐱🏍分享😀 面试题 1. 生产上,redis内存设置的多少 2. 如何配置、修改Redis 内存大小 3. 如果内存满了,如何处理 4. …...

【四旋翼飞行器】模拟四旋翼飞行器的平移和旋转动力学(Simulink仿真实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...