Flutter for OpenHarmony 电子合同签署App实战 - 数据持久化实现

数据持久化是电子合同应用的核心功能。这个功能需要提供安全、高效的数据存储机制,确保用户的合同数据能够被可靠地保存和恢复。在这篇文章中,我们将详细讲解如何实现一个功能完整、安全可靠的数据持久化系统。通过学习本文,你将掌握如何构建高质量的数据存储解决方案。

数据持久化的设计目标

数据持久化功能需要实现以下核心目标:首先是提供安全的数据存储机制,让用户的数据不会丢失。其次是提供高效的数据查询和检索功能,让应用能够快速访问数据。第三是提供数据同步功能,确保多设备间的数据一致性。最后是提供数据备份和恢复功能,让用户能够在需要时恢复他们的数据。

数据持久化的设计应该考虑数据的安全性、性能、可靠性和可扩展性。应用应该支持多种存储方式,以适应不同的数据类型和使用场景。

存储方式的选择

应用可以使用以下方式进行数据存储,每种方式都有其特定的优势和适用场景:

  • 本地文件存储:适合存储大型文件和二进制数据
  • 本地数据库存储:适合存储结构化数据和复杂查询
  • 云存储:适合备份和跨设备同步
  • 混合存储:结合多种存储方式的优势

选择合适的存储方式对应用的性能和用户体验至关重要。

数据模型的定义

首先,我们需要定义数据持久化的数据模型。数据模型应该包含所有必要的字段,并提供序列化和反序列化的方法。

在实现数据持久化时,我们需要创建一个统一的数据模型来表示所有持久化的数据。这个模型包含了数据的基本信息,如ID、合同ID、数据类型等,同时还包含了时间戳和元数据等辅助信息。通过定义清晰的数据模型,我们可以确保数据的一致性和可维护性。模型中的fromJsontoJson方法使得数据可以轻松地在对象和JSON格式之间转换,这对于数据的存储和传输至关重要。

dart 复制代码
class PersistenceModel {
  final String id;
  final String contractId;
  final String dataType;
  final String content;
  final DateTime createdTime;
  final DateTime modifiedTime;
  final String encryptionKey;
  final Map<String, dynamic> metadata;

  PersistenceModel({
    required this.id,
    required this.contractId,
    required this.dataType,
    required this.content,
    required this.createdTime,
    required this.modifiedTime,
    required this.encryptionKey,
    required this.metadata,
  });

  factory PersistenceModel.fromJson(Map<String, dynamic> json) {
    return PersistenceModel(
      id: json['id'] as String,
      contractId: json['contractId'] as String,
      dataType: json['dataType'] as String,
      content: json['content'] as String,
      createdTime: DateTime.parse(json['createdTime'] as String),
      modifiedTime: DateTime.parse(json['modifiedTime'] as String),
      encryptionKey: json['encryptionKey'] as String,
      metadata: json['metadata'] as Map<String, dynamic>,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'contractId': contractId,
      'dataType': dataType,
      'content': content,
      'createdTime': createdTime.toIso8601String(),
      'modifiedTime': modifiedTime.toIso8601String(),
      'encryptionKey': encryptionKey,
      'metadata': metadata,
    };
  }
}

数据模型包含了数据持久化所需的所有基本信息。通过这个模型,我们可以统一管理持久化数据,避免数据散落在各个地方。模型中的每个字段都有明确的含义,使得代码更加易于理解和维护。通过提供fromJsontoJson方法,我们可以轻松地进行数据序列化和反序列化。

本地存储的实现

本地存储是最基础的数据持久化方式。我们可以使用shared_preferences包来存储简单的键值对数据。这种方式适合存储用户偏好设置、应用配置等简单数据。

shared_preferences提供了一个简单而高效的键值对存储机制,特别适合存储应用配置、用户偏好等小型数据。通过这个服务类,我们封装了所有的存储操作,提供了统一的接口来处理字符串、列表、整数和布尔值等多种数据类型。这样的设计使得代码更加模块化,便于维护和扩展。每个方法都是异步的,确保不会阻塞主线程,提高了应用的响应性。

dart 复制代码
import 'package:shared_preferences/shared_preferences.dart';

class LocalStorageService {
  static const String _contractsKey = 'contracts';
  static const String _userPrefsKey = 'user_prefs';
  
  Future<void> saveString(String key, String value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(key, value);
  }

