下面是用WEBIDE开发SAPUI5页面实现一个简单重置ERP用户密码功能,前端又做了一遍,也借此理一下思路。
分析设计

以目标为导向,我们要开发这么一个页面,输入用户名和手机号,或者邮箱,点击提交后,ERP重置密码发送指定的短信或邮箱。我们只做到弹出消息,接下的发送短信和邮件功能不做。
接到这么一个需求,首先想到需求要分为两大部分,前端的页面开发和后端的OData服务(实现密码重置功能)。
前端页面
对于习惯了后端开发的ABAPer来说前端让人无从下手,我是这么做的,因为之前把WalkThrough做了一遍,有了大概的印象,从最简单的HelloWorld只有一个html,到慢慢加入XMLview,再加入Controller,再加入多语言,再加入Component配置文件,再加入Descriptor manifest文件,再加入CSS等等吧,WalkThrough真的是由浅入深的带我们进入到SAPUI的开发,所以我建议像我一样的初学者认真的把这些示例做上n(n>3)遍,对于关键章节,比如View和Controller要一直重复做,直到可以脱离copy、paste,随后就能把框架搭出来,个人认为非常有必要,不啰嗦了,继续。
- index.html

新建项目A_DEMO,创建Fileindex.html,敲入一个页面最基本的节点:123456789<html><head><title>ERP秘密重置</title></head><body></body></html>
再加入两个’meta’,这里不有深究
上面很容易理解,然后因为我们要用sapui5开发所以需要加入bootstrap,然后引入我们的View:
这里我在Fiori-Step4-XML-views里做过介绍,就不再多说了,需要解释一点src="../../resources/sap-ui-core.js",如果src用的是相对路径,那么一定要在项目根目录创建一个项目配置文件’neo-app.json’。
然后我们再加入指定View的代码和把View放到body的代码
|
|
|
|
至此index.html就已经完成不需要做任何调整了,这里就是指定了我们的运行环境和View文件,接下接就完全由View和Controller文件完全接手了。
创建
neo-app.json文件
详细信息可以参考Create a neo-app.json Project Configuration File,后面OData的配置时我们还要此文件进行配置。
创建’view’文件夹
创建’App.view.xml’

我们要写一个XMLview,就一定要<mvc:View>做为根节点,然后一定有一个controllerName属性来指定controller文件的路径然,这里就是文件和文件之间的联系,然后加入View所用到的namespace,就是下面的一堆xmlns。
|
|


怎么理解这个namespace呢,结合上面的API文档,我们可以看到其实它就是我们要用到的不同的API,冒号和后面的’core’ ‘l’ ‘f’ ‘mvc’又是干吗的呢,比如说我要在View中加一个Label控件,简单一搜API文档就看到这几个库里都有Label,这时就需要加一个前缀,就是namespace来区分,第一个'xmlns="sap.m"后面没有冒号,那它就是老大,就是默认namespace,页面中所有什么都不加直接写标签名的都是用的它下面的控件。
看这一个布局,其实就是一个简单的simpleform控件,上面是title,下面是一个分成两列的form结构。
API中那么多控件我应该选择那一个用,怎么入手呢,不用急,SAP提供了很好的参考示例,并且都附有模版代码,我们只需要像逛超市一样选择相中的样式copy过来改改就可以。
打开后可以根据需要进行过滤筛选,也可以在进而进行search
既然来选择布局的,那我就输入layout来进行搜索咯,然后会出现好多layout供我们选择。
下面这个布局很面熟吧,就它了
点击右上角查看源码,找到想要的部分copy下来或者可以整个下载下来慢慢试,下面我想要的部分:

OK,拷过来就可以开始改了,不会?没关系,SAP又提供了API的具体用法,参考API reference

