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

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

程序界面:

SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下)_第1张图片

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

SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下)_第2张图片

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

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

SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下)_第3张图片

可以进行修改操作。

单击 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 的项目,这种类型项目的文件结构相对来说是最简单的。创建完成后,项目的文件结构如下:

SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下)_第4张图片

配置 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 页签,点击 “+” 号来添加一个数据源:

SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下)_第5张图片

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

SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下)_第6张图片

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

SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下)_第7张图片

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

SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下)_第8张图片

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"
            }]
        }
    }
SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下)_第9张图片

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

界面设置

主界面

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


    
        
            
                
                    
                            
                                
                                    
                                    
                                    
                                
                            
                        
                            
                                

对话框


    
    
        
            
        
            
            
    

控制器代码

主要的代码都在 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

参考资料

  • Connecting Remote Systems in SAP Web IDE Personal Edition
  • Descriptor for Applications, Components, and Libraries
  • Connect to Remote Server SAP WEB IDE local
  • Connect the SAPWebIDE On-Premise to your SAP Gateway system On-Premise
  • Create a Project based on a SAP Gateway Service ( OData ) with WebIDE On-Premise

你可能感兴趣的:(SAPUI5 (36) - OData Model 连接后端 SAP 系统 (下))