SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下)

继续上一篇的内容,完成使用 OData Model 连接到后端 SAP 系统,实现 CRUD 操作。

程序界面:

点击 Create 按钮,弹出对话框:

输入 id, name 和 Address,点击 Save 按钮保存数据,点击 Cancel 按钮取消。

单击 table 中某行后,点击 Edit 按钮,弹出对话框:

可以进行修改操作。

单击 table 中某行后,点击 Delete 按钮,提示确认删除对话框,可以进行删除操作。

要点:

  • SAP Web IDE 实现代理
  • 配置数据源
  • 连接到 SAP 后端并实现 CRUD 操作

SAP Web IDE 代理配置

我使用的 IDE 是 Web IDE personal edition,如果把 Web IDE 的安装目录称作 webide_home 的话,我们需要在 webide_home\config_master\service.destinations\destinations 下配置连接,这个连接对于所有 Project 都可以使用。请参考本系列的第 33 篇。

本次我们连接的后端系统标识为 DPH,所以我们的配置文件名为 DPH,没有扩展名。配置文件的内容如下:

Description=DP Hana
Type=HTTP
TrustAll=true
Authentication=NoAuthentication
WebIDEUsage=odata_abap,dev_abap,ui5_execute_abap
Name=DPH
WebIDEEnabled=true
URL=HTTP\://dph01.nodomain\:8180
ProxyType=OnPremise
WebIDESystem=DPH
sap-client=100

配置数据源

在 SAP Web IDE 中,创建类型为 SAPUI5 Application 的项目,这种类型项目的文件结构相对来说是最简单的。创建完成后,项目的文件结构如下:

配置 neo-app.json 文件

在 neo-app.json 文件中,增加一项 path 配置,内容如下:

    {
      "path": "/sap/opu/odata",
      "target": {
        "type": "destination",
        "name": "DPH",
        "entryPath": "/sap/opu/odata"
      },
      "description": "DP Hana"
    }

配置 Application descriptor

Application descriptor 就是 webapp 下面的 manifest.json 文件,使用 App Descriptor Editor 打开,切换到 Data Sources 页签,点击 “+” 号来添加一个数据源:

系统弹出对话框简化配置,切换到 Service URL,选择在前面配置的 SAP 连接,第一行 DP Hana 保存的是 domain 信息,第二行配置的是 service url 的 path:

点击 Test 按钮,提示输入用户名和密码,如果一切 OK, 系统读取到 OData service 并且加载:

选中 EmployeeCollection ,点击 Next 按钮即可完成配置。

metadata.xml 文件会被配置到 model 文件夹下面。但我的 Web IDE 版本将实际文件放在 localServices 文件夹下面,需要手工调整位置。这个文件也可以通过在浏览器中 $metadata 参数的方法得到。

然后在 manifest.json 文件中增加默认 model 为刚才配置的 data source:

"sap.ui5": {
        "_version": "1.1.0",
        "rootView": {
            "viewName": "zui5_odata_sap_crud.view.App",
            "type": "XML"
        },
        "dependencies": {
            "minUI5Version": "1.30.0",
            "libs": {
                "sap.ui.core": {},
                "sap.m": {},
                "sap.ui.layout": {}
            }
        },
        "contentDensities": {
            "compact": true,
            "cozy": true
        },
        "models": {
            "i18n": {
                "type": "sap.ui.model.resource.ResourceModel",
                "settings": {
                    "bundleName": "zui5_odata_sap_crud.i18n.i18n"
                }
            },
            "": {
                "dataSource": "zempprj_srv",
                "settings": {
                    "metadataUrlParams": {
                        "sap-documentation": "heading"
                    }
                }
            }
        },
        "resources": {
            "css": [{
                "uri": "css/style.css"
            }]
        }
    }

此时运行程序,应该会提示输入用户名和密码,表示数据源配置成功。

界面设置

主界面

因为不打算使用 routing,直接在 root view ,即 App.view.xml 文件中设置主要的 UI 元素:

<mvc:View xmlns:html="http://www.w3.org/1999/xhtml" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m"
    controllerName="zui5_odata_sap_backend_crud.controller.App">
    <App>
        <pages>
            <Page title="{i18n>title}">
                <content>
                    <Table noDataText="No data" id="idTable" items="{path:'/EmployeeCollection'}">
                        <items>
                            <ColumnListItem type="Navigation" press="onItemPress">
                                <cells>
                                    <Text text="{EmpId}"/>
                                    <Text text="{EmpName}"/>
                                    <Text text="{EmpAddr}"/>
                                </cells>
                            </ColumnListItem>
                        </items>
                        <columns>
                            <Column id="EmpIdCol">
                                <header>
                                    <Label text="Employee ID"/>
                                </header>
                            </Column>
                            <Column id="EmpNameCol">
                                <header>
                                    <Label text="Name"/>
                                </header>
                            </Column>
                            <Column id="EmpAddrCol">
                                <header>
                                    <Label text="Address"/>
                                </header>
                            </Column>
                        </columns>
                    </Table>
                </content>
                <footer>
                    <Bar>
                        <contentRight>
                            <Button icon="sap-icon://create" text="Create" press="onCreate"/>
                            <Button icon="sap-icon://edit" text="Edit" press="onEdit"/>
                            <Button icon="sap-icon://delete" text="Delete" press="onDelete"/>
                        </contentRight>
                    </Bar>
                </footer>
            </Page>
        </pages>
    </App>
</mvc:View>

对话框

<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:f="sap.ui.layout.form">
    
    <Dialog id="employeeDialog" title="Employee CRUD">
        <f:SimpleForm>
            <Label text="Employee Id"/>
            <Input id="EmpId" value="{EmpId}"/>
            <Label text="Name"/>
            <Input id="EmpName" value="{EmpName}"/>
            <Label text="Address"/>
            <Input id="EmpAddr" value="{EmpAddr}"/>
        </f:SimpleForm>
        <Toolbar>
            <ToolbarSpacer/>
            <Button id="SaveCreate" text="Save"/>
            <Button id="SaveEdit" text="Save Edit"/>
            <Button id="CancelButton" text="Cancel" />
        </Toolbar>
    </Dialog>
    
</core:FragmentDefinition>

控制器代码

主要的代码都在 App.controller.js 中,先给出完整代码:

sap.ui.define([
    "sap/ui/core/mvc/Controller"
], function(Controller) {
    "use strict";

    var oModel;
    var sCurrentPath; // current path
    var sCurrentEmp; // cureent employee

    return Controller.extend("zui5_odata_sap_backend_crud.controller.App", {

        onInit: function() {
            oModel = this.getOwnerComponent().getModel();
            oModel.setUseBatch(false);
            this.getView().setModel(oModel);
        },

        openDialog: function() {
            var oView = this.getView();

            // Open dialog
            var oEmpDialog = oView.byId("employeeDialog");
            if (!oEmpDialog) {
                oEmpDialog = sap.ui.xmlfragment(oView.getId(),
                    "zui5_odata_sap_backend_crud.view.EmployeeDialog");
                oView.addDependent(oEmpDialog);
            }

            oEmpDialog.open();

            // Attach press event for CancelButton
            var oCancelButton = oView.byId("CancelButton");
            oCancelButton.attachPress(function() {
                oEmpDialog.close();
            });
        },

        // onCreate event
        onCreate: function() {
            var oView = this.getView();

            this.openDialog();
            var oEmployeeDialog = oView.byId("employeeDialog");
            oEmployeeDialog.setTitle("Create Employee");
            oView.byId("EmpId").setEditable(true);
            oView.byId("SaveEdit").setVisible(false);
            oView.byId("SaveCreate").setVisible(true);

            // clear
            oView.byId("EmpId").setValue("");
            oView.byId("EmpName").setValue("");
            oView.byId("EmpAddr").setValue("");

            // commit save
            oView.byId("SaveCreate").attachPress(function() {
                var oNewEntry = {
                    "Mandt": "100",
                    "EmpId": "",
                    "EmpName": "",
                    "EmpAddr": ""
                };

                // populate value from form
                oNewEntry.EmpId = oView.byId("EmpId").getValue();
                oNewEntry.EmpName = oView.byId("EmpName").getValue();
                oNewEntry.EmpAddr = oView.byId("EmpAddr").getValue();

                // Commit creation operation
                oModel.create("/EmployeeCollection", oNewEntry, {
                    success: function() {
                        sap.m.MessageToast.show("Created successfully.");
                    },
                    error: function(oError) {
                        window.console.log("Error", oError);
                    }
                });

                // close dialog
                if (oEmployeeDialog) {
                    oEmployeeDialog.close();
                }
            });
        },

        onEdit: function() {
            // no employee was selected
            if (!sCurrentEmp) {
                sap.m.MessageToast.show("No Employee was selected.");
                return;
            }

            var oView = this.getView();

            this.openDialog();
            var oEmployeeDialog = oView.byId("employeeDialog");
            oEmployeeDialog.setTitle("Edit Employee");
            oView.byId("EmpId").setEditable(false);
            oView.byId("SaveEdit").setVisible(true);
            oView.byId("SaveCreate").setVisible(false);

            // populate fields
            oView.byId("EmpId").setValue(oModel.getProperty(sCurrentPath + "/EmpId"));
            oView.byId("EmpName").setValue(oModel.getProperty(sCurrentPath + "/EmpName"));
            oView.byId("EmpAddr").setValue(oModel.getProperty(sCurrentPath + "/EmpAddr"));

            // Attach save event
            oView.byId("SaveEdit").attachPress(function() {
                var oChanges = {
                    "Mandt": "100",
                    "EmpName": "",
                    "EmpAddr": ""
                };

                // populate value from form
                oChanges.EmpName = oView.byId("EmpName").getValue();
                oChanges.EmpAddr = oView.byId("EmpAddr").getValue();

                // commit creation
                oModel.update(sCurrentPath, oChanges, {
                    success: function() {
                        sap.m.MessageToast.show("Changes were saved successfully.");
                    },
                    error: function(oError) {
                        window.console.log("Error", oError);
                    }
                });

                // close dialog
                if (oEmployeeDialog) {
                    oEmployeeDialog.close();
                }
            });
        },

        // onDelete event
        onDelete: function() {
            var that = this;

            // no employee was selected
            if (!sCurrentEmp) {
                sap.m.MessageToast.show("No Employee was selected.");
                return;
            }

            var oDeleteDialog = new sap.m.Dialog();
            oDeleteDialog.setTitle("Deletion");

            var oText = new sap.m.Label({
                text: "Are you sure to delete employee [" + sCurrentEmp + "]?"
            });
            oDeleteDialog.addContent(oText);

            oDeleteDialog.addButton(
                new sap.m.Button({
                    text: "Confirm",
                    press: function() {
                        that.deleteEmployee();
                        oDeleteDialog.close();
                    }
                })
            );

            oDeleteDialog.open();
        },

        // deletion operation
        deleteEmployee: function() {
            oModel.remove(sCurrentPath, {
                success: function() {
                    sap.m.MessageToast.show("Deletion successful.");
                },
                error: function(oError) {
                    window.console.log("Error", oError);
                }
            });
        },

        onItemPress: function(evt) {
            var oContext = evt.getSource().getBindingContext();
            sCurrentPath = oContext.getPath();
            sCurrentEmp = oContext.getProperty("EmpName");
        }
    });
});

