json2Dart工具

最近公司在推动跨平台开发,大佬们有意向使用Flutter编写App中的部分页面,于是自学了一波Flutter,但是在Flutter的学习过程中发现结合json_annotation库时,发现要写一个json解析文件实在太麻烦了,在使用过程中,发现网站json转dart,但是感觉使用起来还是比较麻烦,于是自己动手使用python编写了一个json转dart实体的脚本。并用工具解析编写了公司项目json解析。

文章目录

  • 效果演示
  • 从main开始
  • 参数解析
  • Json数据解析
  • 文件操作
  • 写入dart代码
    • 数据转换
    • 递归解析
  • 命令调用
  • 文件演示
  • 总结
  • 实际项目演示
  • 代码地址

效果演示

运行之后的效果如下图所示:

执行之后,会根据json的内容,生成两个文件,一个.dart文件和一个.g.dart文件,这样就完成了一个json解析文件的生成。

从main开始

main的代码如下所示:

if __name__ == '__main__':
    parser = ArgParser();
    param = parser.parserArgument();

    os.chdir(param.getTarget());
    
    if(param.getOnlyBuild() == True):
        (BuildRunnerProcess()).run();
    else:
        (JsonParser()).parse()

main的代码很简单,首先是解析参数,然后切换到指定的工作目录,如果只做生成操作,则直接执行命令,生成文件,否则解析json。

参数解析

json2Dart工具_第1张图片
可以看到,脚本的参数列表如上图所示,解析如下;

  • -h:显示帮助列表
  • -b:仅编译生成解析文件
  • -u:根据给定的url,请求json数据
  • -f:从文件读取json数据
  • -j:从json字符串读取数据
  • -d:指定Flutter项目目录
  • -c:指定model的类名
  • -p:指定类名的前缀,如果类名已经名含前缀,则不再取前缀

Json数据解析

整个json解析类,包括数据请求,json解析两步操作,代码如下所示:

class JsonParser(object):
    def __init__(self):
        self.__param = param;
        self.__jsonObj = '';

    def __requestJsonFromURL(self, url):
        response = requests.get(url);
        self.__jsonObj = response.text;

    def __readJsonFromFile(self, path):
        filePath = os.path.expanduser(path);

        if filePath != None:
            try:
                with open(filePath, mode='r') as f:
                    jsonstr = f.readline();
                    if jsonstr != None:
                        self.__jsonObj += jsonstr;
            finally:
                f.close();

    def __readJsonFromString(self):
        jsonstr = raw_input(prompt='press ENTER to exit.');
        while(len(jsonstr) > 0):
            self.__jsonObj += jsonstr;
            jsonstr = raw_input(prompt='press ENTER to exit.');
    
    def parse(self):
        if(self.__param.getMethod() == 1):
            self.__requestJsonFromURL(self.__param.getArgument());
        elif(self.__param.getMethod() == 2):
            self.__readJsonFromFile(self.__param.getArgument());
        elif(self.__param.getMethod() == 3):
            self.__readJsonFromString();
        else:
            exit();

        print('Json Contentes like this below:');
        print('');
        print('\033[31m' + self.__jsonObj + '\033[0m');

        self.__parse();

    def __parse(self):
        print('');
        print('Parsing Json URL, Please Wait...');
        self.__jsonObj = json.loads(self.__jsonObj);
        if(self.__jsonObj != None):
            generator = DartGenerator();
            generator.generate(self.__jsonObj);
        else:
            print('');
            print('Incorrect Json String, Program Will be Exit...');
            exit();

可以看到,支持3种方式读取json数据,从url请求,从文件读取,从字符串读取,从url请求使用了reqeusts库。其实这个类的作用就是读取json数据,然后将json数据传递给DartGenerator类生成dart文件。

文件操作

文件操作的代码如下所示:

