服務總線
1. 整體介紹
1.1. 設計目標
用于規范應用之間行為表達方式和對結果的預期。
對于服務提供方來講,通過服務標準化,能夠清晰而簡潔的表達本服務提供了哪些接口、定義、以及他們所應實現的具體功能,并且任何對該服務所提供的能力有依賴的應用,都必須按照這套接口來實現服務供應;
對于服務依賴方來講,(即使用該服務的應用)能夠清晰而簡潔的表達他所依賴的接口有哪些,分別期望這些接口完成什么樣的具體功能,并且任何為其提供服務的應用,只要遵循相同的服務模型,即可實現服務提供方的替換。
1.2. 概念定義
對服務模型的定義,如下幾點說明:
服務即接口。我們這里定義的服務,從概念上理解,這是一個對應用能力的抽象表達;但是從實際操作層面,服務的實際體現方式,就是RESTful風格的HTTP接口。
接口是分組的。分組的原則是能力原子化,即我們按照接口的能力范圍,將一組完成功能閉環的接口標定為一組。并且,我們將這一組接口,定義為“一個服務模型”。
服務模型是受管控的。目前,每一個服務模型都是由行業小二在后臺制定并發布。ISV在實踐過程中可以根據實際情況,向相關小二提出調整意見。
服務模型是有版本的。一個基礎服務模型,隨著不用ISV、不同場景的需求,會有版本迭代。因此,唯一確定一個服務模型提供的接口信息的,是模型ID+版本。
2. 服務管控流程
3. 服務模型的管理
服務模型的定義,是由平臺統一管控的。ISV在應用開發和實踐中,如果需要修改或者全新定義服務模型,請聯系相關人員。
4. 服務模型的聲明
模型的聲明分兩個角度:服務模型的依賴和服務模型的提供。一個應用在正式上架前,需要聲明該應用所提供的服務和所依賴的服務。模型的聲明入口,見下圖:
4.1 服務的依賴配置
如下圖所示:
上圖中顯示,服務的依賴,是需要指定到模型下面的某一個或者多個接口的。進入配置頁面,如下:
4.2 服務的提供配置
如下圖所示:
圖中,需要用戶指定的,除了模型之外,還有指定模型版本和提供該服務能力的節點,如上紅色區域。
5. 服務模型的調試
應用開發完成之后,如果應用依賴或者提供服務模型的能力,那勢必需經過集成調試,方可上架。應用的調試分成兩類:服務依賴的調試、服務提供的調試。
5.1 服務依賴的調試
當應用依賴一個服務時,它的調試過程需要有一個虛擬的服務提供者來為該應用提供服務,并且監測每一次應用的服務調用。
5.2 服務提供的調試
當應用提供一個服務時,它的調試過程需要有一個虛擬的客戶端,來發起對該應用該服務的調用,并且監測每一次應用的服務調用。
首先,進入
,指定要調試的服務,并啟動客戶端,啟動之后界面如下:啟動之后,ISV就可以進入每一個接口,模擬該接口向當前應用發起服務調試了。用戶可以在調試界面看到服務調用的數據
6. 服務模型的集成
在項目集成階段,當應用之間有服務依賴關系時,需要在集成工作臺,將服務的提供方①和依賴方②關聯起來。
7. ISV開發示例
服務模型的開發主要分為兩個部分:服務提供和服務依賴。服務提供,為第三方提供標準化的服務接口;服務依賴,使用第三方提供的服務。
7.1 案例介紹
以實現停車場服務模型(模型ID為:“parking”)的API(標識符為:“qrcodePayAndPush”)為例,分別介紹如何實現一個托管應用,**服務提供方如何實現聲明的服務模型的服務能力,以及服務依賴方如何調用該服務**。模型定義如下:
qrcodePayAndPush接口定義如下:
7.2 服務提供的開發示例
需要實現服務模型中的API定義,應用必須實現聲明的服務模型的所有的API定義,并且實現的API 入參和出參需要完全保持一致。示例代碼:
@Slf4j
@Controller
@Configuration
@RequestMapping("/parking")
public class ParkingController {
@Resource
private ParkingService parkingService;
/**
* 發送支付二維碼到顯示屏(出場時)
*
* @param qrcodeRequest
* @return
*/
@PostMapping("/qrcodePayAndPush")
public @ResponseBody
BaseResponse<PushQrcodeResponse> receiveMessage(
@RequestBody BaseRequest<PushQrcodeRequest> qrcodeRequest) {
System.out.println("qrcodeRequest info: " + qrcodeRequest.toString());
PushQrcodeResponse pushQrcodeResponse = new PushQrcodeResponse();
pushQrcodeResponse.setQrcodeUrl("www.****.com/qrcodePayAndPush");
BaseResponse<PushQrcodeResponse> response = new BaseResponse<>();
response.setId(qrcodeRequest.getId());
response.setData(pushQrcodeResponse);
return response;
}
}
public class PushQrcodeRequest implements Serializable {
private static final long serialVersionUID = 1L;
/**
* deviceUuid
*/
private String campusId;
/**
* 訂單號
*/
private String tradeNo;
/**
* 需要支付的金額
*/
private String totalAmount;
/**
* 設備uuid
*/
private String deviceUuid;
public String getCampusId() {
return campusId;
}
public void setCampusId(String campusId) {
this.campusId = campusId;
}
public String getTradeNo() {
return tradeNo;
}
public void setTradeNo(String tradeNo) {
this.tradeNo = tradeNo;
}
public String getTotalAmount() {
return totalAmount;
}
public void setTotalAmount(String totalAmount) {
this.totalAmount = totalAmount;
}
public String getDeviceUuid() {
return deviceUuid;
}
public void setDeviceUuid(String deviceUuid) {
this.deviceUuid = deviceUuid;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"campusId\":\"")
.append(campusId == null ? "" : campusId).append('\"');
sb.append(",\"tradeNo\":\"")
.append(tradeNo == null ? "" : tradeNo).append('\"');
sb.append(",\"totalAmount\":")
.append(totalAmount);
sb.append(",\"deviceUuid\":\"")
.append(deviceUuid == null ? "" : deviceUuid).append('\"');
sb.append('}');
return sb.toString();
}
}
public class PushQrcodeResponse implements Serializable {
private static final long serialVersionUID = 1L;
/**
* qrcodeUrl
*/
private String qrcodeUrl;
public String getQrcodeUrl() {
return qrcodeUrl;
}
public void setQrcodeUrl(String qrcodeUrl) {
this.qrcodeUrl = qrcodeUrl;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"qrcodeUrl\":\"")
.append(qrcodeUrl == null ? "" : qrcodeUrl).append('\"');
sb.append('}');
return sb.toString();
}
}
public class BaseResponse<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* request里的全局唯一id透傳
*/
private String id;
/**
* code
*/
private int code = 200;
/**
* 失敗時必填,錯誤調試信息;成功時不填
*/
private String message;
/**
* 失敗時必填,用戶可理解語言描述的錯誤信息;成功時不填
*/
private String localizedMsg;
/**
* 成功時必填,失敗時選填
*/
private T data;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getLocalizedMsg() {
return localizedMsg;
}
public void setLocalizedMsg(String localizedMsg) {
this.localizedMsg = localizedMsg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"id\":\"")
.append(id == null ? "" : id).append('\"');
sb.append(",\"code\":")
.append(code);
sb.append(",\"message\":\"")
.append(message == null ? "" : message).append('\"');
sb.append(",\"localizedMsg\":\"")
.append(localizedMsg == null ? "" : localizedMsg).append('\"');
sb.append(",\"data\":")
.append(data);
sb.append('}');
return sb.toString();
}
}
public class BaseRequest<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* request里的全局唯一id透傳
*/
private String id;
/**
* 請求協議版本
*/
private String version;
/**
* 失敗時必填,錯誤調試信息;成功時不填
*/
private Map<String, Object> request;
/**
* 失敗時必填,用戶可理解語言描述的錯誤信息;成功時不填
*/
private T params;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public Map<String, Object> getRequest() {
return request;
}
public void setRequest(Map<String, Object> request) {
this.request = request;
}
public T getParams() {
return params;
}
public void setParams(T params) {
this.params = params;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"id\":\"")
.append(id == null ? "" : id).append('\"');
sb.append(",\"version\":\"")
.append(version == null ? "" : version).append('\"');
sb.append(",\"request\":")
.append(request);
sb.append(",\"params\":")
.append(params);
sb.append('}');
return sb.toString();
}
}
7.3 服務依賴的開發示例
A. 開發包依賴
<dependency>
<groupId>com.aliyun.api.gateway</groupId>
<artifactId>sdk-core-java</artifactId>
<version>1.6.0.3</version>
</dependency>
B. 示例代碼
HttpClientBuilderParams builderParams = new HttpClientBuilderParams();
builderParams.setAppKey("123****"); // 請填寫正確的AppKey
builderParams.setAppSecret("6726732dsfdsdsfd****"); // 請填寫正確的AppSecret
ApacheHttpClient apacheHttpClient = new ApacheHttpClient(builderParams);
IoTApiRequest request = new IoTApiRequest();
//服務模型的API的版本,注意不是服務模型的版本。
request.setApiVer("1.0");
//如果需要登錄,設置當前的會話的token
//設置參數
request.putParam("campusId", "testCampusId");
request.putParam("tradeNo", "tradeNoTest");
request.putParam("totalAmount", "12.2");
request.putParam("deviceUuid", "testUuid");
//請求參數域名、path、request
String host = "service-mesh.api-iot.cn-shanghai.aliyuncs.com";
String path = "/parking/qrcodePayAndPush";
System.out.println(JSON.toJSONString(request));
ApiRequest apiRequest = new ApiRequest(HttpScheme.HTTP, host,
HttpMethod.POST_BODY, path, JSON.toJSONBytes(request));
apiRequest.setHttpConnectionMode(HttpConnectionModel.MULTIPLE_CONNECTION);
ApiResponse response = apacheHttpClient.sendSyncRequest(apiRequest);
System.out.println(request.getId());
System.out.println(
"response code = " + response.getCode() + " response message = " + response.getMessage()
+ " response content = " + new String(response.getBody(),
"utf-8"));