http://services.odata.org 提供了允许进行 CRUD 的 OData 数据服务 ( OData data service ),版本为 v2,可以通过 http://services.odata.org/V2/(S(user-session-token))/OData/OData.svc/
访问。其中 user-session-token
需要替换成进入时网站分配的的 token , CRUD 也仅对该 Session 有效。
本篇介绍基于 OData v2,对 Northwind online data service 进行 CRUD 操作。介绍的重点包括:
- http 请求;
- 使用 Postman 发送 http 请求;
- 使用 ODataModel (v2) 提交 CRUD 方法和查看返回结果。
读取数据
OData Service 读取数据(Read)
读取 OData service 提供的数据,通过 http 的 GET
方法。如果请求成功,返回的状态码为 200,如果请求的资源不存在,返回的状态码为 404.。请求的数据可以是一个实体,也可以是一个集合 ( Set )。
我们先借助 Postman 这个 Chrome 插件来查看 Northwind 数据服务。我们来查看第一个供应商的信息。操作界面:
-
要点:
- URL:
http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/Suppliers(0)?$format=json
- Method type:
GET
- URL:
返回的结果:如上图所示。
ODataModel (v2) 读取 Odata 数据
首先指定 Service URL,因为 Same-origin 原因,使用代理( 请替换成自己的 user-session-token ):
var sServiceUrl = "https://cors-anywhere.herokuapp.com/"
+ "http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/";
读取数据的操作放在 readSupplier()
函数中:
// 读取供应商
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, 在开发者工具的 Console
选项卡中查看结果,因为第一次第一次读取的供应商 ID 存在,所以返回 200 状态码,成功。这是读取第一个供应商返回的对象:
因为第二个供应商不存在,所以返回错误状态码 404 - Not found。下图是读取第二个供应商返回的错误的界面:
ODataModel 读取数据的要点
ODataModel
的read()
方法触发一个GET
请求,如果请求成功,执行success
回调函数,该函数的oData
参数包含response
返回的数据,失败则执行error
回调函数。请求后返回的数据缓存在
OData model
中,可以调用getData()
方法(这个方法已经废弃),这个方法返回整个实体 ( Entity ) ; 调用getProperty()
方法,返回实体中的某一属性。这两个方法都不触发 http 请求,所以获得的是已经请求过并保存在缓存中的数据。示例如下:
// 读取 OData model 缓存的数据
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 的元数据 ( metadata ) 在
read()
方法调用后后被加载到客户端缓存。如果多个 OData model 使用同一个 url,则它们共享一个元数据,只有第一个 model 的请求会触发获取$metadata
请求。元数据的加载是异步的,并且也不能被设置为同步的。元数据是 XML 格式的,但OData model
的getServiceMetadata()
获取到的 model 元数据为元数据所对应的 json 格式。
新建数据
OData Service 可以使用 HTTP 协议的 POST 方法提交创建数据的请求,如果成功,返回的状态码为 201。
在 Chrome 插件 Postman 中提交 POST 请求,可以先用 GET 方法读取一条数据,然后将返回的数据拷贝出来进行修改的方式,简化操作过程。比如,我们想要创建一个新供应商,编号为 #101:
在 Postman 中,选择 POST 方法,URL 中输入:http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/Suppliers
。POST 请求的 URL 是一个集合。然后切换到 headers ,指定 Content-type
为 application/json
。
最后再切换到 Body,使用 Raw 格式,编写要提交的数据:
使用 ODataModel 创建供应商
// 创建供应商
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
});
}
修改数据
修改数据使用 PUT 方法,在 Postman 中操作时,选择 PUT 方法,URL 为:http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/Suppliers(101)
,Headers 页面添加 Content-type 和 If-match:
然后到 Body 页面,选择 Raw,编辑需要修改的数据。如果请求成功,返回状态码为 204 - No content。
使用 ODataModel 修改数据的代码:
// 修改供应商
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);
}
});
}
删除数据
删除 OData 的数据使用 DELETE 方法,在 Postman 中操作时,选择 DELETE 方法,URL 为:http://services.odata.org/V2/(S(tigt4zfne0egj3u25bhqq32a))/OData/OData.svc/Suppliers(101)
。Headers 需要指定 If-match:
因为删除数据不需要提交额外的数据,所以 Body 部分为空。如果请求成功,返回的状态码为 204 - No content。
使用 ODataModel 删除数据的代码如下:
// 删除供应商
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 缓存的数据
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);
}
});
}
// 创建供应商
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>