在零售企业中,大多时间会采用SAP的接口中间PI(早期叫XI,现在取名PO,不过我还是习惯叫PI).在PI与SAP连接时,一般有三种方式:IDOC,RFC,PROXY。
1.IDOC对标准业务是优选
IDOC使用的应该是最稳定的,对于一些标准业务来说,可能使用IDOC可能是最好的选择,并且IDOC本身有很好的日志及重处理机制,所以在使用时,我们可以完整的使用IDOC的优势,但对于自定义的功能,使用IDOC,就要做太多工作了,相对快速开发来说,可能不会是好选择。
2.RFC不太稳定,感觉不太好
在使用PI连接RFC时,其实使用的是tRFC的方式连接的相当于
1 2 3 4 5 6 |
CALL FUNCTION .... IN BACKGROUND TASK DESTINATION EXPORTING .... TABLES .... COMMIT WORK. |
当调用数据频率太高时,很容易造成进程堵塞,这可能是TRFC处理进制的原因,我觉得这个相当于是所有调用都在使用同一个线程在处理,好比是都在使用固定的线程,固定的ECC资源在处理pi来的所有数据,所以容易造成堵塞,所以现在我做的接口方式使用少会采用此种方式。
PROXY方式,自定义功能的最好选择。
在PI与SAP连接时,使用最多的应该是PROXY方式,我使用此方式最好的可能是因为我是ABAP,使用此方式时,可以把接口传入传出参数的定义能PI先定,也就是说需要PI与业务顾问先确认好,那我对于我来说可能少了定义参数的时间及烦心的确认,或许是我最喜欢觉此种方式的原因。
3.PROXY的使用方法
1.PI,开发好接口,此为PI的工作
2.在ECC中使用事务码:SPROXY,生成PROXY,此工作可能由ABAP操作,也可能由PI操作,每个项目都可能不同,
3.PORXY使用时,由于proxy进出方式的不同,主要分两大类,传出(ECC主动调用传出数据并(或)同时 接口返回数据),传入ECC(接收外部传入数据,并处理或返回)
4.对于从ECC主动传出数据的PROXY时,我们需要在我们的程序中主动调用此PROXY,大概的调用试如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
FUNCTION ZFI_697_SEND. *"---------------------------------------------------------------------- *"*"Local interface: *" IMPORTING *" REFERENCE(I_ZDJBH) TYPE ZDJBH *" REFERENCE(I_ZFKZTN) TYPE ZFKZTN *" EXPORTING *" VALUE(O_SUCC) TYPE FLAG *" VALUE(O_MSGTX) TYPE MSGTX *"---------------------------------------------------------------------- *"*"Local interface: *" IMPORTING *" REFERENCE(I_ZDJBH) TYPE ZDJBH *" REFERENCE(I_ZFKZTN) TYPE ZFKZTN *" EXPORTING *" VALUE(O_SUCC) TYPE FLAG *" VALUE(O_MSGTX) TYPE MSGTX *"--------------------------------------------------------------------- DATA: G_PROXY TYPE REF TO ZFI697CO_SI_ECC2QJS_IFI697_SYN. *定义调用PROXY 的输出参数 DATA: OUT TYPE ZFI697MT_ECC2QJS_IFI697_REQ, INT TYPE ZFI697MT_ECC2QJS_IFI697_RES. DATA: LS_TAB TYPE ZFI697DT_ECC2QJS_IFI697_REQ_I1, LT_TAB_OUT TYPE ZFI697DT_ECC2QJS_IFI697_RE_TAB, LS_TAB_OUT TYPE LINE OF ZFI697DT_ECC2QJS_IFI697_RE_TAB, LS_TAB_IN TYPE ZFI697DT_ECC2QJS_IFI697_RES. DATA: LT_ZFI_QJSJS TYPE TABLE OF ZFI_QJSJS, LS_ZFI_QJSJS TYPE ZFI_QJSJS. DATA: L_ERROR_TEXT TYPE STRING, L_FLAG(1). DATA: L_ZFKCS TYPE NUMC2. DATA: OREF TYPE REF TO CX_ROOT. DATA: L_MAX_TIME TYPE INT1. DATA: LS_ZTTRAN_697 TYPE ZTTRAN_697. DATA: L_BELNR TYPE ZFKPZ. LS_ZTTRAN_697-ZDJBH = I_ZDJBH. LS_ZTTRAN_697-ZFKZTN = I_ZFKZTN. LS_ZTTRAN_697-ZCSBS = ''. LS_ZTTRAN_697-ZCSRQ = SY-DATUM. LS_ZTTRAN_697-ZCSSJ = SY-UZEIT. LS_TAB-JYID = I_ZDJBH. IF I_ZFKZTN = '20'. LS_TAB-STATUS = 'B'. LS_TAB-ZTEXT = '冻结支付'. ELSEIF I_ZFKZTN = '90'. LS_TAB-STATUS = 'S'. LS_TAB-ZTEXT = '支付成功'. ELSE. O_SUCC = ''. O_MSGTX = '付款状态只能是20,90的单据'. MODIFY ZTTRAN_697 FROM LS_ZTTRAN_697. RETURN. ENDIF. SELECT * INTO TABLE LT_ZFI_QJSJS FROM ZFI_QJSJS WHERE ZDJBH = I_ZDJBH. SELECT SINGLE BELNR INTO L_BELNR FROM ZFI_OAST WHERE ZDJBH = I_ZDJBH . IF SY-SUBRC <> 0. O_SUCC = ''. O_MSGTX = '单据编号在ZFI_QJSJS中不存在'. MODIFY ZTTRAN_697 FROM LS_ZTTRAN_697. RETURN. ENDIF. LOOP AT LT_ZFI_QJSJS INTO LS_ZFI_QJSJS . LS_TAB_OUT-ZTJSH_JYID = LS_ZFI_QJSJS-ZJYID. LS_TAB_OUT-ZTJSH = LS_ZFI_QJSJS-ZTJSD. LS_TAB_OUT-BELNR = L_BELNR. APPEND LS_TAB_OUT TO LT_TAB_OUT. ENDLOOP. LS_TAB-ITEMS = LT_TAB_OUT. OUT-MT_ECC2QJS_IFI697_REQ-ITEMS = LS_TAB. TRY. CREATE OBJECT G_PROXY . CATCH CX_AI_SYSTEM_FAULT INTO OREF. ENDTRY. IF OREF IS NOT INITIAL. L_ERROR_TEXT = OREF->GET_TEXT( ). CONCATENATE 'FI697接口连接时出错:' L_ERROR_TEXT INTO L_ERROR_TEXT . O_SUCC = ''. O_MSGTX = L_ERROR_TEXT. MODIFY ZTTRAN_697 FROM LS_ZTTRAN_697. RETURN. ENDIF. TRY. CALL METHOD G_PROXY->SI_ECC2QJS_IFI697_SYNC_REQ EXPORTING OUTPUT = OUT IMPORTING INPUT = INT. "COMMIT WORK AND WAIT. CATCH CX_AI_SYSTEM_FAULT INTO OREF. ENDTRY. IF OREF IS NOT INITIAL. L_FLAG = ''. L_ERROR_TEXT = OREF->GET_TEXT( ). CONCATENATE '调用 FI697接口时出错:' L_ERROR_TEXT INTO L_ERROR_TEXT . ELSE. "接收数据。 LS_TAB_IN = INT-MT_ECC2QJS_IFI697_RES. "只会有一行。 IF LS_TAB_IN-STATUS(1) = 'S' OR LS_TAB_IN-STATUS(1) = 'T'."成功 L_FLAG = 'X'. L_ERROR_TEXT = '成功'. LS_ZTTRAN_697-ZCSBS = 'X'. ELSE."失败 L_FLAG = ''. CONCATENATE '出错:' LS_TAB_IN-ZMARK INTO L_ERROR_TEXT . ENDIF. ENDIF. MODIFY ZTTRAN_697 FROM LS_ZTTRAN_697. O_SUCC = L_FLAG. O_MSGTX = L_ERROR_TEXT. ENDFUNCTION. |
对于从外部程序传入的PROXY,需要传入的代理类中写入接收数据及处理数据的代码,为了模块化操作,一般在此程序中写入调用函数,然后在函数中在写调用代码,以下是一个很好的代理类处理方法的例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
METHOD ZPI_II_SI_SD198_IN_ASY~SI_SD198_IN_ASY. *** **** INSERT IMPLEMENTATION HERE **** *** DATA: LV_FUNCTION_NAME TYPE CHAR30, MSG_HEADER TYPE ZPI_DT_HEADER2. *&-Initial CLEAR:LV_FUNCTION_NAME,MSG_HEADER. MOVE INPUT-MT_SD198_REQ-HEADER TO MSG_HEADER. SELECT SINGLE OBJ_NAME FROM ZPIT0041 INTO LV_FUNCTION_NAME WHERE INF_ID = MSG_HEADER-INTERFACE_ID. IF SY-SUBRC = 0. CONDENSE LV_FUNCTION_NAME NO-GAPS. CALL FUNCTION 'FUNCTION_EXISTS' EXPORTING FUNCNAME = LV_FUNCTION_NAME * IMPORTING * group = * include = * namespace = * str_area = EXCEPTIONS FUNCTION_NOT_EXIST = 1 OTHERS = 2. IF SY-SUBRC <> 0. MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4. ENDIF. IF SY-SUBRC = 0. CALL FUNCTION LV_FUNCTION_NAME EXPORTING INPUT = INPUT. ENDIF. ELSE. *&-如果Inbound配置表未维护 ENDIF. ENDMETHOD. |
我们需要在每个一个接口中都定义一个HEADER-INTERFACE_ID节点来标记这个接口的接口号(通常我们应该在此HEAD中定义接口ID,接口传入方,传出方,传出时间),我们在ECC中增加配置表ZPIT0041,在此表中定义所有接口相关的接口ID对应的接口函数,此是否生效(此标记在以后使用中会很有用的),及接口描述等信息。
在此调用中,我用通过表来决定此接口ID在表中是否存在(可以加上是否在生效状态),判断函数是否存在,并调用,其实在此此判断处理的功能可以做一个统一的判断函数,并在其中做处理.
最后才调用我们真正的处理接口的函数