很有必要把MVC单独拿出来认真的讨论一次。
MVC的好处我们就不多谈了,百度很多,但在SAPGUI中是如何做的呢?
简单来说
- Model: 专门管理application中的数据
- View: 定义和渲染UI
- Controller: 对View Event进行反应和在用户对View和Model修改进行交互时进行反应
关系
View和Controller的关系一般是1:1,但也允许多个Controller控件一个View,他们叫们应用控件器。当然View也可没有对应的Controller。一般1个View可以有或继承一个SAPUI5 Model。
Model
数据绑定
| Model | One-way | Two-way | One-time |
|---|---|---|---|
| Resource model | – | – | X |
| JSON model | X | X | X |
| XML model | X | X | X |
| OData model | X | X | X |
| Model | Default binding mode |
|---|---|
| Resource model | One-time |
| JSON model | Two-way |
| XML model | Two-way |
| OData model | One-way |
一般来说, MVC中的Model主要是用来hold数据并且提供方法去访问和更新数据库中的数据。
SAPUI5提供了以下几种预定义的Model:
- OData Model
OData Model支持多种绑定模式:双向(默认)绑定,意向绑定,一定性绑定。但需要注意的是双向绑定只支持属性值,不能对aggregations。OData Model现在有两个版本:OData V2和OData V4。 - JSON Model
JSON Model可以用来绑定控件到序列化的JavaScript对象数据上,它是客户端上的一种Model,所以当数据量不是在太大,完全可以保存在客户端时就可以选择使用JSON Model。它支持双向(默认)绑定、单向绑定和一次性绑定。 - XML Model
使用上基本上和JSON Model一致的,适用少量数据。 - Resource Model
这个主要是用来处理多语言的数据,比如保存多个语言的提示消息和文本信息,因为它只处理静态文本,所以这个只支持一次性绑定。
就是下面这张图,除了OData Model,其它三种都是做在客户端的,不需要访问server就可以使用。OData Model是服务器端的Model,需要UI通过请求从server取数。除这些之外还可以开发自定义的Model。
OData V2 Model
OData Model 是服务器端的Model,意味着数据集只在server端有效,数据的操作,比如排序和过滤都是在server来完成,client只有发送请求得到数据。
发往后端数据请求的发起可以由list binding(ODataListBinding),element binding(ODataContextBinding)和 OData Model的CRUD function来触发。 Property binding(ODataPropertyBinding)不能触发请求。
OData Model现在支持OData version 2.0,相比1.0以下面几个特性:
- 默认是JSON 格式
- 双向绑定只支持Property change,还不支持aggregations
- 默认为单向绑定
- 可以在client端进行排序和数据过滤
- 所有的请求都支持Bundle
- 所有的数据可以被cached in Model
- 支持message handling
创建Model实例
1 个Model实例只能负责 1 个OData服务,如果要访问多个服务,就必须要创建多个实例。创建OData Model实例必须有的一个参数就是服务的URL。第一个参数
每当创建一个ODataModel时就会发送一个metadata的服务请求,如果多个ODataModel使用同一个服务的话,仅第一个实例触发metadata请求。
实例的getServiceMetadata()方法可以查看JSON格式的metadata
可以增加附加参数来配置OData services,SAPUI5会根据相应的绑定方式自动设定一些参数,ODataModel现在支持$select和$expend,可以有不同的方式来增加这些附件参数:
直接在URL后加:
1var oModel = new sap.ui.model.odata.v2.ODataModel("http://myserver/MyService.svc/?myParam=value&myParam2=value");用mparameters map传递给URL(也可以只传入一个):
1234567891011var oModel = new sap.ui.model.odata.v2.ODataModel({serviceUrl: "http://services.odata.org/Northwind/Northwind.svc",serviceUrlParams: {myParam: "value1",myParam2: "value2"},metadataUrlParams: {myParam: "value1",myParam2: "value2"}});
除了serviceUrl和serviceUrlParams之外,还有headers可以指定HTTP的headers:
|
|
注意当指定HTTP header参数时原有的参数会被覆盖,有些内部的参数是改不了的,如:
12345 "accept""accept-language""maxdataserviceversion""dataserviceversion""x-csrf-token"
寻址Entities:绑定语法
ODataModel的路径绑定语法和相对于在OData中用于访问特定Entity或EntitySet服务URL的URL路径相匹配。
根据服务metadata中定义的OData服务的结构,您可以访问OData模型提供的数据。URL参数,例如过滤器,是不能添加到绑定路径中的。绑定路径可以是绝对路径,也可以是相对路径。绝对绑定路径立即被解析。 相对路径只有在能被转换成绝对路径的时候才可用。例如,如果一个Property绑定了一个相对路径而它的父控件绑定了一个绝对路径,那这个相对路径就可以解析成一个绝对路径。
The following binding samples within the ODataModel are taken from the Northwind demo service.
绝对路径:
相对路径如果有一个context的话就可能被解析成绝对路径,比如有一个绝对路径/Customer('ALFKI'),那么下面的相对路径
就可以被转换成下面的绝对路径:
Navigation properties可以被用来视别一个Entity或是多个Entities
访问OData Model的数据
从一个OData服务请求的数据会被cathed到OData Model,可以使用getData()和getProperty()方法访问,分别返回ODataModel的Entity对象和值。这些方法并不是从后台Server访问数据,所以你只能从那些请求过数据的Model中取。
另外,这些方法只能访问单一的Entity和Property,如果要访问EntitySet的数据,需要通过List binding,这样就可以得到这些Entities的Binding context。
不要手工去修改Model内的对象或数据,一定要使用SAP提供的API来操作,或是用双向绑定的控件来修改数据。
创建Entities
为指定的EntitySet创建Entity,用createEntry()方法,方法返回一个context对象指定新创建的Entity,application可以通过双向绑定的方式对它的值进行修改,保存数据需要用到submitChanges(),回滚的话用deleteCreatedEntry()。
application可以选择在创建的对象中包含哪些属性,并且可以为这些属性传递自己的默认值,默认情况下,所有的属性值都是空的,未定义的。
EntitySet和传递的属性值必须在OData服务的metadata中存在
12345678 // create an entry of the Products collection with the specified properties and valuesvar oContext = oModel.createEntry("/Products", { properties: { ID:99, Name:"Product", Description:"new Product", ReleaseDate:new Date(), Price:"10.1", Rating:1} });// binding against this entityoForm.setBindingContext(oContext);// submit the changes (creates entity at the backend)oModel.submitChanges({success: mySuccessHandler, error: myErrorHandler});// delete the created entityoModel.deleteCreatedEntry(oContext);
如果已经提交了创建的Entity,那么Context将通过创建请求返回的路径进行更新,并将新数据导入到模型中,这样Context仍然有效,并指向新创建的Entity。
CRUD Operations
OData service是可以手工进行CRUD(Create,Read,Update,Delete)的,如果手工操作有返回值 ,数据会被Import到这个ODataModel的Cathe中,所有操作都需要一个强制性的sPath参数以及一个可选的mParameters map,Create和Update操作还需要另一个强制的参数oData来传递要创建或修改的对象,每个操作返回一个包含一个函数中止的对象,这个对象可以用来中止请求。如果请求被中止,将调用错误处理程序。这将确保为每个请求执行成功或错误处理程序。还可以传递附加的头数据、URL参数或eTag。
Creating entities
create函数触发一个OData服务的POST请求,该服务是在创建OData模型时指定的。应用程序必须指定EntitySet,其中将创建新的Entity和Entity数据。12345var oData = {ProductId: 999,ProductName: "myProduct"}oModel.create("/Products", oData, {success: mySuccessHandler, error: myErrorHandler});Reading entities
read函数触发一个GET请求到指定的路径。在创建OData模型时,将从OData服务中检索路径。检索到的数据在成功回调处理程序函数中返回。1oModel.read("/Products(999)", {success: mySuccessHandler, error: myErrorHandler});Updating entities
update函数会触发一个对OData服务的put/merge请求,该服务是在OData模型创建时指定的。在成功请求更新模型中的绑定之后,刷新会自动触发。12345var oData = {ProductId: 999,ProductName: "myProductUpdated"}oModel.update("/Products(999)", oData, {success: mySuccessHandler, error: myErrorHandler});Deleting entities
remove函数触发对OData服务的删除请求,该服务是在创建OData模型时指定的。应用程序必须指定要删除的条目的路径。1oModel.remove("/Products(999)", {success: mySuccessHandler, error: myErrorHandler});Refresh after change
该模型提供了一种机制来自动刷新依赖于发生更改的Entity的绑定。如果您执行一个创建、更新或删除功能,该模型将识别绑定并触发这些绑定的刷新。如果模型以批处理模式运行,则刷新请求与相同批处理请求中的更改捆绑在一起。您可以通过调用setRefreshAfterChange(false)禁用自动刷新。如果自动刷新被禁用,应用程序必须处理刷新各自的绑定。1oModel.setRefreshAfterChange(false);
并发控制、ETags
OData使用HTTP ETags来实现优化并发控制。必须配置服务才能提供这些服务。每个CRUD请求的参数映射中都可以传递ETag。如果没有传递ETag,则使用缓存实体的ETag,前提是已经加载了Cach。
XSRF Token
为了解决跨站点请求的伪造,OData服务可能需要XSRF令牌来满足客户端应用程序的更改请求。在这种情况下,客户端必须从服务器获取一个令牌,并将每个更改请求发送到服务器。在读取元数据时,OData模型会获取XSRF标记,然后自动将其发送给每个写请求头。如果令牌不再有效,则可以通过调用OData模型中的refreshSecurityToken函数来获取新的令牌。令牌以对服务文档的请求来获取。为了确保获得有效的令牌,请确保服务文档没有被缓存。
Refreshing the Model
刷新函数刷新了一个OData模型中的所有数据。每个绑定从服务器重新加载它的数据。对于列表或元素绑定,将触发对后端的一个新请求。如果XSRF令牌不再有效,则必须使用对服务文档的read请求再次获取它。通过手动CRUD请求导入的数据不会自动重新加载。
Batch Processing
v2.ODataModel 支持两种方式的batch处理:
- 默认:一个线程中的所有请求都被收集并打包在一个batch批处理请求中,这意味着在当前调用堆栈完成后立即将请求发送到超时。这包括所有的手动CRUD请求以及绑定所触发的请求。
- 延迟:
使用MVC,sapui5如何确定view和controller的文件的名称和位置呢? 有以下三种方法来声明文件的位置:
- sap.ui.localResources()
- jQuery.sap.registerModulePath()
- bootstrap声明: data-sap-ui-resourceroots=’{“name”: “”}’
sap.ui.localResources()
sap.ui.localResources()语法:
将sModuleNamePrefix注册为html文件(比如index.html作为当前文件夹)下sModuleNamePrefix子文件夹。如果sModuleNamePrefix中含有点号,所有的点被替换成/。比如,view name为master,如果sap.ui.localResources("myapp.viewsforbutton");,则sapui在./myapp/viewforbutton文件夹下查找view文件的代码。文件的扩展名由view的类型决定。
jQuery.sap.registerModulePath()
jQuery.sap.registerModulePath()的语法:
把sModuleNamePrefix注册为sURL,比如:jQuery.sap.registerModulePath("mainview", "./mainview/");把mainview注册为当前文件夹下的mainview文件夹。
这种方法能实现sap.ul.localResources()相同的功能,但更加灵活。
bootstrap申明resourcesroots
下面的声明实现上述同样功能。
Model的绑定
一个Model可以被set到core,component controller,view,controls(Aggregation),controls(element),controls(property)不同的level。所有controls和views都会集成父级的model。
注意: Fiori App不要set model到UI core,应该set到对应的view或是component controller。
控件和model需要通过路径绑定进行显示,有以下几种绑定类型:
- Property binding
- Element binding
- Aggregation binding

Aggregation and Expression Binding
Aggregation Binding用于绑定一个多行数据的数据集到一个UI控件上,比如tables,lists或pulldown。语法:bindAggregation(sPath,oTemplate)
Expression Binding可以用表达式来替代custom formatter functions。只要用在一些细微的控制。比如判断字段的visible属性,下面是一个对比的例子:


















