前言

之前的一篇文章,通过传统的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开发相关推荐

  1. 基于vue的动态表单自助建站工具

    基于vue的动态表单自助建站工具 根据自己需求自助搭建移动端营销.投放.信息采集.推广.宣传等页面 主要用到的技术如下: "element-ui": "^2.4.5&qu ...

  2. div+mui+vue.js 制作问卷调查单页 ——题目答案是造的json

    div+mui+vue.js 制作问卷调查单页 --题目答案是造的json 先来看一下效果图: 主要就是用读取json题目和答案,记录答案ID. 一次性去读10道题目,vue.js控制当前题目的显示影 ...

  3. 基于vue Ant-Design 的表单设计器,快速开发

    基于vue Ant-Design 的表单设计器,快速开发https://gitee.com/kcz66/k-form-design/ 表单设计器 k-form-design image 简介 参考项目 ...

  4. 基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1]

    基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1] 原文:基于Vue JS, Webpack 以及Material Design的渐进式web应 ...

  5. [译]基于Vue JS, Webpack 以及Material Design的渐进式web应用 [Part 1]

    渐进式web应用是大势所趋.越来越多的大公司开始使用这些技术(比如推特:https://mobile.twitter.com/). 想象你可以在地铁中浏览一个web应用,这个应用能够向用户推送通知并且 ...

  6. 基于Vue全家桶制作的的高仿美团APP

    美团外卖APP ? 项目演示地址:http://39.108.232.27:9000 ? GitHub:github.com/bxm0927/vue- 基于 Vue 全家桶 (2.x) 制作的美团外卖 ...

  7. 基于Vue.js制作的仿车轮驾考通APP端页面

    背景:学习完Vue,老师要求期末作业以Vue技术做一个手机端或者PC端的前端小项目.期末临近,周围的同学有的仿微信APP端,有的仿QQAPP端.小萍去年考科目一用了车轮驾考通刷题,然后她最后决定基于V ...

  8. 基于Springboot的智慧校园管理系统(PC端和APP端双端应用)

    这里写自定义目录标题 基于Springboot的智慧校园管理系统(PC端和APP端双端应用) 项目整体介绍 项目功能实现 项目源码查询 基于Springboot的智慧校园管理系统(PC端和APP端双端 ...

  9. 陌生交友发布动态圈子单聊打招呼群聊app开发

    陌生交友发布动态圈子单聊打招呼群聊app开发 功能有,发布圈子,发布动态,查看附近的人,发布活动,实人认证,个人主页,相册查看,单聊,群聊. 即时通讯第三方goeasy接口. 好的,以下是陌生交友应用 ...

最新文章

  1. 基于关联规则(Variational Autoencoders)疾病预测系统实战:(pyspark FPGrowth实现频繁项集挖掘、最后给出预测模型topK准确率和召回率)
  2. 最新版GMP规范全文
  3. 从算法到硬件,一文读懂2019年 AI如何演进
  4. gz键盘增强小工具_这些不起眼的Mac小工具,能让你的Macbook效率倍增!
  5. Spark Streaming事务
  6. 【Python】用Python实现十大经典排序算法
  7. SAP Spartacus Table cell显示数据类型的Component决定逻辑
  8. 面向对象代码_面向对象的代码生成方法
  9. 英特尔携手谷歌云加速最新虚拟机;谷歌云平台下调抽成比例;Hitachi Vantara推出全新云成本优化服务...
  10. 创建表空间时ora-01119和ora-27040的处理
  11. java blob字段_java 存取blob字段
  12. linux 命令 读phy_Linux PHY几个状态的跟踪
  13. 推荐算法和机器学习入门
  14. liferay+portlet+开发实例
  15. nova3能用鸿蒙,鸿蒙公测新增6款手机,都是nova系列,包括一款4G手机
  16. office及各类软件的图标修复
  17. 深度学习实现代码汇总
  18. 【科普视频】信号在时域和频域上的区别
  19. nandflash驱动分析 针对K9GAG08U0D uboot1.1.6(上)
  20. scikit-learn 线性回归算法库小结

热门文章

  1. SE16N新改表内容方法 - SE16N_INTERFACE
  2. php酷狗接口,酷狗API口 · VIPTV - 极速,高清,无广告 · 看云
  3. Phoenix 二级索引探究
  4. css减去自身宽度的一半,xHTML / CSS:如何使内部div获得100%的宽度减去另一个div的宽度...
  5. 这18节课手把手教会你入门蚂蚁区块链BAAS系统开发
  6. eNSP中网云不能识别网卡
  7. 使用谷歌libphonenumber获取号码归属地
  8. CSS 实用工具: Google Fonts API 引入免费字体库
  9. 本命年一定要记得穿红裤衩:2015年总结
  10. YOLOV5各结构文件的功能作用