// 获取RFC返回的字段值
11 JCoParameterList exportParam = function.getExportParameterList();
12 String exParamA = exportParam.getString("field_A");
13 String exParamB = exportParam.getString("field_B");
14 // 遍历RFC返回的表对象
15 JCoTable tb = function.getTableParameterList().getTable("table_name");
16 for (int i = 0; i < tb.getNumRows(); i++) {
17 tb.setRow(i);
18 System.out.println(tb.getString("field01"));
19 System.out.println(tb.getString("field02"));
20 }
21 }

  

SAP的R/3系统与Java平台一样有着许多类似的技术理念,以及同样广泛的企业级用户,但是它们完全是两个不同的世界。当用户面临流程或者数据整合方面的需求的时候,就迫切需要一种高效的方式,在R/3系统和Java平台之间实时地交换数据。基于这样的需求,SAP提供了一套高效的基于RFC的ABAP和Java进程间通讯组件:SAP Java Connector(JCo)。

本文将介绍JCo组件的架构,配置,基本使用方法以及调试,同时还将讨论如何对RFC方式调用的ABAP函数进行远程调试。

JCo库提供了可以直接在Java程序中使用的API。该API通过JNI调用部署在客户端的SAP的RFC库。该RFC库是用C语言实现的,并且与JCo库相互独立发布。但是,在下载的JCo库压缩包中也会提供。

该组件支持Inbound(在Java代码中调用ABAP函数)和Outbound(在ABAP代码中调用Java)两种模式。本文只专注于介绍Inbound模式中,如何在Java代码远程调用ABAP函数。

安装与配置

最新版本的JCo库可以在如下网址下载(请选择适合你的软件和硬件平台的版本,本文的示例都基于32位Windows操作系统):

http://service.sap.com/connectors

你可能需要提供SAP Service MarketPlace的用户帐号。解压缩以后,将名为librfc32.dll的文件复制到目录 system32下面。如果该文件已经存在,则覆盖它。这个文件就是SAP的RFC协议实现,可以在http://service.sap.com/connectors下载其最新版本。

然后,确保CLASSPATH环境变量中包含文件sapjco.jar所在的目录。因为这个JAR包中含有在Java程序中需要直接调用的类和接口。

下载的压缩包中还包含了JavaDoc,文档以及示例程序供参考。

建立连接

在执行任何操作之前,必须先建立到SAP系统的连接。本文示例使用的用户名是“DDIC”,登录密码是“minisap”

类JCO是Jco库中最主要的一个入口,它提供了许多静态方法。其中有一系列重载的createClient方法可以用来创建与SAP系统的连接信息。这些信息都保存在返回的JCO.Client类的实例中。常用的两种方式如下:

直接输入参数:

JCO.Client myConnection = JCO.createClient("000", "DDIC", "minisap", "EN", "10.0.0.11", "00");

使用Java Properties:

