• SAP接口编程 之 JCo3.0系列(01):JCoDestination


    SAP接口编程 之 JCo3.0系列(01):JCoDestination

    字数2101 阅读103 评论0 

    JCo3.0是Java语言与ABAP语言双向通讯的中间件。与之前1.0/2.0相比,是重新设计的产品。API和架构设计与NCo3.0比较类似,前面也说过,NCo3.0的设计参考了JCo3.0。从本篇开始,系统介绍JCo3.0编程的技术要点。

    JCo3.0安装

    https://service.sap.com/connectors 可以下载JCo3.0,注意下载的时候根据操作系统JVM版本(32位还是64)选择不同的版本。安装就是解压,将文件解压到目标文件夹。以Windows系统为例,主要的文件包括:

    sapjco3.dll
    sapjco3.jar

    SAP强烈推荐将这两个文件放在同一文件夹下。测试安装是否成功,可以在命令窗口下,进入安装文件夹,运行下面的命令:

    java -jar sapjco3.jar

    如果安装成功,应该显示如下界面:


    jco3安装成功的显示界面

    JCoDestination

    JCoDestination代表后台SAP系统,程序员不用关心与SAP的连接,jco3.0运行时环境负责管理连接和释放连接。我们先以一个简单的例子看看jco3.0 JCoDestination类的一些要点。

    我使用的编程环境是Eclipse,环境准备如下:

    • 新建一个Java项目,项目名为JCo3Demo。
    • 将sapjco3.jar加入到项目的build path中。注意前面所说的sapjco3.jar和sapjco3.dll要放在同一个文件夹下。
    • 在Eclipse Java项目文件夹下,新建一个文本文件,文件名命名为ECC.jocdestination, 文件的内容如下(SAP系统的连接参数的设置):

      #SAP Logon parameters!
      #Tue Dec 08 16:41:30 CST 2015
      jco.client.lang=EN
      jco.client.client=001
      jco.client.passwd=xxxxxx
      jco.client.user=STONE
      jco.client.sysnr=00
      jco.client.ashost=192.168.65.100

    对照SAP GUI,不难理解:


    SAP GUI

    环境准备好了,先来一段最简单的代码:

    package jco3.demo1;
    
    import java.util.Properties;
    import org.junit.Test;
    import com.sap.conn.jco.JCoDestination;
    import com.sap.conn.jco.JCoDestinationManager;
    import com.sap.conn.jco.JCoException;
    
    public class JCoDestinationDemo
    {
        public JCoDestination getDestination() throws JCoException
        {
            /**
             * Get instance of JCoDestination from file: ECC.jcodestination
             * which should be located in the installation folder of project
             */
    
            JCoDestination dest = JCoDestinationManager.getDestination("ECC");
            return dest;
        }
    
        @Test
        public void pingDestination() throws JCoException
        {     
            JCoDestination dest = this.getDestination();
            dest.ping();
        }    
    }

    代码说明:

    • getDestination()方法中,JCoDestinationManager.getDestination("ECC")从ECC.jcodestination文件中获取连接参数,创建JCoDestination对象的实例。
      这里有一个重要的约定,JCoDestinationManager.getDestination("ECC")方法,会从Eclipse Java项目的根目录,查找ECC.jcodestination文件(文件路径和扩展名不能改变)是否存在,如果存在,从文件的内容中获取连接参数。这是DestinationDataProvider接口的一个默认实现,在开发和测试的时候还是很方便的,但如果在真实项目中使用,安全性和灵活性就不够。后面会介绍解决方法。

    • pingDestination()方法调用JcoDestination对象的ping()方法测试SAP系统的连接。

    • @Test: 使用junit进行测试

    配置文件的生成

    刚才我们手工编辑了ECC.jcodestination文件,对于这个配置文件,因为很多连接参数来自于DestinationDataProvider接口,如果想通过代码来创建配置文件,可以使用如下代码:

    package jco3.demo2;
    
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.Properties;
    import org.junit.Test;
    import com.sap.conn.jco.ext.DestinationDataProvider;
    
    public class DestinationFile
    {
        private Properties setProperties()
        {        
            // logon parameters and other properties
            Properties connProps = new Properties();
            connProps.setProperty(DestinationDataProvider.JCO_ASHOST, "192.168.65.100");
            connProps.setProperty(DestinationDataProvider.JCO_SYSNR, "00");
            connProps.setProperty(DestinationDataProvider.JCO_USER, "STONE");
            connProps.setProperty(DestinationDataProvider.JCO_PASSWD, "xxxxxx");
            connProps.setProperty(DestinationDataProvider.JCO_CLIENT, "001");
            connProps.setProperty(DestinationDataProvider.JCO_LANG, "EN");
    
            return connProps;
        }
    
        private void doCreateFile(String fName, String suffix, Properties props) throws IOException
        {
            /**
             * Write contents of properties into a text file
             * which was named [fName+suffix.jcodestination]
             */
    
            File cfg = new File(fName+"."+suffix);
            if (!cfg.exists()){ // file not exists
                // Create file output stream, not using append mode
                FileOutputStream fOutputStream = new FileOutputStream(cfg, false); 
    
                // store the properties in file output stream
                // and also add comments
                props.store(fOutputStream, "SAP logon parameters:"); 
    
                fOutputStream.close();
            }else{
                throw new RuntimeException("File alreay exists.");
            }
        }
    
        @Test
        public void createConfigFile() throws IOException
        {        
            Properties props = this.setProperties();
            String fileName = "SAP_AS"; // sap application server
    
            // jcodestination suffix is required by JCoDestinationManager
            this.doCreateFile(fileName, "jcodestination", props);
        }
    }

    代码说明:

    • setProperties()方法属性参照DestinationDataProvider类的常量设置Properties的实例。
    • doCreateFile()方法根据需求的文件名,扩展名在Eclipse项目的根文件夹下,创建一个文本文件,文件的内容就是Properties实例的内容。
    • createConfigFile()方法,调用上面的两个方法,创建配置文件。

    更改配置文件名的路径和扩展名

    我们看到,默认情况下,SAP对配置文件的路径和扩展名都不能改变,如果我们想把文件放在任意位置,扩展名也使用其他的扩展名,有没有办法?答案是有,方法是实现DestinationDataProvider接口,并改写(override)getDestinationProperties()方法,然后通过Environment.registerDestinationDataProvider()方法进行注册。

    OK, 一起来看看代码,代码分为三个部分:

    • 第一部分: 创建FileDestinationDataProviderImp类,实现DestinationDataProvider接口
    • 第二部分: 创建FileDestinationDataProvider类,注册FileDestinationDataProviderImp的实例,并提供getDestination()方法供调用
    • 第三部分:调用FileDestinationDataProvider类的getDestination()方法

    第一部分:DestinationDataProvider接口的实现:

    package jco3.demo2;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.util.Properties;
    import com.sap.conn.jco.ext.DestinationDataEventListener;
    import com.sap.conn.jco.ext.DestinationDataProvider;
    
    public class FileDestinationDataProviderImp implements DestinationDataProvider
    {    
        private File dir;
        private String destName; // destination name
        private String suffix;
    
        public void setDestinationFile(File dir, String destName, String suffix)
        {
            this.dir = dir;
            this.destName = destName;
            this.suffix = suffix;
        }
    
        private Properties loadProperties(File dir, String destName, String suffix) throws IOException
        {
            Properties props = null;
    
            // create a file with name: fullName in destDirectory
            File destFile = new File(dir, destName+"."+suffix);
    
            if (destFile.exists()){
                FileInputStream fInputStream = new FileInputStream(destFile);
                props = new Properties();
                props.load(fInputStream);
                fInputStream.close();            
            }else{
                throw new RuntimeException("Destination file does not exist.");
            }    
    
            return props;
        }
    
        @Override
        public Properties getDestinationProperties(String destName)
        {        
            Properties props = null;
    
            try {
                props = this.loadProperties(this.dir, this.destName, this.suffix);
            } catch (IOException e) {            
                e.printStackTrace();
            }        
    
            return props;
        }
    
        @Override
        public void setDestinationDataEventListener(DestinationDataEventListener listener)
        {
            throw new UnsupportedOperationException();
        }
    
        @Override
        public boolean supportsEvents()
        {        
            return false;
        }
    }

    第二部分: 创建FileDestinationDataProvider类,注册FileDestinationDataProviderImp的实例,并且提供getDestination()方法。

    package jco3.demo2;
    
    import java.io.File;
    import com.sap.conn.jco.JCoDestination;
    import com.sap.conn.jco.JCoDestinationManager;
    import com.sap.conn.jco.JCoException;
    import com.sap.conn.jco.ext.Environment;
    
    public class FileDestinationDataProvider
    {    
        public static JCoDestination getDestination() throws JCoException    
        {    
            File directory = new File("."); // current directory;
            String fileName = "SAP_AS";
            String suffix = "txt";
    
            FileDestinationDataProviderImp destDataProvider = new FileDestinationDataProviderImp();
            destDataProvider.setDestinationFile(directory, fileName, suffix);        
            Environment.registerDestinationDataProvider(destDataProvider);
    
            JCoDestination dest = JCoDestinationManager.getDestination(fileName);
    
            return dest;        
        }
    }

    我们看到,getDestination方法中,文件的路径,文件的扩展名,都是我们自己定义的。文件名作为JCoDestinationManager.getDestination方法的destination name。从这里也可可以看到,JCoDestinationManager.getDestination方法从哪里查找连接参数,是依赖于Environment注册的DestinationDataProvider实现

    第三部分:测试代码FileDestinationDataProvidergetDestination方法:

    package jco3.demo2;
    
    import org.junit.Test;
    import com.sap.conn.jco.JCoDestination;
    import com.sap.conn.jco.JCoException;
    
    public class TestFileDestinationProvider
    {
        @Test
        public void pingSAPDestination() throws JCoException
        {
            JCoDestination dest = FileDestinationDataProvider.getDestination();
            dest.ping();
        }
    }

    DestinationDataProvider另一种实现

    记得nco3.0可以将登陆参数写在代码中吗,如果我们也想将连接参数直接写在代码中,怎么做呢?刚才说过了,关键就是实现DestinationDataProvider接口,并改写getDestinationProperties()方法。不多说,上代码。

    第一部分:DestinationDataProvider接口实现

    package jco3.demo3;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    import com.sap.conn.jco.ext.DestinationDataEventListener;
    import com.sap.conn.jco.ext.DestinationDataProvider;
    
    public class DestinationDataProviderImp implements DestinationDataProvider
    {
        /**
         * DestinationDataProvider is an interface
         * We define DestinationDataProviderImp class to implements this interface
         * so that we can define the logon parameters more flexibly
         * not just in xxx.jcodestionation file.
         * 
         * The key point is that we override getDestinationProperties() method
         * Afterwards, instance of DestinationDataProvider should be registered
         * using Environment.registerDestinationDataProvider() method to take effect
         */
    
        @SuppressWarnings("rawtypes")
        private Map provider = new HashMap();
    
        @SuppressWarnings("unchecked")
        public void addDestinationProperties(String destName, Properties props)
        {
            provider.put(destName, props);
        }
    
        @Override
        public Properties getDestinationProperties(String destName)
        {        
            if (destName == null){
                throw new NullPointerException("Destinantion name is empty.");
            }
    
            if (provider.size() == 0){
                throw new IllegalStateException("Data provider is empty.");
            }
    
            return (Properties) provider.get(destName);
        }
    
        @Override
        public void setDestinationDataEventListener(DestinationDataEventListener listener)
        {
            throw new UnsupportedOperationException();
        }
    
        @Override
        public boolean supportsEvents()
        {        
            return false;
        }
    }

    第二部分:创建DestinationProivder类,提供getDestination()方法,注册DestinationDataProviderImp类的实例:

    package jco3.demo3;
    
    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.DestinationDataProvider;
    import com.sap.conn.jco.ext.Environment;
    
    public class DestinationProvider
    {    
        private static Properties setProperties()
        {    
            // logon parameters and other properties
            Properties connProps = new Properties();        
            connProps.setProperty(DestinationDataProvider.JCO_ASHOST, "192.168.65.100");
            connProps.setProperty(DestinationDataProvider.JCO_SYSNR, "00");
            connProps.setProperty(DestinationDataProvider.JCO_USER, "STONE");
            connProps.setProperty(DestinationDataProvider.JCO_PASSWD, "xxxxxx");
            connProps.setProperty(DestinationDataProvider.JCO_CLIENT, "001");
            connProps.setProperty(DestinationDataProvider.JCO_LANG, "EN");
    
            return connProps;        
        }
    
        public static JCoDestination getDestination() throws JCoException
        {
            String destName = "SAP_AS";
    
            Properties props = setProperties();        
            DestinationDataProviderImp destDataProvider = new DestinationDataProviderImp();
            destDataProvider.addDestinationProperties(destName, props);
            Environment.registerDestinationDataProvider(destDataProvider);
    
            JCoDestination dest = JCoDestinationManager.getDestination(destName);
            return dest;        
        }
    }

    第三部分:测试DestinationProvidergetDestination()方法:

    package jco3.demo3;
    
    import org.junit.Test;
    import com.sap.conn.jco.JCoDestination;
    import com.sap.conn.jco.JCoException;
    
    public class TestDestionProvider
    {
        @Test
        public void pingSAPDestination() throws JCoException
        {
            JCoDestination dest = DestinationProvider.getDestination();
            dest.ping();
        }
    }
  • 相关阅读:
    推荐美丽的flash网页MP3音乐播放器
    android混合动画实现
    swift UI专项训练39 用Swift实现摇一摇功能
    The return type is incompatible with JspSourceDependent.getDependants():JasperException问题分析与解决方法
    【翻译自mos文章】注意: ASMB process exiting due to lack of ASM file activity
    表格对象QTableWidget相关常见方法
    python 加密解密
    python报错ordinal not in range(128)
    scp,ssh双机互信操作步骤
    PyQt多窗口调用
  • 原文地址:https://www.cnblogs.com/zfswff/p/5670223.html
Copyright © 2020-2023  润新知