JCO 链接SAP

JCO 链接SAP

2月4日
033-使用JCo远程调用SAP系统函数
要用Java程序远程调用ABAP函数可使用SAP提供的RFC针对Java程序的API——JCo。
0.JCo的安装很不幸,虽然JCo是用Java语言编写的但倒是平台相关的。(具体来讲,JCo的Java包sapjco.jar确实是平台无关的,可是运行JCo须要RFC库支持,而RFC库是平台相关的)
目前为止我还只有在Windows系统中安装的版本,由于JCo不是一个开源组件,甚至在SAP官方下载它是须要SAP Service MarketPlace的用户账号的。目前我手上的是JCo2.1.6Windows版本。
除了API文档和一些DEMO程序,你须要用到的有3个文件:librfc32.dll,sapjcorfc.dll,sapjco.jar。
安装配置步骤以下:
(1).将sapjco.jar导入到你的项目库路径中。SAP官方的指导是要你配置CLASSPATH,这种方法在我看来不值得提倡,由于eclipse或netBeans这样的IDE能够帮你轻松导入jar库而无需摆弄系统环境变量。
(2).将sapjcorfc.dll文件拷贝至sapjco.jar所在的文件夹中。注意,这两个文件必须放在同一个文件夹里,它们俩必须像热恋中的情人同样一直黏在一块儿才能使JCo正常工做。
(3). 将librfc32.dll文件拷贝至C:WINDOWSsystem32中。若是系统中已安装过SAP客户端,那么可能原本就已经有一个 librfc32.dll在那里了,SAP官方要求你覆盖那个文件,这是一种很不负责的方法。当你覆盖这个文件后极可能你的SAPLogon就没法工做 了。正确的作法是备份原来的文件,而后尝试覆盖后使用SAPLogon,若是出问题了,把原来那个文件找回来。我在安装了710 Final Release版本的SAPLogon机器上使用原来的librfc32.dll运行JCo目前尚未发生什么异常。
好了,到如今为止,JCo算是安装好了,咱们能够开始编写程序了。
1.使用JCo调用远程ABAP函数
使 用Java程序远程调用ABAP函数的大体流程是这样地:先要有SAP系统所在服务器的IP地址、要登陆的SAP系统的客户端号、系统编号、用户名、用户 密码,有了这些后,就能够创建一个到该SAP系统的链接,而后在这个链接上调用容许远程调用的函数,获得调用后的结果,关闭链接。
这其中牵涉到一些细节,咱们先看程序:
package jcousage;
import com.sap.mw.jco.IFunctionTemplate;
import com.sap.mw.jco.JCO;
import java.util.Properties;
public class TestJCo {
public static void main(String[] args) {
Properties logonProperties = new Properties();
logonProperties.put("jco.client.ashost","192.168.1.123"); //系统的IP地址
logonProperties.put("jco.client.client","800"); //要登陆的客户端
logonProperties.put("jco.client.sysnr","00"); //系统编号
logonProperties.put("jco.client.user","young98"); //登陆用户名
logonProperties.put("jco.client.passwd","password"); //用户登陆口令
//用上述条件建立一个链接对象
JCO.Client myConnection = JCO.createClient( logonProperties );
myConnection.connect(); //进行实际链接
//若是链接不为null而且处于活动状态
if (myConnection != null && myConnection.isAlive()) {
//从链接得到一个逻辑意义上的“仓库”对象(Repository)
JCO.Repository myRepository =
new JCO.Repository("Repository", //只是一个名字
myConnection); //活动的链接
//要调用的SAP函数名称
String strFunc = "BAPI_FLIGHT_GETLIST";
//从“仓库”中得到一个指定函数名的函数模板
IFunctionTemplate ft = myRepository.getFunctionTemplate(strFunc.toUpperCase());
//从这个函数模板得到该SAP函数的对象
JCO.Function function = ft.getFunction();
//得到函数的import参数列表
JCO.ParameterList input = function.getImportParameterList();
//设定一个import参数的值。参数名为“MAX_ROWS”,设定值为10
input.setValue(10, "MAX_ROWS");
//若是参数是一个结构,用参数名得到一个对应类型的结构对象
JCO.Structure sFrom = input.getStructure("DESTINATION_FROM");
//设定结构中的变量。变量名为“CITY”,设定值为“NEW YORK”
sFrom.setValue("NEW YORK", "CITY");
//将处理好的结构赋给该参数
input.setValue(sFrom, "DESTINATION_FROM");
//用参数名得到一个对应类型的内部表对象
JCO.Table tDateRange = function.getTableParameterList().getTable("DATE_RANGE");
//接下来基本属于体力活了......
//新增一条空行
tDateRange.appendRow();
//定位到第0行
tDateRange.setRow(0);
//设定该行对应变量
tDateRange.setValue("I", "SIGN");
tDateRange.setValue("EQ", "OPTION");
tDateRange.setValue("20040330", "LOW");
//新增一条空行
tDateRange.appendRow();
//定位到第1行
tDateRange.setRow(1);
//设定该行对应变量
tDateRange.setValue("I", "SIGN");
tDateRange.setValue("EQ", "OPTION");
tDateRange.setValue("20040427", "LOW");
//......
//执行函数
myConnection.execute(function);
//在执行函数后可用相同方式得到输出结果
JCO.Table flights = function.getTableParameterList().getTable("FLIGHT_LIST");
//JCO.Table对象能够直接输出到html文件
flights.writeHTML("C:/function.html");
//也能够以下单独得到表中个别变量
System.out.println("Airline" + "tt"
+ "from city" + "t"
+ "to city" + "tt"
+ "departure time" + "tt"
+ "price" + "t"
+ "CURR");
for (int i = 0; i < flights.getNumRows(); i++) {
flights.setRow(i);
System.out.println(flights.getString("AIRLINE") + "t"
+ flights.getString("CITYFROM") + "t"
+ flights.getString("CITYTO") + "t"
+ flights.getDate("FLIGHTDATE") + "t"
+ flights.getDouble("PRICE") + "t"
+ flights.getString("CURR"));
}
//断开链接
myConnection.disconnect();
} else {
System.out.println(false);
}
}
}//:~
首先,将链接须要的信息放到一个Properties里,对应的键值都是固定的。须要注意的是给定的用户名必须有足够的权限进行远程调用。
JCO.Client myConnection = JCO.createClient( logonProperties );
这样就建立了一个到SAP系统的链接对象了。接着只要在这个对象上调用connect()方法就能激活链接。为了保证这个链接确实可用,加上这一句:
if (myConnection != null && myConnection.isAlive())
接下来比较麻烦,先要从这个活动的链接上拿到一个“仓库”,而后从这个“仓库”里拿到函数模板,再从函数模板里拿到对应函数对象。
JCO.Repository myRepository =
new JCO.Repository("Repository", //只是一个名字
myConnection); //活动的链接
String strFunc = "BAPI_FLIGHT_GETLIST";
IFunctionTemplate ft = myRepository.getFunctionTemplate(strFunc.toUpperCase());
JCO.Function function = ft.getFunction();
整个过程很唬人,其实也就那么回事。这里咱们调用的是一个叫“BAPI_FLIGHT_GETLIST”函数,这个函数在SAP系统中被声明为Remote-Enabled Module,可以被远程调用的函数都必须声明为Remote-Enabled Module。
好了,咱们如今有函数对象了。咱们知道,SAP函数主要就是有5个输入输出接口:Import、Export、Changing、Tables、Exceptions。其中除了Changing在远程调用中是不被容许的外,其余都是可用的属性:
Import:经过在函数对象上调用getImportParameterList()方法得到Import变量列表。
JCO.ParameterList input = function.getImportParameterList();
Export:在函数被执行后经过在函数对象上调用getExportParameterList()方法得到Export变量列表。
JCO.ParameterList output = function.getExportParameterList();
Changing:不支持。
Tables:经过在函数对象上调用getTableParameterList()方法得到Tables变量列表。
JCO.ParameterList tables = function.getTableParameterList();
Exceptions:可经过在函数对象上调用getExceptionList()方法得到Exceptions变量数组,也可调用getException(java.lang.String key)得到单个异常对象。
JCO.AbapException[] abapExceptions = function.getExceptionList();
JCO.AbapException abapException = function.getException( "1" );
Import、Export、Tables所得到的都是JCO.ParameterList对象。
若是参数是基本类型,则可直接设定:
input.setValue(10, "MAX_ROWS");
Object object = output.getValue("MAX_ROWS");
固然你这样getValue获得的只能是一个Object对象,若是你知道你会获得什么类型(通常状况下你应该知道),你能够直接get这个类型。好比,咱们知道"MAX_ROWS"是个int值,因此:
int maxRows = output.getInt("MAX_ROWS");
若是参数是一个结构(若是你是个面向对象的程序员,请回忆一下C语言中的结构变量,谢谢),那么你得先获得一个对应此参数的结构对象,而后对结构中的变量成员get或者set:
JCO.Structure sFrom = input.getStructure("DESTINATION_FROM");
sFrom.setValue("NEW YORK", "CITY");
固然若是是Import的话最后别忘了把这个结构放回列表中:
input.setValue(sFrom, "DESTINATION_FROM");
在对Tables的参数进行操做时,也得先获得一个与该参数内部表对应的内部表对象:
JCO.Table tDateRange = tables.getTable("DATE_RANGE");
如今这个内部表对象仍是空的,因此要先加一行数据,而后将一个逻辑指针指向该行,再进行各个元素的赋值或取值:
tDateRange.appendRow();
tDateRange.setRow(0);
tDateRange.setValue("I", "SIGN");
tDateRange.setValue("EQ", "OPTION");
tDateRange.setValue("20040330", "LOW");
内部表对象支持直接将表内容发送到HTML文件:
JCO.Table flights = function.getTableParameterList().getTable("FLIGHT_LIST");
flights.writeHTML("C:/function.html");
想知道内部表中有几条数据,能够调用getNumRows()方法:
int rows = flights.getNumRows();
结束调用时要记得断开链接:
myConnection.disconnect();
2.使用链接池不少时候咱们须要进行大量链接,SAP系统原本就脆弱,链接再一多那真的是老牛拉车了。因此咱们要用链接池进行链接。下面是一个使用链接池的例子:
package jcousage;
import com.sap.mw.jco.JCO;
import java.util.Properties;
public class UsageForPool {
public static void createConnectionPool( String poolName,
int maxConnection,
Properties logonProperties) {
JCO.Pool pool = JCO.getClientPoolManager().getPool(poolName);
if(pool == null) {
JCO.addClientPool( poolName, // 链接池名
maxConnection, // 最大链接数
logonProperties ); // logon设定参数
}
}
public static JCO.Client getConnectionInPool( String poolName ) {
JCO.Client connection = null;
JCO.Pool pool = JCO.getClientPoolManager().getPool(poolName);
if(pool != null) {
connection = JCO.getClient(poolName);
}
return connection;
}
public static void releaseConnection( JCO.Client connection ) {
JCO.releaseClient( connection );
}
public static void removeConnectionPool(String poolName) {
JCO.removeClientPool(poolName);
}
public static void main(String[] args) {
Properties logonProperties = new Properties();
logonProperties.put("jco.client.ashost","192.168.1.123");
logonProperties.put("jco.client.client","800");
logonProperties.put("jco.client.sysnr","00");
logonProperties.put("jco.client.user","young98");
logonProperties.put("jco.client.passwd","password");
String poolName = "ThePool";
createConnectionPool(poolName, 6, logonProperties);
JCO.Client connection = getConnectionInPool(poolName);
connection.connect();
if (connection != null && connection.isAlive()) {
System.out.println("Connection is alive!");
releaseConnection(connection);
removeConnectionPool(poolName);
} else {
System.out.println("Connection FALSE!");
}
}
}
首先,咱们仍然须要一个Properties对象用来创建链接,不过此次是创建的链接是一个链接池:
JCO.addClientPool( poolName, maxConnection, logonProperties );
这个方法同时还须要池的名字以及最大链接数一块儿做为参数。固然在新建一个链接池以前,检查一下有没有相同名字的池已经存在是一个好习惯。
有了池咱们就能够在链接池里得到链接啦:
JCO.Client connection = JCO.getClient(poolName);
而后在这个链接对象上激活链接就能够啦:
connection.connect();
接下来就跟上面说的同样用啦,简单吧。
用完别忘了释放链接:
JCO.releaseClient( connection );
相关文章
相关标签/搜索