要点说明:

Model

我们使用的是 OData Model,但是并没有任何代码来显示申明。OData Model 的声明来自 manifest.json。根据 OpenUI5 SDK,如果 DataSource 为 OData,没有指定 type,则默认的 type 为 OData v2,这正是我们想要的。

然后在 Controller 的 onInit 事件中绑定 view 和 model:

onInit: function() {
    oModel = this.getOwnerComponent().getModel();
    oModel.setUseBatch(false);
    this.getView().setModel(oModel);
}

新增记录 ( create )

var oNewEntry = {
    "Mandt": "100",
    "EmpId": "",
    "EmpName": "",
    "EmpAddr": ""
};

// populate value from form
oNewEntry.EmpId = oView.byId("EmpId").getValue();
oNewEntry.EmpName = oView.byId("EmpName").getValue();
oNewEntry.EmpAddr = oView.byId("EmpAddr").getValue();

// Commit creation operation
oModel.create("/EmployeeCollection", oNewEntry, {
    success: function() {
        sap.m.MessageToast.show("Created successfully.");
    },
    error: function(oError) {
        window.console.log("Error", oError);
    }
});

修改记录

var oChanges = {
    "Mandt": "100",
    "EmpName": "",
    "EmpAddr": ""
};

// populate value from form
oChanges.EmpName = oView.byId("EmpName").getValue();
oChanges.EmpAddr = oView.byId("EmpAddr").getValue();

// commit creation
oModel.update(sCurrentPath, oChanges, {
    success: function() {
        sap.m.MessageToast.show("Changes were saved successfully.");
    },
    error: function(oError) {
        window.console.log("Error", oError);
    }
});

删除记录

deleteEmployee: function() {
    oModel.remove(sCurrentPath, {
        success: function() {
            sap.m.MessageToast.show("Deletion successful.");
        },
        error: function(oError) {
            window.console.log("Error", oError);
        }
    });
}

源码

36_01_zui5_odata_sap_backend_crud
36_02_zui5_odata_sap_backend_crud

参考资料

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

推荐阅读更多精彩内容