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 );
相關文章
相關標籤/搜索