前言


公司即将接到一个项目与SAP有接口。老大让我们搞SAP,首先SAP接触过,但是没玩过开发,本周就专心的在研究这一块.


各种碰壁,SAP的系统让我怎么说呢? 算了,说多了都是泪,下面附上本周学习成果,大家一起探讨一下,ABAP 还得多学学.


Package (tcode:se80)

 

java rfc调用SPA接口 java调用sap的rfc函数_JAVA SAP RFC

 

输入需要创建的 Package ,例:ZTP (之前用T打头测试,貌似不行,大家可以试试)

 

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_02

点  Yes 创建.

 

java rfc调用SPA接口 java调用sap的rfc函数_数据_03

输入创建Package的信息.

 

 

Table (tcode:se11)

java rfc调用SPA接口 java调用sap的rfc函数_RFC_04

点击Create.

 

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_05

 

点击保存,弹出选择Package界面

java rfc调用SPA接口 java调用sap的rfc函数_SAP_06

保存即可.

切换到 Fields 选项卡:

java rfc调用SPA接口 java调用sap的rfc函数_SAP_07

一个字段可对应一个数据元素,一个数据元素可对应多个字段.

 

java rfc调用SPA接口 java调用sap的rfc函数_RFC_08

如上图: ZAGE 数据元素不存在,双击可进入:

 

java rfc调用SPA接口 java调用sap的rfc函数_SAP_09


java rfc调用SPA接口 java调用sap的rfc函数_JAVA SAP RFC_10

提示不存在,则创建.

输入数据类型,长度:

 

java rfc调用SPA接口 java调用sap的rfc函数_数据_11

保存,都会提示选择Package,后面就不说了.

 

java rfc调用SPA接口 java调用sap的rfc函数_RFC_12

激活该数据元素.

 

回到创建表界面,即可发现数据类型和长度都已显示.

 

java rfc调用SPA接口 java调用sap的rfc函数_SAP_13

点击 技术设置.

 

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_14

 

java rfc调用SPA接口 java调用sap的rfc函数_SAP_15

保存即可.

 

点击 索引.

 

java rfc调用SPA接口 java调用sap的rfc函数_数据_16

点击创建索引.

 

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_17

 

输入索引名字.

 

java rfc调用SPA接口 java调用sap的rfc函数_JAVA SAP RFC_18

选择字段等

 

java rfc调用SPA接口 java调用sap的rfc函数_JAVA SAP RFC_19

保存,激活索引,激活表.

 

上面忘记设置 Key,选一个字段设置Key即可.

 

java rfc调用SPA接口 java调用sap的rfc函数_SAP_20

Function Group (tcode:se37)

 

java rfc调用SPA接口 java调用sap的rfc函数_RFC_21

 

输入创建Function Group的信息.点击保存后弹出选择 Package 的界面:

 

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_22

 

选择刚刚创建的 Package :

 

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_23

保存即可.

 

 

Function Module (tcode:se37)

 

Z_TEST_1

java rfc调用SPA接口 java调用sap的rfc函数_SAP_24

点击创建 , 选择函数组.

 

java rfc调用SPA接口 java调用sap的rfc函数_数据_25

创建后 , 在Attributes选项卡 选择 Remote 远程调用函数.

 

java rfc调用SPA接口 java调用sap的rfc函数_RFC_26

这里简单说一下 Import,Export,Tables 三个选项卡

Import 就是需要导入的字段,在SAP的测试运行的时候可以输入该值进行测试,外部程序调用时传值进入,可以理解 Java方法参数.

Export 就是导出字段,程序执行完成后返回字段,可以理解 Java方法返回值,不过可以返回多个.

Tables 可以作为导入、导出, 他的字段为数据结果,其实就是一个复杂参数,比如说外围程序调用要传入一批数据,就可以使用他了,导出一样,可以返回一批数据.

 

这里我们就使用Table做一个批量上传数据的一个功能,点击 Tables选项卡,定义字段

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_27

Parameter Name,参数名,自己定义

Type spec,参数类型 ,普通值使用Type即可,不过在Tables这里一般定义复杂类型,使用Like模拟一个结构对象

Associated Type,使用Like 时输入我们的参考对象,可以是表、视图、元素等.

然后回车即可,第一次回车好像报红,再回车一次就可以了,不知道其它大神有没有遇到过.

 

点击 Source code 选项卡,进入编码.

 

java rfc调用SPA接口 java调用sap的rfc函数_RFC_28

小白也不知道复杂的编码,所以只能简单写一下了.

 

我们的目标是将传入的数据插入到SAP的内表中,编码如下


INSERT ZTAB01 FROM TABLEIMPT.





以上代码就可以啦,将传入的 IMPT 导入到内表中.

先保存,点击Check,无错误激活即可.

 

java rfc调用SPA接口 java调用sap的rfc函数_SAP_29

然后点击激活.

 

java rfc调用SPA接口 java调用sap的rfc函数_JAVA SAP RFC_30

左下角会提示激活.

 

然后我们可以测试一下程序是否成功.

 

