实现视图扩展、视图修改与视图替换
学习目标
通过实现视图扩展、视图修改与视图替换来扩展应用
准备基础应用
启用应用扩展
要在 SAPUI5 应用上启用扩展,需要在该基础应用中执行若干步骤:
在 manifest.json 文件中,你需要将 flexEnabled 属性设置为 true ,并确保所有可扩展的视图都具有 id。
在视图中,你需要确保每个控件都具有稳定 ID。
同样在视图中,你还需要创建扩展点。
在控制器中,你需要为希望开发者扩展的方法配置 metadata。
设置 manifest.json 文件
你的 *manifest.json* 文件需要为 flexEnabled 属性和 viewID 目标属性设置正确的配置。
你可以参考以下代码片段了解更多详细信息。
//Extract from manifest.json
...
"sap.ui5": {
"flexEnabled": true,
"dependencies": {
...
"targets": {
"Overview": {
"viewType": "XML",
"viewId": "overview",
"viewName": "Overview",
"viewLevel": 1
},
"NotFound": {
"viewType": "XML",
"viewName": "NotFound",
"controlAggregation": "midColumnPages"
},
"Carrier": {
"viewType": "XML",
"viewId": "carrier",
"viewName": "Carrier",
"viewLevel": 2,
"controlAggregation": "midColumnPages"
}
}
...
添加扩展点
扩展点可用于 XML 模板化,以便用自定义内容扩展标准内容。扩展点具有默认内容,除非通过定制(customizing)替换该扩展点,否则将使用此默认内容。

要将扩展点添加到应用中,请如图中所示添加控件 sap.ui.core.ExtensionPoint,并将扩展点的名称赋值给 name 属性。
扩展点名称可以来自绑定,包括计算结果为常量的表达式绑定。如果扩展点要被 XML 片段(fragment)替换,则扩展点元素会被该片段的 XML DOM 替换,并且预处理也会在该 DOM 上进行。所有当前可用的变量名和别名都会照常继承到该片段中。你将获得与片段指令相同的调试输出,并在其中看到自定义的片段名称。
视图还需要为所有控件提供稳定 ID。
你可以参考以下代码片段了解更多详细信息。
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" xmlns:f="sap.f" xmlns:layout="sap.ui.layout"
xmlns:uxap="sap.uxap" controllerName="student00.sap.training.dynamicpage.controller.Carrier"
xmlns:html="http://www.w3.org/1999/xhtml" id="idView">
<uxap:ObjectPageLayout id="dynamicPageId" showTitleInHeaderContent="true" alwaysShowContentHeader="false"
preserveHeaderStateOnScroll="false" headerContentPinnable="true" isChildPage="true" enableLazyLoading="false">
<uxap:headerTitle>
<uxap:ObjectPageDynamicHeaderTitle id="idHeaderTitle">
<uxap:expandedHeading>
<Title text="{Carrname}"/>
</uxap:expandedHeading>
<uxap:snappedHeading>
<Title text="{Carrname}"/>
</uxap:snappedHeading>
<uxap:expandedContent>
<FlexBox alignItems="Start" justifyContent="SpaceBetween" id="idCarrierDetails">
<items>
<layout:HorizontalLayout allowWrapping="true">
<layout:VerticalLayout class="sapUiMediumMarginEnd">
<ObjectAttribute title="{i18n>urlLabelText}" text="{Url}"/>
</layout:VerticalLayout>
</layout:HorizontalLayout>
</items>
</FlexBox>
<core:ExtensionPoint name="ux410_extension" />
<Button text="{i18n>txtCarrierData}" press="onShowCarrierData"/>
....
配置 metadata
要扩展基础应用的控制器,开发者必须在基础应用相应的控制器中定义标记接口(marker interface)。因此,开发者要在基础应用的 metadata 配置中添加 methods 部分。

例如,此图展示了该配置的样子。如实现中所示,一个名为 onShowCarrierData 的函数被添加到 metadata 的 methods 配置部分。该函数被声明为 public 且非 final。这意味着它可以被覆盖。
sap.ui.define([
"sap/ui/core/mvc/Controller"
],
/**
* @param {typeof sap.ui.core.mvc.Controller} Controller
*/
function (Controller) {
"use strict";
return Controller.extend("student00.sap.training.dynamicpage.controller.Carrier", {
metadata : {
methods: {
onShowCarrierData: {
public:true,
final:false
}
}
},
...
观看视频,了解如何添加视图扩展和控制器扩展
视频:本节含 SAP 官方视频(视频 ID
1_f3c7qigu),需在 learning.sap.com 在线观看。
创建适配项目

SAPUI5 适配项目允许开发者在 SAP Business Application Studio 中以免修改的方式扩展 SAP Fiori 应用。
观看视频,了解如何创建适配项目。
视频:本节含 SAP 官方视频(视频 ID
1_hqfj7tq4),需在 learning.sap.com 在线观看。
文件 manifest.appdescr_variant 是应用变体的清单文件,其中包含应用变体的 App id。它还包含 content 部分中各项更改的配置。在下面的代码中你可以看到,有一个针对 i18n 模型的模型扩展。此 i18n 扩展是默认生成的,可用于覆盖基础应用中的文本或添加新的 i18n 文本。
以下代码展示了 manifest.appdescr_variant 文件。该文件包含某个具体应用变体的基本配置信息。
{
"fileName": "manifest",
"layer": "CUSTOMER_BASE",
"fileType": "appdescr_variant",
"reference": "student00.sap.training.dynamicpage",
"id": "customer.ZUX410APP00Extension",
"namespace": "apps/student00.sap.training.dynamicpage/appVariants/customer.ZUX410APP00Extension/",
"content": [
{
"changeType": "appdescr_app_setTitle",
"content": {},
"texts": {
"i18n": "i18n/i18n.properties"
}
},
{
"changeType": "appdescr_ui5_addNewModelEnhanceWith",
"content": {
"modelId": "i18n",
"bundleUrl": "i18n/i18n.properties",
"supportedLocales": [
""
],
"fallbackLocale": ""
}
},
{
"changeType": "appdescr_ui5_setMinUI5Version",
"content": {
"minUI5Version": "1.96.16"
}
}
]
}
创建应用变体
既然已经创建了适配项目,我们将进一步了解如何通过使用 SAPUI5 Adaptation Editor 修改、扩展或替换基础应用的各个方面来创建应用变体。

观看视频,了解如何使用 SAPUI5 Visual Editor 创建应用变体。
视频:本节含 SAP 官方视频(视频 ID
1_okn1atgs),需在 learning.sap.com 在线观看。
扩展视图实现
如前所述,可以使用 SAPUI5 Adaptation Editor 扩展基础应用中的视图。

你可以添加视图扩展或控制器扩展,以增强或替换基础应用的各个方面。为此,你需要使用扩展点。

扩展点就像一个锚点,开发者可以在其中添加额外的视觉元素。基础应用的开发者会定义他们认为可能需要进行扩展的位置。从 SAPUI5 1.78 起,Business Application Studio 中支持扩展点。该扩展实现为 sap.ui.core.Fragment。
现在我们将了解如何为扩展点实现片段。
要为扩展点添加自定义实现,SAPUI5 Adaptation Editor 将创建一个片段的存根(stub)实现。
以下屏幕截图展示了这样一个生成的文件。

现在开发者可以将自定义代码添加到生成的文件中。请记住,你必须始终使用稳定 ID。
以下代码展示了片段扩展的实现。
<core:FragmentDefinition xmlns:core='sap.ui.core' xmlns='sap.m' xmlns:layout="sap.ui.layout" id="idFragment">
<FlexBox alignItems="Start" justifyContent="SpaceBetween" id="idCarrierDetailsEx">
<items>
<layout:HorizontalLayout allowWrapping="true" id="idHLayout">
<layout:VerticalLayout class="sapUiMediumMarginEnd" id="idVLayout">
<ObjectAttribute title="{i18n>currLabelText}" text="{Currcode}" id="idOA1"/>
<ObjectAttribute title="{i18n>urlLabelText}" text="{Url}" id="idOA2"/>
</layout:VerticalLayout>
</layout:HorizontalLayout>
</items>
</FlexBox>
</core:FragmentDefinition>
此外还会生成一个新的 change 文件,其中包含该配置。
接下来,让我们看看如何扩展基础应用的控制器。
要创建控制器扩展,需要使用 SAPUI5 Adaptation Editor。以下代码展示了这样一个生成的控制器扩展文件。

现在开发者可以添加自己的实现。屏幕截图展示了 onShowCarrierData 函数的控制器扩展。

如上面的控制器扩展实现所示。metadata 部分包含 onShowCarrierData 函数的配置
使用 sap.ui.core.mvc.OverrideExecution 枚举,可以描述该函数应被覆盖还是被增强。
以下代码展示了控制器扩展的实现。
sap.ui.define([
'sap/ui/core/mvc/ControllerExtension',
'sap/ui/core/mvc/OverrideExecution',
'sap/m/MessageBox'
],
function (ControllerExtension, OverrideExecution, MessageBox) {
"use strict";
return ControllerExtension.extend("customer.ZUX410APP00Extension.mycarrierextension", {
metadata: {
methods: {
onShowCarrierData : {
public:true,
final: false,
overrideExecution: OverrideExecution.Instead
}
}
},
override : {
onShowCarrierData : function(oEvent) {
MessageBox.show("You are currently viewing the data of carrier " +
this.getView().getBindingContext().getProperty("Carrname"), {
icon: MessageBox.Icon.Information,
title: "Carrier data"
});
}
}
});
});
探索变更文件
在可视化编辑器中添加或配置的适配内容以 .change 文件的形式存储。

开发工件存储在位于 project.Controller-extensions 中的 changes 文件夹中,它们存储在 coding 子文件夹中,而视图增强存储在 fragments 子文件夹中。
请注意,每次更改属性时都会生成一个新的 .changes 文件。即使某个属性(例如 visible)从 true 改为 false 再改回 true,也会生成两个文件。因此,在更改属性之前,请确保该更改确实是必需的。
对于视图修改,不会生成任何 SAPUI5 代码,只会创建一个 .change 文件。
以下片段展示了针对不同更改类型的变更文件。
{
"fileName": "id_1677228143911_69_propertyChange",
"fileType": "change",
"changeType": "propertyChange",
"moduleName": "",
"reference": "customer.ZUX410APP00Extension",
"packageName": "$TMP",
"content": {
"property": "visible",
"newValue": false
},
"selector": {
"id": "carrier--idCarrierDetails",
"type": "sap.m.FlexBox",
"idIsLocal": true
},
"layer": "CUSTOMER_BASE",
"texts": {},
"namespace": "apps/student00.sap.training.dynamicpage/changes/",
"projectId": "customer.ZUX410APP00Extension",
"creation": "2023-02-24T08:42:24.302Z",
"originalLanguage": "FR",
"support": {
"generator": "sap.ui.rta.command",
"service": "",
"user": "",
"sapui5Version": "1.96.14",
"sourceChangeFileName": "",
"compositeCommand": "",
"command": "property"
},
"oDataInformation": {},
"dependentSelector": {},
"jsOnly": false,
"variantReference": "",
"appDescriptorChange": false
}
{
"fileName": "id_1677228336195_70_addXMLAtExtensionPoint",
"fileType": "change",
"changeType": "addXMLAtExtensionPoint",
"moduleName": "customer/ZUX410APP00Extension/changes/fragments/myextension.fragment.xml",
"reference": "customer.ZUX410APP00Extension",
"packageName": "$TMP",
"content": {
"fragmentPath": "fragments/myextension.fragment.xml"
},
"selector": {
"name": "ux410_extension",
"viewSelector": {
"id": "carrier",
"idIsLocal": true
}
},
"layer": "CUSTOMER_BASE",
"texts": {},
"namespace": "apps/customer.ZUX410APP00Extension/changes/",
"projectId": "customer.ZUX410APP00Extension",
"creation": "2023-02-24T08:45:36.229Z",
"originalLanguage": "FR",
"support": {
"generator": "sap.ui.rta.command",
"service": "",
"user": "",
"sapui5Version": "1.96.14",
"sourceChangeFileName": "",
"compositeCommand": "id_1677228336196_71_composite",
"command": "addXMLAtExtensionPoint"
},
"oDataInformation": {},
"dependentSelector": {},
"jsOnly": false,
"variantReference": "",
"appDescriptorChange": false
}
#Make sure you provide a unique prefix to the newly added keys in this file, to avoid overriding of SAP Fiori application keys.
#XTIT: Application name
customer.ZUX410APP00Extension_sap.app.title=Extension App 00
txtCarrierData=Show Carrier
替换应用的基础服务
如开头所述,也可以更换应用的基础 OData 服务,或者添加例如自定义服务。

当你在适配项目上调用上下文菜单时,你可以访问操作项来替换基础服务,或向适配项目添加自定义 OData 服务。
部署新的应用变体
适配项目提供了部署功能。

要部署新的应用变体,请从你的适配项目中选择文件 manifest.appdescr_variant,然后从上下文菜单中选择 Open Deployment Wizard.。在弹出的界面中根据需要选择目标系统,输入你的用户名和密码,然后按 Next。接着,输入你的包名称,并按 Finish 开始部署。
部署之后,我们可以查看已部署的应用变体。应用变体中的所有更改都存储在分层仓库(Layered Repository,LREP)中。你可以使用事务 SUI_SUPPORT 获取仓库文件的详细信息。

执行该事务后,我们可以使用传输请求编号来搜索已部署的变体文件。

掌握这些详细信息后,管理员现在可以为该应用变体创建新的目标映射。如果你想在总体上隐藏基础应用,请将带有应用变体命名空间的 URL 参数 sap-appvar-id 添加到基础应用的目标映射中。