开发手册

开发 - 数据操作

应用之间共享数据时,需要向提平台操作数据,或者从平台订阅数据。数据操作方面,这里主要涉及4个接口:新增数据、查询数据、删除数据、修改数据。详见后面的API参考。同时,为了便于应用开发,平台提供了SDK,简化开发。

SDK介绍

一. Java SDK

1. 依赖

<dependency>    <groupId>com.aliyun.api.gateway</groupId>    <artifactId>sdk-core-java</artifactId>    <version>1.0.4</version></dependency>

2. 示例代码

SyncApiClientsyncClient=SyncApiClient.newBuilder().appKey("1234567").appSecret("6726732dsfdsdsfdsfds").build();IoTApiRequestrequest=newIoTApiRequest();//设置api的版本request.setApiVer("0.1.0");// 接口参数request.putParam("json","{}");request.putParam("productKey","a1ILGykZVhP");request.putParam("deviceName","Dxb3lv1E78mg5dsVLUQW");request.putParam("serviceName","kkp");//请求参数域名、path、requestApiResponseresponse=syncClient.postBody("test123-cn-shanghai.alicloudapi.com","/invokeThingService",request);System.out.println("response code = "+response.getStatusCode()+" response content = "+newString(response.getBody(),"utf-8"));

二. Python SDK

1. 依赖:无

2. 示例代码  Step 1:下载示例工程代码。示例工程在基于Python 2.7,Python3请自行适配。

Step 2:修改signature_composer.py文件第49行

修改前:string_to_sign.append(_build_resource(uri=uri,body=body))修改后:string_to_sign.append(uri)

Step 3: 修改ClientDemo.py如下,执行调用

#!/usr/bin/env python# -*- coding: utf-8 -*-importosimportsysimportjsonsys_path=sys.path[0]ifnotos.path.isdir(sys_path):sys_path=os.path.dirname(sys_path)os.chdir(sys_path)fromcom.aliyun.api.gateway.sdkimportclientfromcom.aliyun.api.gateway.sdk.httpimportrequestfromcom.aliyun.api.gateway.sdk.commonimportconstanthost="https://api.link.aliyun.com"url="/data/model/data/query"cli=client.DefaultClient(app_key="1234567",app_secret="abcdefghijklmnopq")req_post=request.Request(host=host,protocol=constant.HTTPS,url=url,method="POST",time_out=30000)req_post.set_content_type(constant.CONTENT_TYPE_STREAM)body={    "request":    "apiVer":"0.0.2    "params":{        "modelId":"EMPLOYEE",        "returnFields":["employee_no","name"],        "conditions":[{"fieldName":"id","value":"1","operate":"mt"}],        "pageSize":100,        "pageNum":1    },    "version":"1.0"}bb=json.dumps(body).encode("utf-8")req_post.set_body(bb)print'==================================================='printstr(cli.execute(req_post)).decode('string_escape')print'==================================================='

三. JS SDK

1. 依赖

$# save into package.json dependencies with -S$ npm install aliyun-api-gateway-S$# you can use cnpm for fast install$ cnpm install aliyun-api-gateway-S

2. 示例代码

'use strict';constco=require('co');constClient=require('aliyun-api-gateway').Client;constclient=newClient('YOUR_APP_KEY','YOUR_APP_SECRET');co(function*(){    varurl='http://apiqingdaohttps.foundai.com/test1234';    varresult=yield client.post(url,{        data:{        'testtest':'query1Value'        },        headers:{            accept:'application/json'        }    });    console.log(JSON.stringify(result));});

数据操作API

一. API 描述

API名称

描述

Path

版本

新增数据

基于已经创建且被授权写入的模型,进行数据的新增。

/data/model/data/insert

0.0.3

删除数据

基于已经创建且被授权删除的模型,进行数据的更新。

/data/model/data/delete

0.0.2

修改数据

基于已经创建且被授权更新的模型,进行数据的更新。

/data/model/data/update

0.0.2

查询数据

基于已经创建且被授权查询的模型,进行数据的查询。

/data/model/data/query

0.0.3

获取文件上传地址

对于模型中指定为“图片”标签的字段,在该字段需要填写文件名,并且文件名需要通过该接口获取,该接口同时还会返回一个URL供用户上传文件。该地址有效期是10秒。

/data/model/data/upload

0.0.1