Properties logonProperties = new Properties();           logonProperties.put("jco.client.ashost","10.0.0.11");           logonProperties.put("jco.client.client","000");           logonProperties.put("jco.client.passwd","minisap");           logonProperties.put("jco.client.sysnr","00");           logonProperties.put("jco.client.user","DDIC");
JCO.Client myConnection = JCO.createClient( logonProperties ). 第一种方式比较简单,所有的参数都直接写在代码中。相比之下,第二种方式使用Java Properties,它好处在于,除了硬编码这种方式之外,用户也可以将连接信息保存在一个单独的.properties文件中。这样即使连接信息改变也无需改变代码,只需要修改.properties文件中的数据即可。关于.properties文件的用法,请参考相关的Java语言教程。 JCO.Client提供方法connect方法来建立从当前Java进程到SAP服务器的连接。 this.myConnection.connect(); 可以使用isAlive方法来获取一个连接的状态,还可以使用disconnect方法来关闭一个连接: if ( myConnection != null && myConnection.isAlive()) 很多情况下,频繁创建新的连接可能导致严重的性能问题。典型的情况就是在Web应用程序中,如果每个session创建一个连接,那么用户数量很多的时候系对系统来说就是一场灾难。JCo库支持以连接池的形式重用已创建的连接。只需要调用JCO类的静态方法addClientPool即可创建一个连接池,并且可以在参数中指定连接池的名字和允许同时激活的最大连接数。 如下代码演示了如何创建一个名为“Sample_Pool”的JCo连接池: public static final String POOL_NAME = "Sample_Pool";
public static final int max_connection = 2; …… JCO.Pool pool = JCO.getClientPoolManager().getPool(POOL_NAME);
if (pool == null) {
Properties logonProperties = new Properties();
logonProperties.put("jco.client.ashost","10.0.0.11"); logonProperties.put("jco.client.client","000"); logonProperties.put("jco.client.passwd","minisap"); logonProperties.put("jco.client.sysnr","00"); logonProperties.put("jco.client.user","DDIC");
JCO.addClientPool( POOL_NAME, // pool name
max_connection, // max num of connections,
logonProperties); // properties
} 创建好连接池之后,可以通过如下代码来从连接池中获取一个连接: mConnection = JCO.getClient(POOL_NAME); 在连接使用完毕之后,不要忘记使用releaseClient方法释放当前连接: JCO.releaseClient( myConnection ). 如果需要移除连接池,则可以使用如下代码: JCO.removeClientPool(POOL_NAME); 移除连接池将导致其中所有的活动连接被强行关闭,所以必须在确保连接池中所有的连接都不再被使用的时候才能执行该操作。 调用Function Modules 为了演示如何使用JCo库来调用远程的ABAP函数,本文示例中使用NetWeaver ABAP试用版系统中的一个样例函数BAPI_FLIGHT_GETLIST。 JCo库使用RFC的方式来调用ABAP中的函数,所以被调用的函数必须已经勾选“Remote-enabled”属性。 调用一个函数之前,需要知道函数的元数据,比如函数名字,输入输出参数等等。在JCo库中,必须通过类JCO.Repository来获取所有的ABAP函数的元数据,所以第一步是创建一个JCO.Repository类的对象: JCO.Repository myRepository = new JCO.Repository("Repository", myConnection); JCO.Repository类的构造函数有两个参数,第一个是可以任意指定的名字,第二个是当前使用的连接。此处也可以直接指定一个连接池的名字,JCo库将自动从该连接池中获取连接。 此时,必须保证该连接使用的用户名在目标SAP服务器上有足够的权限。 获得JCO.Repository类的实例之后,就可以通过该实例来获得函数的信息。如下代码演示了如何获取函数BAPI_FLIGHT_GETLIST的信息以及如何设置简单类型的参数: String strFunc = "BAPI_FLIGHT_GETLIST";
IFunctionTemplate ft = myRepository.getFunctionTemplate(strFunc.toUpperCase());
JCO.Function funGetList = ft.getFunction(); // set up scalar parameter
JCO.ParameterList input = funGetList.getImportParameterList();
input.setValue(10, "MAX_ROWS"); JCO.Function对象提供了对应的方法来获取ABAP函数的参数列表。例如,上例中的getImportParameterList方法返回该函数的Import参数列表。 在上面的示例代码中,仅仅设置了一个最简单的int类型的参数。事实上,setValue方法有许多重载形式,允许设置各种复杂类型的参数,比如structure类型和table类型的参数。而且,除了通过参数名字引用要设置的参数之外,还可以通过参数的索引来引用一个参数。 在设置structure和table类型的参数之前,需要通过JCO.Function对象的方法获取相应的JCO.Structure和JCO.Table对象,然后才可以使用对每个字段进行赋值。 在我们使用的函数BAPI_FLIGHT_GETLIST中,Import参数中的DESTINATION_FROM是一个structure,其中包含一个CITY字段。如下代码演示了如何将CITY字段赋值为“NEW YORK”: // set up structure parameter
JCO.Structure sFrom = input.getStructure("DESTINATION_FROM");
sFrom.setValue("NEW YORK", "CITY");
input.setValue(sFrom, "DESTINATION_FROM"); 类似地,可以使用JCO.Function对象的getTableParameterList方法拿到Table参数列表。下面的代码演示了如何拿到一个名为DATE_RANGE的Table参数并且为它创建两行: // set up table parameter
JCO.Table tDateRange = funGetList.getTableParameterList()
.getTable("DATE_RANGE"); tDateRange.appendRow();
tDateRange.setRow(0);
tDateRange.setValue("I", "SIGN");
tDateRange.setValue("EQ", "OPTION");
tDateRange.setValue("20070606", "LOW"); tDateRange.appendRow();
tDateRange.setRow(1);
tDateRange.setValue("I", "SIGN");
tDateRange.setValue("EQ", "OPTION");
tDateRange.setValue("20070704", "LOW"); 参数设置完毕之后,可以通过JCO.Client对象的execute方法执行远程调用: myConnection.execute(funGetList); 获得输出参数的方法与输入参数完全一样。下面的代码演示了如何获取一个包含返回值的Table参数,并且输出它的内容: // get table results
JCO.Table flights = funGetList.getTableParameterList().getTable(
"FLIGHT_LIST"); for (int i = 0; i < flights.getNumRows(); i++) {
flights.setRow(i);
System.out.println("Airline ["
+ flights.getString("AIRLINE")
+ "] from city "
+ flights.getString("CITYFROM")
+ " to city "
+ flights.getString("CITYTO")
+ ", departure time is "
+ flights.getDate("FLIGHTDATE")); } JCO.Structure和JCO.Table都继承自类JCO.Record。JCO.Record对每种类型的参数都提供了对应的get和set方法,并且在运行时自动进行Java数据类型和ABAP数据类型之间的转换。限于篇幅,本文不再详叙,请参考JCo库的JavaDoc文档。 在使用JCo库的过程中,主要有两种类型的异常需要处理: JCO.AbapException
如果ABAP函数执行过程中出现异常,则在Java进程中会触发该异常。 JCO.ConversionException
当执行参数的get和set方法时,如果在Java类型和ABAP类型之间转换失败,则会触发该异常。 作为一种最佳实践,建议使用try-catch封装使用JCo库进行参数设置和函数调用的代码,处理上述两种异常,并且在finally代码块中,释放当前所使用的连接。 远程调试 一般的情况下,在SAP服务器上通过事务代码SE37可以测试ABAP函数。在保证ABAP函数的正确性之后,Java客户端只需要检查输入输出参数是否正确即可。这时可以利用JCo库为了方便调试而提供的了一个很强大的功能,把所有继承自JCO.Record的类的对象格式化输出到一个指定的HTML文档中。通过这种方式,我们可以检查输入输出参数是否正确。比如如下代码输出前面得到的FLIGHT_LIST参数的内容: JCO.Table flights = funGetList.getTableParameterList().getTable(
"FLIGHT_LIST");
flights.writeHTML("c:flight_list.html"); 更进一步地,通过启动ABAP的远程调试功能,可以像调试普通程序一样调试远程调用的ABAP函数。 要实现远程调试,首先需要在Java代码中,通过调用JCO.Client类或者JCO.Pool类的setAbapDebug方法激活JCo的ABAP调试功能。如下代码演示了如何激活一个连接池的ABAP调试功能: JCO.Pool pool = JCO.getClientPoolManager().getPool(POOL_NAME);
pool.setAbapDebug(true); 如果一个连接池的ABAP调试功能被激活,那么其中的所有连接的ABAP调试功能都会被激活。使用这样一个连接来调用ABAP函数的时候,SAP系统会自动弹出一个调试器窗口(如下图所示)。当然,前提是客户端机器上已经安装了SAPGUI。 这时候调试器仅仅停留在RFC调用的入口处,而并未进入所调用的ABAP函数。 为了让调试器直接进入ABAP函数,需要在事务代码SE37中为该函数设置一个外部断点(External BreakPoint)。 设置好外部断点之后,还必须通过事务代码SRDEBUG激活远程调试功能。 如果之前没有直接在代码上设置过外部断点的话,也可以直接在SRDEBUG中设置断点所在的Function Module。 要注意的是,在调试结束之前,不要关闭SRDEBUG的窗口,否则系统将会立即关闭远程调试功能。 此时,再执行Java代码,将会发现系统自动打开的DEBUG窗口自动停留在我们所设置的外部断点的位置,而Java进程在调试结束之前将会被挂起。 在ABAP调试器中,可以检查通过RFC协议传过来的参数,以及ABAP程序运行的结果。通过这种方式,可以更清晰地跟踪整个执行过程。 调试结束的时候,不要忘记关闭SRDEBUG的窗口和清除外部断点。 更多资源 限于篇幅,本文只能介绍关于JCo库的基本使用方法。更进一步的技术细节,可以查看JCo库的下载文件中自带的文档。
开发者还可以在如下连接的SAP的在线帮助文档中找到丰富的文档资料和示例程序: http://help.sap.com/saphelp_nw70/helpdata/EN/6f/1bd5c6a85b11d6b28500508b5d5211/frameset.htm

  报错信息

