SAP 接口 普通参数 表参数 扁平结构参数

本文详细解析了SAP接口开发中的关键步骤,包括接口参数类型、字符串参数与表参数的处理,以及扁平结构参数的构造方法。通过具体示例展示了如何使用JCO库进行SAP连接与数据交互,特别关注了复杂结构参数的正确传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近为SAP的接口开发调测伤透,项目进度再急,也有必要整理下笔记。

1.SAP接口文档

接口中有三种类型的参数:a. 字符串参数 ; b.表参数;  c.扁平结构参数 (SAP术语,个人认为可以理解为在java数据交互中常用的view对象,按照一定表结构初始化的伪表对象,为方便数据组装和流转)

接口名:    ZINDEX_LLD_CREATE                    
                          
输入参数:                         
SI_HEAD         ZLLD_HEAD    领料单抬头          
                          
输入表:    TI_ITEM    ZLLD_ITEM    领料单明细          
                          
输出参数:                         
O_LLDNO              领料单号码          
SO_HEAD         ZLLD_HEAD               
O_OK              成功标识          
                          
输出表:    TO_ITEM    ZLLD_ITEM    领料单明细          
     TO_ERROR         错误消息          
                          
ZLLD_HEAD                         
LLDNO         CHAR    10    0    领料单号
LLDTY         CHAR    1    0    领料单类型 
LLDTR         CURR    13    2    领料单金额 
LLDAR         CURR    13    2    领料单过账金额 
SO         CHAR    1    0    销售订单 
WO         CHAR    1    0    生产订单
CO         CHAR    1    0    成本中心
JOBNO         CHAR    35    0    工作令号
WERKS         CHAR    4    0    工厂
AUFNR         CHAR    12    0    订单号 
VBELN         CHAR    10    0    销售和分销凭证号 


2.字符串参数及表参数的传参接参方式

        sapConn = createConn();
        if(sapConn.isAlive())
            log.info("SAP连接成功!");
        JCO.Function fun = createFunction(sapConn, rfcFunName);
        JCO.ParameterList inputList = fun.getImportParameterList();
        inputList.setValue((String) params.get("jobNum"), "I_JOBNO");    //jobNum 工作令号
        inputList.setValue((String) params.get("ipAddress"), "I_IPADDRESS");    //ipAddress IP地址
        inputList.setValue((String) params.get("pcName"), "I_COMPUTER");    //pcName 计算机名
        inputList.setValue((String) params.get("userName"), "I_USERNAME");    //userName 用户名
        inputList.setValue((String) params.get("proNum"), "I_VERSION");        //proNum 程序版本号
        List<ViewInfo> quotaList = (List<ViewInfo>) params.get("quotaList");
        JCO.Table quotaData = fun.getTableParameterList().getTable(inputTableName);
        for(int i = 0; i < quotaList.size(); i++){
            WeldQuotaInfo weldQuotaInfo = quotaList.get(i);
            quotaData.appendRow();
            quotaData.setRow(i);
            quotaData.setValue(weldQuotaInfo.getJobNum(), "KDMAT");            
            quotaData.setValue(weldQuotaInfo.getGapCode(), "WLDNO");            
            quotaData.setValue(weldQuotaInfo.getMatCode(), "MATNR");            
            quotaData.setValue(weldQuotaInfo.getWeldMatName(), "WLDNA");            
            quotaData.setValue(weldQuotaInfo.getWeldMaterial(), "WLDME");            
            quotaData.setValue(weldQuotaInfo.getMatSize(), "GUIGE");            
            quotaData.setValue(weldQuotaInfo.getQuotaCount(), "MENGE_DE");            
            quotaData.setValue(weldQuotaInfo.getWeldMatDesc(), "MAKTX");            
        }
        try{
            sapConn.execute(fun);
            JCO.ParameterList outputList = fun.getExportParameterList();
            if(null != outputList){
                log.info("outputList=" + outputList.toString());
            }
            result = outputList.getString("E_FLAG");
        }catch(Exception ex){
            log.error("执行RFC函数异常!函数名:" + rfcFunName);
        }finally{
            closeConn();
        }
        return result;


3.难点---扁平结构参数处理
总结:主要难在第一次处理,不知道对于所谓扁平结构怎么入参,尝试过getImportParameterList(),getTableParameterList()皆不可。

我知道入参SI_HEAD对应的结构为ZLLD_HEAD,所以尝试构造一个JCO.MetaData结合JCO.createTable处理,如下


JCO.MetaData jcoMetaComp = new JCO.MetaData(parTableName);
jcoMetaComp.addInfo("ZLLD_HEAD",JCO.TYPE_CHAR,21,0,0);
JCO.Table jcoTable = JCO.createTable(jcoMetaComp);
parDate.setValue((String) billHeadMap.get("LLDTY"), "LLDTY");        
parDate.setValue((String) billHeadMap.get("JOBNO"), "JOBNO");
JCO.ParameterList inputList = fun.getImportParameterList();
inputList .setTableParameterList(jcoTable );


多番尝试还是失败,于是寻来SAP接口代码研究。摘录如下:

function zindex_lld_create.
*"----------------------------------------------------------------------
*"*"Local interface:
*"  IMPORTING
*"     REFERENCE(SI_HEAD) LIKE  ZLLD_HEAD STRUCTURE  ZLLD_HEAD
*"  EXPORTING
*"     REFERENCE(O_OK) TYPE  CHAR1
*"     REFERENCE(O_LLDNO) TYPE  ZLLDNO
*"     VALUE(SO_HEAD) TYPE  ZLLD_HEAD
*"  TABLES
*"      TI_ITEM STRUCTURE  ZLLD_ITEM
*"      TO_ITEM STRUCTURE  ZLLD_ITEM OPTIONAL
*"      TO_ERROR STRUCTURE  BAPIRET2
*"----------------------------------------------------------------------
  tables:  marc.
 
  data: l_lldno like zlld_head-lldno.
  data: l_short(1).
  data: gt_index like zhjindex occurs 0 with header line.
 
********* check data *********
 
  refresh: to_error,to_item.
  clear: to_error,to_item.
 
 
  move si_head to zlld_head.
 
  to_item = ti_item.
 
  zlld_head-source = 'GY'.
 
  zlld_head-lldty = 'HC'.
  zlld_head-stats = '1'.
  zlld_head-prntx = 'X'.
*  zlld_head-gy = 'X'.
*  zlld_head-gz = 'X'.
*  CLEAR zlld_head-sg.

发现亮点两处
 IMPORTING
*"     REFERENCE(SI_HEAD) LIKE  ZLLD_HEAD STRUCTURE  ZLLD_HEAD

move si_head to zlld_head.

我看到了构造器 STRUCTURE  ,以及SI_HEAD和ZLLD_HEAD之间的关系。
于是在JCO中寻找适合的对象,简略若干,最终可行代码如下:

    public List<Map<String,Object>> sendBillToSAP(List<Map<String,Object>> zlldHeadList,List<List<Map<String,Object>>> zlldItemList,
            String rfcFunName, String parTableName, String tableName,String exportParTableName,String exportTableName){
        List<Map<String,Object>> list = new ArrayList<Map<String,Object>>();
        /**Test Start
         * 测试传入的数据
        **/
 
        /**Test End
         */
        
        sapConn = createConn();
        JCO.Function fun;
        if(sapConn.isAlive())
            log.info("SAP连接成功!");
        
        for(int i=0; i<zlldHeadList.size(); i++){
            fun = createFunction(sapConn, rfcFunName);
            Map<String,Object> billHeadMap =  (Map<String,Object>)zlldHeadList.get(i);
            List<Map<String,Object>> billItemList = (ArrayList<Map<String,Object>>)zlldItemList.get(i);
            
            JCO.Structure parDate = fun.getImportParameterList().getStructure(parTableName);
            parDate.setValue((String) billHeadMap.get("LLDTY"), "LLDTY");        
            parDate.setValue((String) billHeadMap.get("JOBNO"), "JOBNO");        
            parDate.setValue((String) billHeadMap.get("LLRQ"), "LLRQ");        
            parDate.setValue((String) billHeadMap.get("PERNR"), "PERNR");        
            parDate.setValue(Integer.parseInt(billHeadMap.get("GRPNR").toString()), "GRPNR");        
            parDate.setValue((String) billHeadMap.get("WLDER"), "WLDER");        
            parDate.setValue(billHeadMap.get("STATS").toString(), "STATS");        
            parDate.setValue((String) billHeadMap.get("PRNTX"), "PRNTX");        
            parDate.setValue((String) billHeadMap.get("P_NH"), "P_NH");        
            parDate.setValue((String) billHeadMap.get("P_NH"), "P_NH");        
            parDate.setValue((String) billHeadMap.get("P_NT"), "P_NT");        
            parDate.setValue((String) billHeadMap.get("GZ"), "GZ");        
            parDate.setValue((String) billHeadMap.get("SG"), "SG");        
            parDate.setValue((String) billHeadMap.get("GY"), "GY");        
            parDate.setValue((String) billHeadMap.get("KDMAT"), "KDMAT");        
            parDate.setValue((String) billHeadMap.get("LAYOUT"), "LAYOUT");        
            parDate.setValue((String) billHeadMap.get("WS"), "WS");        
            parDate.setValue((String) billHeadMap.get("SOURCE"), "SOURCE");        
            parDate.setValue((String) billHeadMap.get("LLTYP"), "LLTYP");        
            parDate.setValue((String) billHeadMap.get("PSDAT"), "PSDAT");        
            parDate.setValue(Integer.parseInt(billHeadMap.get("PSTIM").toString()), "PSTIM");    
            
            
            JCO.Table tableData = fun.getTableParameterList().getTable(tableName);
            for(int j = 0; j < billItemList.size(); j++){
                Map<String,Object> billItems =  (Map<String,Object>)billItemList.get(j);
                
                tableData.appendRow();
                tableData.setRow(i);
                tableData.setValue(Integer.parseInt(billItems.get("ITEMNO").toString()), "ITEMNO");
                tableData.setValue((String) billItems.get("MATNR"), "MATNR");
                tableData.setValue((String) billItems.get("MEINS"), "MEINS");
                tableData.setValue( billItems.get("MENGE1"), "MENGE1");
                tableData.setValue((String) billItems.get("WLDNO"), "WLDNO");
                tableData.setValue((String) billItems.get("WPSNO"), "WPSNO");
                tableData.setValue( billItems.get("WPSVR"), "WPSVR");
                tableData.setValue((String) billItems.get("PQRNO"), "PQRNO");
                tableData.setValue((String) billItems.get("WLDPR"), "WLDPR");
                tableData.setValue((String) billItems.get("WLDIT"), "WLDIT");
                tableData.setValue((String) billItems.get("WLDME"), "WLDME");
                tableData.setValue((String) billItems.get("BASME"), "BASME");
            }
            
            try{
//                sapConn.execute(fun);
                JCO.Structure exportParDate = fun.getExportParameterList().getStructure(exportParTableName);
                JCO.Table outputTable = fun.getTableParameterList().getTable(exportTableName);
                JCO.Table eMessageTable = fun.getTableParameterList().getTable("TO_ERROR");
                
                JCO.ParameterList outputList = fun.getExportParameterList();
                if(null != outputList){
                    log.info("outputList=" + outputList.toString());
                }
                String oOk = outputList.getString("O_OK");//成功标示
                String oLldno = outputList.getString("O_LLDNO");//领料单号码
                if(oOk != null)
                    log.info("SAP-生成领料单接口调用标示:"+oOk);
            }catch(Exception ex){
                log.error("执行RFC函数异常!函数名:" + rfcFunName);
            }
        }
        
        
        closeConn();
        return list;
    }

