Skip to content

SAP RFC对接

1 概述

在SAP系统中,远程调用的能力是由RFC(Remote Function Call的标准通讯方式,即远程函数调用,下文简称RFC)接口系统提供的。RFC允许在两个SAP系统(R/3或者R/2)之间进行调用,或者在一个SAP系统和非SAP系统之间调用。

2 织信如何调用SAP RFC函数

2.1 通过Java扩展库调用SAP RFC函数

调用方法

java
package informat.library.poc;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sap.conn.jco.JCo;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoDestinationManager;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.JCoField;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoParameterList;
import com.sap.conn.jco.ext.DestinationDataProvider;

import informat.library.utils.JSONUtil;

public class SapService {
	//
	private static Logger logger=LoggerFactory.getLogger(SapService.class);
	//
	public static String getVersion() {
		return JCo.getVersion();
	}

	public static void registerDestinationDataProvider(String destinationName, Map<String,String> properties) {
		logger.info("registerDestinationDataProvider destinationName:{}",
				destinationName, JSONUtil.toJson(properties));
		Properties props=new Properties();
		if(properties!=null) {
			properties.forEach((k,v)->{
				props.setProperty(k,v);
			});
		}
		com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(new CustomDestinationDataProvider(destinationName, props));

	}
	
	// 通用SAP函数调用方法
	public static SapFunctionResult callSapFunction(String destinationName, // SAP目标名称(如"SAP_DEST")
			String functionName, // 要调用的函数模块名称
			Map<String, Object> inputs, // 输入参数键值对
			List<String> outputTables // 需要返回的输出表名称数组(可选)
	) throws JCoException {
		logger.info("callSapFunction destinationName:{} functionName:"+
				destinationName+", functionName"+functionName+","+JSONUtil.toJson(inputs)+",outputTables:"+JSONUtil.toJson(outputTables));
		JCoDestination destination = JCoDestinationManager.getDestination(destinationName);
		JCoFunction function = destination.getRepository().getFunction(functionName);
		if (function == null) {
			throw new RuntimeException("SAP函数 " + functionName + " 不存在");
		}

		// 设置输入参数
		if (inputs != null) {
			JCoParameterList importParams = function.getImportParameterList();
			inputs.forEach((k, v) -> importParams.setValue(k, v));
		}

		// 执行函数调用
		function.execute(destination);

		// 处理返回结果
		SapFunctionResult result = new SapFunctionResult();

		// 获取导出参数
		JCoParameterList exportParams = function.getExportParameterList();
		if (exportParams != null) {
			for (JCoField param : exportParams) {
				result.addExportParam(param.getName(), param.getValue());
			}
		}

		// 处理输出表(按需获取)
		if (outputTables != null) {
			JCoParameterList tables = function.getTableParameterList();
			for (String tableName : outputTables) {
				if (tables.isActive(tableName)) {
					result.addOutputTable(tableName, tables.getTable(tableName));
				}
			}
		}
		logger.info("callSapFunction result:{}", JSONUtil.toJson(result));
		return result;
	}

	//
	public static void main(String[] args) throws JCoException {
		System.out.println(JCo.getVersion());
		Map<String,String> props = new HashMap<>();
		props.put(DestinationDataProvider.JCO_ASHOST, "your_sap_host"); // SAP服务器地址
		props.put(DestinationDataProvider.JCO_SYSNR, "00"); // 系统编号
		props.put(DestinationDataProvider.JCO_CLIENT, "100"); // 客户端编号
		props.put(DestinationDataProvider.JCO_USER, "username"); // 用户名
		props.put(DestinationDataProvider.JCO_PASSWD, "password"); // 密码
		props.put(DestinationDataProvider.JCO_LANG, "en"); // 语言
		props.put(DestinationDataProvider.JCO_POOL_CAPACITY, "3");
		props.put(DestinationDataProvider.JCO_PEAK_LIMIT, "10");
		//
		String destinationName = "SAP_DEST";
		registerDestinationDataProvider(destinationName, props);
		Map<String, Object> inputs = new HashMap<>();
		// 3. 设置输入参数
		inputs.put("AUART", "ZOR1");
		inputs.put("ZOAMWLXX", "20_1.05.01.10455");
		inputs.put("KUNSP", "100689");
		//
		List<String> outputTables = List.of( "OT_DATA", "OTHER_TABLE" );
		SapFunctionResult result=callSapFunction(destinationName, "ZFM_SD051", inputs, outputTables);
		System.out.println(JSONUtil.toJson(result));
	}
}

2.2 将java工程打包后上传到织信应用扩展库

2.3 织信脚本调用SAP RFC函数

织信脚本通过informat.system.invokeLibrary调用java扩展库,从而实现调用SAP RFC函数

js
informat.system.invokeLibrary('saplibrary','informat.library.poc.SapService','registerDestinationDataProvider',
["sap_test1",{
    "jco.client.ashost":"192.168.x.x",
    "jco.client.sysnr":"00",
    "jco.client.client":"800",
    "jco.client.user":"user",
    "jco.client.passwd":"password",
    "jco.client.lang":"en",
    "jco.destination.pool_capacity":"3",
    "jco.destination.peak_limit":"10"
}]);

let result=informat.system.invokeLibrary('saplibrary',
	'informat.library.poc.SapService','callSapFunction',
	["sap_test1",'ZFM_SD051',
	{"AUART":"ZOR1"},['OT_DATA','OTHER_TABLE']]
);
console.log('result',result);

SapFunctionResult结构

java
public class SapFunctionResult {
	public Map<String, Object> exportParams = new HashMap<>();
	public Map<String, JCoTable> outputTables = new HashMap<>();
}