这里就可以看到有两个Module都有这个SimpleForm控件,所以我们要用:f来加以区分。这里对每一个属性的用法都有做介绍,非常详细。
改完以后的代码就是下面这样了:
OK至此,view也做完了,剩下的就是controller了。
- 新建
controller文件夹和App.controller.js文件
速度太慢了,加快速度!contrller的写法我在之前的帖子上也做了详细说明了,就不再赘述了,看注释来理解吧,很简单,最关键的就是callFucntion来调用ODATA服务和成功后的处理。
|
|

这里最关键的就是这个callFunction了,两个参数,第一个是要调的function名字,第二个是{}引起来的一个map, 其中又可以有多个参数,比如method,这里写了GET,默认也是GET,所以可以省略,最最重要的就是后面的两个,success和error,这是两个返回函数,分别是ODATA执行成功时和失败时执行的过程,所以我们要写的逻辑也就在这个里面。success: function(oData, response) 和error: function(error)可以理解成固定写法,执行ODATA后所有的返回值都是在这里面,debug打开找吧,这个例子中返回值是一个entity所以直接用oData.属性值就能访问,如果是entityset,就要for循环出来一一处理了。
后端ODATA开发
- SE11 创建结构

这里主要是为了方便后面用import的方式建entity,不建结构也可以 - SEGW 创建Project
import创建entity(如果Import DDIC遇到下拉列表为空的情况,用en语言重新登录GUI即可)
说一下的是这些字段Creatable/Updatable/Sortable/..等这些flag,它们的作用就是在生成metadata时告诉oData的使用者,哪些字段可以做Sort,哪些不为空,这里的设置并不会影响功能。
建了entity以后同样在Data Model那里右键创建一个Function import,


注意我这里Return的是一个Entity,并没有返回EntitySet,意思就是返回的是一行数据或者说一个结构,不是内表。HTTP要用GET。
建完以后生成然后进行到EXT中进行方法的redefine
在这个类中找到EXECUTE_ACTION方法,右键redefine
下面是实现的代码,ABAP的内容就不介绍了,时间仓促,写的也是最简单的代码,不考虑效率。
- 注册服务

注册此服务到前端。
点击Maintain进行Gateway Server,然后打开Gateway Client进行测试


/sap/opu/odata/sap/ZGJZ_PWD_RESET_SRV/$metadata 查看 metadata
/sap/opu/odata/sap/ZGJZ_PWD_RESET_SRV/ZGJZ_PWD_RESET?userMail='aaa@lg.com'&userTel='15801615353'&userId='ZZGUOJZ'直接对我们的函数进行测试,注意多个参数的先后顺序和大小写,中间用’&’分开。可以看出’?’后的部分’userMail=’aaa@lg.com’&userTel=’15801615353’&userId=’ZZGUOJZ’’就是我们在前端页面中需要传入的参数
- 后端debug
执行,此时如果我们在实现的方法中加了外部断点,就可以debug到方法中,注意这里如果停的时候过长,整个请求会connection time out
这里看一下这些传入参数的值:

我们最终的输出就在这里,不论是返回的结构(Entity)还是内表(EntitySet),只要填充到这里就可以。
下面就可以看到服务的返回值了:
OK。接下来我们就要到前端去验证使用这个ODATA服务了
- 前端debug
执行我们开发的前端页面,如果用的是chrome浏览器,点击F12进行控制台,在resource中找到我们要debug的controller,代码前加入断点。
在前端页面输入对应的值后点击按钮“提交”就会自动运行至断点,在这里我们可以查看相应的变量有没有正确赋值。更详细的debug方法可以百度jsdebug,基本都是类似的。
忘了一个重要的内容,以上执行是不能成功的,因为没有连接后端的配置,我一开始也是做到这里,但执行时发现ODATA服务并不是连的后端的域名,而是locaohost:xxxx,原因就是在neo-app.json文件中需要增加后台服务器的配置信息。
完整的neo-app.json文件应该是这样的:
完整代码:http://pan.baidu.com/s/1bpgwAqN 不用谢
结构转化
加入component
上面的示例非常简单,基本实现了需求,但文件结构有点简单,往FLP中迁移的话结构需要再做调整,我们下面就继续按tutorials中文件结构一步步调整它。
- 加入component容器
这里首先要修改index.html,修改<script>标签,加入对component容器的引用声明:
As-Is:1234567<script>sap.ui.getCore().attachInit(function () {sap.ui.xmlview({viewName : "sap.ui.demo.wt.view.App"}).placeAt("content");});</script>
To-Be:
在index.html根目录下新建文件Component.js
可以看到这里首先用metadata/rootview来定义的应用打开的初始view,并且将Model的代码从Controller中挪了过来,真正实现了MVC结构。
- 调整Controller.js

