加拿大进出口外贸从网站的源头去做谷歌优化



加拿大外贸

在某种程度上,大多数应用都需要与外界互动,并从在线终端地址获取数据。借助 Dart 的 http 包,发出 HTTPS get 请求以获取天气预报或世界杯最终比分变得非常简单:

1    import 'dart:async';   
2    import 'package:http/http.dart' as http;
3
4    final response = await http.get(myEndpointUrl);   
5    if (response.statusCode == 200) {   
6    // use the data in response.body   
7    } else {   
8    // handle a failed request   
9    }

response.body 中的数据可能是 JSON 字符串,而我们还需要完成一些工作,才能将其用于微件。首先,您需要将字符串解析为更易于管理的 JSON 表示形式。然后,您必须将该表示形式转化为模型或其他一些强类型变量,如此一来,您就可以有效地使用这些字符串。

幸运的是,Dart 团队和社群对 JSON 已进行过诸多讨论,并且能够提供解决方案。我会按照复杂性从低到高的顺序介绍三种解决方案,分别是手写构造函数、json_serializable 和 built_value。

使用全部三种方法将数据反序列化的调用非常相似。手写构造函数和 json_serializable 的代码行如下所示:

1    final myObject = SimpleObject.fromJson(json.decode(aJsonString));

built_value 的反序列化调用如下所示:

1    final myObject = serializers.deserializeWith(  
2        SimpleObject.serializer, json.decode(aJsonString));  

真正的区别是,在该 “SimpleObject” 类中为您生成多少代码,以及这些代码有何作用。

手写构造函数
复杂性最低的方法:不为您生成代码。
您可以做自己想做的任何事,但您必须进行维护。

json_serializable
为您生成 fromJson 构造函数和 toJson 方法。
在构建应用之前,您需要在项目中加入若干个包,并使用 source_gen 生成部分文件。
对所生成的资源进行自定义可能会很棘手。

built_value
为序列化、不可变性、toString 方法、hashCode 属性等生成代码。这是具备诸多功能的重量级解决方案。
与 json_serializable 一样,您需要导入许多包并使用 source_gen。
拥有基于插件的可扩展序列化架构。
对实例创建和可变性等方面有见解。

正如下文所述,您适合使用哪个内容库其实取决于项目详情,特别是项目大小和状态管理方法。对拥有一位维护者的兴趣项目来说,手写构造函数很有帮助,而由庞大分布式团队(他们需要不可变模型来保持逻辑清晰)构建的应用则会真正从 “built_value” 受益。

不过,现在我们还是从头开始介绍:将 JSON 从字符串解析为更方便使用的内存表示形式。无论您之后决定采取哪种方法,相关流程中的这一步都是一样的。


解析 JSON
您可以使用 dart:convert 库将 JSON 字符串转换为中间格式:

1    import 'dart:convert';
2
3    try {
4        final parsed = json.decode(aJsonStr);
5    } on FormatException catch (e) {
6        print("That string didn't look like Json.");
7    } on NoSuchMethodError catch (e) {
8        print('That string was null!');
9    }

如果该字符串包含有效的 JSON,系统会返回对 List<dynamic> 或 Map<String, dynamic> 的动态引用,具体取决于 JSON 字符串是拥有数组还是单个对象。对于整数列表之类的简单事项,现在已经差不多做完了。在使用之前,您可能会想创建第二个强类型的数据引用:

1    final dynamicListOfInts = json.decode(aJsonArrayOfInts);
2
3    // Create a strongly typed list with references to the data that are casted
4    // immediately. This is probably the better approach for data model classes.
5    final strongListOfInts = List<int>.from(dynamicListOfInts);
6
7    // Or create a strongly typed list with references that will be lazy-casted
8    // when used.
9    final anotherStrongListOfInts = List<int>.from(dynamicListOfInts);

更复杂的有效负载才是有趣之处。将 Map<String, dynamic> 转化为实际模型对象时可能涉及转换默认值、null 和嵌套对象。如果您之后决定重新命名或添加/移除属性,很多方面可能会出错,而且需要更新很多麻烦的细节。


手写构造函数
我们必须从某个地方开始,对吗?如果您有一个小应用,而且数据也不是很复杂,那么自行编写采用 Map<String, dynamic> 参数的工厂构造函数会大有帮助。例如,如果您要获取如下数据:
注:工厂构造函数链接
https://www.dartlang.org/guides/ ... actory-constructors