  Future<String?> getString(String key) async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getString(key);
  }

  Future<void> saveList(String key, List<String> values) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setStringList(key, values);
  }

  Future<List<String>?> getList(String key) async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getStringList(key);
  }

  Future<void> saveInt(String key, int value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setInt(key, value);
  }

  Future<int?> getInt(String key) async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getInt(key);
  }

  Future<void> saveBool(String key, bool value) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setBool(key, value);
  }
}

本地存储服务提供了一套完整的键值对存储接口。通过这个服务,我们可以轻松地保存和读取各种类型的数据。这种方式的优点是简单易用,适合存储小型数据。缺点是不支持复杂的查询操作,也不支持事务处理。

数据库存储的实现

对于复杂的数据,我们应该使用本地数据库来存储。sqflite是Flutter中最流行的本地数据库解决方案。它提供了强大的查询功能和事务支持。

sqflite数据库服务是应用数据持久化的核心。这个服务使用单例模式确保全局只有一个数据库实例,避免了资源浪费和并发问题。通过_onCreate_onUpgrade方法,我们可以灵活地管理数据库的版本和结构。服务提供了完整的CRUD操作接口,包括插入、查询、更新和删除等功能。通过建立外键关系,我们确保了数据的完整性和一致性。

dart 复制代码
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class DatabaseService {
  static const String _databaseName = 'contracts.db';
  static const int _databaseVersion = 1;
  static const String _contractsTable = 'contracts';
  static const String _persistenceTable = 'persistence_data';

  static final DatabaseService _instance = DatabaseService._internal();

  factory DatabaseService() {
    return _instance;
  }

  DatabaseService._internal();

  Database? _database;

  Future<Database> get database async {
    _database ??= await _initDatabase();
    return _database!;
  }

  Future<Database> _initDatabase() async {
    final databasesPath = await getDatabasesPath();
    final path = join(databasesPath, _databaseName);

    return await openDatabase(
      path,
      version: _databaseVersion,
      onCreate: _onCreate,
      onUpgrade: _onUpgrade,
    );
  }

  Future<void> _onCreate(Database db, int version) async {
    await db.execute('''
      CREATE TABLE $_contractsTable (
        id TEXT PRIMARY KEY,
        title TEXT NOT NULL,
        content TEXT NOT NULL,
        status TEXT NOT NULL,
        createdTime TEXT NOT NULL,
        modifiedTime TEXT NOT NULL,
        metadata TEXT
      )
    ''');

    await db.execute('''
      CREATE TABLE $_persistenceTable (
        id TEXT PRIMARY KEY,
        contractId TEXT NOT NULL,
        dataType TEXT NOT NULL,
        content TEXT NOT NULL,
        createdTime TEXT NOT NULL,
        modifiedTime TEXT NOT NULL,
        encryptionKey TEXT,
        metadata TEXT,
        FOREIGN KEY (contractId) REFERENCES $_contractsTable(id)
      )
    ''');
  }

  Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
    // 处理数据库升级逻辑
  }

  Future<int> insertContract(Map<String, dynamic> contract) async {
    final db = await database;
    return await db.insert(_contractsTable, contract);
  }

  Future<List<Map<String, dynamic>>> queryAllContracts() async {
    final db = await database;
    return await db.query(_contractsTable);
  }

  Future<Map<String, dynamic>?> queryContractById(String id) async {
    final db = await database;
    final results = await db.query(
      _contractsTable,
      where: 'id = ?',
      whereArgs: [id],
    );
    return results.isNotEmpty ? results.first : null;
  }
  }

数据库服务提供了完整的数据库操作接口。通过这个服务,我们可以执行复杂的数据查询和管理操作。数据库支持事务处理,确保数据的一致性。这种方式的优点是功能强大,支持复杂查询。缺点是需要更多的资源和配置。

数据加密的实现

在实际应用中,我们应该对敏感数据进行加密。这可以通过使用encrypt包来实现。加密确保即使数据被未授权访问,也无法被读取。

加密服务使用AES算法对数据进行加密和解密,这是业界标准的对称加密算法。通过生成随机的密钥和初始化向量,我们确保了每次加密的安全性。服务提供了encryptDatadecryptData方法来处理数据的加密和解密操作。密钥和初始化向量可以被序列化为Base64格式,便于存储和传输。在实际应用中,这些密钥应该被安全地存储在设备的安全存储区域中。

dart 复制代码
import 'package:encrypt/encrypt.dart' as encrypt;

class EncryptionService {
  late final encrypt.Key _key;
  late final encrypt.IV _iv;