获取文件下载地址

对于模型中指定为“图片”标签的字段,在该字段的内容是一个系统分配的文件名,用户可以通过本接口,传入这个文件名,获取真实的文件下载地址。该地址有效期是10秒。

/data/model/data/download

0.0.1

二. API 约定

  1. 日期类型的参数传入格式:当前时间到格林威治时间1970年01月01日00时00分00秒的毫秒数。

  2. 数量查询的一些约定:

    1. 单次查询最多返回200条数据,未指定分页参数情况下,查询返回满足条件的前200条,可根据返回参数中的hasNext判断是否有更多数据。

    2. 若需要按照指定条件返回数据总数,则指定返回参数为COUNT,API返回参数中会带有COUNT以及对应的值。

    3. 若需要按照指定条件,及按照字段分组进行数量查询,则指定返回参数为COUNT(分组字段1,分组字段2),API返回参数中会带有COUNT以及对应的值。

  3. 更新删除的约定:单次操作,最多支持200条数据。

  4. 运算符定义:

算符

含义

备注

eq

equals

相等

neq

not equals

不相等

lt

less than

小于

lteq

less than or equals

小于等于

mt

more than

大于

mteq

more than or equals

大于等于

bt

between

在..之间

in

in

在..之内

nin

not in

不在..之内

nul

is null

为空

nnul

is not null

不为空

    数据包括系统属性,API中不允许赋值和更新系统属性,系统属性如下:

属性

描述

id

数据主键

creator

数据创建者

modifier

数据修改者

gmt_create

数据创建时间

gmt_modified

