# 序列化

编码序列化数据 是一回事——将数据结构转换为字符串。

解码反序列化数据 则是相反的过程——将字符串转换为数据结构。然而,序列化数据 通常也指代将数据结构转换为更加易读的数据格式的整个过程。

目的:

// 平时使用map数据
map['key1']['key2']

// 但是,如果把map映射到一个class,就可以这样用
mapclass.key1.key2

# 前置准备工作

安装插件flutter helppers

image-20220122113210297

需要添加依赖:

dependencies:
  # 序列化
  json_annotation: ^4.1.0
  
dev_dependencies:
  json_serializable: ^5.0.2
  build_runner: ^2.1.4

使用flutter pub get安装依赖。

# 创建模型文件夹

Entity文件夹用于存放后续helpers自动产生的所有的模型文件 -> 主要目的是json转class,class转json互转。

创建一个send_code.dart的文件:

方法一、手动方式:

  • 使用jsc快速创建json_serilizable的结构

    image-20220122113657359

  • 合作jsf快速创建相关联的.g.dart的文件

    import 'package:json_annotation/json_annotation.dart';
    
    part 'send_code_response.g.dart';
    
    ()
    class SendCodeResponse {
    
      SendCodeResponse();
    
      factory SendCodeResponse.fromJson(Map<String, dynamic> json) => _$SendCodeResponseFromJson(json);
      Map<String, dynamic> toJson() => _$SendCodeResponseToJson(this);
    }
    

方法二、自动方式:

通过json数据反向生成.dart的文件:

在线工具:

推荐工具1https://caijinglong.github.io/json2dart/index.html (opens new window)

推荐工具2https://javiercbk.github.io/json_to_dart/ (opens new window)

vscode插件市场也有插件jsontodart

# 创建send_code及.g文件

使用json转dart工具产生的文件

import 'package:json_annotation/json_annotation.dart';

part 'send_code_response.g.dart';

()
class SendCodeResponse extends Object {
  (name: 'code')
  int code;

  (name: 'result')
  Result result;

  SendCodeResponse(
    this.code,
    this.result,
  );

  factory SendCodeResponse.fromJson(Map<String, dynamic> srcJson) =>
      _$SendCodeResponseFromJson(srcJson);

  Map<String, dynamic> toJson() => _$SendCodeResponseToJson(this);
}

()
class Result extends Object {
  (name: 'result')
  int result;

  (name: 'errmsg')
  String errmsg;

  (name: 'ext')
  String ext;

  (name: 'detail')
  List<Detail> detail;

  Result(
    this.result,
    this.errmsg,
    this.ext,
    this.detail,
  );

  factory Result.fromJson(Map<String, dynamic> srcJson) =>
      _$ResultFromJson(srcJson);

  Map<String, dynamic> toJson() => _$ResultToJson(this);
}

()
class Detail extends Object {
  (name: 'result')
  int result;

  (name: 'errmsg')
  String errmsg;

  (name: 'mobile')
  String mobile;

  (name: 'nationcode')
  String nationcode;

  (name: 'isocode')
  String isocode;

  (name: 'sid')
  String sid;

  (name: 'fee')
  int fee;

  Detail(
    this.result,
    this.errmsg,
    this.mobile,
    this.nationcode,
    this.isocode,
    this.sid,
    this.fee,
  );

  factory Detail.fromJson(Map<String, dynamic> srcJson) =>
      _$DetailFromJson(srcJson);

  Map<String, dynamic> toJson() => _$DetailToJson(this);
}

使用命令flutter pub run build_runner build,产生send_conde_response.g.dart文件:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'send_code_response.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

SendCodeResponse _$SendCodeResponseFromJson(Map<String, dynamic> json) =>
    SendCodeResponse(
      json['code'] as int,
      Result.fromJson(json['result'] as Map<String, dynamic>),
    );

Map<String, dynamic> _$SendCodeResponseToJson(SendCodeResponse instance) =>
    <String, dynamic>{
      'code': instance.code,
      'result': instance.result,
    };

Result _$ResultFromJson(Map<String, dynamic> json) => Result(
      json['result'] as int,
      json['errmsg'] as String,
      json['ext'] as String,
      (json['detail'] as List<dynamic>)
          .map((e) => Detail.fromJson(e as Map<String, dynamic>))
          .toList(),
    );

Map<String, dynamic> _$ResultToJson(Result instance) => <String, dynamic>{
      'result': instance.result,
      'errmsg': instance.errmsg,
      'ext': instance.ext,
      'detail': instance.detail,
    };

Detail _$DetailFromJson(Map<String, dynamic> json) => Detail(
      json['result'] as int,
      json['errmsg'] as String,
      json['mobile'] as String,
      json['nationcode'] as String,
      json['isocode'] as String,
      json['sid'] as String,
      json['fee'] as int,
    );

Map<String, dynamic> _$DetailToJson(Detail instance) => <String, dynamic>{
      'result': instance.result,
      'errmsg': instance.errmsg,
      'mobile': instance.mobile,
      'nationcode': instance.nationcode,
      'isocode': instance.isocode,
      'sid': instance.sid,
      'fee': instance.fee,
    };

# 调整user_service

import 'package:my_app/entity/send_code_response.dart';

// ...
Future sendCode(String mobile) async {
  var params = {
    'mobile': mobile,
  };
  // Map -> Class  Class -> Map
  // res['data']['code'] -> Response.data.code
  // ts -> json
  var res = await DioHttp().get('/public/sendcode', params);
  if (res.statusCode == 200) {
    Map<String, dynamic>? data = res.data;
    // 请求成功
    SendCodeResponse sendCodeResponse = SendCodeResponse.fromJson(data!);
    if (sendCodeResponse.code != 200) {
      // 发送短信验证码失败 -> 给用户一个友好的提示
      // todo
    } else {
      // 发送成功
      // todo
    }
    return sendCodeResponse;
  }
}

这样调整完之后,再次发送请求,就可以使用sendCodeResponse来取用响应回来的数据了。

# 常见问题

image-20211004091321880

产生原因:

  1. 已经有对应的.g.dart的自动产生的文件了。

  2. 修改过实体之后,又去使用flutter pub run build_runner build命令

解决方法:

  1. 删除.g.dart的文件(适合文件比较少的场景)

image-20211004091353408

  1. 加入--delete-conflicting-outputs标签

image-20211004091920677

注意:如果 对.g.dart的文件进行了修改,这样会覆盖之前的文件;