openplanning

Xử lý Dart JSON với gói dart_json_mapper

  1. dart_json_mapper
  2. Cài đặt thư viện
  3. Ví dụ
  4. Phụ lục

1. dart_json_mapper

dart_json_mapper là một thư viện cung cấp một giải pháp tốt hơn so với dart:convert để làm việc với các dữ liệu JSON, nó phù hợp với các ứng dụng có mô hình JSON phức tạp. Tuy nhiên, để sử dụng nó bạn cần một vài bước cấu hình. Với các ứng dụng nhỏ bạn nên sử dụng thư viện dart:convert - đơn giản và không cần bất kỳ một cấu hình bổ xung nào.
Thư viện dart_json_mapper lấy cảm hứng từ json2typescript, serde, gson, tính năng ngang bằng với Java Jackson rất phổ biến và chỉ có bốn Annotation cần nhớ để bao gồm tất cả các trường hợp sử dụng có thể.
dart_json_mapper vs json_serializable
json_serializable là một thư viện xử lý JSON tốt hơn dart:convert. Tuy nhiên, nó chỉ là là một thư viện bán tự động, và không thể so sánh với các tính năng mà dart_json_mapper mang lại.
  • Dart json serializable

2. Cài đặt thư viện

Đế sử dụng thư viện dart_json_mapper bạn cần khai báo nó trong file pubspec.yaml:
pubspec.yaml
dependencies:
  dart_json_mapper:

dev_dependencies:
  build_runner:

3. Ví dụ

Đầu tiên, thêm file build.yaml vào project của bạn. Đây là file cấu hình, được sử dụng để chỉ dẫn cho build_runner sinh ra các file mã nguồn mới từ các file mã nguồn được chỉ định.
build.yaml
targets:
  $default:
    builders:
      dart_json_mapper:
        generate_for:
          # here should be listed entry point files having 'void main()' function
          - lib/model/model.dart

      # This part is needed to tell original reflectable builder to stay away
      # it overrides default options for reflectable builder to an **empty** set of files
      reflectable:
        generate_for:
          - no/files
Tiếp theo, tạo các lớp Model:
dart_14139_dart_json_mapper (Your Project Name)
  - lib
      - model
           - model.dart
           - model_file1.dart
           - model_file2.dart
@jsonSerializable
Chú thích (annotation) này được sử dụng cho một lớp. Thư viện dart_json_mapper sẽ sinh ra mã để chuyển đổi đối tượng của lớp này thành JSON và ngược lại.
@JsonProperty
Chú thích (Annotation) này là một tuỳ chọn, được sử dụng cho các thuộc tính (properties) của lớp. Nó chỉ định tên thuộc tính JSON tương ứng với một tên thuộc tính của lớp nếu chúng khác nhau.
@jsonSerializable
class Employee {
  @JsonProperty(name: 'employeeName') // JSON Property
  String name; // Dart Property 
  String email;
  ...
}
@jsonSerializable
class Employee { 
  @JsonProperty(ignore: true)
  String? privateEmail; // This property will be Ignored.
}
Sử dụng @JsonProperty(ignore:true) cho một thuộc tính để bỏ qua nó.
model_file1.dart: Chứa các lớp ContactEmployee, với các quy tắc để chuyển đổi chúng sang các cấu trúc JSON và ngược lại.
model_file1.dart
part of 'model.dart';

@jsonSerializable
class Contact {
  String address;
  String phone;

  Contact(this.address, this.phone); // Constructor
}

@jsonSerializable
class Employee {
  @JsonProperty(name: 'employeeName') // JSON Property Name!!
  String name; // Dart Property Name
  String email;
  Contact contact;

  @JsonProperty(ignore: true) 
  String? privateEmail; // This property will be Ignored.

  Employee(this.name, this.email, this.contact); // Constructor
}
model_file2.dart: Chứa lớp Company, với các quy tắc để chuyển đổi nó sang các cấu trúc JSON và ngược lại.
model_file2.dart
part of 'model.dart';

@jsonSerializable
class Company {
  @JsonProperty(name: 'companyName') // JSON Property Name
  String name; // Dart Property Name
  Contact contact;

  Company(this.name, this.contact); // Constructor
}
model.dart
import 'package:dart_json_mapper/dart_json_mapper.dart';

part 'model_file1.dart';
part 'model_file2.dart';

// This main() function is required!
void main() {
  // Empty
}
Mở cửa sổ Terminal trên IDE:
  • View > Terminal (Visual Studio Code)
  • View > Tool Windows > Terminal (Android Studio)