  EncryptionService() {
    _key = encrypt.Key.fromSecureRandom(32);
    _iv = encrypt.IV.fromSecureRandom(16);
  }

  String encryptData(String plainText) {
    final encrypter = encrypt.Encrypter(encrypt.AES(_key));
    final encrypted = encrypter.encrypt(plainText, iv: _iv);
    return encrypted.base64;
  }

  String decryptData(String encryptedText) {
    final encrypter = encrypt.Encrypter(encrypt.AES(_key));
    final decrypted = encrypter.decrypt64(encryptedText, iv: _iv);
    return decrypted;
  }

  String getKeyString() {
    return _key.base64;
  }

  String getIVString() {
    return _iv.base64;
  }

  void setKeyFromString(String keyString) {
    _key = encrypt.Key.fromBase64(keyString);
  }

  void setIVFromString(String ivString) {
    _iv = encrypt.IV.fromBase64(ivString);
  }
}

加密服务提供了数据加密和解密的功能。通过使用AES加密算法,我们可以确保敏感数据的安全性。加密密钥应该被安全地存储,不应该被硬编码在代码中。

数据备份的实现

数据备份功能允许用户备份他们的数据到云存储或本地文件。这确保了数据的安全性和可恢复性。

备份服务提供了完整的备份生命周期管理功能。通过createBackup方法,我们可以将所有合同数据导出为JSON格式并保存到本地文件系统。备份文件包含了时间戳和版本信息,便于版本管理和追踪。restoreBackup方法允许用户从备份文件恢复数据,而listBackupsdeleteBackup方法提供了备份的列表和删除功能。这样的设计确保了用户数据的安全性,即使应用崩溃或设备丢失,用户也能恢复他们的数据。

dart 复制代码
import 'dart:io';
import 'package:path_provider/path_provider.dart';

class BackupService {
  Future<String> createBackup(List<Map<String, dynamic>> contracts) async {
    try {
      final directory = await getApplicationDocumentsDirectory();
      final backupDir = Directory('${directory.path}/backups');
      
      if (!await backupDir.exists()) {
        await backupDir.create(recursive: true);
      }

      final timestamp = DateTime.now().millisecondsSinceEpoch;
      final backupFile = File('${backupDir.path}/backup_\$timestamp.json');

      final backupData = {
        'timestamp': DateTime.now().toIso8601String(),
        'version': 1,
        'contracts': contracts,
      };

      await backupFile.writeAsString(
        jsonEncode(backupData),
      );

      return backupFile.path;
    } catch (e) {
      throw Exception('Failed to create backup: \$e');
    }
  }

  Future<List<Map<String, dynamic>>> restoreBackup(String backupPath) async {
    try {
      final backupFile = File(backupPath);
      
      if (!await backupFile.exists()) {
        throw Exception('Backup file not found');
      }

      final content = await backupFile.readAsString();
      final backupData = jsonDecode(content) as Map<String, dynamic>;
      
      return List<Map<String, dynamic>>.from(
        backupData['contracts'] as List,
      );
    } catch (e) {
      throw Exception('Failed to restore backup: \$e');
    }
  }

  Future<List<String>> listBackups() async {
    try {
      final directory = await getApplicationDocumentsDirectory();
      final backupDir = Directory('${directory.path}/backups');

      if (!await backupDir.exists()) {
        return [];
      }

      final files = backupDir.listSync();
      return files
          .whereType<File>()
          .map((f) => f.path)
          .toList();
    } catch (e) {
      throw Exception('Failed to list backups: \$e');
    }
  }

  Future<void> deleteBackup(String backupPath) async {
    try {
      final backupFile = File(backupPath);
      if (await backupFile.exists()) {
        await backupFile.delete();
      }
    } catch (e) {
      throw Exception('Failed to delete backup: \$e');
    }
  }
}

备份服务提供了创建、恢复和管理备份的功能。通过定期创建备份,用户可以在数据丢失时恢复他们的数据。备份应该包含时间戳和版本信息,以便进行版本管理。

数据同步的实现

数据同步功能确保多设备间的数据一致性。当用户在一个设备上修改数据时,其他设备应该能够自动同步这些更改。

同步服务是实现多设备数据一致性的关键组件。通过记录最后同步时间,我们可以实现增量同步,只同步自上次同步以来的更改,从而提高效率。syncData方法定期检查本地数据的修改时间,并与服务器进行同步。uploadChangesdownloadChanges方法分别处理本地更改的上传和远程更改的下载。hasLocalChanges方法可以检测是否存在未同步的本地更改,这对于实现智能同步策略非常有用。