RFC接口调用SAP如果有异常会通过com.sap.mw.jco.JCO$Exception: 抛出异常
在开发中遇到的异常有如下
用户名密码可能是错误或者用户无权限,确认用户,必要时联系SAP负责人,检查用户
(103) RFC_ERROR_LOGON_FAILURE: ##.#####,####
(103) RFC_ERROR_LOGON_FAILURE: Name or password is incorrect (repeat logon)
call信息没有填写完整,检查配置文件各个SAP配置信息是否完整
(101) RFC_ERROR_PROGRAM: Missing R3NAME=... or ASHOST=... in connect_param in RfcOpenEx
ip地址失败:
com.sap.mw.jco.JCO$Exception: (102) RFC_ERROR_COMMUNICATION: Connect to SAP gateway failed
组权限访问 server文件没更新.
(102) RFC_ERROR_COMMUNICATION:Connect to message server failed
C:\WINNT\system32\drivers\etc
端口号错误报错信息:
(103) RFC_ERROR_LOGON_FAILURE: ## 502 ########
超时:
(103) RFC_ERROR_LOGON_FAILURE: Timeout
执行函数,函数的问题
(104) RFC_ERROR_SYSTEM_FAILURE: Error in module RSQL of the database interface.执行函数
(104) RFC_ERROR_SYSTEM_FAILURE: An error occurred when receiving a complex parameter.
(106) JCO_ERROR_RESOURCE: Trying to access row values in a table which does not have any rows yet
返回的表没有值.那个表连第一行都没有,取不到
(106) JCO_ERROR_RESOURCE: Trying to access row values in a table which does not have any rows yet
语法错误
(104) RFC_ERROR_SYSTEM_FAILURE: Syntax error in program SAPMV50A
找不到行
(106) JCO_ERROR_RESOURCE: Trying to access row values in a table which does not ha:ve any rows yet
输入参数不能插入SAP函数输入字段中.
(122) JCO_ERROR_CONVERSION: Integer '4234243' has to many digits at field PO_ITEM
原文地址:http://hi.baidu.com/gary_c/blog/calendar/200809/index/2 函数不能远程调用
(104) RFC_ERROR_SYSTEM_FAILURE: The function module "RP_CHECK_PERNR" cannot be used for 'remote' calls.

  