Thực thi lệnh dưới đây để dart_json_mapper sinh ra mã mở rộng cho các lớp Model.
dart run build_runner build --delete-conflicting-outputs
Xem thêm phần phụ lục ở phía cuối bài viết nếu bạn nhận được một lỗi khi cố gắng chạy lệnh này:
dart run build_runner build --delete-conflicting-outputs
dart run build_runner build --delete-conflicting-outputs
[INFO] Generating build script completed, took 415ms
[INFO] Reading cached asset graph completed, took 144ms
[INFO] Checking for updates since last build completed, took 768ms
[INFO] Running build completed, took 3.7s
[INFO] Caching finalized dependency graph completed, took 83ms
[INFO] Succeeded after 3.8s with 31 outputs (61 actions)
Công cụ sinh ra cho bạn một file Dart. Nếu có bất kỳ thay đổi nào trên các lớp Model hãy chạy lại lệnh ở trên.
  • model.mapper.g.dart
Dart object ==> JSON:
Ví dụ này chỉ cho bạn cách chuyển đổi một đối tượng Dart thành văn bản JSON:
test_dart_to_json_ex1.dart
import 'package:dart_json_mapper/dart_json_mapper.dart';

import 'model/model.dart';
import 'model/model.mapper.g.dart';

void main() {
  initializeJsonMapper(); // <-----------------------

  var contact = Contact('Address 1', '12345');
  var employee = Employee('John Smith', 'john@example.com', contact);

  var jsonString = JsonMapper.toJson(employee);
  print(jsonString);

  print(' --------------------------- ');

  contact = Contact('Address 1', '99999');
  var company = Company('Google', contact);
  jsonString = JsonMapper.toJson(company);

  print(jsonString);
}
Output:
{
 "employeeName": "John Smith",
 "email": "john@example.com",
 "contact": {
  "address": "Address 1",
  "phone": "12345"
 }
}
 ---------------------------
{
 "companyName": "Google",
 "contact": {
  "address": "Address 1",
  "phone": "99999"
 }
}
JSON ==> Dart object:
Tiếp theo là ví dụ chuyển đổi một văn bản JSON thành đối tượng Dart:
test_json_to_dart_ex1.dart
import 'package:dart_json_mapper/dart_json_mapper.dart';

import 'model/model.dart';
import 'model/model.mapper.g.dart';

void main() {
  initializeJsonMapper(); // <-----------------------

  var jsonString1 = '''{
      "employeeName": "John Smith",
      "email": "john@example.com",
      "contact": {
        "address": "Address 1",
        "phone": "12345"
        }
      }''';

  // May be null:
  var employee = JsonMapper.fromJson<Employee>(jsonString1);
  print('Employee Phone: ${employee!.contact.phone}');

  print(' --------------------------- ');

  var jsonString2 = '''{
    "companyName": "Google",
    "contact": {
      "address": "Address 1",
      "phone": "99999"
      }
    }''';
  // May be null:
  var company = JsonMapper.fromJson<Company>(jsonString2);
  print('Company Phone: ${company!.contact.phone}');
}
Output:
Employee Phone: 12345
 ---------------------------
Company Phone: 99999
Map<String,dynamic> ==> Dart object:
test_map_to_dart_ex1.dart
import 'package:dart_json_mapper/dart_json_mapper.dart';

import 'model/model.dart';
import 'model/model.mapper.g.dart';

void main() {
  initializeJsonMapper(); // <-----------------------

  Map<String, dynamic> map1 = {
    "employeeName": "John Smith",
    "email": "john@example.com",
    "contact": {"address": "Address 1", "phone": "12345"}
  };

  // May be null:
  var employee = JsonMapper.fromMap<Employee>(map1);
  print('Employee Phone: ${employee!.contact.phone}');

  print(' --------------------------- ');

  Map<String, dynamic> map2 = {
    "companyName": "Google",
    "contact": {"address": "Address 1", "phone": "99999"}
  };
  // May be null:
  var company = JsonMapper.fromMap<Company>(map2);
  print('Company Phone: ${company!.contact.phone}');
}
Output:
Employee Phone: 12345
 --------------------------- 
Company Phone: 99999

4. Phụ lục

dart run build_runner build --delete-conflicting-outputs
Nếu bạn nhận được lỗi khi cố gắng chạy lệnh trên, hãy xem thử giải pháp dưới đây:
Nếu dự án của bạn là DART:
  • File > Settings > Languages & Frameworks > Dart > Dart SDK path (Windows/Linux)
  • Android Studio > Settings > Languages & Frameworks > Dart > Dart SDK path (Mac)
Run:
/Volumes/Apps/Apps/dart-sdk/bin/dart run build_runner build --delete-conflicting-outputs
Nếu dự án của bạn là FLUTTER:
Run:
/Volumes/Apps/Apps/flutter/bin/dart run build_runner build --delete-conflicting-outputs