背景
设计的初衷:
1、减少重复性工作,提升效率。
把报表常用的过程抽象到全局类 ZCL_REPORT_ 中,将其作为模板类在本地继承后快速开发报表。
2、记录报表运行信息,统计报表使用和运行情况。
通过 save_log 方法记录报表运行数据,后续可用于统计分析报表的使用情况。
3、可按需扩展自定义功能。
在模板类中按需扩展新功能(比如问卷调查等),进行统一管控。
应用展示
一个简单的例子
REPORT zdemo.
CLASS cl_report DEFINITION INHERITING FROM zcl_report_ CREATE PUBLIC FINAL.
PUBLIC SECTION.
METHODS constructor.
PROTECTED SECTION.
METHODS process REDEFINITION. "主要处理过程,在这里取数、处理数据
METHODS set_salv REDEFINITION. "在salv显示前进行设置
METHODS added_function REDEFINITION. "自定义按钮 (已set handler)
METHODS double_click REDEFINITION. "双击(已set handler)
PRIVATE SECTION.
DATA t_list TYPE TABLE OF spfli.
METHODS get_flight_plan.
ENDCLASS.
START-OF-SELECTION.
CAST zif_report_( NEW cl_report( ) )->execute( ).
CLASS cl_report IMPLEMENTATION.
METHOD constructor. "构造方法
super->constructor( ).
config-list_header = `This is a sense of things to come`.
r_display_table = REF #( t_list ). "设置要显示的内表
ENDMETHOD.
METHOD process. "主要处理过程
" ...
get_flight_plan( ). "具体处理内容
" ...
ENDMETHOD.
METHOD get_flight_plan.
SELECT * INTO TABLE t_list FROM spfli.
ENDMETHOD.
METHOD set_salv. "在salv显示前进行设置
TRY.
r_salv_column = r_salv_columns_table->get_column( `CARRID` ).
r_salv_column->set_short_text( `hellokitty` ).
r_salv_column->set_medium_text( `hellokitty` ).
r_salv_column->set_long_text( `hellokitty` ).
r_salv_column->set_zero( space ).
CATCH cx_root.
ENDTRY.
ENDMETHOD.
METHOD added_function. "自定义按钮
ENDMETHOD.
METHOD double_click. "双击
MESSAGE 'double click event triggered' TYPE `S`.
ENDMETHOD.
ENDCLASS.
执行结果:
运行日志:
ZCL_REPORT_中集成了日志记录、SALV显示等功能,
大部分情况下,只要把上面的代码拷到新程序,在process方法
里写一下取数和处理数据的逻辑就完成一个报表开发了,非常方便。
如果遇见了复杂场景,salv显示满足不了需求,那就把display方法重载了再按需实现。
只需两分钟,一个Report Log Statistic报表就出炉了~如下:
有了运行数据就可以掌握报表的运行情况:
哪些报表运行时间长,需要重点关注、优化性能,
交付给用户的报表有没有运行,频率怎么样,
哪个报表(功能)在什么时间被哪个用户执行过,
这些信息都可以轻松查到。
实现过程
接口和类
事物代码 SE24 创建接口 ZIF_REPORT_
创建抽象类 ZCL_REPORT_
类的方法
构造方法:
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_REPORT_->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD constructor.
"标准化报表缺省设置
config-save_log = enabled. "保存运行日志,默认:启用
config-default_salv = enabled. "使用自带的SALV显示,默认:启用
config-list_display = disabled. "LIST显示,默认:不启用
config-report_name = `SAPLKKBL`. "默认的gui status程序名
config-gui_status = `STANDARD_FULLSCREEN`. "默认的gui status名
ENDMETHOD.
主执行方法:
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_REPORT_->ZIF_REPORT_~EXECUTE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD zif_report_~execute.
TRY.
check( ). "检查参数有效性和权限等
save_log( 1 ). "开始记录运行信息
process( ). "主要处理过程
save_log( 2 ). "结束记录运行信息
display( ). "数据显示
CATCH zcx_rp_msg INTO DATA(lcx_rp_msg). "捕获上述方法中抛出的异常
MESSAGE lcx_rp_msg->get_text( ) TYPE `S` DISPLAY LIKE `E`.
ENDTRY.
ENDMETHOD.
日志记录方法:
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_REPORT_->SAVE_LOG
* +-------------------------------------------------------------------------------------------------+
* | [--->] STEP TYPE I
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD save_log.
DATA lv_stamp TYPE timestampl.
CHECK config-save_log EQ enabled.
CASE step.
WHEN 1.
TRY.
s_log-lognm = cl_system_uuid=>create_uuid_c32_static( ).
CATCH cx_uuid_error.
RETURN.
ENDTRY.
IF s_log-lognm IS INITIAL.
RETURN.
ENDIF.
s_log-cprog = sy-cprog.
s_log-tcode = sy-tcode.
s_log-uname = sy-uname.
s_log-batch = sy-batch.
s_log-slset = sy-slset.
s_log-host = sy-host.
SELECT SINGLE unam
INTO s_log-unam
FROM reposrc
WHERE progname EQ sy-cprog.
CALL FUNCTION 'GUI_GET_DESKTOP_INFO'
EXPORTING
type = 5
CHANGING
return = s_log-os_name.
CALL FUNCTION 'TH_USER_INFO'
IMPORTING
terminal = s_log-terminal
addrstr = s_log-ip.
GET TIME STAMP FIELD lv_stamp.
CONVERT TIME STAMP lv_stamp TIME ZONE 'UTC+8' INTO DATE s_log-process_begda
TIME s_log-process_begti.
s_log-process_endda = s_log-process_begda.
s_log-process_endti = s_log-process_begti.
s_log-process_stamp1 = s_log-process_stamp2 = frac( lv_stamp ).
MODIFY zreport_log FROM s_log.
WHEN 2.
IF s_log-lognm IS INITIAL.
RETURN.
ENDIF.
GET TIME STAMP FIELD lv_stamp.
CONVERT TIME STAMP lv_stamp TIME ZONE 'UTC+8' INTO DATE s_log-process_endda
TIME s_log-process_endti.
s_log-process_stamp2 = frac( lv_stamp ).
DATA(s1) = s_log-process_begti+0(2) * 3600
+ s_log-process_begti+2(2) * 60
+ s_log-process_begti+4(2) * 1.
DATA(s2) = s_log-process_endti+0(2) * 3600
+ s_log-process_endti+2(2) * 60
+ s_log-process_endti+4(2) * 1
+ ( s_log-process_endda - s_log-process_begda ) * 86400.
s_log-process_duration = s2 - s1 + s_log-process_stamp2 - s_log-process_stamp1.
UPDATE zreport_log
SET process_endda = s_log-process_endda
process_endti = s_log-process_endti
process_stamp2 = s_log-process_stamp2
process_begda = s_log-process_begda
process_begti = s_log-process_begti
process_stamp1 = s_log-process_stamp1
process_duration = s_log-process_duration
WHERE lognm EQ s_log-lognm.
ENDCASE.
ENDMETHOD.
日志表 ZREPORT_LOG 字段设计
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_REPORT_->DISPLAY
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD display.
FIELD-SYMBOLS <lt_list> TYPE table.
CHECK config-default_salv EQ enabled.
ASSIGN r_display_table->* TO <lt_list>.
CHECK <lt_list> IS ASSIGNED.
TRY.
cl_salv_table=>factory(
EXPORTING
list_display = config-list_display
IMPORTING
r_salv_table = r_salv_table
CHANGING
t_table = <lt_list> ).
CATCH cx_salv_msg INTO DATA(lcx_salv_msg).
MESSAGE lcx_salv_msg->get_text( ) TYPE `E`.
ENDTRY.
"获取 SALV 属性
r_salv_layout = r_salv_table->get_layout( ).
r_salv_selections = r_salv_table->get_selections( ).
r_salv_functions_list = r_salv_table->get_functions( ).
r_salv_columns_table = r_salv_table->get_columns( ).
r_salv_sorts = r_salv_table->get_sorts( ).
r_salv_aggregations = r_salv_table->get_aggregations( ).
r_salv_filters = r_salv_table->get_filters( ).
r_salv_events_table = r_salv_table->get_event( ).
r_salv_events ?= r_salv_events_table.
r_salv_display_settings = r_salv_table->get_display_settings( ).
"设置 SALV 属性
s_salv_layout_key-report = sy-cprog.
s_stbl-row = `X`.
s_stbl-col = `X`.
r_salv_table->set_screen_status( report = config-report_name
pfstatus = config-gui_status ).
r_salv_layout->set_default( `X` ).
r_salv_layout->set_save_restriction( 3 ).
r_salv_layout->set_key( s_salv_layout_key ).
r_salv_columns_table->set_optimize( `X` ).
r_salv_functions_list->set_all( `X` ).
r_salv_selections->set_selection_mode( 4 ).
CREATE OBJECT r_salv_form_layout_grid.
IF config-alv_title IS INITIAL.
config-alv_title = |条目数 { lines( <lt_list> ) }|.
ENDIF.
r_salv_form_layout_grid->create_label(
EXPORTING
row = 1
column = 1
text = config-alv_title ).
r_salv_table->set_top_of_list( r_salv_form_layout_grid ).
IF config-list_header IS NOT INITIAL.
r_salv_display_settings->set_list_header( config-list_header ).
ENDIF.
SET HANDLER added_function FOR r_salv_events.
SET HANDLER double_click FOR r_salv_events_table.
SET HANDLER link_click FOR r_salv_events_table.
set_salv( ). "显示前的自定义设置,覆盖上面的默认设置
r_salv_table->display( ).
ENDMETHOD.
总结
简单的小设计,把一些小点子集中实现,没有什么难点。