1    {
2        "aString": "Blah, blah, blah.",
3        "anInt": 1,
4        "aDouble": 1.0,
5        "aListOfStrings": ["one", "two", "three"],
6        "aListOfInts": [1, 2, 3],
7        "aListOfDoubles": [1.0, 2.0, 3.0]
8    }

匹配类的代码可能如下所示:

1    class SimpleObject {
2        const SimpleObject({
3            this.aString,
4            this.anInt,
5            this.aDouble,
6            this.aListOfStrings,
7            this.aListOfInts,
8            this.aListOfDoubles,
9        });
10
11        final String aString;
12        final int anInt;
13        final double aDouble;
14        final List<String> aListOfStrings;
15        final List<int> aListOfInts;
16        final List<double> aListOfDoubles;
17
18        factory SimpleObject.fromJson(Map<String, dynamic> json) {
19            if (json == null) {
20                throw FormatException("Null JSON provided to SimpleObject");
21            }
22
23            return SimpleObject(
24                    aString: json['aString'],
25                    anInt: json['anInt'],
26                    aDouble: json['aDouble'],
27                    aListOfStrings: json['aListOfStrings'] != null
28                            ? List<String>.from(json['aListOfStrings'])
29                            : null,
30                    aListOfInts: json['aListOfInts'] != null
31                            ? List<int>.from(json['aListOfInts'])
32                            : null,
33                    aListOfDoubles: json['aListOfDoubles'] != null
34                            ? List<double>.from(json['aListOfDoubles'])
35                            : null,
36                );
37            }
38        }

然后按照如下方式使用已命名 fromJson 工厂构造函数:

1    return SimpleObject(
2        aString: json['aString'] ?? "",
3        anInt: json['anInt'] ?? 0,
4        aDouble: json['aDouble'] ?? 1.0,
5        aListOfStrings: List<String>.from(json['aListOfStrings'] ?? []),
6        aListOfInts: List<int>.from(json['aListOfInts'] ?? []),
7        aListOfDoubles: List<double>.from(json['aListOfDoubles'] ?? []),
8    );

缺点在于,您需要手写大约 20 行构造函数代码,而且现在必须对其进行维护。随着您的应用扩大规模以及数据类数量开始增长为几十个,您可能会出现这样的想法:“唉,对这些 JSON 构造函数编码越来越无聊了,要是可以根据数据类的属性自动生成代码就好了。”

事实证明,借助 json_serializable 库,确实可以做到这一点。


使用 json_serializable
在介绍 json_serializable 之前,我们需要转移一下话题,先简要讨论另一个包。

Flutter 目前不支持映射,所以在其他上下文中可以使用的某些技术(例如 Android JSON 库能够在运行时检查注解类)并不适用于 Flutter 开发者。不过,他们 可以 使用名为 source_gen 的 Dart 包。此包提供了实用工具和基本框架,以自动生成源代码。

source_gen 不会直接更新您的代码,而是在代码旁边另外创建新文件。按照惯例,其文件名中会有一个“g”,所以如果您的数据类存在于 model.dart 中,则 source_gen 会创建 model.g.dart。您可以使用 part 关键字引用原来位置中的相应文件,而编译器会嵌入该文件。

json_serializable 包使用 source_gen API 来生成序列化代码,并会为您编写 fromJson 构造函数(及 toJson 方法)。
注:json_serializable 链接
https://pub.dartlang.org/packages/json_serializable

将其用于应用的基本流程如下所示:

将 json_serializable 和 json_annotation 包导入您的项目中。
如往常一样定义数据类。
在类定义中添加 @JsonSerializable 注解。
添加其他一些内容,将此数据类与为其创建的 json_serializable 代码关联起来。
运行 source_gen 以生成代码。
注:导入您的项目链接
https://github.com/dart-lang/jso ... tree/master/example

我会逐个介绍这些步骤。

将 json_serializable 包导入您的项目中
您可以在 Dart 包目录中找到 json_serializable。只需按照指示更新您的 pubspec.yaml 就可以了。
注:Dart 包目录链接
https://pub.dartlang.org/packages/json_serializable
更新您的 pubspec.yaml 链接
https://flutter.io/using-package ... ependency-to-an-app

定义数据类
这部分并没有特别之处。使用基本属性和构造函数构建一个数据类。您计划序列化的属性应该是值类型或配合 json_serializable 使用的其他类。

