java使用Jco连接SAP
JCO为我们提供了另外一种连接的方法:
DestinationDataProvider,通过它我们就可以将一个连接变量信息存放在内存里。
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
{
static class MyDestinationDataProvider implements DestinationDataProvider
{
private DestinationDataEventListener eL;
private HashMap<String, Properties> secureDBStorage = new HashMap<String, Properties>();
// 实现接口:获取连接配置属性
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");
}
}
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"); //系统编号
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "620"); //客户端编号
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "user"); //用户名
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "123456"); //密码
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "ZH"); //语言
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
//连接测试
test.executeCalls(destName);
}
}
然后可以用如下的代码来 call rfc。
import java.util.concurrent.CountDownLatch;
import com.sap.conn.jco.*;
import static com.chunqiu.modules.sap.CustomDestinationDataProvider.getDestinationPropertiesFromUI;
public class StepClient
{
static String ABAP_AS = "ABAP_AS";
static String ABAP_AS_POOLED = "ABAP_AS";
static String ABAP_MS = "ABAP_AS";
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();
}
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();
}
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
//从对象仓库中获取 RFM 函数
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().
// 设置import 参数
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();
}
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;
}
//从返回数据中解析
JCoStructure exportStructure = function.getExportParameterList().getStructure("RFCSI_EXPORT");
System.out.println("System info for " + destination.getAttributes().getSystemID() + ":\n");
/
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
}
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)
{
}
}
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
//从对象仓库中获取 RFM 函数
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 {
//如果传如参数是内表的形式的话就以如下代码传入sap系统
JCoTable T_ACCDOCUMENT = function.getTableParameterList().getTable("IT_MBLNR");
T_ACCDOCUMENT.appendRow();//增加一行
//给表参数中的字段赋值,此处测试,就随便传两个值进去
T_ACCDOCUMENT.setValue("MBLNR", "5001916414");
//执行调用函数
function.execute(destination);
//获取传入参数返回状态表
JCoTable statusTable = function.getTableParameterList().getTable("IT_MBLNR");//得到sap返回的参数,你就把他当作c语言的结构体理解就可以了
for(int i = 0; i < statusTable.getNumRows(); i++) {
statusTable.setRow(i);
//这里获取sap函数传出内表结构的字段
String rc = statusTable.getString("RCODE");
String mblnr= statusTable.getString("MBLNR");//物料凭证编号 记住这里MBLNR一定是大写的,不然得不到值
if(("02").equals(rc)){
System.out.println("物料凭证编号:"+mblnr+" 合同编号未维护");
}else if(("03").equals(rc)){
System.out.println("物料凭证编号:"+mblnr+" 付款条件为空或不一致");
}else if(("04").equals(rc)){
System.out.println("物料凭证编号:"+mblnr+" 质检未通过");
}else if(("05").equals(rc)){
System.out.println("物料凭证编号:"+mblnr+" 物料凭证已被冲销");
}else if(("06").equals(rc)){
System.out.println("物料凭证编号:"+mblnr+" 物料凭证移动类型有误");
}else if(("07").equals(rc)){
System.out.println("物料凭证编号:"+mblnr+" 物料凭证移动不存在");
}else {
JCoTable exportTable = function.getTableParameterList().getTable("ET_DATA");//得到sap返回的参数,你就把他当作c语言的结构体理解就可以了
System.out.println(exportTable);
//有时候sap那边只是返回一个输出参数,sap比方说你这边输入一个物料号,想得到sap那边的物料描述,这是sap方是不会返回一个内表给你的
//而是只是返回一个输出参数给你这时你就要用到下面的方法来得到输出参数
//paramList = function.getExportParameterList();
//paramList.getString("rfc返回字段字段名称");
for(int j = 0; j < exportTable.getNumRows(); j++) {
exportTable.setRow(i);
//这里获取sap函数传出内表结构的字段
String BUKRS = exportTable.getString("BUKRS");//记住这里BUKRS一定是大写的,不然得不到值
System.out.println("公司代码<<<<<<<<<<<<<<<"+BUKRS);
String LIFNR = exportTable.getString("LIFNR");
System.out.println("供应商编号<<<<<<<<<<<<<<<"+LIFNR);
String NAME1 = exportTable.getString("NAME1");
System.out.println("供应商全称<<<<<<<<<<<<<<<"+NAME1);
String SORTL = exportTable.getString("SORTL");
System.out.println("供应商简称<<<<<<<<<<<<<<<"+SORTL);
//得到了sap数据,然后下面就是你java擅长的部分了,想封装成什么类型的都由你
}
}
}
} 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();
//测试访问
rfcCall();
}
}
测试结果
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。