JAVA_用_JCO连接_SAP,实现调用SAP_的_RFC_函数(整理)(附一篇看起来比较全面的说明)(JCO报错信息)的更多相关文章

  1. JDBC:SqlServer连接TCP/IP连接失败,到主机 的 TCP/IP 连接失败。报错信息:com.microsoft.sqlserver.jdbc.SQLServerException: 到主机 的 TCP/IP 连接失败。

    作者QQ:1161493927,欢迎互相交流学习. 报错信息:com.microsoft.sqlserver.jdbc.SQLServerException: 到主机 的 TCP/IP 连接失败. j ...

  2. Navicat 用ssh通道连接时总是报错 (报错信息:SSH:expected key exchange group packet form serve

    转:https://blog.csdn.net/qq_27463323/article/details/76830731 之前下了一个Navicat 11.0 版本 用ssh通道连接时总是报错 (报错 ...

  3. lua报错,看到报错信息有tail call,以为和尾调用有关,于是查了一下相关知识

    尾调用是指在函数return时直接将被调函数的返回值作为调用函数的返回值返回,尾调用在很多语言中都可以被编译器优化, 基本都是直接复用旧的执行栈, 不用再创建新的栈帧, 原理上其实也很简单, 因为尾调 ...

  4. 修改了Mysql密码后连接不到服务且无报错信息解决方法以及修改密码方法

    安装MYSQL后更改了root的密码后用 net start mysql 启动时出现:无法启动,无报错信息 使用以下命令:1.管理员方式cmd进入mysql安装目录的bin目录下2.执行命令:mysq ...

  5. Druid连接池 报错:abandon connection原因分析

    问题现象:使用Druid的数据库连接池,在进行一个查询SQL的时候,抛出了异常: [2017-10-20 01:40:59.269 ERROR com.alibaba.druid.pool.Druid ...

  6. IE报错:模块"scrrun.dll"已加载,但对DllRegisterServer的调用失败,错误代码为0x80004005

    在我的win10系统上打开某内部网页登录的时候弹出'模块"scrrun.dll"已加载,但对DllRegisterServer的调用失败,错误代码为0x80004005'报错信息, ...

  7. eclipse连接远程Hadoop报错,Caused by: java.io.IOException: 远程主机强迫关闭了一个现有的连接。

    eclipse连接远程Hadoop报错,Caused by: java.io.IOException: 远程主机强迫关闭了一个现有的连接.全部报错信息如下: Exception in thread & ...

  8. Atom远程连接服务器报错服务器版本和客户端版本不一致

    Atom远程连接服务器 报错信息: Server version is different than client version Original error message: Version mi ...

  9. 连接虚拟机mysql无法访问,报错编号1130的解决方法

    新装一台虚拟机mysql的时候,往往会出现win无法连接的情况,报错信息1130,是因为没有权限的问题,解决方案如下: mysql -u root -p mysql>use mysql; mys ...

随机推荐

  1. 面向对象程序设计-C++_课时11new & delete

    Dynamic memory allocation new new int; new Stash; new int[10]; new返回这个对象的指针 delete delete p; delete[ ...

  2. schema文件中cube的事实表使用视图方法

    在cube中可以使用查询结果或者视图来当做事实表,其中view的alias相当于表名,这个要和同一个cube中的level的表名对应,代码如下: <Cube name="YHZXZLF ...

  3. MySQL学习笔记(3)

    约束 作用:保证数据的完整性,唯一性 根据字段:分为表级约束(针对2个或者2个以上字段使用),列级约束(针对1个字段使用) 约束类型:NOT NULL 非空约束 PRIMARY KEY  主键约束 U ...

  4. 创建Java项目报错处理

    好久没用Eclipse编写Java程序了,今天创建一个Java项目的时候,老报错,错误信息如下: Implicit super constructor Object() is undefined fo ...

  5. HDU-Billboard-2795(线段树)

    hdu2795 Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  6. CSS截取字符串

    /*溢出的字...处理*/ .updatecsssubstring { text-overflow: ellipsis; -o-text-overflow: ellipsis; white-space ...

  7. FusionCharts属性大全

    属性的分类就以官方的API文档为准吧: 1.Chart: <1>Functional Attributes(功能属性) <2>Titles and AxisNames(标题和坐 ...

  8. hdu 2295 Radar 重复覆盖+二分

    题目链接 给m个雷达, n个城市, 以及每个城市的坐标, m个雷达里只能使用k个, 在k个雷达包围所有城市的前提下, 求最小半径. 先求出每个雷达到所有城市的距离, 然后二分半径, 如果距离小于二分的 ...

  9. hdu 3397 Sequence operation 线段树

    题目链接 给出n个数, 每个数是0或1, 给5种操作, 区间变为1, 区间变为0, 区间0,1翻转, 询问区间内1的个数, 询问区间内最长连续1的个数. 需要将数组开成二维的, 然后区间0, 1翻转只 ...

  10. ExtJS 修改load paging时的参数

    ExtJS 的pagingToolbar 在翻页的时候传入的参数是固定的  分别是start 和 limit(其中limit的值就是store.pageSize的值) 如何在每次翻页的时候传入自己的参 ...