1    class SimpleObject {   
2        SimpleObject({   
3            this.aString,   
4            this.anInt,   
5            this.aDouble,   
6            this.aListOfStrings,   
7            this.aListOfInts,   
8            this.aListOfDoubles,   
9        });   
10
11        final String aString;   
12        final int anInt;   
13        final double aDouble;   
14        final List<String> aListOfStrings;   
15        final List<int> aListOfInts;   
16        final List<double> aListOfDoubles;   
17    }

添加 @JsonSerializable 注注解
json_serializable 包只会为已使用 @JsonSerializable 注解标记过的数据类生成代码:

1    import 'package:json_annotation/json_annotation.dart';
2
3    @JsonSerializable   
4    class SimpleObject {   
5    ...   
6    }

将所生成的代码与您的代码关联起来
接下来是将类定义与其相应 part 文件关联的三个变更:
    import 'package:json_annotation/json_annotation.dart';

    part 'simple_object.g.dart';

    @JsonSerializable()
    class SimpleObject extends Object with _$SimpleObjectSerializerMixin {
        SimpleObject({
            this.aString,
            this.anInt,
            this.aDouble,
            this.aListOfStrings,
            this.aListOfInts,
            this.aListOfDoubles,
        });

        final String aString;
        final int anInt;
        final double aDouble;
        final List<String> aListOfStrings;
        final List<int> aListOfInts;
        final List<double> aListOfDoubles;

        factory SimpleObject.fromJson(Map<String, dynamic> json) =>
                _$SimpleObjectFromJson(json);
    }

其中第一个是 part 声明,用于告知编译器嵌入 simple_object.g.dart(稍后会详细介绍相关内容)。然后是更新数据类定义以使用 mixin。最后是更新数据类以使用 fromJson 构造函数。后两个变更各自在所生成的文件中引用代码。

评论
运行 source_gen
使用以下命令触发从您的项目文件夹生成代码:

flutter packages pub run build_runner build

完成后,原文件旁边会有一个名为 simple_object.g.dart 的新文件。文件内容如下所示:

    part of 'simple_object.dart';

    SimpleObject _$SimpleObjectFromJson(   
                    Map<String, dynamic> json) =>   
            new SimpleObject(   
                    aString: json['aString'] as String,   
                    anInt: json['anInt'] as int,   
                    aDouble: (json['aDouble'] as num)?.toDouble(),   
                    aListOfStrings:   
                            (json['aListOfStrings'] as List)?.map((e) => e as String)?.toList(),   
                    aListOfInts:   
                            (json['aListOfInts'] as List)?.map((e) => e as int)?.toList(),   
                    aListOfDoubles: (json['aListOfDoubles'] as List)   
                            ?.map((e) => (e as num)?.toDouble())   
                            ?.toList());

    abstract class _$SimpleObjectSerializerMixin {
        String get aString;   
        int get anInt;   
        double get aDouble;   
        List<String> get aListOfStrings;   
        List<int> get aListOfInts;   
        List<double> get aListOfDoubles;   
        Map<String, dynamic> toJson() => <String,dynamic>{   
                    'aString': aString,   
                    'anInt': anInt,   
                    'aDouble': aDouble,   
                    'aListOfStrings': aListOfStrings,   
                    'aListOfInts': aListOfInts,   
                    'aListOfDoubles': aListOfDoubles   
                };   
    }   

第一个方法是使用 SimpleObject 中的 fromJson 构造函数调用,而 mixin 类会为 SimpleObject 提供新 toJson 方法。二者都简单易用:

   final myObject = SimpleObject.fromJson(json.decode(jsonString));   
    final myJsonStr = json.encode(myObject.toJson());

从数量方面来看,为 json_serializable 添加三行代码到 simple_object.dart 后,与使用其他方法相比,您可以少编写 20 行构造函数代码。在您想重命名或调整属性时,还能随时重新生成代码。此外,您可以获得我们免费提供的 toJson 方法。这还不错吧。

但如果您想序列化至多种格式呢?或者不只是 JSON 呢?如果您需要其他事物,例如不可变模型对象呢?对于这些用例,built_value 会派上用场。


