http://services.odata.org 提供了允許進行 CRUD 的 OData 數(shù)據(jù)服務 ( OData data service )妆艘,版本為 v2,可以通過 http://services.odata.org/V2/(S(user-session-token))/OData/OData.svc/
訪問麸祷。其中 user-session-token
需要替換成進入時網(wǎng)站分配的的 token , CRUD 也僅對該 Session 有效。
本篇介紹基于 OData v2,對 Northwind online data service 進行 CRUD 操作楚殿。介紹的重點包括:
- http 請求侠畔;
- 使用 Postman 發(fā)送 http 請求结缚;
- 使用 ODataModel (v2) 提交 CRUD 方法和查看返回結果。
讀取數(shù)據(jù)
OData Service 讀取數(shù)據(jù)(Read)
讀取 OData service 提供的數(shù)據(jù)软棺,通過 http 的 GET
方法红竭。如果請求成功,返回的狀態(tài)碼為 200喘落,如果請求的資源不存在茵宪,返回的狀態(tài)碼為 404.。請求的數(shù)據(jù)可以是一個實體瘦棋,也可以是一個集合 ( Set )稀火。
我們先借助 Postman 這個 Chrome 插件來查看 Northwind 數(shù)據(jù)服務。我們來查看第一個供應商的信息赌朋。操作界面:
-
要點:
- URL:
http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/Suppliers(0)?$format=json
- Method type:
GET
- URL:
返回的結果:如上圖所示凰狞。
ODataModel (v2) 讀取 Odata 數(shù)據(jù)
首先指定 Service URL,因為 Same-origin 原因沛慢,使用代理( 請?zhí)鎿Q成自己的 user-session-token ):
var sServiceUrl = "https://cors-anywhere.herokuapp.com/"
+ "http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/";
讀取數(shù)據(jù)的操作放在 readSupplier()
函數(shù)中:
// 讀取供應商
function readSupplier(){
var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl);
function fnSuccess(oData, oResponse){
console.log("Response", oResponse);
console.log("Data", oData);
}
function fnError(oError){
console.log("Error", oError);
}
// 讀取存在的 supplier
oModel.read("/Suppliers(0)", {
success: fnSuccess,
error: fnError
});
// 故意讀取一個不存在的 supplier
oModel.read("/Suppliers(12222)", {
success: fnSuccess,
error: fnError
});
}
在 Chrome 瀏覽器中運行赡若,按下 F12, 在開發(fā)者工具的 Console
選項卡中查看結果,因為第一次第一次讀取的供應商 ID 存在团甲,所以返回 200 狀態(tài)碼逾冬,成功。這是讀取第一個供應商返回的對象:
因為第二個供應商不存在躺苦,所以返回錯誤狀態(tài)碼 404 - Not found粉渠。下圖是讀取第二個供應商返回的錯誤的界面:
ODataModel 讀取數(shù)據(jù)的要點
ODataModel
的read()
方法觸發(fā)一個GET
請求分冈,如果請求成功,執(zhí)行success
回調(diào)函數(shù)霸株,該函數(shù)的oData
參數(shù)包含response
返回的數(shù)據(jù)雕沉,失敗則執(zhí)行error
回調(diào)函數(shù)。請求后返回的數(shù)據(jù)緩存在
OData model
中去件,可以調(diào)用getData()
方法(這個方法已經(jīng)廢棄)坡椒,這個方法返回整個實體 ( Entity ) ; 調(diào)用getProperty()
方法,返回實體中的某一屬性尤溜。這兩個方法都不觸發(fā) http 請求倔叼,所以獲得的是已經(jīng)請求過并保存在緩存中的數(shù)據(jù)。示例如下:
// 讀取 OData model 緩存的數(shù)據(jù)
function getData(){
var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl);
oModel.read("/Suppliers", {
success: function(oData, oResponse){
// 兩種方法讀取 supplier name
var oSupplier = oModel.getData("/Suppliers(1)");
console.log(oSupplier.Name); // 方法1
console.log(oModel.getProperty("/Suppliers(1)/Name")); // 方法2
},
error: function(oError){
console.log("Error", oError);
}
});
}
oDataModel.read()
方法從 OData data service 獲取所有供應商放在oModel
的緩存中宫莱,然后通過getData("/Suppliers(0)")
獲取第一個供應商丈攒。因為oSupplier
是一個對象,所以可以通過oSupplier.Name
獲取供應商名稱授霸,也可直接通過oModel.getProperty("/Suppliers(0)/Name)
獲取供應商名稱巡验。OData data service 的元數(shù)據(jù) ( metadata ) 在
read()
方法調(diào)用后后被加載到客戶端緩存。如果多個 OData model 使用同一個 url碘耳,則它們共享一個元數(shù)據(jù)显设,只有第一個 model 的請求會觸發(fā)獲取$metadata
請求。元數(shù)據(jù)的加載是異步的辛辨,并且也不能被設置為同步的捕捂。元數(shù)據(jù)是 XML 格式的,但OData model
的getServiceMetadata()
獲取到的 model 元數(shù)據(jù)為元數(shù)據(jù)所對應的 json 格式斗搞。
新建數(shù)據(jù)
OData Service 可以使用 HTTP 協(xié)議的 POST 方法提交創(chuàng)建數(shù)據(jù)的請求指攒,如果成功,返回的狀態(tài)碼為 201僻焚。
在 Chrome 插件 Postman 中提交 POST 請求幽七,可以先用 GET 方法讀取一條數(shù)據(jù),然后將返回的數(shù)據(jù)拷貝出來進行修改的方式溅呢,簡化操作過程澡屡。比如,我們想要創(chuàng)建一個新供應商咐旧,編號為 #101:
在 Postman 中驶鹉,選擇 POST 方法,URL 中輸入:http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/Suppliers
铣墨。POST 請求的 URL 是一個集合室埋。然后切換到 headers ,指定 Content-type
為 application/json
。
最后再切換到 Body姚淆,使用 Raw 格式孕蝉,編寫要提交的數(shù)據(jù):
使用 ODataModel 創(chuàng)建供應商
// 創(chuàng)建供應商
function createSupplier(){
var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl);
oModel.setUseBatch(false);
oModel.setHeaders({
"Content-type":"application/json"
});
function fnSuccess(oData, oResponse){
console.log("Response", oResponse);
}
function fnError(oError){
console.log("Error", oError);
}
var oNewSupplier = {
"ID": 101,
"Name": "Stone測試供應商#101",
"Address": {
"Street": "三角湖路",
"City": "武漢",
"State": "HB",
"ZipCode": "430060",
"Country": "中國"
}
};
oModel.create("/Suppliers", oNewSupplier, {
success: fnSuccess,
error: fnError
});
}
修改數(shù)據(jù)
修改數(shù)據(jù)使用 PUT 方法,在 Postman 中操作時腌逢,選擇 PUT 方法降淮,URL 為:http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/Suppliers(101)
,Headers 頁面添加 Content-type 和 If-match:
然后到 Body 頁面搏讶,選擇 Raw佳鳖,編輯需要修改的數(shù)據(jù)。如果請求成功媒惕,返回狀態(tài)碼為 204 - No content系吩。
使用 ODataModel 修改數(shù)據(jù)的代碼:
// 修改供應商
function editSupplier(){
var oModel = new sap.ui.model.odata.v2.ODataModel({
serviceUrl: sServiceUrl,
headers: {
"If-match": "*"
}});
var oChanges = {
"Name": "Stone測試供應商#101",
"Address": {
"Street": "博學路",
"City": "武漢",
"State": "HB",
"ZipCode": "430060",
"Country": "China"
}
};
oModel.update("/Suppliers(101)", oChanges, {
success: function(oData, oResponse){
console.log("Response", oResponse);
},
error: function(oError){
console.log("Error", oError);
}
});
}
刪除數(shù)據(jù)
刪除 OData 的數(shù)據(jù)使用 DELETE 方法,在 Postman 中操作時妒蔚,選擇 DELETE 方法穿挨,URL 為:http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/Suppliers(101)
。Headers 需要指定 If-match:
因為刪除數(shù)據(jù)不需要提交額外的數(shù)據(jù)肴盏,所以 Body 部分為空科盛。如果請求成功,返回的狀態(tài)碼為 204 - No content叁鉴。
使用 ODataModel 刪除數(shù)據(jù)的代碼如下:
// 刪除供應商
function deleteSupplier(){
var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl);
// set headers
oModel.setHeaders({
"If-match": "*"
});
oModel.remove("/Suppliers(101)", {
success: function (oData, oResponse){
console.log(oResponse);
},
error: function (oError){
console.log(oError);
}
});
}
最后給出測試的完整代碼:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv='Content-Type' content='text/html;charset=UTF-8'/>
<script src="../../resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.m"
data-sap-ui-theme="sap_bluecrystal">
</script>
<!-- only load the mobile lib "sap.m" and the "sap_bluecrystal" theme -->
<script>
var sServiceUrl = "https://cors-anywhere.herokuapp.com/"
+ "http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/";
// 讀取供應商
function readSupplier(){
var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl);
function fnSuccess(oData, oResponse){
console.log("Response", oResponse);
console.log("Data", oData);
}
function fnError(oError){
console.log("Error", oError);
}
// 讀取存在的 supplier
oModel.read("/Suppliers(0)", {
success: fnSuccess,
error: fnError
});
// 讀取不存在的 supplier
oModel.read("/Suppliers(12222)", {
success: fnSuccess,
error: fnError
});
}
// 讀取 OData model 緩存的數(shù)據(jù)
function getData(){
var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl);
oModel.read("/Suppliers", {
success: function(oData, oResponse){
// 兩種方法讀取 supplier name
var oSupplier = oModel.getData("/Suppliers(1)");
console.log(oSupplier.Name);
console.log(oModel.getProperty("/Suppliers(1)/Name"));
},
error: function(oError){
console.log("Error", oError);
}
});
}
// 創(chuàng)建供應商
function createSupplier(){
var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl);
oModel.setUseBatch(false);
oModel.setHeaders({
"Content-type":"application/json"
});
function fnSuccess(oData, oResponse){
console.log("Response", oResponse);
}
function fnError(oError){
console.log("Error", oError);
}
var oNewSupplier = {
"ID": 101,
"Name": "Stone測試供應商#101",
"Address": {
"Street": "三角湖路",
"City": "武漢",
"State": "HB",
"ZipCode": "430060",
"Country": "中國"
}
};
oModel.create("/Suppliers", oNewSupplier, {
success: fnSuccess,
error: fnError
});
}
// 修改供應商
function editSupplier(){
var oModel = new sap.ui.model.odata.v2.ODataModel({
serviceUrl: sServiceUrl,
headers: {
"If-match": "*"
}});
var oChanges = {
"Name": "Stone測試供應商-#101",
"Address": {
"Street": "博學路",
"City": "武漢",
"State": "HB",
"ZipCode": "430060",
"Country": "China"
}
};
oModel.update("/Suppliers(101)", oChanges, {
success: function(oData, oResponse){
console.log("Response", oResponse);
},
error: function(oError){
console.log("Error", oError);
}
});
}
// 刪除供應商
function deleteSupplier(){
var oModel = new sap.ui.model.odata.v2.ODataModel(sServiceUrl);
// set headers
oModel.setHeaders({
"If-match": "*"
});
oModel.remove("/Suppliers(101)", {
success: function (oData, oResponse){
console.log(oResponse);
},
error: function (oError){
console.log(oError);
}
});
}
sap.ui.getCore().attachInit(function(){
var oReadButton = new sap.m.Button({
text: "Read",
press: readSupplier
});
var oGetDataButton = new sap.m.Button({
text: "Get data",
press: getData
});
var oCreateButton = new sap.m.Button({
text: "Create",
press: createSupplier
});
var oEditButton = new sap.m.Button({
text: "Edit",
press: editSupplier
});
var oDeleteButton = new sap.m.Button({
text: "Delete",
press: deleteSupplier
});
var oPage = new sap.m.Page({
title: "基于oData Model的增刪改查",
content: [oReadButton, oGetDataButton, oCreateButton, oEditButton, oDeleteButton]
});
var oApp = new sap.m.App({
initialPage: oPage
});
oApp.addPage(oPage);
oApp.placeAt("content");
});
</script>
</head>
<body class="sapUiBody" role="application">
<div id="content"></div>
</body>
</html>