<think>我们正在处理一个关于SAP OData接口如何支持嵌套结构作为参数的问题。根据用户提供的引用,特别是引用[1]和引用[4],我们可以找到一些相关的信息。 引用[1]提到了SAP的JSON_TABLE函数,它可以将JSON文档转换为关系格式。这暗示了在SAP系统中,可以通过JSON格式来处理嵌套结构。同时,引用[4]提到在Gateway Client中调用OData服务时,传递参数的方式,其中提到了TO_RO参数。 在SAP OData服务中,通常使用HTTP POST或PATCH请求来传递数据。对于嵌套结构,OData V4支持通过JSON格式传递复杂类型和集合类型。 步骤: 1. 定义OData服务时,在EDMX模型中定义复杂类型(Complex Type)和实体类型(Entity Type)中包含集合属性(Collection Property)。 2. 在服务实现中,处理传入的嵌套结构。 例如,假设我们有一个销售订单头实体,它包含行项目(一个嵌套)作为集合属性。 在EDMX模型中的定义可能如下: ```xml <ComplexType Name="OrderItem"> <Property Name="Product" Type="Edm.String"/> <Property Name="Quantity" Type="Edm.Decimal"/> </ComplexType> <EntityType Name="SalesOrder"> <Key> <PropertyRef Name="OrderID"/> </Key> <Property Name="OrderID" Type="Edm.String"/> <Property Name="Customer" Type="Edm.String"/> <Property Name="Items" Type="Collection(MyNamespace.OrderItem)"/> </EntityType> ``` 在调用时,我们可以通过POST请求传递一个包含嵌套项目的JSON: ```json { "OrderID": "10001", "Customer": "C001", "Items": [ { "Product": "P001", "Quantity": 10 }, { "Product": "P002", "Quantity": 5 } ] } ``` 在ABAP中,我们需要在OData服务的DEEP_STRUCTURE方法中处理嵌套结构。在SAP Gateway中,可以通过在模型中将属性标记为集合,并在数据提供者类(DPC)中重写相应的方法(如CREATE_DEEP_ENTITY)来处理。 具体实现步骤: 1. 在SAP Gateway Service Builder(SEGW)中定义模型,包括复杂类型和实体类型,并设置集合属性。 2. 在数据提供者类中,重写方法CREATE_DEEP_ENTITY(对于创建操作)或UPDATE_DEEP_ENTITY(对于更新操作)。 3. 在方法中,使用参数IT_DATA获取传入的数据,它是一个包含嵌套结构的数据引用。 4. 解析IT_DATA,将其转换为ABAP内部,然后进行业务处理。 例如,在DPC中: ```abap METHOD /iwbep/if_mgw_appl_srv_runtime~create_deep_entity. DATA: ls_order_header TYPE zsalesorder, lt_order_items TYPE TABLE OF zorderitem. " 获取传入的数据 io_data_provider->read_entry_data( IMPORTING es_data = ls_order_header ). " 获取嵌套的集合 io_data_provider->read_entry_data( EXPORTING iv_property_name = 'Items' IMPORTING es_data = lt_order_items ). " 然后进行业务逻辑处理,例如保存到数据库 ... ENDMETHOD. ``` 注意:在OData V2中,可能不支持原生的嵌套创建,需要分别调用头和行。但在OData V4中,支持深度插入(Deep Insert)。 另外,引用[4]提到了在Gateway Client中调用时,TO_RO参数的使用。在调用OData服务时,如果服务支持嵌套结构,那么在Gateway Client中可以直接在请求体中传递嵌套的JSON。 总结: SAP OData接口支持嵌套结构作为参数,主要通过以下方式: - 在模型定义中,使用复杂类型和集合属性。 - 在服务实现中,使用DEEP_ENTITY相关方法(如CREATE_DEEP_ENTITY)来处理嵌套结构。 - 调用时,通过JSON格式传递嵌套数据。 相关问题: 1. 如何在SAP Gateway中定义支持嵌套结构的OData模型? 2. 在ABAP OData服务中,如何处理深度插入(Deep Insert)? 3. OData V2和V4在处理嵌套结构时有什么不同?</think>### SAP OData 接口嵌套参数支持方法 在 SAP OData 服务中传递嵌套结构作为参数,主要通过以下两种方式实现: #### 1. **JSON 格式参数传递(推荐)** 使用 `JSON_TABLE` 函数解析嵌套结构,这是 SAP HANA 和 S/4HANA 推荐方案: ```sql SELECT * FROM JSON_TABLE( :json_doc, '$' COLUMNS ( "HeaderID" INTEGER PATH '$.HeaderID', NESTED PATH '$.Items[*]' COLUMNS ( "Product" NVARCHAR(50) PATH '$.Product', "Quantity" INTEGER PATH '$.Quantity' ) ) ) AS JT ``` **参数说明**: - `:json_doc`:接收 JSON 格式的输入参数,支持嵌套数组 - `NESTED PATH`:处理嵌套结构(如订单行项目) - `PATH '$.Items[*]'`:解析 JSON 数组中的每个元素 **调用示例**: ```json { "HeaderID": 1001, "Items": [ {"Product": "P-001", "Quantity": 10}, {"Product": "P-002", "Quantity": 5} ] } ``` #### 2. **OData 深度实体操作(Deep Entity)** 在 OData V4 服务中定义复杂结构: ```xml <!-- EDMX 模型定义 --> <EntityType Name="SalesOrder"> <Key><Property Name="OrderID" Type="Edm.String"/></Key> <Property Name="Customer" Type="Edm.String"/> <NavigationProperty Name="Items" Type="Collection(MyApp.OrderItem)"/> </EntityType> <ComplexType Name="OrderItem"> <Property Name="Product" Type="Edm.String"/> <Property Name="Quantity" Type="Edm.Int"/> </ComplexType> ``` **ABAP 实现要点**: ```abap METHOD create_deep_entity. DATA(lo_data) = io_data_provider->read_entry_data( ). " 解析嵌套结构 DATA(ls_header) = VALUE zsalesorder( ). DATA(lt_items) = VALUE zorder_item_tab( ). " 自动映射 JSON 到 ABAP 结构 /ui2/cl_json=>deserialize( EXPORTING json = lo_data->get_data( ) CHANGING data = ls_header ). " 处理嵌套 lt_items = ls_header-items. " 业务处理逻辑... ENDMETHOD. ``` #### 关键注意事项: 1. **网关配置**: - 在 SEGW 项目中启用 `Deep Insert` 选项 - 使用 `ST05` SQL 跟踪验证 JSON 解析性能 2. **版本差异**: - **OData V2**:需通过 `$batch` 请求模拟嵌套操作 - **OData V4**:原生支持深度实体操作(Deep Insert/Update) 3. **性能优化**: - 嵌套层级不超过 3 层(SAP 性能建议) - 使用 `FOR ORDINALITY` 保持数据顺序[^1] - 批量操作时限制单次请求数据量(<5000 行) 4. **错误处理**: ```abap COLUMNS ( "Price" DECIMAL PATH '$.price' ERROR ON ERROR DEFAULT '0' ON EMPTY ) ``` > **实践建议**:在 Fiori Elements 应用中,通过 `manifest.json` 配置 `"template"` 属性自动生成嵌套单 UI,结合 `XMLPreprocessor` 实现元数据驱动的动态渲染[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值