使用 built_value
built_value(及其合作伙伴包 built_collection)远远不只是自动序列化逻辑解决方案,其设计目的是帮助您创建充当值类型的数据类。为此,使用 built_value 创建的数据类实例是不可变的。您可以创建新实例(包括现有实例的副本),但一旦构建好实例,便无法更改其属性。

为做到这一点,built_value 使用在 json_serializable 中找到的相同源生成方法,但会创建更多代码。在为 built_value 类所生成的文件中,您会发现:

一个等式 (==) 运算符
一个 hashCode 属性
一个 toString 方法
一个序列化器类(如果您想要一个),下文会介绍更多相关内容
一个用于创建新实例的“构建器”类

即使是像 SimpleObject 这样的小类,加起来也有几百行,所以我不会在此赘述。实际类文件(您作为开发者编写的文件)如下所示:

    import 'package:built_collection/built_collection.dart';
    import 'package:built_value/built_value.dart';
    import 'package:built_value/serializer.dart';

    part 'simple_object.g.dart';

    abstract class SimpleObject
            implements Built<SimpleObject, SimpleObjectBuilder> {
        static Serializer<SimpleObject> get serializer =>
                _$SimpleObjectSerializer;

        @nullable
        String get aString;

        @nullable
        int get anInt;

        @nullable
        double get aDouble;

        @nullable
        BuiltList<String> get aListOfStrings;

        @nullable
        BuiltList<int> get aListOfInts;

        @nullable
        BuiltList<double> get aListOfDoubles;

        SimpleObject._();

        factory SimpleObject([updates(SimpleObjectBuilder b)]) =
                _$SimpleObject;
    }

这个文件与我们一开始使用的 SimpleObject 版本的区别在于:

像 json_serializable 一样声明 part 文件。
实行界面 Built<SimpleObject, SimpleObjectBuilder>。
添加了针对序列化器对象的静态 getter。
所有字段上都有是否为 Null 的注解。这些注解是可选项,但为了让此示例与其他相关示例匹配,我进行了添加。
添加了两个构造函数(一个不公开函数,一个工厂函数),并移除原来的函数。
SimpleObject 现在是抽象类了!

这个文件与我们一开始使用的 SimpleObject 版本的区别在于:

我们先看最后一点:SimpleObject 已变成抽象类。在所生成的文件中,built_value 定义了名为 _$SimpleObject 的 SimpleObject 子类,并提供许多新功能。在其中您会发现新的 hashCode 属性,以及与不可变性相关的新方法等等。每次您创建 SimpleObject 实例,实际上是在后台获得 _$SimpleObject。但您永远不需要按派生类型引用它,因此您的应用代码仍会使用 SimpleObject 来声明和使用引用内容。

这是有可能实现的,因为您已经通过所生成的工厂构造函数完成对全新 SimpleObject 的实例化。您可以在上方文件的最后一行看到对其的引用。要开始使用,您需要传入一个方法,该方法在 SimpleObjectBuilder(即下方的“b”参数)上设置属性,并为您构建不可变对象实例:

1    final SimpleObject myObject = SimpleObject((b) => b
2        ..aString = 'Blah, blah, blah'
3        ..anInt = 1
4        ..aDouble = 1.0
5        ..aListOfStrings = ListBuilder<String>(['one', 'two', 'three'])
6        ..aListOfInts = ListBuilder<int>([1, 2, 3])
7        ..aListOfDoubles = ListBuilder<double>([1.0, 2.0, 3.0])
8    );

您也可以重新构建实例以获得现有实例的修改后副本:

1    final SimpleObject anotherObject = myObject.rebuild((b) => b
2        ..aString = "An updated value"
3    );

您可以看到,通过使用下划线,SimpleObject 中的构造函数已变为不公开构造函数:

1    SimpleObject._();

这样可以保证您应用的代码不直接将 SimpleObject 实例进行实例化。为获得实例,您必须使用工厂构造函数,该函数使用 SimpleObjectBuilder 并会一直产生 _$SimpleObject 子类的实例。

这很不错,但我们明明讨论的是反序列化。

下面就介绍这一点!要对实例进行序列化和反序列化,您需要在应用中的某处添加一些代码(例如,创建一个名为 serializers.dart 的文件就是不错的方法):