数据修改时间

    三. 数据新增API

    1. 请求参数:

    参数

    类型

    描述

    是否必传

    modelId

    String

    数据模型id

    properties

    JSON

    数据字段键值对,增加的字段的键只能是模型包含的字段,否则会报错,其中 Boolean属性的property传入”true”和”false”或者0和1。如:{“name”:”xxx”,”age”:18}

    scopeId

    String

    经常是项目的id,该参数非必填,一般上架应用被授权之后,会被默认绑定到一个scope中,因此当前操作会被默认操作到被绑定到的这一个scope中。但是,对于集成应用,也有可能被绑定到多个scope中,此时该操作需要填入scopeId。

    appId

    String

    对于SaaS应用,需要填该值

    2. 返回参数

    参数

    类型

    描述

    data

    Long

    数据主键id

    3. 请求示例

    {    "request":{    "apiVer":"0.0.3"//api版本号    },    "id":1508212818676,//request里的全局唯一id透传    "params":{        "modelId":"XXX123",//数据模型id        "scopeId":"fdbsdj1dfjdubgxxx",//数据模型id        "properties":{            "BRAND":"BMW",            "MODE":"5",            "CREATE_DATE":1526969423,            "LONG_SIZE":3.3,            "LONG_SIZE":2.2        }    },    "version":"1.0"//请求协议版本}

    4. 返回示例

    {    "code":200,    "message":"success",    "localizedMsg":null,    "data":12345}

    5. 返回码

    状态码

    描述

    其他说明

    200

    成功

    460

    参数验证异常

    会带有验证异常的详细说明

    500

    服务异常

    server error

    52002

    无访问权限

    52005

    找不到目标存储

    52009

    参数和模型定义不匹配

    52011

    数据类型校验错误

    四. 数据删除API

    1. 请求参数

    参数

    类型

    是否必传

    描述

    modelId

    String

    数据模型id

    conditions

    JSON

    数据条件,由字段名、运算符、比较值组成一个condition。如:[{“fieldName”: “id”,”operate”: “eq”,”value”: 7}]

    appId

    String

    对于SaaS应用,需要填该值

    scopeId

    String

    经常是项目的id,该参数非必填,一般上架应用被授权之后,会被默认绑定到一个scope中,因此当前操作会被默认操作到被绑定到的这一个scope中。但是,对于集成应用,也有可能被绑定到多个scope中,此时该操作需要填入scopeId。

    其中condition针对不同类型的属性支持的运算符:

    属性

    支持的运算符

    Integer

    eq,neq,lt,lteq,mt,mteq,bt,in,nin,nnull

    String

    eq,neq,,nnul,in,nin

    Double

    eq,neq,lt,lteq,mt,mteq,bt,in,nin,nnull

    Boolean

    eq,nnul

    Date

    eq,neq,lt,lteq,mt,mteq,bt,nnul

    2. 返回参数

    参数

    类型

    描述

    data

    Integer

    删除数据的条数

    3. 请求示例

    {"request":{"apiVer":"0.1.0"//api版本号},"id":1508212818676,//request里的全局唯一id透传"params":{"modelId":"XXX123","conditions":[{"fieldName":"BRAND","value":"BMW","operate":"eq"},{"fieldName":"MODE","value":"X5","operate":"eq"}]},"version":"1.0"//请求协议版本}

    4. 返回示例

    {"code":200,"message":"success","localizedMsg":null,"data":100}

    5. 返回码

    状态码

    描述

    说明

    200

    成功

    460

    参数验证异常

    会带有验证异常的详细说明

    500

    服务异常

    server error

    52002

    无访问权限

    五. 数据修改API

    1. 请求参数

    参数

    类型

    是否必传

    描述

    modelId

    String

    数据模型id

    updateDetails

    JSON

    更新的具体字段和值,字段需要是模型中包含的字段,否则会报错,其中 Boolean属性的property传入”true”和”false”或者0和1。如:{“name”:”xxxx”,”age”:20}

    conditions

    JSON

    条件,由字段名、运算符、比较值组成一个condition,格式如下:[{“fieldName”: “id”,”operate”: “eq”,”value”: 7}]fieldName表示 字段的名称operate表示操作符,操作符见上表value表示值

    appId

    String

    对于SaaS应用,需要填该值

    scopeId

    String

    经常是项目的id,该参数非必填,一般上架应用被授权之后,会被默认绑定到一个scope中,因此当前操作会被默认操作到被绑定到的这一个scope中。但是,对于集成应用,也有可能被绑定到多个scope中,此时该操作需要填入scopeId。

    其中condition针对不同类型的属性支持的运算符:

    属性

    支持的运算符

    Integer

    eq,neq,lt,lteq,mt,mteq,bt,in,nin,nnull

    String

    eq,neq,,nnul,in,nin

    Double

    eq,neq,lt,lteq,mt,mteq,bt,in,nin,nnull

    Boolean

    eq,nnul

    Date

    eq,neq,lt,lteq,mt,mteq,bt,nnul

    2. 返回参数

    参数

    类型

    描述

    data

    Integer

    更新数据的条数

    3. 请求示例

    {    "request":{        "apiVer":"0.0.3"//api版本号    },    "id":1508212818676,//request里的全局唯一id透传    "params":{        "modelId":"XXX123",        "conditions":[            {"fieldName":"BRAND","value":"BMW","operate":"eq"},            {"fieldName":"MODE","value":"X5","operate":"eq"}        ],        "updateDetails":{            "LONG_SIZE":4,            "WIDTH_SIZE":3        }    },    "version":"1.0"//请求协议版本}

    4. 返回示例

    {    "code":200,    "message":"success",    "localizedMsg":null,    "data":100}

    5. 返回码

    状态码

    描述

    200

    成功

    460

    参数验证异常

    会带有验证异常的详细说明

    500

    服务异常

    server error

    52002

    无访问权限

    52006

    资源更新错误

    52011

    数据类型校验错误

    六. 数据查询API

    1. 请求参数

    参数

    类型

    是否必传

    说明

    modelId

    String

    数据模型ID

    returnFields

    JSON

    指定返回的字段1.若期望返回所有字段,则传入参数为{““}2.若期望返回数据总数,则传入参数为{“COUNT”}2.若期望按照字段分组返回数据总数,则传入参数为{“COUNT(分组字段1,分组字段2)”}。如:[““]或者[“name”,”age”][COUNT][COUNT(name)]

    conditions

    JSON

    条件,由字段名、运算符、比较值组成一个condition。如:[{“fieldName”: “id”,”operate”: “eq”,”value”: 7}]

    orderBy

    JSON

    排序条件,由增序或降序以及排序字段组成。如:{“asc”:”true”,”orderByFields”:[“name”,”age”]}

    pageNum

    Integer

    分页页数

    pageSize

    Integer

    分页每页数量

    appId

    String

    对于SaaS应用,需要填该值

    scopeId

    String

    经常是项目的id,该参数非必填,一般上架应用被授权之后,会被默认绑定到一个scope中,因此当前操作会被默认操作到被绑定到的这一个scope中。但是,对于集成应用,也有可能被绑定到多个scope中,此时该操作需要填入scopeId。

    其中returnFields支持的函数类型:

    函数名称

    描述

    实例

    COUNT

    函数返回匹配指定条件的行数

    {“COUNT(分组字段1,分组字段2)”}

    DATE_FORMAT

    函数按照format字符串格式化字段值

    {“DATE_FORMAT(分组字段,format)”}

    SUM

    函数返回数值列的总数

    {“SUM(分组字段)”}

    AVG

    函数返回数值列的平均值

    {“AVG(分组字段)”}

    MIN

    函数返回数值列的最小值

    {“MIN(分组字段)”}

    MAX

    函数返回数值列的最大值

    {“MAX(分组字段)”}

    DATE_FORMAT支持的format修饰符

    修饰符名称

    描述

    %Y

    %Y-%m

    年月

    %Y-%m-%d

    年月日

    %Y-%m-%d %H

    年月日时

    %Y-%m-%d %H:%i

    年月日时分

    %Y-%m-%d %H:%i:%s

    年月日时分秒

    其中condition针对不同类型的属性支持的运算符:

    属性

    支持的运算符

    Integer

    eq,neq,lt,lteq,mt,mteq,bt,in,nin,nnull

    String

    eq,neq,,nnul,in,nin

    Double

    eq,neq,lt,lteq,mt,mteq,bt,in,nin,nnull

    Boolean

    eq,nnul

    Date

    eq,neq,lt,lteq,mt,mteq,bt,nnul

    2. 返回参数

    参数

    类型

    描述

    data

    String

    查询返回数据内容,其中,Boolean类型的属性返回值为0或1

    3. 请求示例-1

    {    "request":{        "apiVer":"0.0.2"//api版本号     },    "id":1508212818676,//request里的全局唯一id透传    "params":{        "modelId":"XXX123",        "returnFields":["MODE","ENGINE"],        "conditions":[            {"fieldName":"BRAND","value":"BMW","operate":"eq"},            {"fieldName":"WIDTH_SIZE","value":1,"value2":2,"operate":"bt"},            {"fieldName":"LONG_SIZE","value":"3","operate":"mt"}        ],        "orderBy":{            "asc":true,            "orderByFields":["CREATE_DATA","MODE"]        },        "pageNum":1,        "pageSize":10    },    "version":"1.0"//请求协议版本}

    4. 返回示例-1

    {    "code":200,    "localizedMsg":null,    "data":"{\"count\":1,        \"hasNext\":false,        \"items\":[{\"gmt_create\":1551872701000,\"MODE\":\"33\",\"ENGINE\":\"44\",\"id\":2,\"gmt_modified\":1551872714000}],        \"pageNum\":1,        \"pageSize\":10}",    "message":"success"}

    5. 请求示例-2

    {    "request":{        "apiVer":"0.1.0"//api版本号    },    "id":1508212818676,//request里的全局唯一id透传    "params":{        "modelId":"XXX123",        "returnFields":["COUNT",        "conditions":[            {"fieldName":"BRAND","value":"BMW","operate":"eq"},            {"fieldName":"WIDTH_SIZE","value":1,"value2":2,"operate":"bt"},            {"fieldName":"LONG_SIZE","value":"3","operate":"mt"}        ],        "pageNum":1,        "pageSize":10    },    "version":"1.0"//请求协议版本}

    6. 返回示例-2

    {    "code":200,    "localizedMsg":null,    "data":"{        \"hasNext\":false,        \"items\":[{            \"COUNT\":100        }]    }"    "message":"success"}

    7. 请求示例-分组数量查询

    {    "request":{        "apiVer":"0.1.0"//api版本号    },    "id":1508212818676,//request里的全局唯一id透传    "params":{        "modelId":"XXX123",        "returnFields":["COUNT(BRAND,NAME)"],        "conditions":[            {"fieldName":"BRAND","value":"BMW","operate":"eq"},            {"fieldName":"WIDTH_SIZE","value":1,"value2":2,"operate":"bt"},            {"fieldName":"LONG_SIZE","value":"3","operate":"mt"}        ],        "pageNum":1,        "pageSize":10    },    "version":"1.0"//请求协议版本}

    8. 返回示例分组数量查询

    {    "code":200,    "localizedMsg":null,    "message":"success",    "data":"{        \"hasNext\":false,        \"items\":[        {            \"COUNT\":100,            \"BRAND\":\"BMW\",            \"NAME\":\"X1\"        },{            \"COUNT\":200,            \"BRAND\":\"JEEP\",            \"NAME\":\"M2\"        }]    }"}

    9. 返回码

    状态码

    描述

    200

    成功

    460

    参数验证异常

    会带有验证异常的详细说明

    500

    服务异常

    server error

    52002

    无访问权限

    52005

    目标存储未找到

    七. 获取文件上传地址API

    1. 请求参数

    参数

    类型

    是否必传

    描述

    modelId

    String

    数据模型id

    version

    String

    数据模型的版本号

    fileSize

    Integer

    文件大小,以字节为单位,目前系统不支持5M以上文件

    attrName

    String

    属性名称,模型中包含的属性名称,不包含会报错进行提示

    fileType

    String

    文件类型,目前系统只支持bmp、png、gif、jpg

    appId

    String

    对于SaaS应用,需要填该值

    scopeId

    String

    经常是项目的id,该参数非必填,一般上架应用被授权之后,会被默认绑定到一个scope中,因此当前操作会被默认操作到被绑定到的这一个scope中。但是,对于集成应用,也有可能被绑定到多个scope中,此时该操作需要填入scopeId。

    2. 返回参数

    参数

    类型

    描述

    url

    String

    数据上传的url,url有效时间10s

    fileName

    String

    文件名称,系统随机分配的文件名称,用户在得到这个文件名之后,应该将其放在相应模型数据的文件类型的字段上,例如:xxxxx.jpg

    3. 请求示例

    {    "request":{        "apiVer":"0.0.1"//api版本号    },    "id":1508212818671,//request里的全局唯一id透传    "params":{        "modelId":"XXX123",//数据模型id        "fileSize":"3.2",//文件大小        "attrName":"name",//属性名称        "fileType":"jpg",//文件类型        "version":"1.0",//模型版本    },    "version":"1.0"//请求协议版本}

    4. 返回示例

    {    "code":200,//返回是否成功,只要不是200说明返回不成功    "message":"success",//如果失败会返回失败的信息描述    "localizedMsg":null,    "data":{"url":"http://xxx.xxx.xx","fileName":"xxx.jpg"}返回的数据}

    5. 返回码

    状态码

    描述

    200

    成功

    460

    参数验证异常

    会带有验证异常的详细说明

    500

    服务异常

    server error

    52002

    无访问权限

    52005

    找不到目标存储

    52009

    参数和模型定义不匹配

    52011

    数据类型校验错误

    52064

    属性字段没有相应的图片标签

    52063

    文件大小不能大于5M

    八. 获取文件下载地址API

    1. 请求参数

    参数

    类型

    是否必传

    描述

    modelId

    String

    数据模型id

    version

    String

    数据模型的版本号

    attrName

    String

    属性名称,模型中包含的属性名称,不包含会报错进行提示

    fileType

    String

    文件类型,目前系统只支持bmp、png、gif、jpg

    appId

    String

    对于SaaS应用,需要填该值

    scopeId

    String

    经常是项目的id,该参数非必填,一般上架应用被授权之后,会被默认绑定到一个scope中,因此当前操作会被默认操作到被绑定到的这一个scope中。但是,对于集成应用,也有可能被绑定到多个scope中,此时该操作需要填入scopeId。

    2. 返回参数

    参数

    类型

    描述

    url

    String

    数据上传的url,url有效时间10s

    3. 请求示例

    {    "request":{        "apiVer":"0.0.1"//api版本号    },    "id":1508212818671,//request里的全局唯一id透传    "params":{        "modelId":"XXX123",//数据模型id        "scopeId":"fdbsdj1dfjdubgxxx",//业务隔离id        "attrName":"name",//属性名称        "fileName":"xdsfxv.jpg",//文件类型        "version":"1.0",//模型版本    },    "version":"1.0"//请求协议版本}

    4. 返回示例

    {    "code":200,//返回是否成功,只要不是200说明返回不成功    "message":"success",//如果失败会返回失败的信息描述    "localizedMsg":null,    "data":{"url":"http://xxx.xxx.xx"}返回的数据下载查看的url}

    5. 返回码

    状态码

    描述

    200

    成功

    460

    参数验证异常

    会带有验证异常的详细说明

    500

    服务异常

    server error

    52002

    无访问权限

    52005

    找不到目标存储

    52009

    参数和模型定义不匹配

    52011

    数据类型校验错误

    52064

    属性字段没有相应的图片标签

    开发 - 数据订阅

    应用可以通过HTTP2方式,订阅数据的变更消息(新增、删除、修改)。应用自身不需要发布数据的变更消息到通道中,这些消息的产生是由应用通过上面的数据操作API,对数据进行操作之后,由平台产生。平台产生时间之后,会将消息通过订阅关系发送到订阅方。

    在这个消息通信中,每一个应用实例,由AppKey标识身份。对于单租户型的应用,每一个AppKey代表了一次应用分发的实例;但是,对于SaaS应用,他的一个AppKey代表了该应用对应的所有租户的身份,因此,在SaaS应用按照AppKey得到消息之后,需要自行根据订阅到的数据内容中的AppID字段,将数据对应到不用的用户中。

    SDK 介绍

    1. 依赖引用

    在工程中添加 maven 依赖接入 SDK。

    <dependency>    <groupId>com.aliyun.openservices</groupId>    <artifactId>iot-client-message</artifactId>    <version>1.1.3</version></dependency><dependency>    <groupId>com.aliyun</groupId>    <artifactId>aliyun-java-sdk-core</artifactId>    <version>3.7.1</version></dependency>

    2. 身份认证

    使用服务端订阅功能,需要基于AppKey进行身份认证并建立连接。该AppKey根据应用类型不同,有两种来源:

    • 对于独立单租户托管并分发的应用,该AppKey是由托管平台在应用实例化分发部署应用时,自动产生,并注入在主机的环境变量中,应用事先并不知道该值,需要动态从环境变量中获取。

    • 对于共享型应用,该AppKey是该SaaS应用在注册多租户接口时,从平台创建,并硬编码在应用中。

    StringappKey="XXXXXX";StringappSecret="XXXXXXXXXXXXXXXXXXXXXXX";Stringendpoint=String.format("https://%s.iot-as-http2.cn-shanghai.aliyuncs.com:443",appKey);// 连接配置Profileprofile=Profile.getAppKeyProfile(endpoint,appKey,appSecret);// 构造客户端MessageClientclient=MessageClientFactory.messageClient(profile);// 数据接收client.connect(messageToken->{    System.out.println(messageToken.getMessage());    returnMessageCallback.Action.CommitSuccess;});Thread.sleep(1000000);

    *注意:关于上述代码中的“connect”方法,需要额外说明的是该方法在未经过授权的情况下,会调用失败。所以请务必做好重试逻辑,以便应用一旦被授权之后,可以及时得到订阅消息。

    3. 设置消息接受接口

    连接建立后,服务端会立即向 SDK 推送已订阅的消息。因此,建立链接时,需要提供消息接收接口,用于处理未设置回调的消息。建议在connect之前,调用 setMessageListener 设置消息回调。

    您需要通过 MessageCallback 接口的consume方法,和调用 messageClient 的setMessageListener()方法来设置消息接收接口。consume 方法的返回值决定 SDK 是否发送 ACK。设置消息接收接口的方法如下:

    MessageCallbackmessageCallback=newMessageCallback(){    @Override    publicActionconsume(MessageTokenmessageToken){        Messagem=messageToken.getMessage();        log.info("receive : "+newString(messageToken.getMessage().getPayload()));        // TODO: 处理消息逻辑        returnMessageCallback.Action.CommitSuccess;    }};Stringtopic=String.format("/sys/appkey/%s/dop/model/data/change",appkey);messageClient.setMessageListener(topic,messageCallback);

    其中,Message消息字段如下:

    // 消息体byte[]payload;// TopicStringtopic;// 消息IDStringmessageId;// QoSintqos;

    payload内容是一个JSON对象字符串,字段信息如下:

    // 模型ID 
    StringmodelId; 
     
    // 变更数据的ID 
    List<Long>dataIds; 
     
    // 操作类型:insert/update/delete 
    StringoperateType; 
     
    // 订阅的appId, 以appKey授权时为空 
    StringappId;

    阿里云首页 AIoT能力中心 相关技术圈