输出EXCEL文件是ABAP开发工作中的常见需求,为了学习相关技术,我翻译过一篇文章:使用OLE2对象创建EXCEL文件,并且一度乐在其中。
最近几个月,经过与若干EXCEL打印程序的艰苦斗争,以及对abap2xlsx和XLSX Workbench的使用。我逐渐意识到OLE实在是一种不适合输出EXCEL的技术,虽然它似乎是大部分ABAP开发者实现相关功能的首选方案。它的缺点很多,优点则乏善可陈...它的过度使用,对业界是一件不好的事情。为了让一些新人不至于误入歧途、选用不合理的技术进行开发工作,我决定写下这篇文章。
下面就来逐一列数以OLE方式生成EXCEL文件的各种缺点,以及它的替代品。
本文链接:
转载请注明
OLE的缺点OLE即Object Linking and Embedding对象链接与嵌入,通过查阅ABAP文档可知,在ABAP中,OLE可以用于在表示层处理外部对象。只支持windows自动化对象。典型的应用场景是与Microsoft Office产品进行交互。
基于这一信息,我们可以得知两件事情:
OLE需要在表示层运行(通俗地说,即用户的设备上)
OLE只能经由SAP客户端与支持OLE的应用进行交互
这两个特性是使用OLE方式输出EXCEL时产生各种的问题的重要来源。下面来一一说明这些问题。
(注:下文中所提到的OLE,如无特指,均指使用生成EXCEL文件时使用的OLE)
1,运行速度慢使用OLE生成EXCEL的速度很慢,是每个有过相关开发经验的人都体验到的事情,特别是某些涉及到动态行列的表单(需要用到大量复制/粘贴操作),有时这类程序的99%以上的运行时间都花在OLE操作上面。此外,既然OLE需要在用户的电脑上通过应用程序交互的方式来运作,用户的计算机的性能和可用资源也可能会对程序的运行效率产生一定影响。
2,兼容性差OLE的技术原理决定了用户必须装有Office软件和SAP客户端软件(如SAP GUI, NWBC等)才能正常运行相关程序。如果软件安装不正确,或者某些版本之间的兼容性不良好,就可能会导致程序无法正常运行。而且问题会很难排查和解决,最后往往只能请IT支持人员为用户升级Office软件、SAP客户端,甚至重装Windows系统。
另一方面,如果用户没有安装SAP客户端,而是使用基于Web的客户端访问SAP系统,OLE程序也无法运行。本人在前些天就遇到这样一个需求:把ERP已有的某个打印程序迁移到SRM系统上面。这本来是很简单的事情,但是,由于该打印程序选择了OLE输出EXCEL、调用EXCEL打印预览的方式实现打印功能,因此无法迁移到SRM,因为SRM的用户界面是基于浏览器的,无论是WebDynpro还是SAP GUI for HTML,都不会支持OLE。最终只好用SmartForms重写了打印部分。
一个速度慢、兼容性差的程序,其用户体验是不好的。重视用户体验的程序设计者,不应该使用这一技术。
3,开发效率低ABAP中有几个专门用来处理OLE的关键字:CALL METHOD,CREATE OBJECT,GET PROPERTY,SET PROPERTY,FREE OBJECT。通过它们开发者可以在ABAP中写出类似于VBA的代码。大部分ABAP开发者在写OLE代码之前的第一件是是在EXCEL中录制宏,然后将宏中的代码"翻译"成ABAP代码,对于不了解VBA的开发者来说,这是一个额外的负担。此外,开发者需要将数据从ABAP的数据结构(内表,结构)映射至EXCEL的单元格,很多开发者特别是新入门的开发者在这方面没有很好的组织能力,写出的代码中充满了魔法数、不合理的数据结构。耦合度高、可读性差、也较难改用其它表单输出技术输出。
由于1和2的存在,开发者自己在调试程序时甚至都要花上不少额外的时间,等待程序完成...综合各种原因,OLE的开发效率是很低的。重视开发速度的实施项目里,不应该选择使用这一技术。
以下是一段典型的OLE代码,可以看到意义不显明的数字,动态的行操作等...
DATA: c_line TYPE i. c_line = 27. DO 3 TIMES. c_line = c_line + 1. ADD 1 TO lc_row. PERFORM excel_row_insert USING wsheetobj c_line lc_row 1. CASE sy-index. WHEN 1. PERFORM frm_fill_xls USING lc_row 8 gw_mseg-dmbtr. PERFORM frm_fill_xls USING lc_row 9 gw_mseg-tax. PERFORM frm_fill_xls USING lc_row 10 gw_mseg-dmbtr_t. CLEAR gw_mseg. WHEN 2. PERFORM frm_fill_xls USING lc_row 1 '本次收货总计:'. PERFORM frm_fill_xls USING lc_row 4 lwa_out-menge. PERFORM frm_fill_xls USING lc_row 8 lwa_out-dmbtr. PERFORM frm_fill_xls USING lc_row 9 lwa_out-tax1. PERFORM frm_fill_xls USING lc_row 10 lwa_out-dmbtr_t. IF lc_page <> lwa_out-page. PERFORM frm_delete_row USING lc_row. lc_row = lc_row - 1. ENDIF. WHEN 3. PERFORM frm_fill_xls USING lc_row 11 gc_name. WHEN OTHERS. ENDCASE. ENDDO.