這是 Jerry 2021 年的第 71 篇文章,也是汪子熙公眾號(hào)總共第 348 篇原創(chuàng)文章。
Jerry 之前發(fā)布過(guò)一篇文章 不使用任何框架,手寫純 JavaScript 實(shí)現(xiàn)上傳本地文件到 ABAP 服務(wù)器,之后不少朋友留言,提出的問(wèn)題概括為以下兩類:
(1) 客戶端通過(guò) multipart/form-data 格式發(fā)送的數(shù)據(jù),ABAP 端除了像 Jerry 文章采取字符串解析這種比較繁瑣的方式處理外,還有其他方法嗎?
(2) 能否上傳二進(jìn)制文件比如 Excel 到 ABAP 并進(jìn)行解析?
本文就來(lái)解答這兩個(gè)問(wèn)題。
使用 JavaScript 通過(guò) multipart/form-data 格式發(fā)送 PDF 和 Excel 文件到 ABAP 服務(wù)器
關(guān)于 multipart/form-data 格式的詳細(xì)說(shuō)明,參考 Mozilla 開發(fā)社區(qū)和 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
我在前文例子的基礎(chǔ)上稍作修改,在 Form 里使用兩個(gè)類型為 file 的 input 標(biāo)簽,分別上傳 PDF 和 Excel 文件:
用來(lái)測(cè)試的本地 PDF 文件:PDF.pdf,大小為 30129 字節(jié)。
內(nèi)容如下:
本地用來(lái)測(cè)試的 Excel 文件:TEST.xlsx,內(nèi)容如下:
點(diǎn)擊 HTML 頁(yè)面上傳文件的超鏈接,在 Chrome 開發(fā)者工具觀察到 HTTP POST 請(qǐng)求的負(fù)載,包含了 PDF 和 Excel 兩個(gè) input 控件包含的二進(jìn)制流(stream):
點(diǎn)擊 view source,查看 multipart/form-data 數(shù)據(jù)明細(xì):
我們?nèi)匀豢梢栽?Chrome 開發(fā)者工具里觀察到上傳的 PDF 和 Excel 的文件名和 Content-Type 即文件類型。同前文上傳文本文件的例子不同,這里無(wú)法看到兩個(gè)文件的二進(jìn)制內(nèi)容——這些二進(jìn)制內(nèi)容可以在 ABAP 服務(wù)器端調(diào)試器里觀察到。
以上傳的 PDF 文件為例,在 ABAP 服務(wù)器端接收到的 form-data 數(shù)據(jù),如下圖所示,綠色高亮區(qū)域即為上圖 Chrome 開發(fā)者工具里能夠觀測(cè)到的文件名 PDF.pdf 和文件類型 application/pdf, 而%PDF-1.4# 開頭的,就是 PDF 文件的二進(jìn)制內(nèi)容。
準(zhǔn)確的說(shuō),PDF 格式是文本和二進(jìn)制流的混合模式。用文本編輯器打開 PDF.pdf, 能看到其文件頭部包含的是文本字符描述的文件元數(shù)據(jù),比如該文件的創(chuàng)建和修改時(shí)間,創(chuàng)建該文件的工具名等等,后半部分才是二進(jìn)制流。
現(xiàn)在已經(jīng)有很多開源工具比如 JavaScript 庫(kù)可以用來(lái)生成和解析 PDF 文件了,感興趣的朋友可以在搜索引擎里搜索 Jerry 這幾篇文章:
- 使用 ABAP 和 JavaScript 代碼生成 PDF 文件的幾種方式
- 使用 JavaScript 將當(dāng)前頁(yè)面保存成 PDF,支持圖片和文字的保存
- PDF 文件如何轉(zhuǎn)成 markdown 格式
對(duì)于上傳到 ABAP 服務(wù)器的 PDF 文件的文件名,我們?nèi)匀徊扇『颓耙黄恼峦瑯拥姆绞浇馕觯瑥南聢D紅色矩形框中的字符串中提取。
而對(duì)于上圖綠色高亮的 PDF 的二進(jìn)制數(shù)據(jù),CL_HTTP_REQUEST 提供了相應(yīng)方法來(lái)提取。關(guān)鍵代碼如下圖所示:
當(dāng) ABAP 服務(wù)器接收到的客戶端數(shù)據(jù)格式為 multipart/form-data 時(shí),調(diào)用 CL_HTTP_REQUEST 的num_multiparts 方法可以得到 parts 的個(gè)數(shù),再使用 get_multipart 方法,傳入每個(gè) part 的索引,就可以得到代表這個(gè) part 的一個(gè)實(shí)例引用。
調(diào)用該引用的get_content_type 和 get_data 方法,就能解析出上傳文件的類型(比如 pdf 格式對(duì)應(yīng)的 application/pdf)和二進(jìn)制內(nèi)容。
至此調(diào)用 SAP CRM 附件創(chuàng)建 API 的三大參數(shù):文件名,文件類型和文件二進(jìn)制內(nèi)容均已就緒,調(diào)用 API 即可將上傳的 PDF 和 Excel 數(shù)據(jù),創(chuàng)建成為 SAP CRM 銷售訂單的附件。
創(chuàng)建好的 PDF 和 Excel 附件在 SAP CRM 系統(tǒng)里顯示如下:
打開這兩個(gè)附件,確保上傳之后,其內(nèi)容同本地文件完全一致:
如何使用 ABAP 解析上傳的 Excel 文件
這個(gè)話題,其實(shí) Jerry 2019 年的文章 使用ABAP操作Excel的幾種方法 已經(jīng)系統(tǒng)介紹過(guò)。
我們?cè)?ABAP 調(diào)試器里觀察到,本地?cái)U(kuò)展名為 xlsx 的 Excel 文件,上傳到 ABAP 服務(wù)器時(shí),其 content-type 為:
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
什么是 openxmlformats?下面通過(guò)具體的例子來(lái)說(shuō)明。
以我這個(gè)本地 Excel 文件為例,將擴(kuò)展名從 xlsx 更改為 zip,然后解壓:
發(fā)現(xiàn) xlsx 文件其實(shí)是一個(gè)壓縮包,解壓之后生成了一個(gè)文件夾,包含了下圖所示的若干子文件夾和文件。
上圖 Excel 文件有一個(gè)名為 Sheet1 的內(nèi)容頁(yè),A1 值為 ABAP,B1 值為 Java,這個(gè)信息維護(hù)在解壓出來(lái)的 worksheets 文件夾的子文件 sheet1.xml 內(nèi):
上圖高亮的 XML c 節(jié)點(diǎn)代表 Cell,r="A1" 和 r="B1", 代表這兩個(gè) cell 所在的 Row ID,c 的子節(jié)點(diǎn) v 包含了 Cell 的具體值。
不難發(fā)現(xiàn),sheet1.xml 里并未直接將 ABAP 和 Java 的字符串字面量在內(nèi),而僅僅存放了其索引,0 和 1. 做過(guò) Java 開發(fā)的朋友,可以把這種設(shè)計(jì)類比成 Java 的字符串常量池。
在解壓出的文件夾里有另一個(gè)文件 sharedStrings.xml, 顧名思義,維護(hù)了 Excel worksheets 里出現(xiàn)的所有字符串,用于在 sheets 之間共享。每個(gè)多帶帶的 sheet xml 文件只維護(hù)使用到的字符串的索引,以減小 Excel 文件的尺寸。
因此,只要熟悉了 TEST.xlsx 重命名為 TEST.zip 并解壓之后生成的每一個(gè)文件的用途,即 Open XML Formats 的協(xié)議規(guī)范,就可以使用任何高級(jí)編程語(yǔ)言解析 Excel 文件。
可以在 WikiPedia 里找到 Open XML Formats 協(xié)議定義的每個(gè)文件的作用:
https://en.wikipedia.org/wiki/Office_Open_XML_file_formats
SAP CRM 提供了一個(gè)工具類,基于 Open XML Formats 解析 Excel 文件內(nèi)容:cl_xlsx_document.
只需將 Excel 文件的二進(jìn)制內(nèi)容傳入,該工具類即返回一個(gè) Excel 文件的引用,根據(jù)該引用的各種 GET 方法,即可訪問(wèn)到 Excel 文件內(nèi)由 Open XML Formats 協(xié)議定義的各個(gè)部分的內(nèi)容。
核心邏輯如下圖所示,代碼都是自描述的,這里不再贅述。
當(dāng)然,開源項(xiàng)目 abap2xlsx 也是另一個(gè)選擇:
https://github.com/sapmentors/abap2xlsx
至于 SAP Fiori 應(yīng)用通過(guò) SAP Gateway 上傳附件的技術(shù)細(xì)節(jié),Jerry 將來(lái)會(huì)介紹。
本文涉及到的前后端完整源代碼,請(qǐng)?jiān)谶@個(gè)鏈接處下載。
感謝閱讀。
Jerry 的 ABAP 專題
-
Jerry的ABAP, Java和JavaScript亂燉
-
ABAP開發(fā)人員未來(lái)應(yīng)該學(xué)些什么
-
Jerry 2017年的五一小長(zhǎng)假:8種經(jīng)典排序算法的ABAP實(shí)現(xiàn)
-
Jerry的ABAP原創(chuàng)技術(shù)文章合集
-
300行ABAP代碼實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的區(qū)塊鏈原型
-
使用Java+SAP云平臺(tái)+SAP Cloud Connector調(diào)用ABAP On-Premise系統(tǒng)里的函數(shù)
-
在SAP云平臺(tái)的CloudFoundry環(huán)境下消費(fèi)ABAP On-Premise OData服務(wù)
-
ABAP vs Java, 蛙泳 vs 自由泳
-
聊聊C語(yǔ)言和ABAP
-
動(dòng)手使用ABAP Channel開發(fā)一些小工具,提升日常工作效率
-
我用ABAP做過(guò)的那些無(wú)聊的事情
-
不喜歡SAP GUI?那試試用Eclipse進(jìn)行ABAP開發(fā)吧
-
使用Visual Studio Code編寫和激活A(yù)BAP代碼
-
你的ABAP程序給佛祖開過(guò)光么?來(lái)試試Jerry這個(gè)小技巧
-
在SAP云平臺(tái)ABAP編程環(huán)境上編寫第一段ABAP程序
-
SAP官方發(fā)布的ABAP編程規(guī)范
-
ABAP Code Inspector那些隱藏的功能,您都知道嗎?
-
還在用ABAP進(jìn)行SAP產(chǎn)品的二次開發(fā)?來(lái)了解下這種全新的二次開發(fā)理念吧
-
ABAP Netweaver體內(nèi)的那些寄生式編程語(yǔ)言
-
從SAP社區(qū)上的一篇博客開始,聊聊SAP產(chǎn)品命名背后的那份情懷
-
云端的ABAP Restful服務(wù)開發(fā)
-
如何在SAP云平臺(tái)ABAP編程環(huán)境里把CDS view暴露成OData服務(wù)
-
使用abapGit在ABAP On-Premises系統(tǒng)和SAP云平臺(tái)ABAP環(huán)境之間進(jìn)行代碼傳輸
-
30分鐘用Restful ABAP Programming模型開發(fā)一個(gè)支持增刪改查的Fiori應(yīng)用
-
Jerry帶您了解Restful ABAP Programming模型系列之二:Action和Validation的實(shí)現(xiàn)
-
Jerry帶您了解Restful ABAP Programming模型系列之三:云端ABAP應(yīng)用調(diào)試
-
SAP云平臺(tái)上的ABAP編程環(huán)境里如何消費(fèi)第三方服務(wù)
-
ABAP開發(fā)者上云的時(shí)候到了 - 現(xiàn)在大家可以免費(fèi)使用SAP云平臺(tái)ABAP環(huán)境的試用版了
-
學(xué)而不思則罔 - SAP云平臺(tái)ABAP編程環(huán)境的由來(lái)和適用場(chǎng)景
-
SAP云平臺(tái)里的三叉戟應(yīng)用
-
如何基于Restful ABAP Programming模型開發(fā)并部署一個(gè)支持增刪改查的Fiori應(yīng)用
-
SAP 2019 TechEd Key Note解讀:云時(shí)代下SAP從業(yè)人員如何做二次開發(fā)?
-
有哪些ABAP關(guān)鍵字和語(yǔ)法,到了ABAP云環(huán)境上就沒(méi)辦法用了?
-
ABAP開發(fā)環(huán)境終于支持以駝峰命名法自動(dòng)格式化ABAP變量名了
-
利用ABAP 740的新關(guān)鍵字REDUCE完成一個(gè)實(shí)際工作任務(wù)
-
一段讓人瑟瑟發(fā)抖的ABAP代碼
-
昨日萬(wàn)圣節(jié)ABAP怪獸級(jí)代碼謎團(tuán),公布答案啦
-
介紹一種在ABAP內(nèi)核態(tài)進(jìn)行內(nèi)表高效拷貝的方法
-
使用SAP Cloud Application Programming模型開發(fā)OData的一個(gè)實(shí)際例子
-
當(dāng)ABAP遇見普羅米修斯
-
使用ABAP繪制可伸縮矢量圖
-
ABAP開發(fā)環(huán)境語(yǔ)法高亮的那些事兒
-
SAP錯(cuò)誤消息調(diào)試之七種武器:讓所有的錯(cuò)誤消息都能被定位
-
使用ABAP操作Excel的幾種方法
-
SAP GUI里的收藏夾事務(wù)碼管理工具
-
SAP GUI和Windows注冊(cè)表
-
有了Debug權(quán)限就能干壞事?小心了,你的一舉一動(dòng)盡在系統(tǒng)監(jiān)控中
-
ABAP CCDEF, CCIMP, CCMAC, CCAU, CMXXX這些東東是什么鬼
-
實(shí)現(xiàn)ABAP條件斷點(diǎn)的三種方式
-
使用SAT跟蹤監(jiān)控從瀏覽器打開的SAP應(yīng)用的性能和調(diào)用棧
-
一個(gè)13年ABAP老兵的建議:了解這些基礎(chǔ)知識(shí),對(duì)ABAP開發(fā)有百利而無(wú)一害
-
SAP ABAP Netweaver容器化, 不可能完成的任務(wù)嗎?
-
SAP產(chǎn)品增強(qiáng)技術(shù)回顧
-
SAP API開發(fā)方法大全
-
淺談Java和SAP ABAP的靜態(tài)代理和動(dòng)態(tài)代理,以及ABAP面向切面編程的嘗試
-
SAP ABAP應(yīng)用服務(wù)器的HTTP響應(yīng)狀態(tài)碼(Status Code)
-
SAP ABAP里存在Java List這種集合工具類么?CL_OBJECT_COLLECTION了解一下
-
ABAP面試題系列:寫一組會(huì)出現(xiàn)死鎖(Deadlock)的ABAP程序
-
SAP ABAP Netweaver服務(wù)器的標(biāo)準(zhǔn)登錄方式講解
-
SAP ABAP關(guān)鍵字語(yǔ)法圖和ABAP代碼自動(dòng)生成工具Code Composer
-
SAP ABAP SM50的另類用途 - ABAP工作進(jìn)程對(duì)數(shù)據(jù)庫(kù)表讀取操作的檢測(cè)
-
關(guān)于SAP ABAP字符變量和字符串變量字符個(gè)數(shù)的一個(gè)知識(shí)點(diǎn),和一個(gè)血案
-
SAP ABAP一組關(guān)鍵字 IS BOUND, IS NOT INITIAL和IS ASSIGNED的用法辨析
-
SAP ABAP和Java里的弱引用(WeakReference)和軟引用(SoftReference)
-
SAP AMDP介紹 - ABAP托管的HANA數(shù)據(jù)庫(kù)過(guò)程
-
給你的ABAP對(duì)象打上標(biāo)簽(Tag)
-
歷史上的今天:編程語(yǔ)言中null引用的十億美元錯(cuò)誤
-
ABAP Development Tool 代碼模板和其他一些實(shí)用技巧匯總
-
SAP ABAP Development Tool 提高開發(fā)效率的十個(gè)小技巧
-
如何在 SAP BTP 平臺(tái) ABAP 編程環(huán)境里消費(fèi)基于 SOAP 的 Web Service
-
ABAP 真的會(huì)過(guò)時(shí)嗎?聊聊 ABAP 的過(guò)去,現(xiàn)在和未來(lái)
-
基于 abapGit 和 abaplint 的 ABAP 持續(xù)集成的一個(gè)例子
- 不使用任何框架,手寫純 JavaScript 實(shí)現(xiàn)上傳本地文件到 ABAP 服務(wù)器
更多Jerry的原創(chuàng)文章,盡在:"汪子熙"。