JAVA通过JCo连接SAP
关于JCo
SAP Java Connector (SAP JCo) 是JAVA与SAP相互通信的中间件组建。该组建支持双向通讯模式(inbound calls 和 outbound calls )。
JCo支持Connection Pools和Direct两种方式的连接。直接连接需要开发者来控制连接的创建和释放,使用连接池方式可以让池来管理连接的分配、管理和释放,可以最大限度的节省系统开销,相比直接方式优势也是明显的。本文的示例也是使用池方式连接。
安装JCo
到https://service.sap.com/connectors 下载3.0 或 2.1版本的JCo(需要 SAP Service MarketPlace账号),至于用32bit的还是64bit的要根据你的JVM来选择。
怎么查看自己的JVM版本?
-cmd 用 java -version32位:Java HotSpot(TM) Client VM ....64位:Java HotSpot(TM) 64-Bit Server VM ....-或System.out.println("JVM Bit size: " + System.getProperty("sun.arch.data.model"));-或System.out.println("JVM Bit size: " + System.getProperty("os.arch"));
1。 ZIP包解压到一个目录(像我,如果只是开发Web App,可以选择不安装的。。直接把sapjco3.dll和sapjco3.jar丢到lib目录中就可以了)
2。在PATH环境变量中指定JCo的安装目录
3。CLASSPASS 指定 安装目录\sapjco3.jar
打开 cmd 到安装目录 执行java -jar sapjco3.jar,安装成功你可以看到如下的信息。。
注: 你也可以把
sapjco3.dll丢进
system32或
SysWOW64目录,这样做就不用设置环境变量了,不过SAP官方不建议你这么做。。
解压目录中的javadoc,examples文件夹里面有一些简单示例和文档供参考。
JCo的使用
用JCo3做开发的时候都会涉及到Destination。在运行时,这个Destination会从 DestinationDataProvider 或 ServerDataProvider的实现类中获取server addr. 和 logon info等相关信息。之后我们通过它来找到相应的RFC。下面是用来注册 DestinationDataProvider的工具类。
import java.util.HashMap; import java.util.Properties; import com.sap.conn.jco.ext.DataProviderException; import com.sap.conn.jco.ext.DestinationDataEventListener; import com.sap.conn.jco.ext.DestinationDataProvider; public class JCOProvider implements DestinationDataProvider { private HashMap<String, Properties> secureDBStorage = new HashMap<String, Properties>(); private DestinationDataEventListener eL; @Override 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); } } @Override public void setDestinationDataEventListener( DestinationDataEventListener eventListener) { this.eL = eventListener; } @Override public boolean supportsEvents() { return true; } //implementation that saves the properties in a very secure way public void changePropertiesForABAP_AS(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 } } } }
再创建一个RfcManager的类,用来读取src目录下的sap_conf.properties 来注册Provider,获取RFC Function和执行execute()方法。
sap_conf.properties
#Thu Nov 01 11:17:09 KST 2012 jco.client.ashost=*********** jco.client.client=300 jco.client.langu=KO jco.client.passwd=password jco.client.sysnr=02 jco.client.user=ABAP-01
RfcManager.java
import java.io.IOException; import java.util.Properties; import org.apache.log4j.Logger; import com.sap.conn.jco.JCoDestination; import com.sap.conn.jco.JCoDestinationManager; import com.sap.conn.jco.JCoException; import com.sap.conn.jco.JCoFunction; import com.sap.conn.jco.JCoParameterList; import com.sap.conn.jco.ext.Environment; import com.shany.common.util.StringUtil; public final class RfcManager { private static Logger logger = Logger.getLogger(RfcManager.class); private static String ABAP_AS_POOLED = "XXX"; private static JCOProvider provider = null; private static JCoDestination destination = null; static { Properties properties = loadProperties(); provider = new JCOProvider(); // catch IllegalStateException if an instance is already registered try { Environment.registerDestinationDataProvider(provider); } catch (IllegalStateException e) { logger.debug(e); } provider.changePropertiesForABAP_AS(ABAP_AS_POOLED, properties); } public static Properties loadProperties() { RfcManager manager = new RfcManager(); Properties prop = new Properties(); try { prop.load(manager.getClass().getResourceAsStream( "/sap_conf.properties")); } catch (IOException e) { logger.debug(e); } return prop; } public static JCoDestination getDestination() throws JCoException { if (destination == null) { destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED); } return destination; } public static JCoFunction getFunction(String functionName) { JCoFunction function = null; try { function = getDestination().getRepository() .getFunctionTemplate(functionName).getFunction(); } catch (JCoException e) { logger.error(e); } catch (NullPointerException e) { logger.error(e); } return function; } public static void execute(JCoFunction function) { logger.debug("SAP Function Name : " + function.getName()); JCoParameterList paramList = function.getImportParameterList(); if (paramList != null) { logger.debug("Function Import Structure : " + paramList.toString()); } try { function.execute(getDestination()); } catch (JCoException e) { logger.error(e); } paramList = function.getExportParameterList(); if (paramList != null) { logger.debug("Function Export Structure : " + paramList.toString()); } } /* * SAP 연결 Ping 테스트 */ public static String ping() { String msg = null; try { getDestination().ping(); msg = "Destination " + ABAP_AS_POOLED + " is ok"; } catch (JCoException ex) { msg = StringUtil.getExceptionTrace(ex); } logger.debug(msg); return msg; } public static void main(String[] args) { RfcManager.ping(); } }
然后可以用如下的代码来 call rfc.
public void callRfcExample() { // 获取RFC 对象 JCoFunction function = RfcManager.getFunction("function_name"); // 设置import 参数 JCoParameterList importParam = function.getImportParameterList(); importParam.setValue("field_name", "val"); // 执行RFC RfcManager.execute(function); // 获取RFC返回的字段值 JCoParameterList exportParam = function.getExportParameterList(); String exParamA = exportParam.getString("field_A"); String exParamB = exportParam.getString("field_B"); // 遍历RFC返回的表对象 JCoTable tb = function.getTableParameterList().getTable("table_name"); for (int i = 0; i < tb.getNumRows(); i++) { tb.setRow(i); System.out.println(tb.getString("field01")); System.out.println(tb.getString("field02")); } }