class FileOperator:
    def __init__(self):
        global filePath;

        target = os.path.join(param.getTarget(), 'lib');
        if(os.path.exists(target) == False or os.path.isdir(target) == False):
            raise Exception, 'Where is the lib Directory?';
        target = os.path.join(target, 'Models');
        if(os.path.exists(target) == False or os.path.isdir(target) == False):
            os.mkdir(target);
        
        if param.getName() == None:
            if param.getPrefix() == None:
                target = os.path.join(target, 'AutoGenerated.dart');
            else:
                target = os.path.join(target, param.getPrefix() + 'AutoGenerated.dart');
        else:
            if param.getPrefix() == None:
                target = os.path.join(target, param.getName() + '.dart');
            else:
                target = os.path.join(target, param.getPrefix() + param.getName() + '.dart');

        filePath = target;

        # 清空文件
        with open(filePath, 'w') as f:
            f.truncate(0);

    def write(self, content):
        with open(filePath, 'a+') as f:
            f.write(content);

该类首先检查指定目录是否为一个正确的Flutter项目目录,目前这里只是通过检查目录下是否有lib目录,如果没有的话,就当做指定目录不合格。最后如果没有指定文件,则使用AutoGenerated.dart作为默认文件名。

写入dart代码

主要代码在DartGenerator类中,解析后的json数据是一个dict,其实就是一个n叉树,DartGenerator的作用就是递归遍历n叉树,生成.dart文件,代码如下所示:

class DartGenerator:
    def __init__(self):
        self.__fileOperator = FileOperator();

    def __getStandardizedObjName(self, name):
        prefix = param.getPrefix();

        if(prefix == None or name.startswith(prefix)):
            return self.__myCapitalize(name);
        return prefix + self.__myCapitalize(name);

    def __Encoding(self, key, value):
        if(type(value) == bool):
            return 'bool';
        elif(type(value) == int):
            return 'int';
        elif(type(value) == float):
            return 'double';
        elif(type(value) == str or type(value) == unicode):
            return 'String';
        elif(type(value) == list):
            if(len(value) == 0):
                return 'List';
            fObj = value[0];
            if(type(fObj) == dict):
                return 'List<' + self.__getStandardizedObjName(key) + '>';
            return 'List<' + self.__Encoding(key, fObj) + '>';
        elif(type(value) == dict):
            return self.__getStandardizedObjName(key);
        else:
            return 'dynamic';

    def generate(self, jsonObj):
        #生成dart文件
        fileContent = '/// This File is Generated by ' + os.path.basename(sys.argv[0]) + ' and you SHOULD NOT MODIFY this file' + os.linesep + \
            '/// UNLESS the property we not recognized named property(number) and mark on the top.' + os.linesep + os.linesep;
        fileContent += self.__writeHeaderImport();
        
        clsName = param.getName();
        if(clsName == None):
            clsName = 'AutoGenerated';
        fileContent += self.__writePartAnnouncement(clsName)
        self.__fileOperator.write(fileContent);

        self.__generateRecursive(jsonObj, self.__getClassName(clsName));

        #生成json解析文件
        (BuildRunnerProcess()).run();

    def __myCapitalize(self, name):
        if(len(name) <= 0):
            return name;
        elif(len(name) == 1):
            return name.capitalize();
        return name[0:1].upper() + name[1:len(name)];

    def __is_contain_chinese(self, check_str):
        for ch in check_str:
            if u'\u4e00' <= ch <= u'\u9fff':
                return True
            return False

    def __getClassName(self, name):
        if(param.getPrefix() == None or name.startswith(param.getPrefix())):
            return self.__myCapitalize(name);
        return param.getPrefix() + self.__myCapitalize(name);

    def __generateRecursive(self, jsonObj, clsName):
        if(type(jsonObj) != dict and type(jsonObj) != list):
            print('');
            print('\033[31m Json Parse Error. Exiting...');
            print('');
            exit();

        fileContent = self.__writeClassHeader(clsName);
        props = []; 

        for (key, value) in jsonObj.items():
            if self.__is_contain_chinese(key): 
                fileContent += os.linesep + '    /// This property we not recognized' + os.linesep + \
                    '    /// You MUST Modify it BY YOURSELF.' + os.linesep;

                name = 'property' + str((len(props) + 1));
                props.append(name);
                fileContent += self.__writeProperty('dynamic', name);
            else:
                props.append(key);
                fileContent += self.__writeProperty(self.__Encoding(key, value), key);

            if(type(value) == dict and len(value.keys()) > 0):
                self.__generateRecursive(value, self.__getClassName(key));
            elif(type(value) == list and len(value) > 0):
                #取最长的元素为参照对象
                obj = None;
                for i in range(0, len(value)):
                    dic = value[i];
                    if type(dic) == dict:
                        if obj == None:
                            obj = dic;
                        else:
                            if len(dic.keys()) > len(obj.keys()):
                                obj = dic;

                if(type(obj) == dict):
                    self.__generateRecursive(obj, self.__getClassName(key));

        fileContent += self.__writeConstruct(clsName, props);

        fileContent += self.__writeFromJsonMethod(clsName);
        fileContent += self.__writeToJsonMethod(clsName);
        fileContent += self.__writeEnding();
        self.__fileOperator.write(fileContent);

    def __writePartAnnouncement(self, clsName):
        fileContent = 'part \'' + self.__getClassName(clsName) + '.g.dart\';' + os.linesep + os.linesep;
        return fileContent;

    def __writeHeaderImport(self):
        fileContent = 'import \'package:json_annotation/json_annotation.dart\';' + os.linesep + os.linesep;
        return fileContent;

    def __writeClassHeader(self, clsName):
        fileContent = '@JsonSerializable(nullable: true)';
        fileContent += os.linesep;
        fileContent += 'class ' + clsName + ' {' + os.linesep;
        return fileContent;

    def __writeProperty(self, typeName, name):
        fileContent = '    ' + typeName + ' ' + name + ';' + os.linesep;
        return fileContent;

    def __writeEnding(self):
        fileContent = '}' + os.linesep + os.linesep;
        return fileContent;
    
    def __writeConstruct(self, clsName, props):
        fileContent = os.linesep + '    ' + clsName + '({';

        isFirst = True;

        count = 0;
        for (idx, p) in enumerate(props):
            count = count + 1;
            if isFirst:
                fileContent += 'this.' + p;
                isFirst = False;
            else:
                fileContent += ', this.' + p;

            if count % 4 == 0 and idx != len(props):
                fileContent += os.linesep + '        ';
        
        fileContent += '});' + os.linesep + os.linesep;
        return fileContent;

    def __writeFromJsonMethod(self, clsName):
        fileContent = '    factory ' + clsName + '.fromJson(Map json) => _$' + clsName + 'FromJson(json);';
        fileContent += os.linesep;
        return fileContent;
    
    def __writeToJsonMethod(self, clsName):
        fileContent = '    Map toJson() => _$' + clsName + 'ToJson(this);';
        fileContent += os.linesep + os.linesep;
        return fileContent;

class JsonParser(object):
    def __init__(self):
        self.__param = param;
        self.__jsonObj = '';

    def __requestJsonFromURL(self, url):
        response = requests.get(url);
        self.__jsonObj = response.text;

    def __readJsonFromFile(self, path):
        filePath = os.path.expanduser(path);

        if filePath != None:
            try:
                with open(filePath, mode='r') as f:
                    jsonstr = f.readline();
                    if jsonstr != None:
                        self.__jsonObj += jsonstr;
            finally:
                f.close();

    def __readJsonFromString(self):
        jsonstr = raw_input(prompt='press ENTER to exit.');
        while(len(jsonstr) > 0):
            self.__jsonObj += jsonstr;
            jsonstr = raw_input(prompt='press ENTER to exit.');
    
    def parse(self):
        if(self.__param.getMethod() == 1):
            self.__requestJsonFromURL(self.__param.getArgument());
        elif(self.__param.getMethod() == 2):
            self.__readJsonFromFile(self.__param.getArgument());
        elif(self.__param.getMethod() == 3):
            self.__readJsonFromString();
        else:
            exit();

        print('Json Contentes like this below:');
        print('');
        print('\033[31m' + self.__jsonObj + '\033[0m');

        self.__parse();

    def __parse(self):
        print('');
        print('Parsing Json URL, Please Wait...');
        self.__jsonObj = json.loads(self.__jsonObj);
        if(self.__jsonObj != None):
            generator = DartGenerator();
            generator.generate(self.__jsonObj);
        else:
            print('');
            print('Incorrect Json String, Program Will be Exit...');
            exit();

