json2dart Guide
简体中文 | Deutsch | Português | 日本語 | 한국어 | English
I. Overview
json2dart is a Flutter plugin collection that provides:
- JSON to Dart Model Conversion
- Null safety support
- Multi-field parsing
- Type-safe conversion
- Default value handling
- SQLite Database Operations
- Automatic table structure generation
- Complete CRUD operations
- Complex type support
- Batch operation support
- Database Visualization Debugging
- View all data tables
- View table structures
- View table data
- SQL statement highlighting
II. Installation
1. Add Dependencies
dependencies:
# JSON parsing base package
json2dart_safe: ^1.5.8
# Database support (choose one)
json2dart_db: ^latest_version # Standard version
json2dart_dbffi: ^latest_version # FFI version (better performance)
# Database viewer tools (choose one)
json2dart_viewer: ^latest_version # Standard version
json2dart_viewerffi: ^latest_version # FFI version
2. Debug Tool Configuration
Requires flutter_ume:
import 'package:json2dart_viewerffi/json2dart_viewerffi.dart';
void main() {
PluginManager.instance
..register(const DBViewer()) // Register database viewer plugin
// ... other plugin registrations
}
III. Basic Usage
1. JSON Parsing
// Parse from Map
Map json = {...};
json.asString("key"); // Get String, returns "" if null
json.asInt("key"); // Get int, returns 0 if null
json.asDouble("key"); // Get double, returns 0.0 if null
json.asBool("key"); // Get bool, returns false if null
json.asBean<T>("key"); // Parse object
json.asList<T>("key"); // Parse array
// Multi-field parsing
json.asStrings(["name", "user_name"]); // Try parsing name then user_name
json.asInts(["id", "user_id"]);
json.asBools(["is_vip", "vip"]);
2. Error Handling
// Add error callback
Json2Dart.instance.addCallback((String error) {
print("Parsing error: $error");
});
// Detailed error information
Json2Dart.instance.addDetailCallback((String method, String key, Map? map) {
print("Method: $method, Key: $key, Data: $map");
});
IV. Usage Scenarios
1. JSON Parsing Only
If you only need JSON parsing functionality, just add the base package:
dependencies:
json2dart_safe: ^1.5.8
Example Model:
import 'package:json2dart_safe/json2dart.dart';
class UserModel {
final String? username;
final String? nickname;
final int? age;
final List<String>? hobbies;
UserModel({
this.username,
this.nickname,
this.age,
this.hobbies,
});
// JSON serialization
Map<String, dynamic> toJson() => {
'username': username,
'nickname': nickname,
'age': age,
'hobbies': hobbies,
};
// JSON deserialization
factory UserModel.fromJson(Map json) {
return UserModel(
username: json.asString('username'),
nickname: json.asString('nickname'),
age: json.asInt('age'),
hobbies: json.asList<String>('hobbies'),
);
}
}
Usage example:
// Parse JSON
Map<String, dynamic> json = {
'username': 'test',
'age': 18,
'hobbies': ['reading', 'gaming']
};
var user = UserModel.fromJson(json);
// Convert to JSON
Map<String, dynamic> data = user.toJson();
2. With Database Support
If you need database support, add the complete dependencies:
dependencies:
json2dart_safe: ^1.5.8
json2dart_db: ^latest_version
json2dart_viewer: ^latest_version
In this case you need to:
- Have your Model class extend BaseDbModel
- Implement the primaryKeyAndValue method
- Create corresponding Dao class
See the next chapter for a complete example.
V. Complete Example
1. Model Definition (user_model.dart)
import 'dart:convert';
import 'package:json2dart_safe/json2dart.dart';
/// User information model
class UserModel with BaseDbModel {
// Database primary key, auto-increment
int? userId;
// Basic fields
String? username;
String? nickname;
String? avatar;
int? age;
double? height;
bool? isVip;
DateTime? birthday;
// Complex types
List<String>? hobbies; // Hobby list
List<int>? followingIds; // Following user IDs
Map<String, dynamic>? extra; // Extension fields
// Constructor
UserModel({
this.userId,
this.username,
this.nickname,
this.avatar,
this.age,
this.height,
this.isVip,
this.birthday,
this.hobbies,
this.followingIds,
this.extra,
});
// JSON serialization
Map<String, dynamic> toJson() => {
'user_id': userId,
'username': username,
'nickname': nickname,
'avatar': avatar,
'age': age,
'height': height,
'is_vip': isVip,
'birthday': birthday?.millisecondsSinceEpoch,
'hobbies': hobbies,
'following_ids': followingIds,
'extra': extra,
};
// JSON deserialization
factory UserModel.fromJson(Map json) {
return UserModel(
userId: json.asInt('user_id'),
username: json.asString('username'),
nickname: json.asString('nickname'),
avatar: json.asString('avatar'),
age: json.asInt('age'),
height: json.asDouble('height'),
isVip: json.asBool('is_vip'),
birthday: json.asInt('birthday') != null
? DateTime.fromMillisecondsSinceEpoch(json.asInt('birthday'))
: null,
hobbies: json.asList<String>('hobbies'),
followingIds: json.asList<int>('following_ids'),
extra: json.asMap('extra'),
);
}
// Static method for database operations
static UserModel toBean(Map json) => UserModel.fromJson(json);
// Override toString for debugging
@override
String toString() => jsonEncode(toJson());
// Override equality operator
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is UserModel &&
runtimeType == other.runtimeType &&
userId == other.userId;
@override
int get hashCode => userId.hashCode;
// Implement BaseDbModel method, return primary key and value
@override
Map<String, dynamic> get primaryKeyAndValue => {'user_id': userId};
}
2. Database Operations Class (user_dao.dart)
import 'package:json2dart_db/database/base_dao.dart';
import '../models/user_model.dart';
class UserDao extends BaseDao<UserModel> {
UserDao() : super('tb_user', UserModel.toBean);
// Query by username
Future<UserModel?> queryByUsername(String username) async {
List<UserModel> users = await query(
where: 'username = ?',
whereArgs: [username],
);
return users.isEmpty ? null : users.first;
}
// Query VIP users
Future<List<UserModel>> queryVipUsers() async {
return query(
where: 'is_vip = ?',
whereArgs: [1],
orderBy: 'user_id DESC',
);
}
// Update user VIP status
Future<bool> updateVipStatus(int userId, bool isVip) async {
int count = await update(
{'is_vip': isVip ? 1 : 0},
where: 'user_id = ?',
whereArgs: [userId],
);
return count > 0;
}
// Batch update following status
Future<void> updateFollowingIds(int userId, List<int> followingIds) async {
await update(
{'following_ids': followingIds},
where: 'user_id = ?',
whereArgs: [userId],
);
}
}
3. Usage Example (user_page.dart)
import '../database/dao/user_dao.dart';
import '../models/user_model.dart';
class UserPage extends StatefulWidget {
@override
_UserPageState createState() => _UserPageState();
}
class _UserPageState extends State<UserPage> {
final UserDao _userDao = UserDao();
Future<void> _addUser() async {
// Create user
var user = UserModel(
username: 'test_user',
nickname: 'Test User',
age: 18,
isVip: false,
hobbies: ['reading', 'gaming'],
followingIds: [1, 2, 3],
extra: {'score': 100},
);
// Insert into database
int userId = await _userDao.insert(user);
print('Insert successful, User ID: $userId');
// Query user
UserModel? dbUser = await _userDao.queryOne(userId);
print('Query result: $dbUser');
// Update VIP status
await _userDao.updateVipStatus(userId, true);
// Update following list
await _userDao.updateFollowingIds(userId, [4, 5, 6]);
// Query all VIP users
List<UserModel> vipUsers = await _userDao.queryVipUsers();
print('VIP user count: ${vipUsers.length}');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('User Management')),
body: Center(
child: ElevatedButton(
onPressed: _addUser,
child: Text('Add Test User'),
),
),
);
}
}
VI. Database Table Structure
The above model will automatically generate the following table structure:
CREATE TABLE IF NOT EXISTS tb_user (
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT,
nickname TEXT,
avatar TEXT,
age INTEGER,
height REAL,
is_vip INTEGER,
birthday INTEGER,
hobbies TEXT, -- List type will be automatically converted to JSON string
following_ids TEXT, -- List type will be automatically converted to JSON string
extra TEXT -- Map type will be automatically converted to JSON string
)
Key features:
- Supported Data Types:
- INTEGER: for int type
- REAL: for double type
- TEXT: for String type
- INTEGER: for bool type (0/1)
- Complex Type Handling:
- List and Map types are automatically converted to JSON strings
- Automatically parsed back to original types when reading
- No need to write manual type converters
- Primary Key Configuration:
- Uses user_id as primary key
- Set to auto-increment
- Specified through primaryKeyAndValue method
VII. Important Notes
- Database Related:
- New fields must be added manually during database upgrades
- Complex types will occupy more storage space
- Debug tools are recommended for Debug mode only
- FFI version offers better performance but requires additional configuration
- Type Safety:
- All fields should be nullable
- Type checking during JSON parsing
- Type conversion during database operations
- Performance Optimization:
- Avoid storing large complex types
- Design table structure and indexes properly
- Use transactions for batch operations
VIII. Example Projects
For complete examples, refer to: