最新版本源码见我的GitHub
看效果
为啥写这个
前段时间BI那边调整、新增了不少取SAP数据的工作,之前的取数方式都是调用的RFC,这些RFC里面有是沿用的报表的逻辑,有的是submit调用的报表,调整起来比较费时间,还不一定能保证SAP的数据和BI的一致,因此想到了做一个统一的接口供外围系统调用,这样以后新增或者调整接口也不需要开发介入,也能保证两边数据的一致性,同时为了保证返回的数据格式一致性,我也对返回数据进行了格式化处理。
相关构成
报表选择屏幕字段与外围系统入参映射表
ZTBICONFIG
解析调用报表的事务码和请求参数的类(SICF发布这个类)
ZCL_BI_DATA_PROCE
CLASS zcl_bi_data_proce DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_http_extension .
METHODS get_query
IMPORTING
VALUE(query_string) TYPE string
VALUE(key) TYPE string
EXPORTING
VALUE(value) TYPE string .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_BI_DATA_PROCE IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_BI_DATA_PROCE->GET_QUERY
* +-------------------------------------------------------------------------------------------------+
* | [--->] QUERY_STRING TYPE STRING
* | [--->] KEY TYPE STRING
* | [<---] VALUE TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_query.
DATA:lt_kv_tab TYPE TABLE OF string,
BEGIN OF wa_kv,
key TYPE string,
value TYPE string,
END OF wa_kv,
lt_kv LIKE TABLE OF wa_kv.
CLEAR:lt_kv_tab,wa_kv,lt_kv.
SPLIT query_string AT '&' INTO TABLE lt_kv_tab.
LOOP AT lt_kv_tab ASSIGNING FIELD-SYMBOL(<lt_kv_tab>).
CLEAR wa_kv.
SPLIT <lt_kv_tab> AT '=' INTO wa_kv-key wa_kv-value.
APPEND wa_kv TO lt_kv.
ENDLOOP.
READ TABLE lt_kv INTO wa_kv WITH KEY key = key.
IF sy-subrc EQ 0.
value = wa_kv-value.
ENDIF.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_BI_DATA_PROCE->IF_HTTP_EXTENSION~HANDLE_REQUEST
* +-------------------------------------------------------------------------------------------------+
* | [--->] SERVER TYPE REF TO IF_HTTP_SERVER
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD if_http_extension~handle_request.
DATA:it_tihttpnvp TYPE tihttpnvp,
wa_tihttpnvp TYPE ihttpnvp,
json TYPE string,
rtype TYPE bapi_mtype,
rtmsg TYPE bapi_msg,
tcode_str TYPE string,
tcode TYPE sy-tcode.
CLEAR:wa_tihttpnvp,it_tihttpnvp,json,rtype,rtmsg,tcode_str,tcode.
server->request->get_header_fields( CHANGING fields = it_tihttpnvp ).
READ TABLE it_tihttpnvp INTO DATA(wa_tih) WITH KEY name = '~query_string' .
IF sy-subrc EQ 0.
CALL METHOD me->get_query
EXPORTING
query_string = wa_tih-value
key = 'tcode'
IMPORTING
value = tcode_str.
tcode = to_upper( tcode_str ).
ENDIF.
READ TABLE it_tihttpnvp INTO wa_tihttpnvp WITH KEY name = '~request_method' .
CASE wa_tihttpnvp-value.
WHEN 'GET' OR 'POST'.
json = server->request->if_http_entity~get_cdata( ).
CALL FUNCTION 'ZFM_BI_DATA_PROC'
EXPORTING
tcode = tcode
in_json = json
IMPORTING
rtype = rtype
rtmsg = rtmsg
out_json = json.
IF json IS INITIAL.
json = '[]'.
ENDIF.
WHEN OTHERS.
rtype = 'E'.
rtmsg = '方法只允许GET或者POST'.
json = '[]'.
ENDCASE.
CONCATENATE `{ "rtype":"` rtype `", "rtmsg":"` rtmsg `", "data":` json `}` INTO json.
server->response->set_header_field( name = 'Content-Type' value = 'application/json;charset=utf-8' ).
server->response->set_cdata( EXPORTING data = json ).
ENDMETHOD.
ENDCLASS.
处理报表取数的RFC
FUNCTION zfm_bi_data_proc.
*"----------------------------------------------------------------------
*"*"本地接口:
*" IMPORTING
*" VALUE(TCODE) TYPE SY-TCODE
*" VALUE(IN_JSON) TYPE STRING OPTIONAL
*" EXPORTING
*" VALUE(RTYPE) TYPE BAPI_MTYPE
*" VALUE(RTMSG) TYPE BAPI_MSG
*" VALUE(OUT_JSON) TYPE STRING
*"----------------------------------------------------------------------
IF tcode IS INITIAL.
rtype = 'E'.
rtmsg = 'tcode不能为空'.
EXIT.
ENDIF.
SELECT SINGLE * FROM tstc
WHERE tcode = @tcode
INTO @DATA(wa_tstc)
.
IF sy-subrc NE 0.
rtype = 'E'.
rtmsg = 'tcode:' && tcode && '不存在'
EXIT.
ENDIF.
DATA:submit_data TYPE REF TO data,
ls_data TYPE REF TO data,
seltab TYPE TABLE OF rsparams,
seltab_wa LIKE LINE OF seltab,
pri_params TYPE pri_params,
gt_rsparams TYPE TABLE OF rsparams,
gt_rsparams_255 TYPE TABLE OF rsparamsl_255,
sign_range TYPE RANGE OF rsparams-sign,
option_range TYPE RANGE OF rsparams-option.
FIELD-SYMBOLS:<submit_data> TYPE any.
CALL FUNCTION 'RS_REFRESH_FROM_SELECTOPTIONS'
EXPORTING
curr_report = wa_tstc-pgmna
* IMPORTING
* SP =
TABLES
selection_table = gt_rsparams
* selection_table_255 = gt_rsparams_255
EXCEPTIONS
not_found = 1
no_report = 2
OTHERS = 3.
IF sy-subrc <> 0.
rtype = 'E'.
rtmsg = 'tcode:' && tcode && '获取选择屏幕参数出现问题'.
EXIT.
ENDIF.
CLEAR submit_data.
UNASSIGN <submit_data>.
/ui2/cl_json=>deserialize( EXPORTING json = in_json CHANGING data = submit_data ).
IF submit_data IS NOT INITIAL.
ASSIGN submit_data->* TO <submit_data>.
ENDIF.
CLEAR:seltab,seltab_wa.
SELECT * FROM ztbiconfig
WHERE tcode = @tcode
ORDER BY selname,zindex
INTO TABLE @DATA(gt_biconf)
.
IF gt_rsparams IS NOT INITIAL AND gt_biconf IS INITIAL.
rtype = 'E'.
rtmsg = '请配置ZTBICONFIG表tcode:' && tcode && '的选择屏幕参数后再试'.
EXIT.
ENDIF.
sign_range = VALUE #( sign = 'I' option = 'EQ'
( low = '' )
( low = 'I' )
( low = 'E' )
).
option_range = VALUE #( sign = 'I' option = 'EQ'
( low = '' )
( low = 'EQ' )
( low = 'NE' )
( low = 'GT' )
( low = 'LT' )
( low = 'GE' )
( low = 'LE' )
( low = 'CP' )
( low = 'NP' )
( low = 'BT' )
( low = 'NB' )
).
CLEAR:seltab,seltab_wa.
LOOP AT gt_biconf ASSIGNING FIELD-SYMBOL(<gt_biconf>).
READ TABLE gt_rsparams ASSIGNING FIELD-SYMBOL(<gt_rsparams>) WITH KEY selname = <gt_biconf>-selname.
IF sy-subrc NE 0.
rtype = 'E'.
rtmsg = 'tcode:' && tcode && '选择屏幕参数' && <gt_biconf>-selname && '不存在'
RETURN.
ENDIF.
CLEAR:seltab_wa.
"赋屏幕参数名称和类型
seltab_wa-selname = <gt_rsparams>-selname.
seltab_wa-kind = <gt_rsparams>-kind.
IF <gt_biconf>-sign NOT IN sign_range.
rtype = 'E'.
rtmsg = 'tcode:' && tcode && '选择屏幕参数' && <gt_biconf>-selname && '的SIGN值' && <gt_biconf>-sign &&'配置不正确'.
RETURN.
ENDIF.
seltab_wa-sign = <gt_biconf>-sign.
IF <gt_biconf>-zoption NOT IN option_range.
rtype = 'E'.
rtmsg = 'tcode:' && tcode && '选择屏幕参数' && <gt_biconf>-selname && '的ZOPTION值' && <gt_biconf>-zoption &&'配置不正确'.
RETURN.
ENDIF.
seltab_wa-option = <gt_biconf>-zoption.
"判断屏幕参数有没有映射,优先以底表配置的默认值为准
"下限
IF <gt_biconf>-low IS NOT INITIAL.
seltab_wa-low = <gt_biconf>-low.
ELSE."底表没配置的默认值则取值传递值
IF <gt_biconf>-low_map IS INITIAL."传递值和报表字段名一致的话底表无需配置映射字段名
<gt_biconf>-low_map = <gt_biconf>-selname.
ENDIF.
IF <submit_data> IS ASSIGNED.
DATA(field_low) = |<SUBMIT_DATA>-{ <gt_biconf>-low_map }->*|.
ASSIGN (field_low) TO FIELD-SYMBOL(<submit_data_value_low>).
IF sy-subrc EQ 0.
seltab_wa-low = <submit_data_value_low>.
ELSE.
rtype = 'E'.
rtmsg = 'tcode:' && tcode && '选择屏幕参数' && <gt_biconf>-selname && '的映射字段' && <gt_biconf>-low_map && '未获取到'.
RETURN.
ENDIF.
UNASSIGN <submit_data_value_low>.
ELSE.
rtype = 'E'.
rtmsg = 'tcode:' && tcode && '请传递选择屏幕参数' && <gt_biconf>-selname && '的映射字段' && <gt_biconf>-low_map.
RETURN.
ENDIF.
ENDIF.
"上限
IF <gt_rsparams>-kind = 'S'.
IF <gt_biconf>-high IS NOT INITIAL.
seltab_wa-high = <gt_biconf>-high.
ELSE.
IF <gt_biconf>-high_map IS NOT INITIAL.
IF <submit_data> IS ASSIGNED.
DATA(field_high) = |<SUBMIT_DATA>-{ <gt_biconf>-high_map }->*|.
ASSIGN (field_high) TO FIELD-SYMBOL(<submit_data_value_high>).
IF sy-subrc EQ 0.
seltab_wa-high = <submit_data_value_high>.
ELSE.
rtype = 'E'.
rtmsg = 'tcode:' && tcode && '选择屏幕参数' && <gt_biconf>-selname && '的映射字段' && <gt_biconf>-high_map && '未获取到'.
RETURN.
ENDIF.
UNASSIGN <submit_data_value_high>.
ELSE.
rtype = 'E'.
rtmsg = 'tcode:' && tcode && '请传递选择屏幕参数' && <gt_biconf>-selname && '的映射字段' && <gt_biconf>-high_map.
RETURN.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
"赋值选择参数
IF seltab_wa-sign IS INITIAL.
seltab_wa-sign = 'I'.
ENDIF.
CASE <gt_rsparams>-kind.
WHEN 'P'.
IF seltab_wa-option IS INITIAL.
seltab_wa-option = 'EQ'.
ENDIF.
CLEAR:seltab_wa-high.
WHEN 'S'.
IF seltab_wa-high IS NOT INITIAL AND seltab_wa-low IS NOT INITIAL.
IF seltab_wa-high LT seltab_wa-low.
rtype = 'E'.
rtmsg = 'tcode:' && tcode && '传递选择屏幕参数' && <gt_biconf>-selname && '的上限' && seltab_wa-high && '不能小于下限' && seltab_wa-low.
RETURN.
ENDIF.
IF seltab_wa-sign IS INITIAL.
seltab_wa-option = 'BT'.
ENDIF.
ELSEIF seltab_wa-high IS NOT INITIAL AND seltab_wa-low IS INITIAL.
IF seltab_wa-sign IS INITIAL.
seltab_wa-option = 'BT'.
ENDIF.
ELSEIF seltab_wa-high IS INITIAL AND seltab_wa-low IS NOT INITIAL.
IF seltab_wa-sign IS INITIAL.
seltab_wa-option = 'EQ'.
ENDIF.
ELSEIF seltab_wa-high IS INITIAL AND seltab_wa-low IS INITIAL.
CONTINUE.
ENDIF.
ENDCASE.
IF to_lower( seltab_wa-low ) = 'true'.
seltab_wa-low = 'X'.
ELSEIF to_lower( seltab_wa-low ) = 'false'.
seltab_wa-low = ''.
ENDIF.
APPEND seltab_wa TO seltab.
ENDLOOP.
cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ).
SUBMIT (wa_tstc-pgmna) TO SAP-SPOOL SPOOL PARAMETERS pri_params WITHOUT SPOOL DYNPRO
WITH SELECTION-TABLE seltab
AND RETURN
.
TRY .
cl_salv_bs_runtime_info=>get_data_ref(
IMPORTING r_data = ls_data ).
CATCH cx_salv_bs_sc_runtime_info.
rtype = 'E'.
rtmsg = '无法获取' && tcode && '的数据'.
EXIT.
ENDTRY.
ASSIGN ls_data->* TO FIELD-SYMBOL(<fs_tab>).
cl_salv_bs_runtime_info=>clear_all( ).
IF <fs_tab> IS ASSIGNED.
rtype = 'S'.
IF <fs_tab> IS NOT INITIAL.
rtmsg = '成功获取' && tcode && '的数据'.
out_json = /ui2/cl_json=>serialize( data = <fs_tab> compress = abap_false pretty_name = /ui2/cl_json=>pretty_mode-camel_case ).
ELSE.
rtmsg = tcode && '空数据'.
ENDIF.
UNASSIGN <fs_tab>.
ELSE.
rtype = 'S'.
rtmsg = tcode && '无数据'.
ENDIF.
ENDFUNCTION.