再次执行程序,一样的效果说明我们的component加入成功
加入manifest和多语言i18n
在加入component之后,我们再来尝试加入manifest文件,同时将文本字段写到一个多语言的i18n.properties文件中集中进行维护。
- 在
index.html根目录下新建文件manifest.json:12345678910111213141516171819202122232425262728293031323334353637383940414243444546{"_version": "1.1.0","sap.app": {"_version": "1.1.0","id": "sap.ui.demo.wt","type": "application","i18n": "i18n/i18n.properties","title": "{{appTitle}}","description": "{{appDescription}}","applicationVersion": {"version": "1.0.0"}},"sap.ui": {"_version": "1.1.0","technology": "UI5","deviceTypes": {"desktop": true,"tablet": true,"phone": true},"supportedThemes": ["sap_belize"]},"sap.ui5": {"_version": "1.1.0","rootView": "sap.ui.demo.wt.view.App","dependencies": {"minUI5Version": "1.30","libs": {"sap.m": {}}},"models": {"i18n": {"type": "sap.ui.model.resource.ResourceModel","settings": {"bundleName": "sap.ui.demo.wt.i18n.i18n"}}},"contentDensities": {"compact": true,"cozy": true}}}
我们来分别理解一下这个APP配置文件中这些内容都是什么意思,其中像’version’这类直观就能看懂的就不再说了,捡几个重要的:
"id":看内容应该也能猜到这里配置的是这个APP的resourceroot属性"i18n":配置了多语言文件的相对路径和文件名,一般都是"i18n/i18n.properties""rootView":这里又将rootvie从component中挪到了这里来定义"models":至此我们发现model可以远处不在,可以在manifest中定义,可以在component中定义,可以在controller中定义,如果实在是懒甚至可以写在html中,但一个清晰的文件结构也是我们的学习内容之一,从此以后我们就尝试将model定义在manifest文件中,不论是JSONModel、XMLModel(最好以文件形式出现)还是ODataModel,都是在这里进行定义,WEBIDE提供的Descriptor Editor也方便我们直观的进行配置
- 调整
Component.js
123metadata : {manifest: "json"},
使用metadata/manifest来声明应用将使用的配置文件
- 创建
i18n.properties
接下来要建一个i18n文件夹和一个i18n.properties文件,这个文件完全可以理解成ABAP开发中的“文本元素”,就不多说了
- 替代文本元素
接下来我们将view中的文本都替代到i18n文件中,下图可以看到一个修改后的和修改前的一个对比,这里我已经将“用户帐号”用{i18n>userID}进行了替代,其实利用WEBIDE的layout Editor维护起来非常的方便,比如下面的“手机号”文本,只需要点点击Text后面的链接按钮
删除原来的文本,选择’i18n’,然后点击’+’
在弹出的窗口中填入占位符和相应的文本
把常量文本全部替换后App.view.xml和i18n.properties的样子,这样维护起来是不是轻松多了

此时再执行程序,效果和原来一模一样:
- 创建Model
使用Descriptor Editor来创建oModel,以替换在component中定义oModel的语句:(同时可以看到在manifest文件中已经写入了ResourceModel的配置)







此时再执行程序,效果依然和原来一模一样:
至此,我们又成功加入的manifest.json和i18n.properties!
下面放上导出的完整代码,供参考:
http://pan.baidu.com/s/1pL2tb8B