使用 JavaScript 上传 PDF 和 Excel 等二进制文件到 ABAP 服务器并进行解析
Jerry 之前发布过一篇文章 不使用任何框架,手写纯 JavaScript 实现上传本地文件到 ABAP 服务器,之后不少朋友留言,提出的问题概括为以下两类:
(1) 客户端通过 multipart/form-data 格式发送的数据,ABAP 端除了像 Jerry 文章采取字符串解析这种比较繁琐的方式处理外,还有其他方法吗?
(2) 能否上传二进制文件比如 Excel 到 ABAP 并进行解析?
本文就来解答这两个问题。
使用 JavaScript 通过 multipart/form-data 格式发送 PDF 和 Excel 文件到 ABAP 服务器
关于 multipart/form-data 格式的详细说明,参考 Mozilla 开发社区和 W3 Org 的文档:
-
https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects
-
https://www.w3.org/html/wg/spec/association-of-controls-and-forms.html#multipart-form-data
我在前文例子的基础上稍作修改,在 Form 里使用两个类型为 file 的 input 标签,分别上传 PDF 和 Excel 文件:
用来测试的本地 PDF 文件:PDF.pdf,大小为 30129 字节。
内容如下:
本地用来测试的 Excel 文件:TEST.xlsx,内容如下:
点击 HTML 页面上传文件的超链接,在 Chrome 开发者工具观察到 HTTP POST 请求的负载,包含了 PDF 和 Excel 两个 input 控件包含的二进制流(stream):
点击 view source,查看 multipart/form-data 数据明细:
我们仍然可以在 Chrome 开发者工具里观察到上传的 PDF 和 Excel 的文件名和 Content-Type 即文件类型。同前文上传文本文件的例子不同,这里无法看到两个文件的二进制内容——这些二进制内容可以在 ABAP 服务器端调试器里观察到。
以上传的 PDF 文件为例,在 ABAP 服务器端接收到的 form-data 数据,如下图所示,绿色高亮区域即为上图 Chrome 开发者工具里能够观测到的文件名 PDF.pdf 和文件类型 application/pdf, 而%PDF-1.4# 开头的,就是 PDF 文件的二进制内容。
准确的说,PDF 格式是文本和二进制流的混合模式。用文本编辑器打开 PDF.pdf, 能看到其文件头部包含的是文本字符描述的文件元数据,比如该文件的创建和修改时间,创建该文件的工具名等等,后半部分才是二进制流。
现在已经有很多开源工具比如 JavaScript 库可以用来生成和解析 PDF 文件了,感兴趣的朋友可以在搜索引擎里搜索 Jerry 这几篇文章:
- 使用 ABAP 和 JavaScript 代码生成 PDF 文件的几种方式
- 使用 JavaScript 将当前页面保存成 PDF,支持图片和文字的保存
- PDF 文件如何转成 markdown 格式
对于上传到 ABAP 服务器的 PDF 文件的文件名,我们仍然采取和前一篇文章同样的方式解析,从下图红色矩形框中的字符串中提取。
而对于上图绿色高亮的 PDF 的二进制数据,CL_HTTP_REQUEST 提供了相应方法来提取。关键代码如下图所示:
当 ABAP 服务器接收到的客户端数据格式为 multipart/form-data 时,调用 CL_HTTP_REQUEST 的num_multiparts 方法可以得到 parts 的个数,再使用 get_multipart 方法,传入每个 part 的索引,就可以得到代表这个 part 的一个实例引用。
调用该引用的get_content_type 和 get_data 方法,就能解析出上传文件的类型(比如 pdf 格式对应的 application/pdf)和二进制内容。
至此调用 SAP CRM 附件创建 API 的三大参数:文件名,文件类型和文件二进制内容均已就绪,调用 API 即可将上传的 PDF 和 Excel 数据,创建成为 SAP CRM 销售订单的附件。
创建好的 PDF 和 Excel 附件在 SAP CRM 系统里显示如下:
打开这两个附件,确保上传之后,其内容同本地文件完全一致:
如何使用 ABAP 解析上传的 Excel 文件
这个话题,其实 Jerry 2019 年的文章 使用ABAP操作Excel的几种方法 已经系统介绍过。
我们在 ABAP 调试器里观察到,本地扩展名为 xlsx 的 Excel 文件,上传到 ABAP 服务器时,其 content-type 为:
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
什么是 openxmlformats?下面通过具体的例子来说明。
以我这个本地 Excel 文件为例,将扩展名从 xlsx 更改为 zip,然后解压:
发现 xlsx 文件其实是一个压缩包,解压之后生成了一个文件夹,包含了下图所示的若干子文件夹和文件。
上图 Excel 文件有一个名为 Sheet1 的内容页,A1 值为 ABAP,B1 值为 Java,这个信息维护在解压出来的 worksheets 文件夹的子文件 sheet1.xml 内:
上图高亮的 XML c 节点代表 Cell,r=“A1” 和 r=“B1”, 代表这两个 cell 所在的 Row ID,c 的子节点 v 包含了 Cell 的具体值。
不难发现,sheet1.xml 里并未直接将 ABAP 和 Java 的字符串字面量在内,而仅仅存放了其索引,0 和 1. 做过 Java 开发的朋友,可以把这种设计类比成 Java 的字符串常量池。
在解压出的文件夹里有另一个文件 sharedStrings.xml, 顾名思义,维护了 Excel worksheets 里出现的所有字符串,用于在 sheets 之间共享。每个单独的 sheet xml 文件只维护使用到的字符串的索引,以减小 Excel 文件的尺寸。
因此,只要熟悉了 TEST.xlsx 重命名为 TEST.zip 并解压之后生成的每一个文件的用途,即 Open XML Formats 的协议规范,就可以使用任何高级编程语言解析 Excel 文件。
可以在 WikiPedia 里找到 Open XML Formats 协议定义的每个文件的作用:
https://en.wikipedia.org/wiki/Office_Open_XML_file_formats
SAP CRM 提供了一个工具类,基于 Open XML Formats 解析 Excel 文件内容:cl_xlsx_document.
只需将 Excel 文件的二进制内容传入,该工具类即返回一个 Excel 文件的引用,根据该引用的各种 GET 方法,即可访问到 Excel 文件内由 Open XML Formats 协议定义的各个部分的内容。
核心逻辑如下图所示,代码都是自描述的,这里不再赘述。
当然,开源项目 abap2xlsx 也是另一个选择:
https://github.com/sapmentors/abap2xlsx
至于 SAP Fiori 应用通过 SAP Gateway 上传附件的技术细节,Jerry 将来会介绍。
本文涉及到的前后端完整源代码,请在这个链接处下载。
感谢阅读。
- 点赞
- 收藏
- 关注作者
评论(0)