Урок 10. SapUI5: Имитация oData — mockserver.

Как правило, в крупных и средних по величине проектах frontend (SapUI5, JS) и backend (oData, ABAP) делают разные люди (на самом деле нет 🙂).
Может сложиться такая ситуация, когда приложение разрабатывается, а oData еще не готова. Для этого в SapUI5 существует инструмент имитации oData — mockserver!

Пример приложения с использованием mockserver — https://github.com/kannade/mockserver_sapui5.
Импортируйте его в свой WebIDE.

Что такое mockserver в SapUI5?

mockserver — это имитация oData сервиса!
Если OData недоступна, не разработана или вы просто не хотите зависеть от OData сервиса, можно просто его имитировать при помощи mockserver!

Перейдем к примеру!
Начнем со стартовой страницы index.html!
Подключаем SapUI5, пространство имен «sap.ui.demo.walkthrough«:

/mockserver_sapui5/blob/master/webapp/index.html
<script id="sap-ui-bootstrap"
	src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
	data-sap-ui-theme="sap_belize"
	data-sap-ui-libs="sap.m"
	data-sap-ui-compatVersion="edge"
	data-sap-ui-preload="async"
	data-sap-ui-resourceroots='{
		"sap.ui.demo.walkthrough": "./"
	}'>
</script>

затем:

/mockserver_sapui5/blob/master/webapp/index.html
<script>
sap.ui.getCore().attachInit(function () {
	sap.ui.require([
		"sap/ui/demo/walkthrough/localService/mockserver",		"sap/m/Shell",
		"sap/ui/core/ComponentContainer"
	], function (mockserver, Shell, ComponentContainer) {		mockserver.init();		new Shell({
			app : new ComponentContainer({
				name : "sap.ui.demo.walkthrough",
				settings : {
					id : "walkthrough"
				}
			})
		}).placeAt("content");
	});
});
</script>

После инициализации вызывается метод attachInit, в котором мы инициируем mockserver, создаем новый sap.m.Shell, в котором делаем ComponentContainer.
Простыми словами мы объявили область (Контейнер), в которую будет помещено SapUI5 приложение.
Если с sap.m.Shell мы уже встречались раньше, то mockserver видим впервые.

Что мы делаем в коде выше?

  • загружаем библиотеку mockserver.js (sap/ui/demo/walkthrough/ — пространство имен, localService/mockserver — файл библиотеки localService/mockserver.js).
  • а затем инициализировали mockserver — mockserver.init();

В папке /localService/ помимо библиотеки mockserver.js находиться файл, описывающий нашу модель — metadata.xml:

/mockserver_sapui5/blob/master/webapp/localService/metadata.xml
<entityset Name="Invoices" EntityType="NorthwindModel.Invoice"></entityset>

Из metadata.xml mockserver берет имя сущности Invoices, затем ищет json файлы с такими же названиями в папке mockdata.
Почему именно в папке mockdata? Эта логика заложена в коде инициализации mockserver — mockserver.js:

/mockserver_sapui5/blob/master/webapp/localService/mockserver.js
sap.ui.define([
	"sap/ui/core/util/MockServer"
], function (MockServer) {
	"use strict";
 
	return {
 
		init: function () {
 
			// Создаем MockServer. rootUri — /here/goes/your/serviceUrl/ , произвольный путь, который мы будем использовать потом для 
                        // определения модели.
			var oMockServer = new MockServer({
				rootUri: "/here/goes/your/serviceUrl/"
			});
 
			var oUriParameters = jQuery.sap.getUriParameters();
 
			// Устанавливаем два глобальных параметра конфигурации для всех экземпляров MockServer, которые сообщают серверу о том,
                        // что он отвечает автоматически, и вводим задержку в одну секунду для имитации типичного времени отклика сервера.
			MockServer.config({
				autoRespond: true,
				autoRespondAfter: oUriParameters.get("serverDelay") || 1000
			});
 
			// Имитируем реальный сервис. Первым параметр — это путь к документу metadata.xml службы, второй — путь до json файлов
			var sPath = jQuery.sap.getModulePath("sap.ui.demo.walkthrough.localService");
			oMockServer.simulate(sPath + "/metadata.xml", sPath + "/mockdata");
 
			// Поехали!
			oMockServer.start();
		}
	};
 
});

Теперь перейдем к шагу установки модели и выведем информацию на экран!

В manifest.json для приложения установим модель с именем invoice:

/mockserver_sapui5/blob/master/webapp/manifest.json
"models": {
	"i18n": {
		"type": "sap.ui.model.resource.ResourceModel",
		"settings": {
			"bundleName": "sap.ui.demo.walkthrough.i18n.i18n"
			}
	},
	"invoice": {		"dataSource": "invoiceRemote"	}},

Первая модель i18n, вторая модель invoice — это наш mockserver.

Чуть выше определим, что «dataSource»: «invoiceRemote» это у нас OData ver. 2.0 с url — /here/goes/your/serviceUrl/:

/mockserver_sapui5/blob/master/webapp/manifest.json
"sap.app": {
…,
		"dataSources": {			"invoiceRemote": {				"uri": "/here/goes/your/serviceUrl/",				"type": "OData",				"settings": {					"odataVersion": "2.0"				}			}		}	},

Готово!
Осталось вывести информацию на экран!

В manifest.json установили «домашнее» (стартовое) представление

/mockserver_sapui5/blob/master/webapp/manifest.json
"rootView": {
	"viewName": "sap.ui.demo.walkthrough.view.App",	"type": "XML",
	"async": true,
	"id": "app"
},

В главном представлении подключаем другие представления, в том числе и то, где выводим информацию с mockserver:

/mockserver_sapui5/blob/master/webapp/view/App.view.xml
<mvc:xmlview viewName="sap.ui.demo.walkthrough.view.InvoiceList"></mvc:xmlview>

В представлении /view/InvoiceList выведем массив Invoices:

/mockserver_sapui5/blob/master/webapp/view/InvoiceList.view.xml
items="{
	path : 'invoice>/Invoices',	sorter : {
		path : 'ShipperName',
		group : true
	}
}"

Запустим приложение и убедимся в том, что данные из модели выводятся корректно!

mockserver sapui5

В данном примере также реализован механизм поиска по mockserver! В представлении /view/InvoiceList есть поле ввода со свойством search=»onFilterInvoices»:

/mockserver_sapui5/blob/master/webapp/view/InvoiceList.view.xml
<toolbar>
	<title text="{i18n>invoiceListTitle}" />
	<toolbarspacer></toolbarspacer>
	<searchfield width="50%" search="onFilterInvoices" selectOnFocus="false"></searchfield></title></toolbar>

В контроллере controller/InvoiceList.controller.js, который отвечает за это представление, ищем метод onFilterInvoices:

/mockserver_sapui5/blob/master/webapp/controller/InvoiceList.controller.js
onFilterInvoices : function (oEvent) {
 
// создаем массив с условиями для фильтрации
var aFilter = [];
var sQuery = oEvent.getParameter("query");
if (sQuery) {
	aFilter.push(new Filter("ProductName", FilterOperator.Contains, sQuery));
}
 
// Фильтруем
var oList = this.byId("invoiceList");
var oBinding = oList.getBinding("items");
oBinding.filter(aFilter);
}

Помимо всего этого в примере реализован:

Отличный повод освежить знания и посмотреть пример реализации! 😉

Подробнее про mockserver — https://help.sap.com/saphelp_snc700_ehp04/helpdata/de/3a/9728ec31f94ca18a7d543ce419d85d/frameset.htm.