鸿蒙Flutter JSON综合练习:Flutter在鸿蒙平台的数据处理实战
·


概述
经过前面章节的学习,我们已经掌握了JSON解析的核心技术,包括数据结构、手动解析、序列化反序列化、复杂结构处理、错误处理、格式化和文件IO等。本章将通过综合练习,将这些知识融会贯通,解决实际开发中常见的JSON数据处理问题。
本章将涵盖以下实战场景:
- JSON验证与格式检查
- 数据统计与分析
- 字段提取与路径遍历
- 数据转换与重组
- API响应处理综合案例
练习任务一:JSON验证
任务描述
实现一个JSON验证工具,能够检查JSON字符串的格式是否正确,并给出详细的验证结果。
实现方案
import 'dart:convert';
class JsonValidator {
static ValidationResult validate(String input) {
if (input.isEmpty) {
return ValidationResult(
isValid: false,
errorMessage: '输入为空',
jsonType: JsonType.none,
elementCount: 0,
);
}
try {
final dynamic parsed = json.decode(input);
if (parsed is Map) {
return ValidationResult(
isValid: true,
errorMessage: '',
jsonType: JsonType.object,
elementCount: parsed.length,
);
} else if (parsed is List) {
return ValidationResult(
isValid: true,
errorMessage: '',
jsonType: JsonType.array,
elementCount: parsed.length,
);
} else {
return ValidationResult(
isValid: true,
errorMessage: '',
jsonType: JsonType.primitive,
elementCount: 1,
);
}
} on FormatException catch (e) {
return ValidationResult(
isValid: false,
errorMessage: 'JSON格式错误: $e',
jsonType: JsonType.none,
elementCount: 0,
);
} on TypeError catch (e) {
return ValidationResult(
isValid: false,
errorMessage: '类型错误: $e',
jsonType: JsonType.none,
elementCount: 0,
);
} catch (e) {
return ValidationResult(
isValid: false,
errorMessage: '未知错误: $e',
jsonType: JsonType.none,
elementCount: 0,
);
}
}
}
enum JsonType {
none,
object,
array,
primitive,
}
class ValidationResult {
final bool isValid;
final String errorMessage;
final JsonType jsonType;
final int elementCount;
ValidationResult({
required this.isValid,
required this.errorMessage,
required this.jsonType,
required this.elementCount,
});
String toString() {
if (isValid) {
final String typeName = jsonType == JsonType.object ? 'Object' :
jsonType == JsonType.array ? 'Array' : 'Primitive';
return '✅ JSON验证通过!\n类型: $typeName\n元素数量: $elementCount';
} else {
return '❌ JSON格式错误: $errorMessage';
}
}
}
使用示例
void main() {
// 测试有效JSON
final String validJson = '{"name":"张三","age":25,"isStudent":true}';
final ValidationResult result1 = JsonValidator.validate(validJson);
print(result1);
// 测试无效JSON
final String invalidJson = '{"name":"张三",age:25}';
final ValidationResult result2 = JsonValidator.validate(invalidJson);
print(result2);
// 测试数组
final String arrayJson = '[1, 2, 3, 4, 5]';
final ValidationResult result3 = JsonValidator.validate(arrayJson);
print(result3);
}
练习任务二:数据统计
任务描述
实现一个JSON数据统计工具,能够统计JSON中的各种元素类型和数量。
实现方案
import 'dart:convert';
class JsonStatistics {
static StatisticsResult analyze(String jsonString) {
final dynamic parsed = json.decode(jsonString);
if (parsed is Map<String, dynamic>) {
return _analyzeObject(parsed);
} else if (parsed is List) {
return _analyzeArray(parsed);
} else {
return StatisticsResult(
totalElements: 1,
stringCount: parsed is String ? 1 : 0,
numberCount: parsed is num ? 1 : 0,
boolCount: parsed is bool ? 1 : 0,
arrayCount: 0,
objectCount: 0,
nullCount: parsed == null ? 1 : 0,
nestedDepth: 0,
);
}
}
static StatisticsResult _analyzeObject(Map<String, dynamic> obj) {
int stringCount = 0;
int numberCount = 0;
int boolCount = 0;
int arrayCount = 0;
int objectCount = 0;
int nullCount = 0;
int maxDepth = 0;
for (final dynamic value in obj.values) {
final ValueAnalysis analysis = _analyzeValue(value, 1);
stringCount += analysis.stringCount;
numberCount += analysis.numberCount;
boolCount += analysis.boolCount;
arrayCount += analysis.arrayCount;
objectCount += analysis.objectCount;
nullCount += analysis.nullCount;
if (analysis.maxDepth > maxDepth) {
maxDepth = analysis.maxDepth;
}
}
return StatisticsResult(
totalElements: obj.length,
stringCount: stringCount,
numberCount: numberCount,
boolCount: boolCount,
arrayCount: arrayCount,
objectCount: objectCount + 1,
nullCount: nullCount,
nestedDepth: maxDepth,
);
}
static StatisticsResult _analyzeArray(List<dynamic> arr) {
int stringCount = 0;
int numberCount = 0;
int boolCount = 0;
int arrayCount = 0;
int objectCount = 0;
int nullCount = 0;
int maxDepth = 0;
for (final dynamic value in arr) {
final ValueAnalysis analysis = _analyzeValue(value, 1);
stringCount += analysis.stringCount;
numberCount += analysis.numberCount;
boolCount += analysis.boolCount;
arrayCount += analysis.arrayCount;
objectCount += analysis.objectCount;
nullCount += analysis.nullCount;
if (analysis.maxDepth > maxDepth) {
maxDepth = analysis.maxDepth;
}
}
return StatisticsResult(
totalElements: arr.length,
stringCount: stringCount,
numberCount: numberCount,
boolCount: boolCount,
arrayCount: arrayCount + 1,
objectCount: objectCount,
nullCount: nullCount,
nestedDepth: maxDepth,
);
}
static ValueAnalysis _analyzeValue(dynamic value, int depth) {
if (value is String) {
return ValueAnalysis(1, 0, 0, 0, 0, 0, depth);
} else if (value is num) {
return ValueAnalysis(0, 1, 0, 0, 0, 0, depth);
} else if (value is bool) {
return ValueAnalysis(0, 0, 1, 0, 0, 0, depth);
} else if (value == null) {
return ValueAnalysis(0, 0, 0, 0, 0, 1, depth);
} else if (value is List) {
int stringCount = 0;
int numberCount = 0;
int boolCount = 0;
int arrayCount = 1;
int objectCount = 0;
int nullCount = 0;
int maxDepth = depth;
for (final dynamic item in value) {
final ValueAnalysis analysis = _analyzeValue(item, depth + 1);
stringCount += analysis.stringCount;
numberCount += analysis.numberCount;
boolCount += analysis.boolCount;
arrayCount += analysis.arrayCount;
objectCount += analysis.objectCount;
nullCount += analysis.nullCount;
if (analysis.maxDepth > maxDepth) {
maxDepth = analysis.maxDepth;
}
}
return ValueAnalysis(stringCount, numberCount, boolCount, arrayCount, objectCount, nullCount, maxDepth);
} else if (value is Map) {
int stringCount = 0;
int numberCount = 0;
int boolCount = 0;
int arrayCount = 0;
int objectCount = 1;
int nullCount = 0;
int maxDepth = depth;
for (final dynamic item in value.values) {
final ValueAnalysis analysis = _analyzeValue(item, depth + 1);
stringCount += analysis.stringCount;
numberCount += analysis.numberCount;
boolCount += analysis.boolCount;
arrayCount += analysis.arrayCount;
objectCount += analysis.objectCount;
nullCount += analysis.nullCount;
if (analysis.maxDepth > maxDepth) {
maxDepth = analysis.maxDepth;
}
}
return ValueAnalysis(stringCount, numberCount, boolCount, arrayCount, objectCount, nullCount, maxDepth);
}
return ValueAnalysis(0, 0, 0, 0, 0, 0, depth);
}
}
class ValueAnalysis {
final int stringCount;
final int numberCount;
final int boolCount;
final int arrayCount;
final int objectCount;
final int nullCount;
final int maxDepth;
ValueAnalysis(
this.stringCount,
this.numberCount,
this.boolCount,
this.arrayCount,
this.objectCount,
this.nullCount,
this.maxDepth,
);
}
class StatisticsResult {
final int totalElements;
final int stringCount;
final int numberCount;
final int boolCount;
final int arrayCount;
final int objectCount;
final int nullCount;
final int nestedDepth;
StatisticsResult({
required this.totalElements,
required this.stringCount,
required this.numberCount,
required this.boolCount,
required this.arrayCount,
required this.objectCount,
required this.nullCount,
required this.nestedDepth,
});
String toString() {
return '''
✅ 统计结果:
- 顶层元素数量: $totalElements
- 字符串字段数: $stringCount
- 数字字段数: $numberCount
- 布尔字段数: $boolCount
- 数组字段数: $arrayCount
- 对象字段数: $objectCount
- 空值字段数: $nullCount
- 最大嵌套深度: $nestedDepth''';
}
}
使用示例
void main() {
final String complexJson = '''
{
"user": {
"name": "张三",
"age": 25,
"isStudent": true,
"scores": [95, 88, 92],
"address": {
"city": "北京",
"district": "朝阳区"
}
},
"projects": [
{"name": "App1", "stars": 100},
{"name": "App2", "stars": 200}
]
}''';
final StatisticsResult result = JsonStatistics.analyze(complexJson);
print(result);
}
练习任务三:字段提取
任务描述
实现一个JSON字段提取工具,能够递归遍历JSON结构,提取所有字段的完整路径。
实现方案
import 'dart:convert';
class JsonFieldExtractor {
static List<String> extractFieldPaths(String jsonString) {
final List<String> paths = [];
final dynamic parsed = json.decode(jsonString);
if (parsed is Map<String, dynamic>) {
_extractFromObject(parsed, '', paths);
} else if (parsed is List) {
_extractFromArray(parsed, '', paths);
}
return paths;
}
static void _extractFromObject(Map<String, dynamic> obj, String prefix, List<String> paths) {
for (final String key in obj.keys) {
final String currentPath = prefix.isEmpty ? key : '$prefix.$key';
paths.add(currentPath);
final dynamic value = obj[key];
if (value is Map<String, dynamic>) {
_extractFromObject(value, currentPath, paths);
} else if (value is List) {
_extractFromArray(value, currentPath, paths);
}
}
}
static void _extractFromArray(List<dynamic> arr, String prefix, List<String> paths) {
for (int i = 0; i < arr.length; i++) {
final String currentPath = '$prefix[$i]';
final dynamic value = arr[i];
if (value is Map<String, dynamic>) {
_extractFromObject(value, currentPath, paths);
} else if (value is List) {
_extractFromArray(value, currentPath, paths);
} else {
paths.add(currentPath);
}
}
}
static Map<String, dynamic> extractFieldsByType(String jsonString, Type type) {
final Map<String, dynamic> result = {};
final dynamic parsed = json.decode(jsonString);
if (parsed is Map<String, dynamic>) {
_extractFieldsByTypeFromObject(parsed, '', type, result);
} else if (parsed is List) {
_extractFieldsByTypeFromArray(parsed, '', type, result);
}
return result;
}
static void _extractFieldsByTypeFromObject(
Map<String, dynamic> obj,
String prefix,
Type type,
Map<String, dynamic> result,
) {
for (final String key in obj.keys) {
final String currentPath = prefix.isEmpty ? key : '$prefix.$key';
final dynamic value = obj[key];
if (value.runtimeType == type) {
result[currentPath] = value;
} else if (value is Map<String, dynamic>) {
_extractFieldsByTypeFromObject(value, currentPath, type, result);
} else if (value is List) {
_extractFieldsByTypeFromArray(value, currentPath, type, result);
}
}
}
static void _extractFieldsByTypeFromArray(
List<dynamic> arr,
String prefix,
Type type,
Map<String, dynamic> result,
) {
for (int i = 0; i < arr.length; i++) {
final String currentPath = '$prefix[$i]';
final dynamic value = arr[i];
if (value.runtimeType == type) {
result[currentPath] = value;
} else if (value is Map<String, dynamic>) {
_extractFieldsByTypeFromObject(value, currentPath, type, result);
} else if (value is List) {
_extractFieldsByTypeFromArray(value, currentPath, type, result);
}
}
}
}
使用示例
void main() {
final String jsonString = '''
{
"user": {
"name": "张三",
"profile": {
"city": "北京",
"hobbies": ["编程", "阅读"]
}
},
"projects": [
{"name": "App1", "stars": 100},
{"name": "App2", "stars": 200}
]
}''';
// 提取所有字段路径
final List<String> allPaths = JsonFieldExtractor.extractFieldPaths(jsonString);
print('所有字段路径:');
for (final String path in allPaths) {
print('• $path');
}
// 提取所有字符串字段
final Map<String, dynamic> stringFields = JsonFieldExtractor.extractFieldsByType(jsonString, String);
print('\n所有字符串字段:');
for (final MapEntry<String, dynamic> entry in stringFields.entries) {
print('${entry.key}: "${entry.value}"');
}
}
练习任务四:数据转换
任务描述
实现一个JSON数据转换工具,能够将复杂的JSON结构转换为扁平化的键值对形式。
实现方案
import 'dart:convert';
class JsonTransformer {
static Map<String, dynamic> flatten(String jsonString) {
final Map<String, dynamic> result = {};
final dynamic parsed = json.decode(jsonString);
if (parsed is Map<String, dynamic>) {
_flattenObject(parsed, '', result);
} else if (parsed is List) {
_flattenArray(parsed, '', result);
} else {
result[''] = parsed;
}
return result;
}
static void _flattenObject(Map<String, dynamic> obj, String prefix, Map<String, dynamic> result) {
for (final String key in obj.keys) {
final String currentKey = prefix.isEmpty ? key : '$prefix.$key';
final dynamic value = obj[key];
if (value is Map<String, dynamic>) {
_flattenObject(value, currentKey, result);
} else if (value is List) {
_flattenArray(value, currentKey, result);
} else {
result[currentKey] = value;
}
}
}
static void _flattenArray(List<dynamic> arr, String prefix, Map<String, dynamic> result) {
for (int i = 0; i < arr.length; i++) {
final String currentKey = '$prefix[$i]';
final dynamic value = arr[i];
if (value is Map<String, dynamic>) {
_flattenObject(value, currentKey, result);
} else if (value is List) {
_flattenArray(value, currentKey, result);
} else {
result[currentKey] = value;
}
}
}
static Map<String, String> extractAllStrings(String jsonString) {
final Map<String, String> result = {};
final Map<String, dynamic> flattened = flatten(jsonString);
for (final String key in flattened.keys) {
if (flattened[key] is String) {
result[key] = flattened[key] as String;
}
}
return result;
}
static Map<String, num> extractAllNumbers(String jsonString) {
final Map<String, num> result = {};
final Map<String, dynamic> flattened = flatten(jsonString);
for (final String key in flattened.keys) {
if (flattened[key] is num) {
result[key] = flattened[key] as num;
}
}
return result;
}
static List<Map<String, dynamic>> convertToListOfMaps(String jsonString) {
final dynamic parsed = json.decode(jsonString);
if (parsed is List) {
return parsed.where((item) => item is Map).map((item) => item as Map<String, dynamic>).toList();
} else if (parsed is Map) {
return [parsed as Map<String, dynamic>];
} else {
return [];
}
}
}
使用示例
void main() {
final String nestedJson = '''
{
"data": {
"items": [
{"id": 1, "name": "Item1", "details": {"price": 100, "stock": 50}},
{"id": 2, "name": "Item2", "details": {"price": 200, "stock": 30}}
],
"pagination": {"page": 1, "total": 100}
}
}''';
// 扁平化JSON
final Map<String, dynamic> flattened = JsonTransformer.flatten(nestedJson);
print('扁平化结果:');
for (final MapEntry<String, dynamic> entry in flattened.entries) {
print('${entry.key}: ${entry.value}');
}
// 提取所有字符串
final Map<String, String> strings = JsonTransformer.extractAllStrings(nestedJson);
print('\n所有字符串:');
for (final MapEntry<String, String> entry in strings.entries) {
print('${entry.key}: "${entry.value}"');
}
// 提取所有数字
final Map<String, num> numbers = JsonTransformer.extractAllNumbers(nestedJson);
print('\n所有数字:');
for (final MapEntry<String, num> entry in numbers.entries) {
print('${entry.key}: ${entry.value}');
}
}
综合案例:API响应处理
场景描述
在实际开发中,我们经常需要处理来自API的JSON响应。这个案例将展示如何综合运用前面学到的知识来处理一个完整的API响应。
实现方案
import 'dart:convert';
class ApiResponseHandler {
static ApiResult<T> parseResponse<T>(
String responseBody,
T Function(Map<String, dynamic>) fromJson,
) {
try {
final Map<String, dynamic> response = json.decode(responseBody) as Map<String, dynamic>;
// 验证响应格式
if (!response.containsKey('data')) {
return ApiResult.error('缺少data字段');
}
// 检查状态码
final int? statusCode = response['status'] as int?;
if (statusCode != null && statusCode >= 400) {
final String? message = response['message'] as String?;
return ApiResult.error(message ?? '请求失败');
}
// 提取数据
final dynamic data = response['data'];
if (data is List) {
final List<T> items = data.map((item) => fromJson(item as Map<String, dynamic>)).toList();
return ApiResult.success(items);
} else if (data is Map) {
final T item = fromJson(data as Map<String, dynamic>);
return ApiResult.success(item);
} else {
return ApiResult.error('数据格式不正确');
}
} on FormatException catch (e) {
return ApiResult.error('JSON格式错误: $e');
} catch (e) {
return ApiResult.error('解析失败: $e');
}
}
static ApiResult<List<T>> parseListResponse<T>(
String responseBody,
T Function(Map<String, dynamic>) fromJson,
) {
try {
final Map<String, dynamic> response = json.decode(responseBody) as Map<String, dynamic>;
if (!response.containsKey('data')) {
return ApiResult.error('缺少data字段');
}
final dynamic data = response['data'];
if (data is Map && data.containsKey('items')) {
final dynamic items = data['items'];
if (items is List) {
final List<T> result = items.map((item) => fromJson(item as Map<String, dynamic>)).toList();
// 提取分页信息
final Pagination? pagination;
if (data.containsKey('pagination')) {
pagination = Pagination.fromJson(data['pagination'] as Map<String, dynamic>);
} else {
pagination = null;
}
return ApiResult.success(result, pagination: pagination);
}
} else if (data is List) {
final List<T> result = data.map((item) => fromJson(item as Map<String, dynamic>)).toList();
return ApiResult.success(result);
}
return ApiResult.error('数据格式不正确');
} catch (e) {
return ApiResult.error('解析失败: $e');
}
}
}
class ApiResult<T> {
final bool success;
final T? data;
final String? error;
final Pagination? pagination;
ApiResult._({
required this.success,
this.data,
this.error,
this.pagination,
});
factory ApiResult.success(T data, {Pagination? pagination}) {
return ApiResult._(
success: true,
data: data,
pagination: pagination,
);
}
factory ApiResult.error(String error) {
return ApiResult._(
success: false,
error: error,
);
}
}
class Pagination {
final int page;
final int total;
final int? pageSize;
final int? totalPages;
Pagination({
required this.page,
required this.total,
this.pageSize,
this.totalPages,
});
factory Pagination.fromJson(Map<String, dynamic> json) {
return Pagination(
page: json['page'] as int,
total: json['total'] as int,
pageSize: json['pageSize'] as int?,
totalPages: json['totalPages'] as int?,
);
}
}
class Product {
final int id;
final String name;
final double price;
final int stock;
Product({
required this.id,
required this.name,
required this.price,
required this.stock,
});
factory Product.fromJson(Map<String, dynamic> json) {
return Product(
id: json['id'] as int,
name: json['name'] as String,
price: (json['price'] as num).toDouble(),
stock: json['stock'] as int,
);
}
}
使用示例
void main() {
// 模拟API响应
final String apiResponse = '''
{
"status": 200,
"message": "success",
"data": {
"items": [
{"id": 1, "name": "iPhone 15", "price": 5999, "stock": 100},
{"id": 2, "name": "MacBook Pro", "price": 12999, "stock": 50},
{"id": 3, "name": "iPad Air", "price": 4799, "stock": 80}
],
"pagination": {
"page": 1,
"pageSize": 10,
"total": 100,
"totalPages": 10
}
}
}''';
// 解析响应
final ApiResult<List<Product>> result = ApiResponseHandler.parseListResponse(
apiResponse,
Product.fromJson,
);
if (result.success && result.data != null) {
print('✅ 解析成功!');
print('产品数量: ${result.data!.length}');
for (final Product product in result.data!) {
print('• ${product.name}: ¥${product.price} (库存: ${product.stock})');
}
if (result.pagination != null) {
print('\n分页信息:');
print('当前页: ${result.pagination!.page}');
print('总记录: ${result.pagination!.total}');
print('总页数: ${result.pagination!.totalPages}');
}
} else {
print('❌ 解析失败: ${result.error}');
}
}
综合案例:数据清洗与转换
场景描述
在数据处理过程中,我们经常需要对原始JSON数据进行清洗和转换,去除不需要的字段,重命名字段,或者转换数据格式。
实现方案
import 'dart:convert';
class DataCleaner {
static Map<String, dynamic> clean(
Map<String, dynamic> data, {
List<String>? removeFields,
Map<String, String>? renameFields,
Map<String, dynamic Function(dynamic)>? transformFields,
}) {
final Map<String, dynamic> result = {};
for (final String key in data.keys) {
// 移除指定字段
if (removeFields != null && removeFields.contains(key)) {
continue;
}
// 重命名字段
final String newKey = renameFields != null && renameFields.containsKey(key)
? renameFields[key]!
: key;
dynamic value = data[key];
// 转换字段值
if (transformFields != null && transformFields.containsKey(key)) {
try {
value = transformFields[key]!(value);
} catch (e) {
print('字段转换失败: $key - $e');
}
}
// 递归处理嵌套对象
if (value is Map<String, dynamic>) {
value = clean(value,
removeFields: removeFields,
renameFields: renameFields,
transformFields: transformFields,
);
}
// 递归处理数组
if (value is List) {
value = _cleanArray(value,
removeFields: removeFields,
renameFields: renameFields,
transformFields: transformFields,
);
}
result[newKey] = value;
}
return result;
}
static List<dynamic> _cleanArray(
List<dynamic> arr, {
List<String>? removeFields,
Map<String, String>? renameFields,
Map<String, dynamic Function(dynamic)>? transformFields,
}) {
final List<dynamic> result = [];
for (final dynamic item in arr) {
if (item is Map<String, dynamic>) {
result.add(clean(item,
removeFields: removeFields,
renameFields: renameFields,
transformFields: transformFields,
));
} else if (item is List) {
result.add(_cleanArray(item,
removeFields: removeFields,
renameFields: renameFields,
transformFields: transformFields,
));
} else {
result.add(item);
}
}
return result;
}
static Map<String, dynamic> filterByType(Map<String, dynamic> data, Type type) {
final Map<String, dynamic> result = {};
for (final String key in data.keys) {
if (data[key].runtimeType == type) {
result[key] = data[key];
} else if (data[key] is Map<String, dynamic>) {
final Map<String, dynamic> filtered = filterByType(data[key] as Map<String, dynamic>, type);
if (filtered.isNotEmpty) {
result[key] = filtered;
}
}
}
return result;
}
static Map<String, dynamic> merge(Map<String, dynamic> base, Map<String, dynamic> updates) {
final Map<String, dynamic> result = Map.from(base);
for (final String key in updates.keys) {
if (base.containsKey(key) && base[key] is Map && updates[key] is Map) {
result[key] = merge(base[key] as Map<String, dynamic>, updates[key] as Map<String, dynamic>);
} else if (base.containsKey(key) && base[key] is List && updates[key] is List) {
result[key] = [...base[key] as List, ...updates[key] as List];
} else {
result[key] = updates[key];
}
}
return result;
}
}
使用示例
void main() {
// 原始数据
final Map<String, dynamic> rawData = {
'id': 1,
'user_name': 'zhangsan',
'user_email': 'zhang@example.com',
'age': 25,
'created_at': '2024-01-15T10:30:00Z',
'password': '******',
'meta': {
'version': 1,
'tags': ['admin', 'active'],
'internal_id': 'INT-001',
},
'profile': {
'full_name': '张三',
'address': '北京市朝阳区',
'phone': '13800138000',
},
};
// 数据清洗配置
final cleaned = DataCleaner.clean(
rawData,
removeFields: ['password', 'internal_id'],
renameFields: {
'user_name': 'username',
'user_email': 'email',
'created_at': 'createdAt',
'full_name': 'fullName',
},
transformFields: {
'created_at': (value) => DateTime.parse(value as String),
'age': (value) => (value as int).toString(),
},
);
print('清洗后的数据:');
print(json.encode(cleaned));
// 合并更新
final Map<String, dynamic> updates = {
'age': 26,
'profile': {
'phone': '13900139000',
},
};
final Map<String, dynamic> merged = DataCleaner.merge(cleaned, updates);
print('\n合并后的数据:');
print(json.encode(merged));
}
鸿蒙平台综合实践
场景描述
在鸿蒙平台上开发一个完整的JSON数据处理应用,包含数据验证、统计、提取和转换功能。
实现方案
import 'dart:convert';
import 'package:flutter/material.dart';
class JsonPracticeApp extends StatelessWidget {
const JsonPracticeApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'JSON综合练习',
theme: ThemeData(primaryColor: const Color(0xFF00CEC9)),
home: const JsonPracticeHome(),
);
}
}
class JsonPracticeHome extends StatefulWidget {
const JsonPracticeHome({super.key});
State<JsonPracticeHome> createState() => _JsonPracticeHomeState();
}
class _JsonPracticeHomeState extends State<JsonPracticeHome> {
String _inputJson = '';
String _result = '';
bool _showResult = false;
String _selectedTask = 'validate';
void _executeTask() {
setState(() {
_showResult = false;
});
if (_inputJson.isEmpty) {
setState(() {
_result = '请输入JSON内容';
_showResult = true;
});
return;
}
try {
switch (_selectedTask) {
case 'validate':
_validateJson();
break;
case 'count':
_countElements();
break;
case 'extract':
_extractFields();
break;
case 'transform':
_transformJson();
break;
}
} catch (e) {
setState(() {
_result = '❌ 操作失败: $e';
_showResult = true;
});
}
}
void _validateJson() {
final dynamic parsed = json.decode(_inputJson);
setState(() {
if (parsed is Map) {
_result = '✅ JSON验证通过!\n类型: Object\n键数量: ${parsed.length}';
} else if (parsed is List) {
_result = '✅ JSON验证通过!\n类型: Array\n元素数量: ${parsed.length}';
} else {
_result = '✅ JSON验证通过!\n值: $parsed';
}
_showResult = true;
});
}
void _countElements() {
final dynamic parsed = json.decode(_inputJson);
if (parsed is Map<String, dynamic>) {
final StatisticsResult stats = JsonStatistics.analyze(_inputJson);
setState(() {
_result = stats.toString();
_showResult = true;
});
} else if (parsed is List) {
setState(() {
_result = '''
✅ 数组统计:
- 元素总数: ${parsed.length}
- 字符串元素: ${parsed.where((v) => v is String).length}
- 数字元素: ${parsed.where((v) => v is num).length}
- 布尔元素: ${parsed.where((v) => v is bool).length}
- 对象元素: ${parsed.where((v) => v is Map).length}''';
_showResult = true;
});
}
}
void _extractFields() {
final List<String> paths = JsonFieldExtractor.extractFieldPaths(_inputJson);
setState(() {
_result = '✅ 提取的字段路径:\n${paths.map((k) => '• $k').join('\n')}';
_showResult = true;
});
}
void _transformJson() {
final Map<String, String> strings = JsonTransformer.extractAllStrings(_inputJson);
setState(() {
_result = '✅ 提取的字符串值:\n${strings.entries.map((e) => '${e.key}: "${e.value}"').join('\n')}';
_showResult = true;
});
}
void _loadExample(String type) {
setState(() {
switch (type) {
case 'simple':
_inputJson = '{"name":"张三","age":25,"isStudent":true,"scores":[95,88,92]}';
break;
case 'nested':
_inputJson = '{"user":{"name":"张三","profile":{"city":"北京","hobbies":["编程","阅读"]}},"projects":[{"name":"App1","stars":100},{"name":"App2","stars":200}]}';
break;
case 'array':
_inputJson = '["苹果","香蕉","橙子","葡萄"]';
break;
case 'complex':
_inputJson = '{"status":200,"data":{"items":[{"id":1,"name":"Item1","details":{"price":100,"stock":50}},{"id":2,"name":"Item2","details":{"price":200,"stock":30}}],"pagination":{"page":1,"total":100}}}';
break;
}
});
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('JSON综合练习'),
backgroundColor: const Color(0xFF00CEC9),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTaskSelector(),
_buildInputArea(),
_buildExampleButtons(),
_buildExecuteButton(),
if (_showResult) _buildResultCard(),
_buildCaseStudy(),
],
),
),
);
}
Widget _buildTaskSelector() {
final tasks = [
{'value': 'validate', 'label': '验证JSON', 'desc': '检查JSON格式是否正确'},
{'value': 'count', 'label': '统计元素', 'desc': '统计JSON中的各种元素数量'},
{'value': 'extract', 'label': '提取字段', 'desc': '提取所有字段路径'},
{'value': 'transform', 'label': '转换数据', 'desc': '提取所有字符串值'},
];
return Card(
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const Text('选择练习任务', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
const SizedBox(height: 12),
...tasks.map((task) => RadioListTile(
title: Text(task['label']!),
subtitle: Text(task['desc']!),
value: task['value'],
groupValue: _selectedTask,
onChanged: (value) => setState(() => _selectedTask = value!),
activeColor: const Color(0xFF00CEC9),
)),
],
),
),
);
}
Widget _buildInputArea() {
return Card(
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('输入JSON:', style: TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 12),
Container(
height: 150,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: const Color(0xFF1E1E1E),
border: Border.all(color: Colors.grey),
),
child: TextField(
onChanged: (value) => _inputJson = value,
maxLines: null,
expands: true,
decoration: const InputDecoration(
hintText: '在此输入JSON内容...',
border: InputBorder.none,
contentPadding: EdgeInsets.all(12),
),
style: const TextStyle(fontFamily: 'Monaco', fontSize: 13, color: Colors.green),
),
),
],
),
),
);
}
Widget _buildExampleButtons() {
final examples = [
{'label': '简单对象', 'type': 'simple', 'color': Colors.green},
{'label': '嵌套对象', 'type': 'nested', 'color': Colors.blue},
{'label': '数组', 'type': 'array', 'color': Colors.orange},
{'label': '复杂结构', 'type': 'complex', 'color': Colors.purple},
];
return Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Wrap(
spacing: 8,
children: examples.map((example) {
final String type = example['type'] as String;
return ElevatedButton(
onPressed: () => _loadExample(type),
style: ElevatedButton.styleFrom(
backgroundColor: example['color'] as Color,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
),
child: Text(example['label']!, style: const TextStyle(fontSize: 13)),
);
}).toList(),
),
);
}
Widget _buildExecuteButton() {
return Center(
child: ElevatedButton(
onPressed: _executeTask,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF00CEC9),
padding: const EdgeInsets.symmetric(horizontal: 48, vertical: 16),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)),
),
child: const Text('执行任务', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
),
);
}
Widget _buildResultCard() {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
color: _result.contains('❌') ? const Color(0xFFFFEBEE) : const Color(0xFFE8F5E9),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_result.contains('❌') ? '❌ 执行结果' : '✅ 执行结果',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: _result.contains('❌') ? Colors.red : Colors.green,
),
),
const SizedBox(height: 12),
Text(_result),
],
),
),
),
);
}
Widget _buildCaseStudy() {
return Card(
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('综合案例: API响应处理', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
const SizedBox(height: 12),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: const Color(0xFFF5F5F5),
),
padding: const EdgeInsets.all(12),
child: const Text(
'''// 综合应用场景:处理API响应
// 1. 验证响应格式
if (!response.containsKey('data')) {
throw Exception('缺少data字段');
}
// 2. 提取列表数据
List<Product> products = (response['data']['items'] as List)
.map((item) => Product.fromJson(item))
.toList();
// 3. 获取分页信息
Pagination pagination = Pagination.fromJson(
response['data']['pagination']);
// 4. 处理可选字段
String? nextPage = response['data']['next_page'] as String?;
// 5. 格式化输出日志
print(JsonEncoder.withIndent(' ').convert(response));''',
style: TextStyle(fontFamily: 'Monaco', fontSize: 12),
),
),
],
),
),
);
}
}
总结
通过本章的综合练习,我们将前面所学的JSON解析知识融会贯通,实现了以下功能:
- JSON验证:检查JSON格式是否正确,识别JSON类型
- 数据统计:统计JSON中各种元素的数量和嵌套深度
- 字段提取:递归遍历JSON结构,提取所有字段路径
- 数据转换:扁平化JSON结构,提取特定类型的数据
- API响应处理:完整的API响应解析和错误处理
- 数据清洗:字段移除、重命名和值转换
这些功能在实际开发中非常实用,掌握它们可以帮助我们更高效地处理JSON数据。在鸿蒙平台上开发时,还需要注意性能优化和资源限制,确保应用在各种设备上都能流畅运行。
通过不断练习和实践,相信你已经成为JSON处理的高手!
更多推荐



所有评论(0)