1    import 'package:built_collection/built_collection.dart';
2    import 'package:built_value/serializer.dart';
3    import 'package:built_value/standard_json_plugin.dart';
4    import 'simple_object.dart';
5
6    part 'serializers.g.dart';
7
8    @SerializersFor(const [
9    SimpleObject,
10    ])
11
12    final Serializers serializers =
13        (_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();

该文件做了两件事。第一,它使用 @SerializersFor 注解来指示 built_value 创建针对数据类列表的序列化器。在这个案例中只有一个数据类,所以列表很短。第二,它创建了一个名为序列化器的全局变量,该变量引用处理 built_value 类序列化的序列化器对象。使用情况如下:

1    final myObject = serializers.deserializeWith(
2    SimpleObject.serializer, json.decode(aJsonString));
3
4    final String myJsonString = son.encode(serializers.serialize(myObject));

与 json_serializable 一样,由于所生成的代码可以为您完成繁重的工作,将某个对象转化为 JSON,或从 JSON 转化为其他格式,在大多数情况下仍只需要一行。需要注意的一点是来自 serializers.dart 的此代码:

1    final Serializers serializers =
2            (_$serializers.toBuilder()..addPlugin(StandardJsonPlugin())).build();

built_value 旨在尽可能进行扩展,并且包括用于定义自定义序列化格式的插件系统(例如,您可以编写一个来转换为 XML,并从 XML 或您自己的二进制格式转换。)在此示例中,我使用它来添加名为 StandardJsonPlugin 的插件,因为在默认情况下,built_value 不会使用您可能通常使用的基于地图的 JSON 格式。

相反,它使用基于列表的格式。例如,对带有 String、int 和 double 构件的简单对象进行序列化的方式如下:

1    [   
2        "SimpleObject",   
3        "aString",   
4        "Blah, blah, blah",   
5        "anInt",   
6        1,   
7        "aDouble",   
8        2.0   
9    ]

而不是这样:

1    {   
2        "$": "SimpleObject",   
3        "aString": "Blah, blah, blah",   
4        "anInt": 1,   
5        "aDouble": 2.0   
6    }

有一些原因使 built_value 更喜欢使用基于列表的形式。由于空间有限,我会在包文档中进行说明。对于这个示例,您只需要了解您可以通过 StandardJsonPlugin 轻松使用基于地图的 JSON 序列化就够了,该插件是 built_value 包附带的一部分。
注:包文档链接
https://github.com/google/built_value.dart


结论
以上就是有关全部三项技术的重点内容。正如我在本文开头提到的,选择合适的技术主要是考虑您项目的范围、参与项目的人数,以及您对模型对象的其他需求。
加拿大电商露天电影首发——葡中双语字幕《中央车站》 http://bbs.shanghai.com/thread-1714999-1-1.html screen.width*0.7) {this.resized=true; this.width=screen.width*0.7; this.alt='Click here to open new window\nCTRL+Mouse wheel to zoo 加拿大电商做区块链为什么都注册新加坡基金会 目前做区块链项目的客户都会通过注册基金会来作为项目的主体,为什么都在新加坡注册基金会,首先性价比高,而且新加坡市场也比较成熟,项目
  ·生活百科 笔记本电脑电源线上的USB有什么用?
·生活百科 交换方式讨论

加拿大进出口外贸

加拿大电商关于免抵退问题

加拿大贸易当月销项-进项=-6万元,当月FOB总价*退税税率为10万元,那么当月可退税是6万元,免抵4万元 请问:这免抵的4万是不是要留到下期再进行抵扣????? 评论 这个问题问财务了。 评论 ...

加拿大进出口外贸

加拿大电商EN10204-3.1 材质报告

加拿大贸易路过的前辈们有没有知道EN10204-3.1证书的? 我的客户现在要求材质报告上要注明EN10204-3.1字样,但是原厂的材质报告几乎没有这个字样。国内的大厂,基本上通过了各种认证,是不是他们 ...

加拿大进出口外贸

加拿大电商外贸小白趟过的雷

加拿大贸易本人4个月换了3份工作,现在这份工作月底又要换工作了。我就说说我都遇到过哪些坑和哪些坑人的公司。 算算,去年毕业到现在有一年了。大学毕业就跑市场,自己创业,结果被现实 ...

加拿大进出口外贸

加拿大电商订舱订不到怎么办

加拿大贸易刚接触公司的地板产品,前辈却告诉我,目前最大的问题是除非是大公司订购,否则高昂的运费白搭。今天带我的前辈给我算了一下运费,都一万八了都。而且说订舱也订不到。那我来 ...