我们知道,如果需要使用json_serialization并使用flutter packages pub run build_runner build命令正确的生成文件,则一个dart文件必须要包含以下几个方面的内容:

  1. import ‘package:json_annotation/json_annotation.dart’; 模块引入,对应__writeHeaderImport函数
  2. part声明,使用命令生成的文件是在一个part文件中,所以必须用part指定文件名,一般以.g.dart结尾,对应函数__writePartAnnouncement
  3. ‘@JsonSerializable’,该注解指定该类需要生成json解析,如果没有该注解,则该类无法正确解析,对应__writeClassHeader函数,该函数首先写入注解,然后写入类头。
  4. 属性,一般我们在进行解析的时候,使用json的key对应属性名,然后解析value的类型,生成属性,对应__writeProperty函数。
  5. 构造函数:构造函数用于初始化属性,写法是固定的,但必须枚举类中需要被解析的各个属性,对应函数__writeConstruct,每4个为一行。
  6. fromJson工厂函数,这个函数接收json数据,生成模型对象,写法固定为:factory ClassName.fromJson(Map json) => _$ClassNameFromJson(json);,对应函数__writeFromJsonMethod
  7. toJson函数,这个函数用于将模型对象解析为json对象,写法也是固定的:Map toJson() => _$ClassNameToJson(this);,对应函数__writeToJsonMethod
  8. 加上类结尾之后,一个完整的dart类就已经结束,此时即可生成解析文件

数据转换

def __Encoding(self, key, value):
        if(type(value) == bool):
            return 'bool';
        elif(type(value) == int):
            return 'int';
        elif(type(value) == float):
            return 'double';
        elif(type(value) == str or type(value) == unicode):
            return 'String';
        elif(type(value) == list):
            if(len(value) == 0):
                return 'List';
            fObj = value[0];
            if(type(fObj) == dict):
                return 'List<' + self.__getStandardizedObjName(key) + '>';
            return 'List<' + self.__Encoding(key, fObj) + '>';
        elif(type(value) == dict):
            return self.__getStandardizedObjName(key);
        else:
            return 'dynamic';

根据value的类型转换为Dart的类型,普通类型可以直接转换,如果类型为一个数组,则取第一个数据做为解析对象,如果第一个数据为一个字典,因为之后会生成一个新的对象,此时可以直接返回之后生成的对象的类名的List对象,否则继续递归解析,直至类型编码结束。若类型无法解析,则返回一个dynamic,表示任意类型。

递归解析

递归解析是最关键的一步,代码如下:

def __generateRecursive(self, jsonObj, clsName):
        if(type(jsonObj) != dict and type(jsonObj) != list):
            print('');
            print('\033[31m Json Parse Error. Exiting...');
            print('');
            exit();

        fileContent = self.__writeClassHeader(clsName);
        props = []; 

        for (key, value) in jsonObj.items():
            if self.__is_contain_chinese(key): 
                fileContent += os.linesep + '    /// This property we not recognized' + os.linesep + \
                    '    /// You MUST Modify it BY YOURSELF.' + os.linesep;

                name = 'property' + str((len(props) + 1));
                props.append(name);
                fileContent += self.__writeProperty('dynamic', name);
            else:
                props.append(key);
                fileContent += self.__writeProperty(self.__Encoding(key, value), key);

            if(type(value) == dict and len(value.keys()) > 0):
                self.__generateRecursive(value, self.__getClassName(key));
            elif(type(value) == list and len(value) > 0):
                #取最长的元素为参照对象
                obj = None;
                for i in range(0, len(value)):
                    dic = value[i];
                    if type(dic) == dict:
                        if obj == None:
                            obj = dic;
                        else:
                            if len(dic.keys()) > len(obj.keys()):
                                obj = dic;

                if(type(obj) == dict):
                    self.__generateRecursive(obj, self.__getClassName(key));

        fileContent += self.__writeConstruct(clsName, props);

        fileContent += self.__writeFromJsonMethod(clsName);
        fileContent += self.__writeToJsonMethod(clsName);
        fileContent += self.__writeEnding();
        self.__fileOperator.write(fileContent);

写入一些基本的信息之后,根据上述说明,首先要写入类头部信息,然后遍历其中的key,不排除有不合法的key出现,但此处只判断了key是否包含中文,如果包含中文,则生成一个默认的属性名,并加以注释,告诉用户该key需要自己处理,否则写入属性。当检测到另外一个dict时,此时需要生成一个新的对象,首先写入原类中关于该对象的属性,然后暂停原类写入,递归从新写入dict对应的新类。如果检测到一个list,同样需要一个新类,但为了防止丢失key,我们选取最长的一个元素进行写入。最后加上构造函数
fromJson、toJson和结尾等,之后再把整个类写入到文件当中。

命令调用

最后一步就是调用命令生成part文件,代码如下所示:

class BuildRunnerProcess:
    def run(self):
        cmd = 'flutter packages pub run build_runner build --delete-conflicting-outputs';
        child = subprocess.Popen([cmd], shell = True, stdout = subprocess.PIPE);
        while child.poll() == None:
            print(child.stdout.readline());

        print('Generate Dart File Complete, Exiting....');
        print('File Path:' + '\033[31m ' + filePath + '\033[0m');

使用subprocess生成另外一个进程,调用命令并输出提示信息,生成结束之后返回文件路径,到此全部结束。

文件演示

最终使用工具生成的结果文件如下图的所示:

/// This File is Generator by json2dart.py and you SHOULD NOT MODIFY this file
/// UNLESS the property we not recognized named property(number) and mark on the top.

import 'package:json_annotation/json_annotation.dart';

part 'YJRecommendItemsForYouModel.g.dart';

@JsonSerializable(nullable: true)
class YJTwoFontCategoryBo {
    int categoryStatus;
    int categoryLevel;
    String categoryName;
    int categoryId;

    YJTwoFontCategoryBo({this.categoryStatus, this.categoryLevel, this.categoryName, this.categoryId
        });

    factory YJTwoFontCategoryBo.fromJson(Map<String, dynamic> json) => _$YJTwoFontCategoryBoFromJson(json);
    Map<String, dynamic> toJson() => _$YJTwoFontCategoryBoToJson(this);

}

@JsonSerializable(nullable: true)
class YJThreeFontCategoryBo {
    int categoryStatus;
    int categoryLevel;
    String categoryName;
    int categoryId;

    YJThreeFontCategoryBo({this.categoryStatus, this.categoryLevel, this.categoryName, this.categoryId
        });

    factory YJThreeFontCategoryBo.fromJson(Map<String, dynamic> json) => _$YJThreeFontCategoryBoFromJson(json);
    Map<String, dynamic> toJson() => _$YJThreeFontCategoryBoToJson(this);

}

@JsonSerializable(nullable: true)
class YJFirstFontCategoryBo {
    int categoryStatus;
    int categoryLevel;
    String categoryName;
    int categoryId;

    YJFirstFontCategoryBo({this.categoryStatus, this.categoryLevel, this.categoryName, this.categoryId
        });

