谈谈企业级 Web 应用的前端消息展示的定制化问题

笔者在社区上已经发布了一些技术文章,记录了自己工作于企业级前端应用几年以来积累的一些项目经验和教训。

之前的文章关于企业级 Web 应用搜索引擎优化 Search Engine Optimization 的一些工作经验分享已经提到,所谓企业级前端应用,是指为大型企业或组织开发的前端应用,这些应用具有超过一般 2C 软件的技术复杂度,高度定制化和可扩展性,因为企业级前端应用程序,通常需要满足企业特定的业务需求和技术要求,因此除了实现业务需求之外,还必须具备强大的性能、可扩展性、安全性和可维护性。在企业级前端开发中,开发者需要面对大规模数据处理、复杂的业务逻辑、多模块协同工作等挑战。

Web 应用的消息展示,属于人机交互领域的一个重要话题。当涉及到企业级 Web 应用中消息展示时,确保用户能够清晰、高效地接收和理解信息是至关重要的。本文不会对消息展示这个话题的方方面面展开论述,而是着重分享笔者在实际工作中,对前端消息展示定制化这个领域积累的一些经验。

本文从 StackOverflow 上一个实际的需求谈起。

这个需求的背景是,客户在 SAP 电商云的产品明细页面,可以留下自己的评论,点击 Submit 按钮提交。

提交之后,能看到"谢谢评论"的提示消息。

客户定制化需求是:不执行这个默认的消息显示逻辑,即不显示消息,而是执行其他逻辑,比如短信通知或邮件通知。

我们先简单回顾 SAP 其他产品的 UI 消息显示机制。

消息是应用程序执行过程中给用户提供反馈的重要渠道之一,通常由用户某个动作直接触发,显示在产品界面上。当然应用程序后台作业运行到某个阶段,在满足指定条件时也能触发消息显示。简明、清晰而准确的消息,能帮助用户明确程序当前的运行状况,指引其下一步的操作。

SAP 产品 UI 显示的消息文本,均有专业的 Knowledge Management 即 KM 团队负责审查和发布。

对于 SAP 开发人员来说,更关心的则是这些消息显示的上下文;换言之,看到 UI 上显示一条消息之后,能否在最短的时间内,高效定位到抛出该消息的准确代码位置。

如下图所示,在经典的 SAPGUI SE38 ABAP 程序编辑器,输入一个不存在的报表名称,会显示一条消息:

Program XX does not exist.

其中 XX 是占位符,会被用户实际输入的报表名称所替换。

基于 ABAP 实现的所有 SAP 产品,比如 SAP CRM,SAP SRM,SAP S/4HANA,SAP Cloud for Customer,UI 上显示的每一条消息,在 ABAP 后台均有一条对应的消息记录,维护在事物码 SE91 里。

以上图的消息为例,其号码为 DS017,其中 DS 为消息类别, 017 为消息编号,二者唯一确认一条消息记录。

到了 SAP CRM WebClient UI 里,浏览器上看到的每一条消息,比如下图 Data Contains errors and cannot be saved, 仍然唯一对应后台一条消息记录 CRM_BUPA_BOL/036:

这条消息是由 Business Partner 应用负责维护的。

到了 SAP Cloud for Customer,虽然 Partners 无法直接登录 ABAP 后台,然而仍然可以通过 Chrome 开发者工具,得到 UI 消息对应的 ABAP 后台消息记录的消息类和消息编号:

在 SAP Cloud for Customer 里,Partners 可以通过 Cloud Application Studio 新建 UI 消息:

在 ABSL 代码里,通过 raise 语句显示消息到 UI 上:

javascript 复制代码
raise delivery_message.Create("S", this.OutboundDeliveryID);

运行时 delivery_message 定义的消息文本里的 &1,会被 this.outboundDeliveryID 字段的值取代。

到了 SAP S/4HANA 里,所有基于 Fiori Elements 创建的 Fiori 应用,共享同一套视图模板和控制器实现,因此大多数消息不再由应用程序各自定义,而由框架统一维护。

