java使用Jco連接SAP過(guò)程
java使用Jco連接SAP
JCO為我們提供了另外一種連接的方法:
DestinationDataProvider,通過(guò)它我們就可以將一個(gè)連接變量信息存放在內(nèi)存里。
import java.util.HashMap;
import java.util.Properties;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoDestinationManager;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.ext.DataProviderException;
import com.sap.conn.jco.ext.DestinationDataEventListener;
import com.sap.conn.jco.ext.DestinationDataProvider;
public class CustomDestinationDataProvider
{
/**
* 配置生成連接
* qj
*/
static class MyDestinationDataProvider implements DestinationDataProvider
{
private DestinationDataEventListener eL;
private HashMap<String, Properties> secureDBStorage = new HashMap<String, Properties>();
// 實(shí)現(xiàn)接口:獲取連接配置屬性
public Properties getDestinationProperties(String destinationName)
{
try
{
//read the destination from DB
Properties p = secureDBStorage.get(destinationName);
if(p!=null)
{
//check if all is correct, for example
if(p.isEmpty())
throw new DataProviderException(DataProviderException.Reason.INVALID_CONFIGURATION, "destination configuration is incorrect", null);
return p;
}
return null;
}
catch(RuntimeException re)
{
throw new DataProviderException(DataProviderException.Reason.INTERNAL_ERROR, re);
}
}
public void setDestinationDataEventListener(DestinationDataEventListener eventListener)
{
this.eL = eventListener;
}
public boolean supportsEvents()
{
return true;
}
//implementation that saves the properties in a very secure way 添加連接配置屬性
void changeProperties(String destName, Properties properties)
{
synchronized(secureDBStorage)
{
if(properties==null)
{
if(secureDBStorage.remove(destName)!=null)
eL.deleted(destName);
}
else
{
secureDBStorage.put(destName, properties);
eL.updated(destName); // create or updated
}
}
}
} // end of MyDestinationDataProvider
//business logic
void executeCalls(String destName)
{
JCoDestination dest;
try
{
dest = JCoDestinationManager.getDestination(destName);
dest.ping();
System.out.println("Destination " + destName + " works");
}
catch(JCoException e)
{
e.printStackTrace();
System.out.println("Execution on destination " + destName+ " failed");
}
}
/**
* 配置連接信息
* @return
*/
static Properties getDestinationPropertiesFromUI()
{
//adapt parameters in order to configure a valid destination
Properties connectProperties = new Properties();
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "***********"); //IP
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "01"); //系統(tǒng)編號(hào)
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "620"); //客戶(hù)端編號(hào)
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "user"); //用戶(hù)名
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "123456"); //密碼
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "ZH"); //語(yǔ)言
return connectProperties;
}
public static void main(String[] args)
{
//初始化配置信息
MyDestinationDataProvider myProvider = new MyDestinationDataProvider();
//register the provider with the JCo environment;
//catch IllegalStateException if an instance is already registered
try
{
com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(myProvider);
}
catch(IllegalStateException providerAlreadyRegisteredException)
{
//somebody else registered its implementation,
//stop the execution
throw new Error(providerAlreadyRegisteredException);
}
//連接池名,名字隨意取
String destName = "ABAP_AS";
CustomDestinationDataProvider test = new CustomDestinationDataProvider();
//set properties for the destination and ...
myProvider.changeProperties(destName, getDestinationPropertiesFromUI());
//... work with it
//連接測(cè)試
test.executeCalls(destName);
}
}然后可以用如下的代碼來(lái) call rfc。
import java.util.concurrent.CountDownLatch;
import com.sap.conn.jco.*;
import static com.chunqiu.modules.sap.CustomDestinationDataProvider.getDestinationPropertiesFromUI;
/**
* basic examples for Java to ABAP communication
* qj
*/
public class StepClient
{
static String ABAP_AS = "ABAP_AS";
static String ABAP_AS_POOLED = "ABAP_AS";
static String ABAP_MS = "ABAP_AS";
/**
* This example demonstrates the destination concept introduced with JCO 3.
* The application does not deal with single connections anymore. Instead
* it works with logical destinations like ABAP_AS and ABAP_MS which separates
* the application logic from technical configuration.
* 測(cè)試連接
* @throws JCoException
*/
public static void step1Connect() throws JCoException
{
JCoDestination destination = JCoDestinationManager.getDestination(ABAP_AS);
System.out.println("Attributes:");
System.out.println(destination.getAttributes());
System.out.println();
destination = JCoDestinationManager.getDestination(ABAP_MS);
System.out.println("Attributes:");
System.out.println(destination.getAttributes());
System.out.println();
}
/**
* This example uses a connection pool. However, the implementation of
* the application logic is still the same. Creation of pools and pool management
* are handled by the JCo runtime.
* 使用連接池連接
* @throws JCoException
*/
public static void step2ConnectUsingPool() throws JCoException
{
JCoDestination destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED);
destination.ping();
System.out.println("Attributes:");
System.out.println(destination.getAttributes());
System.out.println();
}
/**
* The following example executes a simple RFC function STFC_CONNECTION.
* In contrast to JCo 2 you do not need to take care of repository management.
* JCo 3 manages the repository caches internally and shares the available
* function metadata as much as possible.
* 使用getExportParameterList() 設(shè)置參數(shù)
* @throws JCoException
*/
public static void step3SimpleCall() throws JCoException
{
//JCoDestination is the logic address of an ABAP system and ...
JCoDestination destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED);
// ... it always has a reference to a metadata repository
//從對(duì)象倉(cāng)庫(kù)中獲取 RFM 函數(shù)
JCoFunction function = destination.getRepository().getFunctionTemplate("ZFM_FI_TAXPLATFORM_PRICE").getFunction();
System.out.println("function================="+function);
if(function == null)
throw new RuntimeException("ZFM_FI_TAXPLATFORM_PRICE not found in SAP.");
//JCoFunction is container for function values. Each function contains separate
//containers for import, export, changing and table parameters.
//To set or get the parameters use the APIS setValue() and getXXX().
// 設(shè)置import 參數(shù)
JCoParameterList importParam = function.getExportParameterList();
importParam.setValue("ZFIS_MBLNR", "123456789");
try
{
//execute, i.e. send the function to the ABAP system addressed
//by the specified destination, which then returns the function result.
//All necessary conversions between Java and ABAP data types
//are done automatically.
function.execute(destination);
}
catch(AbapException e)
{
//System.out.println(e.toString());
return;
}
System.out.println("STFC_CONNECTION finished:");
System.out.println(" Echo: " + function.getExportParameterList().getString("ECHOTEXT"));
System.out.println(" Response: " + function.getExportParameterList().getString("RESPTEXT"));
System.out.println();
}
/**
* ABAP APIs often uses complex parameters. This example demonstrates 訪問(wèn)結(jié)構(gòu) (Structure)
* how to read the values from a structure.
* 構(gòu)造訪問(wèn)
* @throws JCoException
*/
public static void step3WorkWithStructure() throws JCoException
{
JCoDestination destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED);
JCoFunction function = destination.getRepository().getFunctionTemplate("ZFM_FI_TAXPLATFORM_PRICE").getFunction();
if(function == null)
throw new RuntimeException("ZFM_FI_TAXPLATFORM_PRICE not found in SAP.");
try
{
function.execute(destination);
}
catch(AbapException e)
{
System.out.println(e.toString());
return;
}
//從返回?cái)?shù)據(jù)中解析
JCoStructure exportStructure = function.getExportParameterList().getStructure("RFCSI_EXPORT");
System.out.println("System info for " + destination.getAttributes().getSystemID() + ":\n");
//*********也可直接通過(guò)結(jié)構(gòu)中的字段名或字段所在的索引位置來(lái)讀取某個(gè)字段的值
System.out.println("RFCPROTO:\t"+exportStructure.getString(0));
System.out.println("RFCPROTO:\t"+exportStructure.getString("RFCPROTO"));
//The structure contains some fields. The loop just prints out each field with its name.
for(int i = 0; i < exportStructure.getMetaData().getFieldCount(); i++)
{
System.out.println(exportStructure.getMetaData().getName(i) + ":\t" + exportStructure.getString(i));
}
System.out.println();
//JCo still supports the JCoFields, but direct access via getXXX is more efficient as field iterator
// efficient as field iterator 也可以使用下面的方式來(lái)遍歷
System.out.println("The same using field iterator: \nSystem info for " + destination.getAttributes().getSystemID() + ":\n");
for(JCoField field : exportStructure)
{
System.out.println(field.getName() + ":\t" + field.getString());
}
System.out.println();
}
/**
* A slightly more complex example than before. Query the companies list 訪問(wèn)表
* returned in a table and then obtain more details for each company.
* 表結(jié)構(gòu)訪問(wèn)
* @throws JCoException
*/
public static void step4WorkWithTable() throws JCoException
{
JCoDestination destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED);
JCoFunction function = destination.getRepository().getFunction("ZFM_FI_TAXPLATFORM_PRICE");
if(function == null)
throw new RuntimeException("ZFM_FI_TAXPLATFORM_PRICE not found in SAP.");
try
{
function.execute(destination);
}
catch(AbapException e)
{
System.out.println(e.toString());
return;
}
JCoStructure returnStructure = function.getExportParameterList().getStructure("RETURN");
if (! (returnStructure.getString("TYPE").equals("")||returnStructure.getString("TYPE").equals("S")) )
{
throw new RuntimeException(returnStructure.getString("MESSAGE"));
}
JCoTable codes = function.getTableParameterList().getTable("COMPANYCODE_LIST");
for (int i = 0; i < codes.getNumRows(); i++)
{
codes.setRow(i);
System.out.println(codes.getString("COMP_CODE") + '\t' + codes.getString("COMP_NAME"));
}
//move the table cursor to first row
codes.firstRow();
for (int i = 0; i < codes.getNumRows(); i++, codes.nextRow())
{
function = destination.getRepository().getFunction("BAPI_COMPANYCODE_GETDETAIL");
if (function == null)
throw new RuntimeException("BAPI_COMPANYCODE_GETDETAIL not found in SAP.");
function.getImportParameterList().setValue("COMPANYCODEID", codes.getString("COMP_CODE"));
//We do not need the addresses, so set the corresponding parameter to inactive.
//Inactive parameters will be either not generated or at least converted.
function.getExportParameterList().setActive("COMPANYCODE_ADDRESS",false);
try
{
function.execute(destination);
}
catch (AbapException e)
{
System.out.println(e.toString());
return;
}
returnStructure = function.getExportParameterList().getStructure("RETURN");
if (! (returnStructure.getString("TYPE").equals("") ||
returnStructure.getString("TYPE").equals("S") ||
returnStructure.getString("TYPE").equals("W")) )
{
throw new RuntimeException(returnStructure.getString("MESSAGE"));
}
JCoStructure detail = function.getExportParameterList().getStructure("COMPANYCODE_DETAIL");
System.out.println(detail.getString("COMP_CODE") + '\t' +
detail.getString("COUNTRY") + '\t' +
detail.getString("CITY"));
}//for
}
/**
* this example shows the "simple" stateful call sequence. Since all calls belonging to one
* session are executed within the same thread, the application does not need
* to take into account the SessionReferenceProvider. MultithreadedExample.java
* illustrates the more complex scenario, where the calls belonging to one session are
* executed in different threads.
*
* Note: this example uses Z_GET_COUNTER and Z_INCREMENT_COUNTER. Most ABAP systems
* contain function modules GET_COUNTER and INCREMENT_COUNTER that are not remote-enabled.
* Copy these functions to Z_GET_COUNTER and Z_INCREMENT_COUNTER (or implement as wrapper)
* and declare them to be remote enabled.
* 多線程 構(gòu)造訪問(wèn)
* @throws JCoException
*/
public static void step4SimpleStatefulCalls() throws JCoException
{
final JCoFunctionTemplate incrementCounterTemplate, getCounterTemplate;
JCoDestination destination = JCoDestinationManager.getDestination(ABAP_MS);
incrementCounterTemplate = destination.getRepository().getFunctionTemplate("Z_INCREMENT_COUNTER");
getCounterTemplate = destination.getRepository().getFunctionTemplate("Z_GET_COUNTER");
if(incrementCounterTemplate == null || getCounterTemplate == null)
throw new RuntimeException("This example cannot run without Z_INCREMENT_COUNTER and Z_GET_COUNTER functions");
final int threadCount = 5;
final int loops = 5;
final CountDownLatch startSignal = new CountDownLatch(threadCount);
final CountDownLatch doneSignal = new CountDownLatch(threadCount);
Runnable worker = new Runnable()
{
public void run()
{
startSignal.countDown();
try
{
//wait for other threads
startSignal.await();
JCoDestination dest = JCoDestinationManager.getDestination(ABAP_MS);
JCoContext.begin(dest);
try
{
for(int i=0; i < loops; i++)
{
JCoFunction incrementCounter = incrementCounterTemplate.getFunction();
incrementCounter.execute(dest);
}
JCoFunction getCounter = getCounterTemplate.getFunction();
getCounter.execute(dest);
int remoteCounter = getCounter.getExportParameterList().getInt("GET_VALUE");
System.out.println("Thread-" + Thread.currentThread().getId() +
" finished. Remote counter has " + (loops==remoteCounter?"correct":"wrong") +
" value [" + remoteCounter + "]");
}
finally
{
JCoContext.end(dest);
}
}
catch(Exception e)
{
System.out.println("Thread-" + Thread.currentThread().getId() + " ends with exception " + e.toString());
}
doneSignal.countDown();
}
};
for(int i = 0; i < threadCount; i++)
{
new Thread(worker).start();
}
try
{
doneSignal.await();
}
catch(Exception e)
{
}
}
/**
* 內(nèi)表結(jié)構(gòu)訪問(wèn)
* @throws JCoException
*/
public static void rfcCall() throws JCoException
{
//JCoDestination is the logic address of an ABAP system and ...
JCoDestination destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED);
// ... it always has a reference to a metadata repository
//從對(duì)象倉(cāng)庫(kù)中獲取 RFM 函數(shù)
JCoFunction function = destination.getRepository().getFunctionTemplate("ZFM_FI_TAXPLATFORM_PRICE").getFunction();
if(function == null)
throw new RuntimeException("ZFM_FI_TAXPLATFORM_PRICE not found in SAP.");
try {
//如果傳如參數(shù)是內(nèi)表的形式的話(huà)就以如下代碼傳入sap系統(tǒng)
JCoTable T_ACCDOCUMENT = function.getTableParameterList().getTable("IT_MBLNR");
T_ACCDOCUMENT.appendRow();//增加一行
//給表參數(shù)中的字段賦值,此處測(cè)試,就隨便傳兩個(gè)值進(jìn)去
T_ACCDOCUMENT.setValue("MBLNR", "5001916414");
//執(zhí)行調(diào)用函數(shù)
function.execute(destination);
//獲取傳入?yún)?shù)返回狀態(tài)表
JCoTable statusTable = function.getTableParameterList().getTable("IT_MBLNR");//得到sap返回的參數(shù),你就把他當(dāng)作c語(yǔ)言的結(jié)構(gòu)體理解就可以了
for(int i = 0; i < statusTable.getNumRows(); i++) {
statusTable.setRow(i);
//這里獲取sap函數(shù)傳出內(nèi)表結(jié)構(gòu)的字段
String rc = statusTable.getString("RCODE");
String mblnr= statusTable.getString("MBLNR");//物料憑證編號(hào) 記住這里MBLNR一定是大寫(xiě)的,不然得不到值
if(("02").equals(rc)){
System.out.println("物料憑證編號(hào):"+mblnr+" 合同編號(hào)未維護(hù)");
}else if(("03").equals(rc)){
System.out.println("物料憑證編號(hào):"+mblnr+" 付款條件為空或不一致");
}else if(("04").equals(rc)){
System.out.println("物料憑證編號(hào):"+mblnr+" 質(zhì)檢未通過(guò)");
}else if(("05").equals(rc)){
System.out.println("物料憑證編號(hào):"+mblnr+" 物料憑證已被沖銷(xiāo)");
}else if(("06").equals(rc)){
System.out.println("物料憑證編號(hào):"+mblnr+" 物料憑證移動(dòng)類(lèi)型有誤");
}else if(("07").equals(rc)){
System.out.println("物料憑證編號(hào):"+mblnr+" 物料憑證移動(dòng)不存在");
}else {
JCoTable exportTable = function.getTableParameterList().getTable("ET_DATA");//得到sap返回的參數(shù),你就把他當(dāng)作c語(yǔ)言的結(jié)構(gòu)體理解就可以了
System.out.println(exportTable);
//有時(shí)候sap那邊只是返回一個(gè)輸出參數(shù),sap比方說(shuō)你這邊輸入一個(gè)物料號(hào),想得到sap那邊的物料描述,這是sap方是不會(huì)返回一個(gè)內(nèi)表給你的
//而是只是返回一個(gè)輸出參數(shù)給你這時(shí)你就要用到下面的方法來(lái)得到輸出參數(shù)
//paramList = function.getExportParameterList();
//paramList.getString("rfc返回字段字段名稱(chēng)");
for(int j = 0; j < exportTable.getNumRows(); j++) {
exportTable.setRow(i);
//這里獲取sap函數(shù)傳出內(nèi)表結(jié)構(gòu)的字段
String BUKRS = exportTable.getString("BUKRS");//記住這里BUKRS一定是大寫(xiě)的,不然得不到值
System.out.println("公司代碼<<<<<<<<<<<<<<<"+BUKRS);
String LIFNR = exportTable.getString("LIFNR");
System.out.println("供應(yīng)商編號(hào)<<<<<<<<<<<<<<<"+LIFNR);
String NAME1 = exportTable.getString("NAME1");
System.out.println("供應(yīng)商全稱(chēng)<<<<<<<<<<<<<<<"+NAME1);
String SORTL = exportTable.getString("SORTL");
System.out.println("供應(yīng)商簡(jiǎn)稱(chēng)<<<<<<<<<<<<<<<"+SORTL);
//得到了sap數(shù)據(jù),然后下面就是你java擅長(zhǎng)的部分了,想封裝成什么類(lèi)型的都由你
}
}
}
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} finally {
destination = null;
}
}
public static void main(String[] args) throws JCoException
{
//建立連接
CustomDestinationDataProvider.MyDestinationDataProvider myProvider = new CustomDestinationDataProvider.MyDestinationDataProvider();
//register the provider with the JCo environment;
//catch IllegalStateException if an instance is already registered
try
{
com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(myProvider);
}
catch(IllegalStateException providerAlreadyRegisteredException)
{
//somebody else registered its implementation,
//stop the execution
throw new Error(providerAlreadyRegisteredException);
}
String destName = "ABAP_AS";
CustomDestinationDataProvider test = new CustomDestinationDataProvider();
//set properties for the destination and ...
myProvider.changeProperties(destName, getDestinationPropertiesFromUI());
//... work with it
test.executeCalls(destName);
//step1Connect();
//step2ConnectUsingPool();
//step3SimpleCall();
//step3WorkWithStructure();
//step4WorkWithTable();
//step4SimpleStatefulCalls();
//測(cè)試訪問(wèn)
rfcCall();
}
}測(cè)試結(jié)果

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java從后臺(tái)重定向(redirect)到另一個(gè)項(xiàng)目的方法
這篇文章主要介紹了詳解Java從后臺(tái)重定向(redirect)到另一個(gè)項(xiàng)目的方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-04-04
Java實(shí)現(xiàn)的校驗(yàn)銀行卡功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的校驗(yàn)銀行卡功能,結(jié)合完整實(shí)例形式分析了java針對(duì)銀行卡類(lèi)型、歸屬地等信息的判斷、讀取相關(guān)操作技巧,需要的朋友可以參考下2018-06-06
springboot 設(shè)置局域網(wǎng)訪問(wèn)的實(shí)現(xiàn)步驟
Spring Boot是一個(gè)開(kāi)源Java-based框架,用于創(chuàng)建獨(dú)立的、生產(chǎn)級(jí)別的Spring應(yīng)用,它旨在簡(jiǎn)化Spring應(yīng)用的初始搭建及開(kāi)發(fā)過(guò)程,通過(guò)提供各種自動(dòng)配置的starter包,Spring Boot使得項(xiàng)目配置變得簡(jiǎn)單快速,感興趣的朋友一起看看吧2024-02-02
Java實(shí)現(xiàn)自定義ArrayList類(lèi)的示例代碼
這篇文章主要為大家簡(jiǎn)單的介紹ArrayList一下里面的add方法、size方法、isEmpty方法,以及如何實(shí)現(xiàn)自定義ArrayList類(lèi),感興趣的可以了解一下2022-08-08
Java編程實(shí)現(xiàn)驗(yàn)證哥德巴赫猜想
這篇文章主要介紹了Java編程實(shí)現(xiàn)驗(yàn)證哥德巴赫猜想,具有一定參考價(jià)值,需要的朋友可以了解下。2017-12-12