    factory YJFirstFontCategoryBo.fromJson(Map<String, dynamic> json) => _$YJFirstFontCategoryBoFromJson(json);
    Map<String, dynamic> toJson() => _$YJFirstFontCategoryBoToJson(this);

}

@JsonSerializable(nullable: true)
class YJFontCategoryWrapperBos {
    YJTwoFontCategoryBo twoFontCategoryBo;
    YJThreeFontCategoryBo threeFontCategoryBo;
    YJFirstFontCategoryBo firstFontCategoryBo;

    YJFontCategoryWrapperBos({this.twoFontCategoryBo, this.threeFontCategoryBo, this.firstFontCategoryBo});

    factory YJFontCategoryWrapperBos.fromJson(Map<String, dynamic> json) => _$YJFontCategoryWrapperBosFromJson(json);
    Map<String, dynamic> toJson() => _$YJFontCategoryWrapperBosToJson(this);

}

@JsonSerializable(nullable: true)
class YJSpuPropertyBoList {
    int itemId;
    int modifyTime;
    String propertyName;
    int propType;
    String spuCode;
    String propertyValue;
    int propSort;
    int propId;
    int createTime;
    int propSource;

    YJSpuPropertyBoList({this.itemId, this.modifyTime, this.propertyName, this.propType
        , this.spuCode, this.propertyValue, this.propSort, this.propId
        , this.createTime, this.propSource});

    factory YJSpuPropertyBoList.fromJson(Map<String, dynamic> json) => _$YJSpuPropertyBoListFromJson(json);
    Map<String, dynamic> toJson() => _$YJSpuPropertyBoListToJson(this);

}

@JsonSerializable(nullable: true)
class YJItemExpandRedisBo {
    List<YJSpuPropertyBoList> spuPropertyBoList;
    int itemTuType;
    String transparentImage;
    dynamic perfectChoice;
    String productSpot;
    String limitTransparentImage;
    int quanlityFiveHundred;
    int dimensionPurchase;

    YJItemExpandRedisBo({this.spuPropertyBoList, this.itemTuType, this.transparentImage, this.perfectChoice
        , this.productSpot, this.limitTransparentImage, this.quanlityFiveHundred, this.dimensionPurchase
        });

    factory YJItemExpandRedisBo.fromJson(Map<String, dynamic> json) => _$YJItemExpandRedisBoFromJson(json);
    Map<String, dynamic> toJson() => _$YJItemExpandRedisBoToJson(this);

}

@JsonSerializable(nullable: true)
class YJTuRelationList {
    int itemId;
    double skuPrice;
    int itemMainType;
    String skuCode;
    int skuNum;
    int relationId;

    YJTuRelationList({this.itemId, this.skuPrice, this.itemMainType, this.skuCode
        , this.skuNum, this.relationId});

    factory YJTuRelationList.fromJson(Map<String, dynamic> json) => _$YJTuRelationListFromJson(json);
    Map<String, dynamic> toJson() => _$YJTuRelationListToJson(this);

}

@JsonSerializable(nullable: true)
class YJTuList {
    int itemId;
    int skuStatus;
    double bossAmount;
    String tuName;
    String specLevel1Val;
    double teacherAmount;
    double specPrice;
    String tuCode;
    int specStock;
    int version;
    List<YJTuRelationList> tuRelationList;
    String skuSmallImg;
    double partnerAmount;

    YJTuList({this.itemId, this.skuStatus, this.bossAmount, this.tuName
        , this.specLevel1Val, this.teacherAmount, this.specPrice, this.tuCode
        , this.specStock, this.version, this.tuRelationList, this.skuSmallImg
        , this.partnerAmount});

    factory YJTuList.fromJson(Map<String, dynamic> json) => _$YJTuListFromJson(json);
    Map<String, dynamic> toJson() => _$YJTuListToJson(this);

}

@JsonSerializable(nullable: true)
class YJItemBizWordsBo {
    int mallImgType;
    String simpleName;
    String mallImg;

