SAPUI5 (26) - 基于 ODataModel 的增删改查

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

返回的结果:如上图所示。

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。下图是读取第二个供应商返回的错误的界面:

07.png

ODataModel 读取数据的要点

  • ODataModelread() 方法触发一个 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 modelgetServiceMetadata() 获取到的 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-typeapplication/json

041.png

最后再切换到 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>

源代码

26_zui5_odata_crud_northwind

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容