應(yīng)用開發(fā)
本章主要介紹應(yīng)用托管邊緣集群中需要的應(yīng)用改造和相關(guān)的操作流程。
1. 對接說明
應(yīng)用開發(fā)對接分為:操作系統(tǒng)適配、OAuth對接、數(shù)據(jù)模型對接、服務(wù)模型對接、LinkEdge對接、LinkVisual對接、其他平臺相關(guān)的組件對接。其中,“操作系統(tǒng)適配”是必須項,其他均為可選項,根據(jù)使用場景和項目總體設(shè)計方案而定
操作系統(tǒng)適配
:目前平臺基于CentOS 7.6構(gòu)建,因此應(yīng)用在對接前,請先確保能夠在此操作系統(tǒng)上正常運行,否則應(yīng)用需要做適當(dāng)適配;OAuth對接
:通過邊緣集群控制臺,直接訪問應(yīng)用內(nèi)部,無需重復(fù)登錄;數(shù)據(jù)模型、服務(wù)模型對接
:通過集成工作臺,對接領(lǐng)域服務(wù);Link IoT Edge對接
:云端指令下發(fā)邊緣集群,LE平臺會將指令轉(zhuǎn)發(fā)至某一組設(shè)備;LinkVisual對接
:邊緣集群內(nèi)部調(diào)用功能算法與圖像處理;2. OAuth對接
2.1 業(yè)務(wù)代碼改造
系統(tǒng)應(yīng)用環(huán)境變量中獲取訪問域名。System.getenv(“iot.hosting.api.domain”)
應(yīng)用跳轉(zhuǎn)IoT oauth驗證地址,同時攜帶認(rèn)證后跳轉(zhuǎn)的callback地址
IoT認(rèn)證后,攜帶授權(quán)碼oauthcode跳轉(zhuǎn)第2步callback的地址
應(yīng)用獲取到oauthcode后可以換取accesscode,并通過accesscode獲取到用戶的完整信息
調(diào)用流程
接入流程
獲取部署應(yīng)用的免登地址應(yīng)用通過API發(fā)送請求,獲取部署在邊緣集群內(nèi)部應(yīng)用的免登地址url。請求格式及示例具體參考文檔:邊緣集群免登開發(fā)文檔
http://30.42.82.42:32187/api/console/app/get?appKey=28135051
獲取部署應(yīng)用的host請求地址應(yīng)用通過API發(fā)起請求,獲取部署在邊緣集群內(nèi)部應(yīng)用的請求host。請求格式及示例具體參考文檔:邊緣集群免登開發(fā)文檔
http://30.42.82.42:32187/api/console/host/account
3.應(yīng)用請求發(fā)起用戶通過在應(yīng)用免登地址配置時的默認(rèn)地址來發(fā)起瀏覽器訪問,應(yīng)用需要判斷當(dāng)前請求需要進行IoT OAuth2免登IoT在驗證當(dāng)前用戶合法后,將生成當(dāng)前用戶授權(quán)碼oauthcode,在回跳redirect_uri地址時通過GET方式傳遞oauthcode,并同時返回state
2.2 請求格式及示例
具體參考文檔:邊緣集群免登開發(fā)文檔
http://30.42.82.42:32187/oauth2/auth?
redirect_uri=http://30.42.82.42:32187/index&
client_id=28135051&state=28135051&
response_type=code
2.3 入?yún)⒄f明
入?yún)⒚Q | 數(shù)據(jù)類型 | 是否必須 | 入?yún)⑹纠?/p> | 入?yún)⒚枋?/p> |
client_id | String | 是 | 28135051 | 應(yīng)用的appkey |
redirect_uri | String | 是 | OAuth認(rèn)證通過后的重定向應(yīng)用的URI,包含完整的域名 | |
response_type | String | 是 | code | 返回類型。根據(jù)OAuth 2.0標(biāo)準(zhǔn),目前支持設(shè)置此參數(shù)的取值為 |
state | String | 否 | 28135051 | 應(yīng)用的appkey攜帶項 |
scope | String | 否 | 空格分隔的OAuth范圍列表。如不指定此參數(shù)取值,則默認(rèn)為應(yīng)用注冊的全部OAuth范圍,加上scopid |
2.4 出參列表
出參名稱 | 數(shù)據(jù)類型 | 出參描述 |
code | 整形 | 響應(yīng)碼, 200: 成功 |
message | 字符串 | 錯誤消息 |
localizedMsg | 字符串 | 本地語言錯誤消息 |
data | 長整型 | 響應(yīng)結(jié)果 |
返回結(jié)果示例
http://30.42.82.42:32187/index?code=64a67ee15534defea7ad0d0535189b24&state=28135051
1.通過oauthcode換取accessToken接口獲取OAuth授權(quán)code后可通過該接口獲取accessToken身份信息。具體參考文檔:邊緣集群免登開發(fā)文檔2.通過accessToken換取用戶信息獲取accessToken信息后,可通過accessToken來換取登錄用戶的用戶信息。具體參考文檔:邊緣集群免登開發(fā)文檔
3. 數(shù)據(jù)模型-代碼改造
數(shù)據(jù)集成標(biāo)準(zhǔn)化的目標(biāo)是規(guī)范應(yīng)用之間數(shù)據(jù)的傳遞方式和表達方式。
傳遞方式:即應(yīng)用之間的數(shù)據(jù)如何流通。平臺提供了對數(shù)據(jù)進行增刪改查的4個API,以及HTTP2方式的消息訂閱機制。
表達方式:即應(yīng)用之間如何對數(shù)據(jù)內(nèi)容有一致的理解。為了實現(xiàn)這個目標(biāo),需要做到如下兩點,一是數(shù)據(jù)結(jié)構(gòu)需要由小二后臺統(tǒng)一管控(目前全部由小二后臺錄入,未來會引入審核機制);二是應(yīng)用集成對接之前(比如應(yīng)用上架的時候)需要聲明本應(yīng)用對哪些數(shù)據(jù)模型產(chǎn)生什么樣的數(shù)據(jù)操作(如查詢、新增,或者訂閱)。
API 描述
具體參考文檔:邊緣集群數(shù)據(jù)模型開發(fā)文檔
API名稱 | API描述 | API Path | API 版本 |
新增數(shù)據(jù) | 基于已經(jīng)創(chuàng)建且被授權(quán)寫入的模型,進行數(shù)據(jù)的新增。 | /data/model/data/insert | 0.0.3 |
刪除數(shù)據(jù) | 基于已經(jīng)創(chuàng)建且被授權(quán)刪除的模型,進行數(shù)據(jù)的更新。 | /data/model/data/delete | 0.0.2 |
修改數(shù)據(jù) | 基于已經(jīng)創(chuàng)建且被授權(quán)更新的模型,進行數(shù)據(jù)的更新。 | /data/model/data/update | 0.0.2 |
查詢數(shù)據(jù) | 基于已經(jīng)創(chuàng)建且被授權(quán)查詢的模型,進行數(shù)據(jù)的查詢。 | /data/model/data/query | 0.0.3 |
獲取文件上傳地址 | 對于模型中指定為“圖片”標(biāo)簽的字段,在該字段需要填寫文件名,并且文件名需要通過該接口獲取,該接口同時還會返回一個URL供用戶上傳文件。該地址有效期是10秒。 | /data/model/data/upload | 0.0.1 |
獲取文件下載地址 | 對于模型中指定為“圖片”標(biāo)簽的字段,在該字段的內(nèi)容是一個系統(tǒng)分配的文件名,用戶可以通過本接口,傳入這個文件名,獲取真實的文件下載地址。該地址有效期是10秒。 | /data/model/data/download | 0.0.1 |
日期類型的參數(shù)傳入格式:當(dāng)前時間到格林威治時間1970年01月01日00時00分00秒的毫秒數(shù)。
數(shù)量查詢的一些約定:
單次查詢最多返回200條數(shù)據(jù),未指定分頁參數(shù)情況下,查詢返回滿足條件的前200條,可根據(jù)返回參數(shù)中的hasNext判斷是否有更多數(shù)據(jù)。
若需要按照指定條件返回數(shù)據(jù)總數(shù),則指定返回參數(shù)為COUNT,API返回參數(shù)中會帶有COUNT以及對應(yīng)的值。
若需要按照指定條件,及按照字段分組進行數(shù)量查詢,則指定返回參數(shù)為COUNT(分組字段1,分組字段2),API返回參數(shù)中會帶有COUNT以及對應(yīng)的值。
更新刪除的約定:單次操作,最多支持200條數(shù)據(jù)。
運算符定義:
運算符 | 含義 | 備注 |
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 | 在..之內(nèi) |
nin | not in | 不在..之內(nèi) |
nul | is null | 為空 |
nnul | is not null | 不為空 |
5.數(shù)據(jù)包括系統(tǒng)屬性,API中不允許賦值和更新系統(tǒng)屬性,系統(tǒng)屬性如下:
屬性 | 描述 |
id | 數(shù)據(jù)主鍵 |
creator | 數(shù)據(jù)創(chuàng)建者 |
modifier | 數(shù)據(jù)修改者 |
gmt_create | 數(shù)據(jù)創(chuàng)建時間 |
gmt_modified | 數(shù)據(jù)修改時間 |
4.服務(wù)模型-代碼改造
4.1設(shè)計目標(biāo)
用于規(guī)范應(yīng)用之間行為表達方式和對結(jié)果的預(yù)期。
對于服務(wù)提供方來講,通過服務(wù)標(biāo)準(zhǔn)化,能夠清晰而簡潔的表達本服務(wù)提供了哪些接口、定義、以及他們所應(yīng)實現(xiàn)的具體功能,并且任何對該服務(wù)所提供的能力有依賴的應(yīng)用,都必須按照這套接口來實現(xiàn)服務(wù)供應(yīng);
對于服務(wù)依賴方來講,(即使用該服務(wù)的應(yīng)用)能夠清晰而簡潔的表達他所依賴的接口有哪些,分別期望這些接口完成什么樣的具體功能,并且任何為其提供服務(wù)的應(yīng)用,只要遵循相同的服務(wù)模型,即可實現(xiàn)服務(wù)提供方的替換。
4.2 概念定義
對服務(wù)模型的定義,如下幾點說明:
服務(wù)即接口。我們這里定義的服務(wù),從概念上理解,這是一個對應(yīng)用能力的抽象表達;但是從實際操作層面,服務(wù)的實際體現(xiàn)方式,就是RESTful風(fēng)格的HTTP接口。
接口是分組的。分組的原則是能力原子化,即我們按照接口的能力范圍,將一組完成功能閉環(huán)的接口標(biāo)定為一組。并且,我們將這一組接口,定義為“一個服務(wù)模型”。
服務(wù)模型是受管控的。目前,每一個服務(wù)模型都是由行業(yè)小二在后臺制定并發(fā)布。ISV在實踐過程中可以根據(jù)實際情況,向相關(guān)小兒提出調(diào)整意見。
服務(wù)模型是有版本的。一個基礎(chǔ)服務(wù)模型,隨著不用ISV、不同場景的需求,會有版本迭代。因此,唯一確定一個服務(wù)模型提供的接口信息的,是模型ID+版本。
具體參考文檔:邊緣集群服務(wù)模型開發(fā)文檔
4.3 具體對接步驟
系統(tǒng)應(yīng)用環(huán)境變量中獲取訪問域名。System.getenv(“iot.hosting.mesh.domain”)
用appkey和appsecret進行鑒權(quán)和建立連接。
填寫對應(yīng)服務(wù)模型接口的參數(shù)值和API版本。
發(fā)送請求到iot網(wǎng)關(guān)路由,獲取到服務(wù)模型接口返回結(jié)果。
請求示例
/**
* 系統(tǒng)環(huán)境變量中獲取的
*/
public static final String appKey = System.getenv("iot.hosting.appKey");
public static final String AppSecret = System.getenv("iot.hosting.appSecret");
//服務(wù)模型請求的路由
private static final String SERVICE_EDGE__PATH = System.getenv("iot.hosting.mesh.domain");
public static void main(String[] args) throws UnsupportedEncodingException {
IoTApiClientBuilderParams ioTApiClientBuilderParams =
new IoTApiClientBuilderParams();
ioTApiClientBuilderParams.setAppKey("你的<AppKey>");
ioTApiClientBuilderParams.setAppSecret("你的<AppSecret>");
SyncApiClient syncClient = new SyncApiClient(ioTApiClientBuilderParams);
IoTApiRequest request = new IoTApiRequest();
//設(shè)置api的版本
request.setApiVer("1.0");
request.putParam("requestId", "213123");
request.putParam("meterNo", "213123");
request.putParam("amount", "213123");
request.putParam("sourceAppId", "213123");
request.putParam("targetAppId", "213123");
//請求參數(shù)版本,域名、path、request
request.setVersion("1.0");
//請求參數(shù)域名、path、request
ApiResponse response = syncClient.postBody(SERVICE_EDGE__PATH,
"/服務(wù)名稱/接口名稱", request, true);
System.out.println( "response code = " + response.getCode()
+ " response = " + new String(response.getBody(), "UTF-8"));
}