    YJItemBizWordsBo({this.mallImgType, this.simpleName, this.mallImg});

    factory YJItemBizWordsBo.fromJson(Map<String, dynamic> json) => _$YJItemBizWordsBoFromJson(json);
    Map<String, dynamic> toJson() => _$YJItemBizWordsBoToJson(this);

}

@JsonSerializable(nullable: true)
class YJData {
    String itemDetail;
    int urlType;
    int soldNumber;
    int autoChangeLogistics;
    double minCommission;
    String serviceStateValue;
    int likeCount;
    int errorCode;
    String limitDiscountStr;
    String subtitle;
    double taxPrice;
    int commissionPoint;
    int onlineTime;
    int ifInvoice;
    int taxType;
    int isLike;
    List<YJFontCategoryWrapperBos> fontCategoryWrapperBos;
    String storeCode;
    String errorMessage;
    int maxBigImageIndex;
    int activityItemStatus;
    int areaWarehouseStatus;
    int activityTotalStock;
    int itemId;
    int disabled;
    int profitType;
    int subType;
    int isShowStock;
    String fineImg;
    int itemPurchaseMin;
    int bankRate;
    double maxPrice;
    String itemImgBig;
    int endTime;
    String itemParameters;
    List<String> bigImgList;
    int categoryOrder;
    int specialPushFlag;
    int addressPurchase;
    int isClearGoods;
    int selected;
    int packageType;
    bool isSelfSupport;
    int itemCategory;
    int stockPercentage;
    int shipmentsType;
    int limitItemUV;
    int brandId;
    int itemSnapshotVersion;
    int itemCategoryLevel3;
    int itemCategoryLevel2;
    int itemCategoryLevel1;
    int isFirstOrderPrice;
    YJItemExpandRedisBo itemExpandRedisBo;
    int itemOrder;
    int textCount;
    int saleType;
    String itemName;
    int ifGuarantee;
    String itemBrandName;
    int itemType;
    String shopCode;
    int itemTextCount;
    int isHotSale;
    String activityName;
    int activityTimesId;
    int favoriteItemTopstatus;
    int totalStock;
    double minItemVipPrice;
    int dailyPurchase;
    String barCode;
    int releaseTime;
    int phonePurchase;
    int userTextCount;
    int markType;
    String strBankRate;
    int groupId;
    int tradeMode;
    int manageType;
    int itemBrand;
    int limitActivityId;
    String activityDesc;
    String businessCertifyImage;
    int currentTime;
    String itemImg;
    int packageId;
    double maxCommission;
    List<YJTuList> tuList;
    double itemVipPrice;
    int sellPersons;
    int itemPurchaseMax;
    int serviceState;
    double sCommission;
    String purchaseNotice;
    YJItemBizWordsBo itemBizWordsBo;
    int itemChannel;
    String itemImgSmall;
    int isSkuList;
    int stock;
    int status;
    int shipmentsTime;
    int startTime;
    String smallImgList;
    double minPrice;
    String userName;
    String sellType;
    double itemPrice;
    double maxItemVipPrice;
    bool isNewItem;
    int hideProgress;

