Java连接SAP RFC实现数据抽取的示例详解

 更新时间:2023年08月02日 09:00:58   作者:易样  
这篇文章主要为大家学习介绍了Java如何连接SAP RFC实现数据抽取的功能,文中的示例代码讲解详细,具有一定的参考价值,需要的可以了解下

包管理

首先要连接SAP需要两个包,分别为sapjco3.jar和sapjco3.dll,切记这两个包需要放在同一目录;否则会报错。

我先尝试将这两个包发到私服上,再在pom.xml文件中引入,发现.dll文件下载不了;于是就将这两个包放在根目录sap下,dockerfile构建镜像时将这两个包copy到jdk/lib目录下。

COPY sap/sapjco3.dll /usr/local/jdk-17.0.5/lib/
COPY sap/sapjco3.jar /usr/local/jdk-17.0.5/bin/

功能介绍

  • 连接SAP
  • 入参获取
  • 出参获取
  • 函数列表获取
  • 表名获取
  • 函数执行
  • 执行结果获取

Java连接SAP RFC

public class CheckSnFromSAP {
    private static final String ABAP_AS_POOLED = "ABAP_AS_WITH_POOL";
    public static void main(String[] args) {
        JCoFunction function = null;
        MyDestinationDataProvider destDataProvider = new MyDestinationDataProvider();
        try {
            Properties connectProperties = new Properties();
            connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "xxx");// 服务器
            connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "xx"); // 系统编号
            connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "xxx"); // SAP集团
            connectProperties.setProperty(DestinationDataProvider.JCO_USER, "xxx"); // SAP⽤户名
            connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "xxx"); // 密码
            connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "ZH"); // 登录语⾔:ZH EN
            connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "3"); // 最⼤连接数
            connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10"); // 最⼤连接线程
            // 注册连接参数
            destDataProvider.addDestination(ABAP_AS_POOLED, connectProperties);
            Environment.registerDestinationDataProvider(destDataProvider);
            // 创建一个与SAP系统的连接
            JCoDestination destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED);
            // 调用函数
            function = destination.getRepository().getFunction("funcationName");
            if(null == function) {
                throw new RuntimeException("无此函数");
            }
            // 输入字段
            JCoListMetaData listMetaData = function.getImportParameterList().getListMetaData();
            List<Map<String, String>> inputFields = new ArrayList<>();
            for (int i=0; i< listMetaData.getFieldCount(); i++) {
                Map<String, String> row = new HashMap<>();
                String name = listMetaData.getName(i);
                String type = listMetaData.getTypeAsString(i);
                String sapType = listMetaData.getRecordTypeName(i);
                String description = listMetaData.getDescription(i);
                row.put("name", name);
                row.put("type", type);
                row.put("sapType", sapType);
                row.put("description", description);
                inputFields.add(row);
            }
            // 输出字段
            JCoTable output = function.getTableParameterList().getTable("XXX");
            JCoRecordMetaData recordMetaData = output.getRecordMetaData();
            List<Map<String, String>> outputFields = new ArrayList<>();
            for (int i=0; i< recordMetaData.getFieldCount(); i++) {
                Map<String, String> row = new HashMap<>();
                String name = recordMetaData.getName(i);
                String type = recordMetaData.getTypeAsString(i);
                String sapType = recordMetaData.getRecordTypeName(i);
                String description = recordMetaData.getDescription(i);
                row.put("name", name);
                row.put("type", type);
                row.put("sapType", sapType);
                row.put("description", description);
                outputFields.add(row);
            }
            // 获取所有函数
            function = destination.getRepository().getFunction("RFC_FUNCTION_SEARCH");
                    if(null == function) {
                throw new RuntimeException("无此函数");
            }
            JCoParameterList importParams = function.getImportParameterList();
                    importParams.setValue("FUNCNAME", "*"); // Search for all functions
                    function.execute(destination);
            JCoTable functionTable = function.getTableParameterList().getTable("FUNCTIONS");
            int max = Math.min(functionTable.getNumRows(),500);
                    for (int i = 0; i <max; i++) {
                functionTable.setRow(i);
                String functionName = functionTable.getString("FUNCNAME");
                System.out.println("函数名:"+functionName);
            }
            //获取所有表名
            JCoParameterList tableParameterList = function.getTableParameterList();
            if(tableParameterList!=null){
                for (JCoField jCoField : tableParameterList) {
                    System.out.println("表:" + jCoField.getName());
                }
            }
            // 输⼊参数修改
            JCoParameterList input = function.getImportParameterList();
            input.setValue("I_END", "2017-05-01");
            input.setValue("I_START", "2017-01-01");
//            JCoTable it_matnr = function.getTableParameterList().getTable("XXX");//以表作为请求参数
//            it_matnr.appendRow();
//            it_matnr.setValue("age",18);//设置表值
            //方法执行
            function.execute(destination);
            // 函数执行结果
            JCoTable jcoTable = function.getTableParameterList().getTable("tableName");
            int numRows = jcoTable.getNumRows();//行数为0可以直接return
            for (int i = 0; i < numRows; i++) {
                jcoTable.setRow(i);//设置索引 获取返回表里的数据
                String fieldValue= jcoTable.getString("fieldName");//解析表字段值
                System.out.println(fieldValue);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 取消环境注册
            Environment.unregisterDestinationDataProvider(destDataProvider);
        }
    }
}
/**
 * 实现DestinationDataProvider接口,用于注册连接参数
 */