dart 复制代码
class SyncService {
  final DatabaseService _dbService = DatabaseService();
  final LocalStorageService _storageService = LocalStorageService();

  Future<void> syncData() async {
    try {
      final lastSyncTime = await _storageService.getString('last_sync_time');
      final contracts = await _dbService.queryAllContracts();

      // 这里应该调用API来同步数据
      await Future.delayed(const Duration(milliseconds: 500));

      await _storageService.saveString(
        'last_sync_time',
        DateTime.now().toIso8601String(),
      );
    } catch (e) {
      throw Exception('Failed to sync data: \$e');
    }
  }

  Future<void> uploadChanges(List<Map<String, dynamic>> changes) async {
    try {
      // 这里应该调用API来上传更改
      await Future.delayed(const Duration(milliseconds: 500));
    } catch (e) {
      throw Exception('Failed to upload changes: \$e');
    }
  }

  Future<void> downloadChanges() async {
    try {
      // 这里应该调用API来下载更改
      final changes = <Map<String, dynamic>>[];
      
      for (final change in changes) {
        await _dbService.updateContract(change);
      }
    } catch (e) {
      throw Exception('Failed to download changes: \$e');
    }
  }

  Future<bool> hasLocalChanges() async {
    try {
      final lastSyncTime = await _storageService.getString('last_sync_time');
      if (lastSyncTime == null) {
        return true;
      }

      final lastSync = DateTime.parse(lastSyncTime);
      final contracts = await _dbService.queryAllContracts();

      for (final contract in contracts) {
        final modifiedTime = DateTime.parse(contract['modifiedTime'] as String);
        if (modifiedTime.isAfter(lastSync)) {
          return true;
        }
      }

      return false;
    } catch (e) {
      return false;
    }
  }
}

同步服务提供了数据同步的功能。通过定期同步数据,我们可以确保多设备间的数据一致性。同步应该是增量的,只同步自上次同步以来的更改,以提高效率。

关键功能说明

这个数据持久化功能包含了以下核心功能:

  1. 本地存储:使用SharedPreferences存储简单数据
  2. 数据库存储:使用SQLite存储复杂数据
  3. 数据加密:对敏感数据进行加密保护
  4. 数据备份:支持创建和恢复备份
  5. 数据同步:支持多设备间的数据同步
  6. 备份管理:提供备份的创建、恢复和删除功能

设计考虑

数据持久化功能的设计需要考虑以下几个方面:

  1. 安全性:对敏感数据进行加密,防止未授权访问
  2. 性能:使用高效的存储方式,避免性能瓶颈
  3. 可靠性:提供备份和恢复功能,确保数据不丢失
  4. 可扩展性:支持多种存储方式,适应不同需求
  5. 用户体验:提供清晰的管理界面,让用户能够轻松管理数据

总结

这个数据持久化功能为应用提供了一个安全、高效的数据存储解决方案。通过提供多种存储方式和完善的备份恢复机制,我们能够确保用户数据的安全性和可靠性。用户可以轻松管理他们的数据,并在需要时恢复数据。通过遵循本文的设计原则和实现方法,你可以构建高质量的Flutter应用。


欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

相关推荐
码农阿豪2 小时前
基于Milvus与混合检索的云厂商文档智能问答系统:Java SpringBoot全栈实现
java·spring boot·milvus
阿蒙Amon2 小时前
C#每日面试题-Task和Thread的区别
java·面试·c#
无心水2 小时前
数据库字符串类型详解:VARCHAR、VARCHAR2、CHARACTER VARYING的区别与选择指南
数据库·后端·varchar·varchar2·character·字符串类型·2025博客之星
KIN_DIN2 小时前
数据库索引
数据库·oracle
索荣荣2 小时前
Java异步编程终极实战指南
java·开发语言
shehuiyuelaiyuehao2 小时前
11String类型知识点
java·开发语言
毕设源码-赖学姐2 小时前
【开题答辩全过程】以 基于Java的图书馆座位预约管理系统设计为例,包含答辩的问题和答案
java·开发语言
代码N年归来仍是新手村成员2 小时前
DynamoDB 速通
数据库·nosql·aws
zhougl9962 小时前
Java Object.clone() 浅拷贝与深拷贝全解析
java·开发语言