java rfc调用SPA接口 java调用sap的rfc函数_JAVA SAP RFC_31

进入到输入参数界面,即可看到我们定义的Tables字段.

 

java rfc调用SPA接口 java调用sap的rfc函数_SAP_32

点击进入编辑数据.

 

java rfc调用SPA接口 java调用sap的rfc函数_SAP_33

 

java rfc调用SPA接口 java调用sap的rfc函数_JAVA SAP RFC_34

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_35

完成编辑后,返回.

 

java rfc调用SPA接口 java调用sap的rfc函数_JAVA SAP RFC_36

点击执行即可.

 

java rfc调用SPA接口 java调用sap的rfc函数_SAP_37

此为执行结果.

 

通过 tcode:se11 进入到数据库表查看数据

 

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_38

 

java rfc调用SPA接口 java调用sap的rfc函数_RFC_39

数据已插入到SAP内表.

 

Z_TEST_2

 

数据上传已经完成,这个时候我们做一个数据查询的Function.

 

java rfc调用SPA接口 java调用sap的rfc函数_SAP_40

 

同样我们选择 远程调用函数

 

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_41

这个时候我们加一个 Import参数,有选择性的根据条件来查询.

 

java rfc调用SPA接口 java调用sap的rfc函数_数据_42

在Tables参数我们加一个返回参数.

 

java rfc调用SPA接口 java调用sap的rfc函数_RFC_43

设置好后,进入编码 source code.

 

java rfc调用SPA接口 java调用sap的rfc函数_RFC_44


*判断传入参数是否为空
IF DZNAME = '' .
*为空查询所有数据
SELECT * INTOTABLE OUTT FROM ZTAB01.
ELSE.
SELECT * INTOTABLE OUTT FROM ZTAB01 WHERE ZNAME = DZNAME.
ENDIF.



点击 Check,无问题后,激活测试.

 

测试时,输入参数显示出来了.

 

java rfc调用SPA接口 java调用sap的rfc函数_RFC_45

java rfc调用SPA接口 java调用sap的rfc函数_JAVA SAP RFC_46

java rfc调用SPA接口 java调用sap的rfc函数_SAP_47

 

 

执行后,上图已出结果,点击进入查看明细.

 

java rfc调用SPA接口 java调用sap的rfc函数_数据_48



不输入条件时查询.

 

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_49

 

java rfc调用SPA接口 java调用sap的rfc函数_java rfc调用SPA接口_50


到此RFC我们就已经创建好了.

 

 

Java

 

准备工具

Eclipse

SapJco.jar

librfc32.dll

sapjcorfc.dll

(以上两个动态连接需要加载,最简单的办法就是放在和Java执行程序放在一起,其实就是JDK环境 bin 目录下)

环境

Window 环境

JDK 1.6 32位

 

首先准备了一个工具类,连接SAP.

 

import com.sap.mw.jco.IFunctionTemplate;
import com.sap.mw.jco.JCO;
import com.sap.mw.jco.JCO.Client;

/**
 * SAP 连接工具类
 * @author berr
 * 2014.11.7
 */
public class SapConn {

	private JCO.Client client; //客户端连接对象
	private JCO.Function function; //RFC Function 对象
	String host,clientId,userName, password,lang, sysnr; //地址,客户端,用户名,密码,语言,系统标识
	
	public SapConn(){
	
	}
	
	/**
	 * 创建连接对象
	 */
	public void connect(){
		client = JCO.createClient(clientId, userName,password,lang,host,sysnr);  
		client.connect();
	}
	
	/**
	 * 断开连接
	 */
	public void disconnect(){
		client.disconnect(); 
	}
	
	
	public Client getClient() {
		return client;
	}
	
	public void setClient(Client client) {
		this.client = client;
	}
	
	
	
	/**
	 * 注册并获取一个RFC函数
	 * @param reName 注册名称,任意
	 * @param ftName RFC 名称
	 */
	public void regFunction(String reName,String ftName){ 
		JCO.Repository mRepository = new JCO.Repository(reName,this.client); 
		IFunctionTemplate ft = mRepository.getFunctionTemplate(ftName.toUpperCase());
		this.function = ft.getFunction();
	}
	
	/**
	 * 设置输入参数
	 * @param parameter 参数名
	 * @param value 值
	 */
	public void setImport(String parameter,String value){
		JCO.ParameterList im = this.function.getImportParameterList();
		im.setValue(value,parameter);
	}
	
	/**
	 * 获取Tables结构对象
	 * @param tableName 参数名称
	 * @return
	 */
	public JCO.Table getTable(String tableName){
		return this.function.getTableParameterList().getTable(tableName);
	}
	
	/**
	 * 执行当前注册的函数
	 */
	public void execute(){
		this.client.execute(this.function);
	}

	public JCO.Function getFunction() {
		return function;
	}

	public void setFunction(JCO.Function function) {
		this.function = function;
	}
	
}



 

 

这里我们开始准备测试类

测试插入RFC函数,代码如下


 

import com.sap.mw.jco.JCO;

public class CallInsert {

	
	public static void main(String[] args) {
		
		SapConn sc = new SapConn();
		sc.host="192.168.0.140";
		sc.clientId = "001";
		sc.userName = "dev";
		sc.password = "d123456";
		sc.lang = "zh";
		sc.sysnr="000";
		/*以上都是连接SAP需要的信息,登录SAP GUI也需要这些,就不多解释了*/
		
		
		sc.connect();//创建连接
		
		String function1 = "Z_TEST_1";
		sc.regFunction(function1,function1); //注册并获取一个Function
		
		JCO.Table imt =  sc.getTable("IMPT"); //获取Function 中设置的Tables参数
		
		for (int i = 0; i < 10; i++) {
			imt.appendRow(); //增加一行
			imt.setValue(i, "ZAGE"); // 设置 ZAGE 值,必须为大写
			imt.setValue("C" + i, "ZNAME");//  设置 ZNAME 值,必须为大写
		}
		
		sc.execute();
		
		
		sc.disconnect();
		
	}
}






执行成功后,返回SAP查看结果.

 

java rfc调用SPA接口 java调用sap的rfc函数_RFC_51



测试查询RFC函数,代码如下


 

import com.sap.mw.jco.JCO;


public class CallQuery {

	
	public static void main(String[] args) {
		
		SapConn sc = new SapConn();
		sc.host="192.168.0.140";
		sc.clientId = "001";
		sc.userName = "dev";
		sc.password = "d123456";
		sc.lang = "zh";
		sc.sysnr="000";
		/*以上都是连接SAP需要的信息,登录SAP GUI也需要这些,就不多解释了*/
		
		
		String tpl = "name:%s,age:%s";
		
		sc.connect();//创建连接
		
		String function1 = "Z_TEST_1";
		sc.regFunction(function1,function1); //注册并获取一个Function
		
		String zname = "C1";
		sc.setImport("DZNAME",zname); //设置输入参数
		
		sc.execute();
		
		JCO.Table imt =  sc.getTable("OUTT"); //获取Function Tables中的数据
		
		System.out.println("-------根据条件"+zname+"查询-----------");
		do{
			Object name = imt.getValue("ZNAME");
			Object age = imt.getValue("ZAGE");
			System.out.println(String.format(tpl, name,age));
			
		}while(imt.nextRow());
		
		
		System.out.println("-------不根据条件查询-----------");
		
		
		sc.regFunction(function1,function1); //注册并获取一个Function
		sc.execute();
		
		imt =  sc.getTable("OUTT"); //获取Function Tables中的数据
		
		do{
			Object name = imt.getValue("ZNAME");
			Object age = imt.getValue("ZAGE");
			System.out.println(String.format(tpl, name,age));
			
		}while(imt.nextRow());
		
		
		sc.disconnect();
		

	}
}





执行结果如下:

java rfc调用SPA接口 java调用sap的rfc函数_数据_52

 

以上,简单的RFC程序开发与外部程序调用就完成了,欢迎大家一起交流.

 

 

下面再总结一些外部程序调用的异常情况.

 

动态链接库未加载


Exceptionin thread "main" java.lang.ExceptionInInitializerError:JCO.classInitialize(): Could not load middleware layer'com.sap.mw.jco.rfc.MiddlewareRFC'
JCO.nativeInit():Could not initialize dynamic link library sapjcorfc [no sapjcorfc injava.library.path]. java.library.path[D:\work\wms\jdk1.6.0_26\jre\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;E:/jdk15/BIN/../jre/bin/client;E:/jdk15/BIN/../jre/bin;E:/jdk15/BIN/../jre/lib/i386;d:\app\berr\product\11.2.0\client_1\bin;E:\jdk15\BIN;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;D:\eclipse-jee-indigo-SR2-win32\eclipse;;.]
            atcom.sap.mw.jco.JCO.<clinit>(JCO.java:776)
            at SapConn.connect(SapConn.java:26)
            at CallInsert.main(CallInsert.java:18)




解决方案:将sapjcorfc.dll,librfc32.dll 加载到JDK动态链接库中,最简单的办法及复制到JAVA_HOME/bin目录下.

 

 

RFC 未开启远程调用


Exceptionin thread "main" com.sap.mw.jco.JCO$Exception: (104)RFC_ERROR_SYSTEM_FAILURE: The function module "Z_TEST_2" cannot beused for 'remote' calls.
            atcom.sap.mw.jco.rfc.MiddlewareRFC$Client.nativeExecute(NativeMethod)
            at com.sap.mw.jco.rfc.MiddlewareRFC$Client.execute(MiddlewareRFC.java:1242)
            atcom.sap.mw.jco.JCO$Client.execute(JCO.java:3816)
            atcom.sap.mw.jco.JCO$Client.execute(JCO.java:3261)
            at SapConn.execute(SapConn.java:82)
            at CallQuery.main(CallQuery.java:30)



解决方案:开启远程调用即可.


 

 


以上,希望大家交流交流! 本人邮箱:berr@live.cn  ,博客不能上传附件,需要Java源码的可以Email我。

 

 Java 源码已上传 .