SAP 基于VUE的BSP OO单页移动端Web App开发
前言
之前的一篇文章,通过传统的Page with Flow Logic形式去实现了基于Vue的One Page Application。这种做法其实存在一些设计上的问题,前端页面交互层还好说,但后端服务层明显不符合RESTful设计风格,一个API居然还有View的代码?(二当家:帮主哇,我们不用OO,光去看人家的Page with Flow Logic,被同行知道了会笑我们变态的)咳咳,有鉴于此,恰好近日因肺炎推迟上班,被禁足在家,所以特别补全一个OO方式实现的例子。
注:本篇仍将实现一个查询库存的例子,但项目的结构、前端HTML页面代码以及SAP后端代码很多重要细节都与上一篇文章有所不同,请留意。
与传统BSP方式相比,OO实现BSP的方式有两点好处
- 前后端逻辑可以完全分离,符合MVC,代码更易阅读和维护
- 可以独立于页面实现类似RESTful风格的API,显得更专业
但受制于NetWeaver平台,BSP本身也还有如下缺点
- 不能完全实现MVC,Model在BSP里面其实不存在,直接Open SQL完事。skr…skr…
- 尽管能做成RESTful API,但分发还得通过SICF,一个服务一个Application。另外,个人猜测,可能并非所有的HTTP方法BSP都支持,但这个无伤大雅,一般HTTP POST日常也足够了。
GKD 搞快点
Step I 资源和业务分开
在上一篇中,我们将应用依赖的js和css文件都上传到了应用本身的目录下,但它们其实是可以被整个Package下的BSP应用共享的,如果你其它的BSP应用也引用了这些文件,那么类库的版本、前端样式能够统一,利于代码复用和后期维护,同时浏览器当发现资源来自同一个url时,不会去重复下载,节约带宽资源。基于这种种好处,也为了避免这些MIME中的文件被业务代码污染,笔者建议单独创建一个BSP应用,专门用于存储这些常用类库。见下:
为确保允许匿名访问,请注意去掉Application中缺省勾选的XSRF Protection。下面的YBSP_OO_DEMO也是同样的,不再赘述。
将这些公用的类库放到一个归口的应用后,我们就可以创建一个空的业务BSP应用,YBSP_OO_DEMO:
Step II 通过Page Fragments复用html
正如之前我们的BSP应用,Buefy控制前端控件样式的展现,Vue.js扮演Controller的角色来做渲染和事件处理,axios调用HTTP POST异步访问SAP Server。这三板斧是我们每次都会用到的,所以必定在每个应用的html header中引用到它们。虽说我们的例子目前只涉及一个前端页面,但实际生产环境中,随着业务复杂,一个应用中可能还会包含多个页面。为了减少重复的代码,我们把这个通用的html header代码存放到Page Fragments中,以利于后续的项目使用。
_header.htm的代码见下,代码中备注的信息请留意:
<%@page language="ABAP"%>
<!DOCTYPE html> <!--解决Safari中Buefy移动模式mobile card显示不正确的问题-->
<html><head><title>Inventory Report</title><meta charset="utf-8"><meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0"><!--页面自适应移动端--><meta name="format-detection" content="telephone=no"><!--防止纯数字被识别为手机号码--><meta name="apple-mobile-web-app-capable" content="yes" ><!--Safari识别为Web应用--><meta name="mobile-web-app-capable" content="yes"><!--Chrome识别为Web应用--><link rel="icon" href="../YBSP_LIBRARY/monkey.png" type="image/x-icon"/> <!--页面图标--><link rel="stylesheet" href="../YBSP_LIBRARY/buefy.min.css" /> <!--buefy--><script src="../YBSP_LIBRARY/vue.js"></script> <!--vue.js--><script src="../YBSP_LIBRARY/axios.min.js"></script> <!--axios--></head><body><script src="../YBSP_LIBRARY/buefy.min.js"></script> <!--buefy--><script src="../YBSP_LIBRARY/all.min.js"></script> <!--icon相关--><div id="app"> <!--app 根节点-->
Buefy 支持两种icon类型,缺省是Materail Design Icon,而另一种是FontAwesome。最大的区别在于icon的实现机制不同。使用Material Design Icon,会有访问SAP服务资源导致弹出账号密码验证的问题,故放弃。使用FontAwesome,须要引入其js文件,即上面的
all.min.js
。这个文件,你可以在FontAwesome在Github上的代码库中找到并下载下载:https://github.com/FortAwesome/Font-Awesome
Step III 创建查询页面
不同于传统方式,OO的BSP,我们创建的View是不带Flow Logic的。
main.htm的代码见下,它在头部引用了我们的Page Fragments。
<%@page language="abap"%>
<%@include file="_header.htm" %><section class="section"><b-field label="Material Number" :label-position="labelPosition"><b-input maxlength="18" v-model="matnr"></b-input></b-field><b-field label="Plant" :label-position="labelPosition"><b-input type="search" maxlength="4" v-model="werks" @keyup.enter.native="search"></b-input><p class="control"><b-button class="button is-primary" @click="search">Search</b-button></p></b-field><b-table:data="tab":bordered="false":striped="true":narrowed="false":hoverable="false":loading="false":focusable="false":icon-pack="icon_pack":mobile-cards="true":paginated="true":per-page="20"><template slot-scope="tab"><b-table-column field="id" label="ID" sortable numeric>{{ tab.row.id }}</b-table-column><b-table-column field="matnr" label="Material" sortable>{{ tab.row.matnr }}</b-table-column><b-table-column field="maktx" label="Description">{{ tab.row.maktx }}</b-table-column><b-table-column field="lgort" label="Location" sortable>{{ tab.row.lgort }}</b-table-column><b-table-column field="labst" label="Quantity" centered sortable numeric><span class="tag is-success">{{ tab.row.labst }}</span></b-table-column></template><template slot="empty"><section class="section"><div class="content has-text-grey has-text-centered"><b>No Data</b></div></section></template></b-table></section><b-loading :is-full-page="true" :active.sync="isLoading" :can-cancel="false"></b-loading></div><script>const restService = '_main.do';var app = new Vue({el: "#app",data:{viewName: "Inventory Report",labelPosition: 'on-border',isLoading: false,matnr: '',werks: '',tab: [],hide_hd: true,icon_pack: 'fa'},methods:{search: function(){axios.post(restService,{data:{'matnr': this.matnr,'werks': this.werks}}).then((response) =>{try{if(response.data.msg.msgty == "E"){this.$buefy.toast.open({duration: 5000,message: response.data.msg.msg,position: 'is-bottom',type: 'is-danger'});}else if(response.data.msg.msgty == "S"){this.tab = eval(response.data.tab);}else{this.$buefy.toast.open({duration: 5000,message: 'Unknow Exceptions',position: 'is-bottom',type: 'is-danger'});}}catch(err){this.$buefy.toast.open({duration: 5000,message: 'Unknow Exceptions',position: 'is-bottom',type: 'is-danger'});}finally{this.isLoading = false;}});this.isLoading = true;this.hide_hd = false;}}});</script>
</body>
</html>
上面的代码中icon-pack使用fa即是使用FontAwesome中的图标,以免Buefy缺省使用Material Design中的icon导致界面图标无法显示。
OO中的View是不能直接访问的,必须通过Controller去调用它。所以我们必须新建一个Controller,在SE24
中我们创建一个类YCL_BSP_DEMO,它继承了一个BSP标准父类CL_BSP_CONTROLLER2
:
我们须要实现它的方法DO_REQUEST
,当它接收到HTTP GET请求时,返回main.htm:
method DO_REQUEST.
*CALL METHOD SUPER->DO_REQUEST
* .DATA: MYVIEW TYPE REF TO IF_BSP_PAGE.MYVIEW = CREATE_VIEW( VIEW_NAME = 'main.htm' ).CALL_VIEW( MYVIEW ).endmethod.
再次回到SE80
控制台,我们新建一个Controller YBSP_OO_DEMO:
Controller Class使用我们刚才创建的类并保存激活:
接着在SICF
中设置好登陆页面时使用的公共账号和密码:
回到SE80
控制台中,在YBSP_OO_DEMO.do
上右击并选择Test:
如无意外,你将看到熟悉的查询界面:
Step IV 创建RESTful服务
完成了前端展现页面的实现后,我们接着须要实现后端查询的功能。就像前面一早提过的,API不须要页面,它只是个接口,所以这次我们只须要新建一个Controller来实现查询功能就行了,和上面一样,我们先在SE24
中新建一个继承了CL_BSP_CONTROLLER2
的类,YCL_BSP_DEMOS:
同样实现DO_REQUEST
方法如下:
METHOD DO_REQUEST.
*CALL METHOD SUPER->DO_REQUEST
* .DATA:LS_PARA TYPE TY_INPUT,LV_STR TYPE STRING.DATA:BEGIN OF RESP,MSG TYPE TY_MSG,TAB TYPE TY_T_TAB,END OF RESP.CLEAR:LS_PARA,LV_STR,RESP.LV_STR = RUNTIME->SERVER->REQUEST->GET_CDATA( ).CALL METHOD CL_FDT_JSON=>JSON_TO_DATAEXPORTINGIV_JSON = LV_STRCHANGINGCA_DATA = LS_PARA.TRANSLATE:LS_PARA-DATA-MATNR TO UPPER CASE,LS_PARA-DATA-WERKS TO UPPER CASE.IF LS_PARA-DATA-MATNR IS INITIAL.RESP-MSG-MSGTY = 'E'.RESP-MSG-MSG = 'Please input a Materail Number!'.ELSEIF LS_PARA-DATA-WERKS IS INITIAL.RESP-MSG-MSGTY = 'E'.RESP-MSG-MSG = 'Please input a Plant Number!'.ELSE.RESP-MSG-MSGTY = 'S'.SELECT A~MATNRA~LGORTA~LABSTINTO CORRESPONDING FIELDS OF TABLE RESP-TABFROM MARD AS AWHERE A~MATNR LIKE LS_PARA-DATA-MATNRAND A~WERKS EQ LS_PARA-DATA-WERKSAND A~LABST GT 0.IF RESP-TAB[] IS NOT INITIAL.SELECT MATNR,MAKTXINTO TABLE @DATA(LT_MAKTX)FROM MAKTFOR ALL ENTRIES IN @RESP-TABWHERE MATNR EQ @RESP-TAB-MATNR.SORT:LT_MAKTX BY MATNR,RESP-TAB BY MATNR LGORT.LOOP AT RESP-TAB ASSIGNING FIELD-SYMBOL(<FS_TAB>).<FS_TAB>-ID = SY-TABIX.READ TABLE LT_MAKTX ASSIGNING FIELD-SYMBOL(<FS_MAKTX>)WITH KEY MATNR = <FS_TAB>-MATNRBINARY SEARCH.IF SY-SUBRC EQ 0.<FS_TAB>-MAKTX = <FS_MAKTX>-MAKTX.ENDIF.ENDLOOP.ENDIF.ENDIF.LV_STR = /UI2/CL_JSON=>SERIALIZE( DATA = RESP COMPRESS = ABAP_TRUE PRETTY_NAME = /UI2/CL_JSON=>PRETTY_MODE-CAMEL_CASE ).RUNTIME->SERVER->RESPONSE->SET_HEADER_FIELD( NAME = 'Content-Type' VALUE = 'application/json;charset=utf-8' ).RUNTIME->SERVER->RESPONSE->SET_CDATA( DATA = LV_STR ).ENDMETHOD.
上面的代码和之前一篇文章的代码大同小异,但有几点须要注意:
- 都须要通过一个结构去解析传过来的JSON格式Request
- 都须要在返回的HTTP header中指明Response的类型格式和编码
- 非常重要的一点,使用/UI2/CL_JSON这个类去将表结构转化为了JSON格式,而在上篇文章中,我们使用的是CL_TREX_JSON_SERIALIZER。两者的区别在于,/UI2/CL_JSON不会将数字转化成文本格式返回,这样前端Buefy的Table控件才能正常的对它们排序,而后者则是无脑全部以文本形式返回,这点使用时须留意。
另用到的TYPE的定义:
CLASS YCL_BSP_DEMOS DEFINITIONPUBLICINHERITING FROM CL_BSP_CONTROLLER2FINALCREATE PUBLIC .PUBLIC SECTION.TYPES:BEGIN OF TY_DATA,MATNR TYPE MATNR,WERKS TYPE WERKS_D,END OF TY_DATA,BEGIN OF TY_INPUT,DATA TYPE TY_DATA,END OF TY_INPUT,BEGIN OF TY_TAB,ID TYPE I,MATNR TYPE MATNR,MAKTX TYPE MAKTX,LGORT TYPE LGORT_D,LABST TYPE LABST,END OF TY_TAB,TY_T_TAB TYPE STANDARD TABLE OF TY_TAB,BEGIN OF TY_MSG,MSGTY TYPE C LENGTH 1, "S/E.MSG TYPE CHAR50, "Message.END OF TY_MSG.METHODS DO_REQUESTREDEFINITION .
最后,让我们回到BSP应用中,创建一个基于YCL_BSP_DEMOS类的Controller。细心的读者可能已经猜到这个Controller的命名,在上面的html代码中,已经提示了这个Controller _main.do
:
至此,我们已经完成了从前端页面到后端服务的搭建,回到浏览器中,输入查询条件并执行,如数据没有问题,即宣告BSP开发成功:
附
YBSP_OO_DEMO 最终目录结构:
SAP 基于VUE的BSP OO单页移动端Web App开发相关推荐
- 基于vue的动态表单自助建站工具
基于vue的动态表单自助建站工具 根据自己需求自助搭建移动端营销.投放.信息采集.推广.宣传等页面 主要用到的技术如下: "element-ui": "^2.4.5&qu ...
- div+mui+vue.js 制作问卷调查单页 ——题目答案是造的json
div+mui+vue.js 制作问卷调查单页 --题目答案是造的json 先来看一下效果图: 主要就是用读取json题目和答案,记录答案ID. 一次性去读10道题目,vue.js控制当前题目的显示影 ...
- 基于vue Ant-Design 的表单设计器,快速开发
基于vue Ant-Design 的表单设计器,快速开发https://gitee.com/kcz66/k-form-design/ 表单设计器 k-form-design image 简介 参考项目 ...
- 基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1]
基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1] 原文:基于Vue JS, Webpack 以及Material Design的渐进式web应 ...
- [译]基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1]
渐进式web应用是大势所趋.越来越多的大公司开始使用这些技术(比如推特:https://mobile.twitter.com/). 想象你可以在地铁中浏览一个web应用,这个应用能够向用户推送通知并且 ...
- 基于Vue全家桶制作的的高仿美团APP
美团外卖APP ? 项目演示地址:http://39.108.232.27:9000 ? GitHub:github.com/bxm0927/vue- 基于 Vue 全家桶 (2.x) 制作的美团外卖 ...
- 基于Vue.js制作的仿车轮驾考通APP端页面
背景:学习完Vue,老师要求期末作业以Vue技术做一个手机端或者PC端的前端小项目.期末临近,周围的同学有的仿微信APP端,有的仿QQAPP端.小萍去年考科目一用了车轮驾考通刷题,然后她最后决定基于V ...
- 基于Springboot的智慧校园管理系统(PC端和APP端双端应用)
这里写自定义目录标题 基于Springboot的智慧校园管理系统(PC端和APP端双端应用) 项目整体介绍 项目功能实现 项目源码查询 基于Springboot的智慧校园管理系统(PC端和APP端双端 ...
- 陌生交友发布动态圈子单聊打招呼群聊app开发
陌生交友发布动态圈子单聊打招呼群聊app开发 功能有,发布圈子,发布动态,查看附近的人,发布活动,实人认证,个人主页,相册查看,单聊,群聊. 即时通讯第三方goeasy接口. 好的,以下是陌生交友应用 ...
最新文章
- 基于关联规则(Variational Autoencoders)疾病预测系统实战:(pyspark FPGrowth实现频繁项集挖掘、最后给出预测模型topK准确率和召回率)
- 最新版GMP规范全文
- 从算法到硬件,一文读懂2019年 AI如何演进
- gz键盘增强小工具_这些不起眼的Mac小工具,能让你的Macbook效率倍增!
- Spark Streaming事务
- 【Python】用Python实现十大经典排序算法
- SAP Spartacus Table cell显示数据类型的Component决定逻辑
- 面向对象代码_面向对象的代码生成方法
- 英特尔携手谷歌云加速最新虚拟机;谷歌云平台下调抽成比例;Hitachi Vantara推出全新云成本优化服务...
- 创建表空间时ora-01119和ora-27040的处理
- java blob字段_java 存取blob字段
- linux 命令 读phy_Linux PHY几个状态的跟踪
- 推荐算法和机器学习入门
- liferay+portlet+开发实例
- nova3能用鸿蒙,鸿蒙公测新增6款手机,都是nova系列,包括一款4G手机
- office及各类软件的图标修复
- 深度学习实现代码汇总
- 【科普视频】信号在时域和频域上的区别
- nandflash驱动分析 针对K9GAG08U0D uboot1.1.6(上)
- scikit-learn 线性回归算法库小结
热门文章
- SE16N新改表内容方法 - SE16N_INTERFACE
- php酷狗接口,酷狗API口 · VIPTV - 极速,高清,无广告 · 看云
- Phoenix 二级索引探究
- css减去自身宽度的一半,xHTML / CSS:如何使内部div获得100%的宽度减去另一个div的宽度...
- 这18节课手把手教会你入门蚂蚁区块链BAAS系统开发
- eNSP中网云不能识别网卡
- 使用谷歌libphonenumber获取号码归属地
- CSS 实用工具: Google Fonts API 引入免费字体库
- 本命年一定要记得穿红裤衩:2015年总结
- YOLOV5各结构文件的功能作用