    YJData({this.itemDetail, this.urlType, this.soldNumber, this.autoChangeLogistics
        , this.minCommission, this.serviceStateValue, this.likeCount, this.errorCode
        , this.limitDiscountStr, this.subtitle, this.taxPrice, this.commissionPoint
        , this.onlineTime, this.ifInvoice, this.taxType, this.isLike
        , this.fontCategoryWrapperBos, this.storeCode, this.errorMessage, this.maxBigImageIndex
        , this.activityItemStatus, this.areaWarehouseStatus, this.activityTotalStock, this.itemId
        , this.disabled, this.profitType, this.subType, this.isShowStock
        , this.fineImg, this.itemPurchaseMin, this.bankRate, this.maxPrice
        , this.itemImgBig, this.endTime, this.itemParameters, this.bigImgList
        , this.categoryOrder, this.specialPushFlag, this.addressPurchase, this.isClearGoods
        , this.selected, this.packageType, this.isSelfSupport, this.itemCategory
        , this.stockPercentage, this.shipmentsType, this.limitItemUV, this.brandId
        , this.itemSnapshotVersion, this.itemCategoryLevel3, this.itemCategoryLevel2, this.itemCategoryLevel1
        , this.isFirstOrderPrice, this.itemExpandRedisBo, this.itemOrder, this.textCount
        , this.saleType, this.itemName, this.ifGuarantee, this.itemBrandName
        , this.itemType, this.shopCode, this.itemTextCount, this.isHotSale
        , this.activityName, this.activityTimesId, this.favoriteItemTopstatus, this.totalStock
        , this.minItemVipPrice, this.dailyPurchase, this.barCode, this.releaseTime
        , this.phonePurchase, this.userTextCount, this.markType, this.strBankRate
        , this.groupId, this.tradeMode, this.manageType, this.itemBrand
        , this.limitActivityId, this.activityDesc, this.businessCertifyImage, this.currentTime
        , this.itemImg, this.packageId, this.maxCommission, this.tuList
        , this.itemVipPrice, this.sellPersons, this.itemPurchaseMax, this.serviceState
        , this.sCommission, this.purchaseNotice, this.itemBizWordsBo, this.itemChannel
        , this.itemImgSmall, this.isSkuList, this.stock, this.status
        , this.shipmentsTime, this.startTime, this.smallImgList, this.minPrice
        , this.userName, this.sellType, this.itemPrice, this.maxItemVipPrice
        , this.isNewItem, this.hideProgress});

    factory YJData.fromJson(Map<String, dynamic> json) => _$YJDataFromJson(json);
    Map<String, dynamic> toJson() => _$YJDataToJson(this);

}

@JsonSerializable(nullable: true)
class YJRecommendItemsForYouModel {
    int errorCode;
    List<YJData> data;
    bool success;

    YJRecommendItemsForYouModel({this.errorCode, this.data, this.success});

    factory YJRecommendItemsForYouModel.fromJson(Map<String, dynamic> json) => _$YJRecommendItemsForYouModelFromJson(json);
    Map<String, dynamic> toJson() => _$YJRecommendItemsForYouModelToJson(this);
    
}

生成的文件统一放在一个叫做Models的目录下面,这样可以直接使用,当然也可以自己移到另外的目录结构中去。在实际的使用过程中,除了没有返回的字段和不合法的字段之外,并没有出现过其他的问题。我业余用Flutter重写了公司的很多页面,其中的json解析全都是用的自己的工具,同事说网上其实已经有人写了这样的插件了,当然限于本人水平,我这个工具并没有写的多好,但终究自己写的知根知底,相比其他的工具来,还是使用自己写的工具靠谱。

总结

对比开头说的那个网站,我觉得我的json2Dart工具有以下几个优点:

  1. 解析方法多样,网站需要自己手动复制json数据,而该工具可以直接从url请求数据
  2. 实际项目中一般都是使用json_serializable库来解析json,使用网站生成需要自己删除很多冗余代码并手动添加必要代码,再执行命令。而该工具一步到位。简化了操作
  3. 网站对于不合法的json无法生成模型文件,该工具则做了处理,虽然不是很全部,但也相对简化了很多不必要的操作。

实际项目演示

最后演示一下用Flutter改写的公司项目的一点点页面吧,也算给自己半个多月以来的成果做个展示,但是由于公司的政策规定,不能上传任何与公司相关的代码或资料到外网,所以只能简单的做个展示。Flutter写的项目还是相当流畅的,估计以后会成为主流,不过公司最近在转向RN,所以最近都加紧学习RN了。

代码地址

json2Dart
有兴趣的朋友可以一起研究,没兴趣的朋友可以无视。

你可能感兴趣的:(Python)