class MyDestinationDataProvider implements DestinationDataProvider {
    private DestinationDataEventListener eventListener;
    private Map<String, Properties> destinationProperties;
    public MyDestinationDataProvider() {
        destinationProperties = new HashMap<>();
    }
    public void addDestination(String destinationName, Properties properties) {
        destinationProperties.put(destinationName, properties);
    }
    @Override
    public Properties getDestinationProperties(String destinationName) {
        if (destinationProperties.containsKey(destinationName)) {
            return destinationProperties.get(destinationName);
        }
        return null;
    }
    @Override
    public void setDestinationDataEventListener(DestinationDataEventListener eventListener) {
        this.eventListener = eventListener;
    }
    @Override
    public boolean supportsEvents() {
        return true;
    }
}

当然也可以通过创建文件的方式保存连接属性

public class SapConnection {
    private static final String ABAP_AS_POOLED = "ABAP_AS_WITH_POOL";
    static {
        Properties connectProperties = new Properties();
        connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "xxx");// 服务器
        connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "xx"); // 系统编号
        connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "xxx"); // SAP集团
        connectProperties.setProperty(DestinationDataProvider.JCO_USER, "xxx"); // SAP⽤户名
        connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "xxx"); // 密码
        connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "ZH"); // 登录语⾔:ZH EN
        connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "3"); // 最⼤连接数
        connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10"); // 最⼤连接线程
        createDataFile(ABAP_AS_POOLED, "jcoDestination", connectProperties);
    }
    /**
     * 创建sap接口属性文件
     * @param name
     * @param suffix
     * @param properties
     */
    private static void createDataFile(String name, String suffix, Properties properties) {
        File cfg = new File(name + "." + suffix);
        if (cfg.exists()) {
            cfg.deleteOnExit();
        }
        try {
            FileOutputStream fos = new FileOutputStream(cfg, false);
            properties.store(fos, "for tests only !");
            fos.close();
        } catch (Exception e) {
            System.out.println("Create Data file fault, error msg: " + e.toString());
            throw new RuntimeException("Unable to create the destination file " + cfg.getName(), e);
        }
    }
    /**
     * 获取sap连接
     * @return
     */
    public static JCoDestination connect() {
        JCoDestination destination = null;
        try {
            destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED);
        } catch (JCoException e) {
            System.out.println("Connect SAP fault, error msg: " + e.toString());
        }
        return destination;
    }
}

在使用场景中,我遇到了这样一种情况:

SpringBoot服务已启动,sap函数入参两个,上面代码获取sap函数入参两个; 我将sap函数入参改为三个后,上面代码获取还是两个,重启服务后获取就是正确的三个了。

经过研究发现,JCoDestinationManager.getDestination(ABAP_AS_POOLED);会缓存destination连接,每次都是先从缓存中取

RfcDestination destination = (RfcDestination)this.destinations.get(destinationName);

查看destination.getRepository()会发现storage字段缓存了function等信息;解决办法是:

// 清除缓存
destination.getRepository().clear();

清除缓存后,每次会获取新的内容。

到此这篇关于Java连接SAP RFC实现数据抽取的示例详解的文章就介绍到这了,更多相关Java数据抽取内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于idea2020.3升级lombok不能使用的问题

    关于idea2020.3升级lombok不能使用的问题

    这篇文章主要介绍了关于idea2020.3升级lombok不能使用的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • 基于Java实现音乐播放器的示例代码

    基于Java实现音乐播放器的示例代码

    这篇文章主要为大家详细介绍了如何利用Java编写一个简单的音乐播放器,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2023-07-07
  • springboot基于docsify 实现随身文档

    springboot基于docsify 实现随身文档

    这篇文章主要介绍了springboot基于docsify实现随身文档的相关资料,需要的朋友可以参考下
    2022-09-09
  • Java实现双链表的示例代码

    Java实现双链表的示例代码

    双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。本文将用Java语言实现双链表,需要的可以参考一下
    2022-09-09
  • MyBatis进阶教程之动态SQL、关联查询与缓存

    MyBatis进阶教程之动态SQL、关联查询与缓存

    在Java持久层技术体系中,MyBatis凭借其灵活的SQL映射和强大的动态SQL能力,成为企业级应用开发的首选框架,这篇文章主要介绍了MyBatis进阶教程之动态SQL、关联查询与缓存的相关资料,需要的朋友可以参考下
    2025-11-11
  • SpringBoot项目打成War包部署的方法步骤

    SpringBoot项目打成War包部署的方法步骤

    这篇文章主要介绍了springboot项目如何打war包流程的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • IDEA创建Maven项目后报错不出现src文件夹的情况解决

    IDEA创建Maven项目后报错不出现src文件夹的情况解决

    最近刚开始学习maven,正准备使用idea创建一个maven项目练手,却发现自己创建的maven项目始终没有src目录,下面这篇文章主要给大家介绍了关于IDEA创建Maven项目后报错不出现src文件夹的情况解决,需要的朋友可以参考下
    2023-05-05
  • Java分析Lambda表达式Stream流合并分组内对象数据合并

    Java分析Lambda表达式Stream流合并分组内对象数据合并

    Lambda表达式,基于Lambda所带来的函数式编程,又引入了一个全新的Stream概念,用于解决集合类库既有的弊端,Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑
    2022-12-12
  • Java基础之不简单的数组

    Java基础之不简单的数组

    数组(Array)是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量
    2021-09-09
  • Java使用策略模式实现聚石塔接口调用的问题

    Java使用策略模式实现聚石塔接口调用的问题

    这篇文章主要介绍了Java使用策略模式实现聚石塔接口调用,为了避免多重判断,而且有更好的扩展性,首选了策略模式来实现,具体解决方法跟随小编一起看看吧
    2021-12-12

最新评论