跳至主要內容

Json与DartModel

chanchaw大约 3 分钟flutter

概述

类似 java ,项目中有实体类作为模型,标准写法如下。注意构造方法 fromJson 的参数要兼容传入 null 的情况

使用 ? 兼容 factory ResponseResult.fromJson(Map<String,dynamic>? json){

/**
 * 标准的 dart 模型类
 */
class ResponseResult<T> {
  bool? success;
  T? data;
  String? msg;
  int? code;

  ResponseResult({this.success,this.data,this.msg,this.code});
  ResponseResult.fromJson(Map<String,dynamic> json){
    success = json['success'];
    data = json['data'];
    msg = json['msg'];
    code = json['code'];
  }
  
  /* 上面的方法也可以如下
  factory ResponseResult.fromJson(Map<String,dynamic>? json){
	if(map == null) return LoginUser(id:-1);
    return ResponseResult<T>(
      success: json['success'],
      data: json['data'],
      msg: json['msg'],
      code: json['code'],
    );
  }
  */
    // 用于创建空对象
    factory ResponseResult.empty(){
      return ResponseResult<T>(
          success: false,
          data: null,
          msg: '',
          code: 0,
      );
    }

  Map<String,dynamic> toJson(){
    final Map<String,dynamic> data = <String,dynamic>{};
    data['success'] = success;
    data['data'] = data;
    data['msg'] = msg;
    data['code'] = code;
    return data;
  }
}
// 调用方法如下,res.body 是请求响应来的结果,是 json 字符串,通过 jsonDecode 转换为 Map 类型
// 然后再通过实体类自己的 fromJson 方法将 Map 转换为实体类对象
// 注意可能会在 ResponseResult 的泛型位置报错,要通过IDE的 Invalide Caches... 并重启后可解决虚假报错
var body = jsonDecode(res.body);
var entity = ResponseResult<Map<String,String>>.fromJson(body);

参照如下文档

反序列化响应结果

一般响应结果是实体类包含实体类,可能存在多层嵌套,例如 ResponseResult 中包含 LoginData 后者又包含 LoginUser,如下响应结果:

{// ResponseResult
    "success":true,
    "msg":"登录成功",
    "data":{// LoginData
        "userToken":"userToken:dafd9a6ee74c40c399235bcb5dbe71cd",
        "user":{// LoginUser
            "id":8,
            "email":"chanchaw@126.com",
            "nickname":"爱思考的飞飞",
            "headPic":"https://cdn.vuetifyjs.com/images/john.jpg",
            "level":0,
            "time":"2023-05-05 15:03:33",
            "status":1
        }
    }
}

dart 中的实体类定义如下:

class ResponseResult<T> {
  bool? success;
  T? data;
  String? msg;
  int? code;
    ......

由于成员变量 data 是多层嵌套的实体类对象,在接受到响应结果转换为响应结果实体类时做法如下:

  1. 将响应结果体按照字节类型处理字符集(处理中文)
  2. 处理字符集后的结果转换为 map 对象
  3. map 对象转换为 ResponseResult 对象(不要指定 data 的数据类型)
  4. 将响应结果的 data 转换为实体类对象
  5. 实体类中嵌套的实体类成员变量都不要指定类名称,而要使用 Map<String,dynamic>,在获取数据后使用 实体类.fromJson() 转换为实体类对象
var res = await http.post(
    uri,
    body: jsonEncode(reqData),
    headers: {
        'Content-Type': 'application/json; charset=UTF-8', // 关键:设置 Content-Type
    },
);

if(res.statusCode == 200) print('请求来的响应:${res.body}');
else print('登录请求异常,code:${res.statusCode},msg:${res.body}');

// 处理中文
Utf8Decoder utf8decoder = const Utf8Decoder();
String bodyString = utf8decoder.convert(res.bodyBytes);

// 下面是处理中后的响应结果,即 bodyString:
// {"success":true,"msg":"登录成功","data":{"userToken":"userToken:dafd9a6ee74c40c399235bcb5dbe71cd","user":{"id":8,"email":"chanchaw@126.com","nickname":"爱思考的飞飞","headPic":"https://cdn.vuetifyjs.com/images/john.jpg","level":0,"time":"2023-05-05 15:03:33","status":1}}}
var resMap = jsonDecode(bodyString);
var resEntity = ResponseResult.fromJson(resMap);
print('响应结果处理中文并反序列化为响应对象:${resEntity.toString()}');
print('响应结果中的data:${resEntity.data}');
LoginData loginData = LoginData.fromJson(resEntity.data);
print('响应结果数据实体对象:${loginData.toString()}');

注意 ResponseResult.data = LoginData ,而实体类 LoginData 中的 user 不可指定为实体类 LoginUser 而要使用 Map<String,dynamic>

class LoginData {
  String? userToken;
  Map<String,dynamic>? user;

  LoginData({this.userToken,this.user});
    ......