比如下列 S/4HANA 物料主数据维护时的错误消息:

Product Type 03 is not valid:

这条消息维护于所谓的 Business Suite Foundation Reusable Components 开发包中的消息类 /BOFU/CODE_LISTS 内部。

我们再来分析本文开头提到的 SAP Commerce Cloud 的消息显示定制化需求。

"感谢评论"的消息文本 ID 为 productReview.thankYouForReview,在 ProductReviewEffects 接收到 POST_PRODUCT_REVIEW_SUCCESS 这个 Action 之后通过 MessageService 显示到 UI 上。

一种最常规的二次开发思路就是,继承 SAP Commerce Cloud UI 标准发布的 ProductReviewEffects 类,重载其接收到 POST_PRODUCT_REVIEW_SUCCESS 之后的实现代码,将调用 MessageService 抛出感谢评论的代码删除掉即可。

然而 SAP Commerce Cloud UI 发布的所有 Effects 实现类都是不可扩展的,因此这条思路行不通。

SAP 电商云 Spartacus UI,同 Commerce 后台交互的逻辑:

Spartacus 同 Commerce 系统的通信,通过 HTTP 协议调用 OCC API 完成。Connector 是 HTTP调用的发起者,维护了静态的配置信息,即 API endpoint.

比如,从 Commerce 系统读取产品主数据,读取的字段列表以 url 参数的形式出现在 API endpoint 里。这些字段列表可以在 Connector 的静态配置点里进行配置。

Connector 并不会直接同 Commerce 交互,而是把请求转发给 Adapter,具体通信由 Adapter 完成,Connector 只负责调度 Adapter. Spartacus 发布的 Adapter 默认使用 OCC Module,即 Commerce 标准的 OCC Restful API,但是客户也可以实现自己的 Adapter,连接 Commerce 之外的其他后台系统。

Connector 将 Adapter 取回的数据交给 NgRx Store 结构统一管理,后者的复杂度被 Facade 层所隐藏,而Spartacus UI 组件只会同 Facade 层交互,进行数据绑定和页面展示。这体现了关注点分离的设计原则。

再回到本文开头客户提出的定制化需求。为了实现该需求,我们需要深入了解下图红色高亮区域即 NgRx Store 和 SAP Spartacus Connector 交互的细节。

NgRx 是 Angular 基于 RxJs 的一个响应式状态管理库,包含下列核心概念,Jerry 会结合 SAP Commerce Cloud UI 对 NgRx 的实际使用情况来举例说明。

Action:其实就是编程领域的事件的别名。SAP Commerce Cloud UI 组件,能响应用户操作,通过组件的 Service 实例,投递出相应的 Action. Action 投递方和 Action 接收方是解耦的,彼此感知不到对方。 下图是 SAP 电商云产品明细页面评论区域的 Submit 按钮被点击之后,对应的 Service 类抛出 PostProductReview Action 的代码:

ProductActions.PostProductReview 是 NgRx Action 的一个子类,type 字段为 POST_PRODUCT_REVIEW,构造函数的参数 payload,定义了调用 Commerce OCC API 持久化用户评论需要传递的数据结构:

Effects:SAP Commerce Cloud UI Action 的接收方之一。下图 Effects 代码的语义是:接收类型为 POST_PRODUCT_REVIEW 的 Action(第46行),调用前文介绍的 Connector,向 Commerce 后台发起 OCC API 调用(第49行),根据 API 返回结果,分别投递评论保存成功或失败的 Action: PostProductReviewSuccess(第53行) PostProductReviewFail(第56行)

Store:Angular 应用维护在内存中的存储结构,存放了 SAP Commerce Cloud UI 所有组件的运行时数据。每当 Effects 调用 Commerce OCC API 拿到新的数据时,调用 Reducer,将增量数据填充到 Store 中去。

Reducer:本质上是一个有限状态自动机,每当收到代表来自 Commerce 后台的数据发生变化的 Action 时,状态机驱动对应的 Reducer, 根据新的 Action 包含的负载,对 Store 中的数据进行调整。

例如产品明细页面第一次渲染时,Effects 需要从 Commerce 后台读取所有的评论数据。读取成功后,抛出 LOAD_PRODUCT_REVIEWS_SUCCESS Action. 下图的 ProductReviewsReducer 接收到该 Action,从其 payload 中解析出实际评论数据并返回。这些返回的数据会被 NgRx 框架接收,并合并到 Store 中去。

Selector:纯函数,作为应用程序从 NgRx Store 中读取最新数据的接口。 理清楚 SAP Commerce Cloud UI 使用 NgRx 进行状态管理的细节之后,对于文章开头的客户定制化需求,也就不难实现了。

既然下图所示的 SAP Commerce Cloud UI 标准的 Effects 无法扩展,我们注意到 UI 组件的 Service 层,才是所有事件流的起始点,因此可以实现新的 Service,来替换 SAP 电商云 UI 标准的 Service,然后基于该定制化 Service,实现配套的 Effects 和 Action.

如此一来,标准的和用户评论相关的逻辑流(如下图 1-2-3 所示)将不会再得到执行,取而代之的是我们自己定制化的执行流,如下图 A-B-C 所示,其中蓝色的图例均为 Partners 需要开发的定制化代码。

这个解决方案的简要介绍:

(1) 创建新的 Action CustPostProductReview,CustPostProductReviewSuccess 和 CustPostProductReviewFail. 其实就是在标准的实现类之前,添加 Cust 的前缀。

(2) 创建新的 CustProductReviewService,继承标准的 ProductReviewService. 重载其 add 方法,抛出新的 CustPostProductReview Action.

(3) 新建 CustProductReviewsEffects,接收新的 Action CUST_POST_PRODUCT_REVIEW(第25行),仍旧调用 Connector 将用户评论持久化到 Commerce 后台(第28行),然后抛出新的 Action CustPostProductReviewSucess.

自定义 Effect 接收到新的 Action CUST_POST_PRODUCT_REVIEW_SUCCESS 之后,就可以进行自定义逻辑编写。

4)将自定义的 Effect 和 Service 实现,通过 Angular 依赖注入框架,配置到对应的 Module 中。

本需求在 SAP Spartacus 3.1 版本测试通过。

总结

本文首先给出了企业级 Web 应用的前端消息展示领域需要实现的需求,接着从消息展示的定制化这个细分领域出发,分别通过 ABAP,CRM WebClient UI,Cloud for Customer 和 Commerce Cloud 等几款企业级应用的 Web UI 为例,详细参数了消息定制化在这些企业级解决方案中的详细技术实现。

相关推荐
还是大剑师兰特26 分钟前
D3的竞品有哪些,D3的优势,D3和echarts的对比
前端·javascript·echarts
王解27 分钟前
【深度解析】CSS工程化全攻略(1)
前端·css
一只小白菜~33 分钟前
web浏览器环境下使用window.open()打开PDF文件不是预览,而是下载文件?
前端·javascript·pdf·windowopen预览pdf
方才coding38 分钟前
1小时构建Vue3知识体系之vue的生命周期函数
前端·javascript·vue.js
阿征学IT42 分钟前
vue过滤器初步使用
前端·javascript·vue.js
王哲晓43 分钟前
第四十五章 Vue之Vuex模块化创建(module)
前端·javascript·vue.js
丶213643 分钟前
【WEB】深入理解 CORS(跨域资源共享):原理、配置与常见问题
前端·架构·web
发现你走远了43 分钟前
『VUE』25. 组件事件与v-model(详细图文注释)
前端·javascript·vue.js
Mr.咕咕1 小时前
Django 搭建数据管理web——商品管理
前端·python·django
张张打怪兽1 小时前
css-50 Projects in 50 Days(3)
前端·css