使用 JCo3 库实现 Java 与 SAP RFC 函数对接的详细代码指南

Java 代码使用 JCo3 对接 SAP RFC 函数

  • 1、环境配置
  • 1.1、Windows 项目部署环境配置
  • 1.1.1、sapjco3.dll 需要与 sapjco3.jar 在同一目录
  • 1.1.2、设置系统环境变量
  • 1.1.3、项目部署环境配置
  • 1.2、Linux 项目部署环境配置
  • 1.2.1、放置 libsapjco3.so
  • 1.2.2、给文件授权
  • 1.3、部署异常问题
  • 1.3.1、 Can't load IA 64-bit .dll on a AMD 64-bit platform
  • 1.3.2、java.lang.UnsatisfiedLinkError: no sapjco3 in java.library.path
  • 1.4、开发环境配置
  • 1.4.1、将 sapjco3.jar 加入本地 maven 库
  • 2、Java 代码
  • 2.1、公共代码
  • 2.1.1、键值对参数 KeyValueParam
  • 2.1.2、Structure 参数 ObjectParam
  • 2.1.3、Table 类型参数 ArrayListParam
  • 2.1.4、请求体 Request
  • 2.1.5、响应体 Response
  • 2.1.6、SAP 连接配置 SapConfig
  • 2.2、基于 JCo3 + sapjco-spring-boot-starter
  • 2.2.1、依赖
  • 2.2.2、RFC 函数执行器 RfcExecutor
  • 2.2.3、测试代码
  • 2.3、基于 JCo3
  • 2.3.1、依赖
  • 2.3.2、创建连接文件
  • 2.3.3、RFC 函数执行器 RfcExecutor
  • 2.3.4、测试代码
  • 2.3.4.1、无状态连接测试
  • 2.3.4.2、有状态连接测试
  • 2.3.5、将 RFC 函数的入参/出参导出为 Excel 文件
  • 2.3.5.1、POI 实体类 SheetData
  • 2.3.5.2、POI 写文件
  • 2.3.5.3、将 RFC 函数的入参/出参导出为 Excel 文件
  • 2.4、基于 JCo3 多线程调用 RFC 函数
  • 2.4.1、多步骤任务接口
  • 2.4.2、无状态多步骤作业
  • 2.4.3、有状态多步骤作业
  • 2.4.4、会话引用线程
  • 2.4.5、测试代码
  • 1、环境配置

    JCo3 依赖:官方下载

    1.1、Windows 项目部署环境配置

    1.1.1、sapjco3.dll 需要与 sapjco3.jar 在同一目录

    1.1.2、设置系统环境变量

    新建环境变量

    变量名: JAVA_SAPJCO

    变量值: D:\Program Files\sapjco3

    将新建的 JAVA_SAPJCO 环境变量加入系统环境变量 Path变量集合中。

    %JAVA_SAPJCO%\sapjco3.jar

    打开cmd,验证是否配置成功,出现弹窗即为配置成功。

    java -jar "D:\Program Files\sapjco3\sapjco3.jar"
    

    1.1.3、项目部署环境配置

  • 32位系统:将 sapjco3.dll 加入到 <JDK_HOME>/jre/bin 目录下
  • 64位系统:将 sapjco3.dll 加入到 <JDK_HOME>/jre/bin 目录下
  • 1.2、Linux 项目部署环境配置

    1.2.1、放置 libsapjco3.so

    系统版本 说明
    Linux 32位 将 libsapjco3.so 文件放到 <JDK_HOME>/jre/lib/i386/server
    Linux 64位 将 libsapjco3.so 文件放到 <JDK_HOME>/jre/lib/amd64

    执行 echo $JAVA_HOME 后输出 jdk 部署目录,然后切换到表格中指定目录将 libsapjco3.so 文件拷贝进去。如果未配置 java 环境变量,就执行 which java 命令,再找到对应的目录。

    1.2.2、给文件授权

    如上图所示,文件所属用户应该是 10143,并且缺少执行权限,因此在当前目录下执行以下命令更换文件的所属用户

    chown 10143 libsapjco3.so
    chgrp 10143 libsapjco3.so
    

    再执行以下命令赋予执行权限

    chmod 755 libsapjco3.so
    

    1.3、部署异常问题

    1.3.1、 Can’t load IA 64-bit .dll on a AMD 64-bit platform

    项目编译及运行,根据自己的操作系统版本选择对应的 sapjco3 包。32位和64位不兼容

    1.3.2、java.lang.UnsatisfiedLinkError: no sapjco3 in java.library.path

    是因为没有找到 sapjco3.dll 这个库的路径,安装了JDK的环境中,这个库默认的位置不是在 system32 下,而是在 JDK/JRE/BIN 下面

    1.4、开发环境配置

    1.4.1、将 sapjco3.jar 加入本地 maven 库

    mvn install:install-file -DgroupId=com.sap.jco3 -DartifactId=sapjco -Dversion=3.0.16 -Dpackaging=jar -Dfile="D:\\Program Files\\sapjco3\\sapjco3.jar"
    

    然后用以下方法在 pom 添加依赖:

    <dependency>
        <groupId>com.sap.jco3</groupId>
        <artifactId>sapjco</artifactId>
        <version>3.0.16</version>
    </dependency>
    

    2、Java 代码

    2.1、公共代码

    2.1.1、键值对参数 KeyValueParam

    /**
     * 键值对参数
     *
     * @author wxhnyfy
     */
    public class KeyValueParam {
        private String name;
        private String value;
    
        public KeyValueParam(String name, String value) {
            this.name = name;
            this.value = value;
        }
    
        public KeyValueParam() {
        }
    
        public String getName() {
            return name;
        }
    
        public String getValue() {
            return value;
        }
    }
    

    2.1.2、Structure 参数 ObjectParam

    /**
     * Structure结构体参数
     *
     * @author wxhnyfy
     */
    public class ObjectParam {
        private String name;
        private Map<String, String> value;
    
        public ObjectParam(String name, Map<String, String> value) {
            this.name = name;
            this.value = value;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Map<String, String> getValue() {
            return value;
        }
    
        public void setValue(Map<String, String> value) {
            this.value = value;
        }
    }
    

    2.1.3、Table 类型参数 ArrayListParam

    /**
     * Table表类型参数
     *
     * @author wxhnyfy
     */
    public class ArrayListParam {
        private String name;
        private List<Map<String, String>> value;
    
        public ArrayListParam(String name, List<Map<String, String>> value) {
            this.name = name;
            this.value = value;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<Map<String, String>> getValue() {
            return value;
        }
    
        public void setValue(List<Map<String, String>> value) {
            this.value = value;
        }
    }
    

    2.1.4、请求体 Request

    /**
     * 请求体
     * 
     * @author chenwc
     */
    public class Request {
        //RFC函数名
        private String functionName;
    
        //键值对参数
        private List<KeyValueParam> keyValueParams;
    
        //structure结构体参数
        private List<ObjectParam> objectParams;
    
        //table表参数
        private List<ArrayListParam> arrayListParams;
    
        public String getFunctionName() {
            return functionName;
        }
    
        public void setFunctionName(String functionName) {
            this.functionName = functionName;
        }
    
        public List<KeyValueParam> getKeyValueParams() {
            return keyValueParams;
        }
    
        public void setKeyValueParams(List<KeyValueParam> keyValueParams) {
            this.keyValueParams = keyValueParams;
        }
    
        public List<ObjectParam> getObjectParams() {
            return objectParams;
        }
    
        public void setObjectParams(List<ObjectParam> objectParams) {
            this.objectParams = objectParams;
        }
    
        public List<ArrayListParam> getArrayListParams() {
            return arrayListParams;
        }
    
        public void setArrayListParams(List<ArrayListParam> arrayListParams) {
            this.arrayListParams = arrayListParams;
        }
    }
    

    2.1.5、响应体 Response

    /**
     * 响应体
     * 
     * @author wxhnyfy
     */
    public class Response {
        /**
         * json参数返回,返回所有类型
         */
        private JSONObject exportJson;
    
        /**
         * 异常信息
         */
        private JSONObject exceptionJson;
    
        public JSONObject getExportJson() {
            return exportJson;
        }
    
        public void setExportJson(JSONObject exportJson) {
            this.exportJson = exportJson;
        }
    
        public JSONObject getExceptionJson() {
            return exceptionJson;
        }
    
        public void setExceptionJson(JSONObject exceptionJson) {
            this.exceptionJson = exceptionJson;
        }
    }
    

    2.1.6、SAP 连接配置 SapConfig

    /**
     * SAP 连接配置
     * 
     * @author wxhnyfy
     */
    public class SapConfig {
        // 服务器
        private String ashost;
        // 系统编号
        private String sysnr;
        // SAP集团
        private String client;
        // SAP用户名
        private String user;
        // 密码
        private String password;
        // 登录语言
        private String lang;
        //客户端名称
        private String clientname;
        //路由
        private String router;
    
        public SapConfig(String ashost, String sysnr, String client, String user, String password, String lang, String clientname) {
            this.ashost = ashost;
            this.sysnr = sysnr;
            this.client = client;
            this.user = user;
            this.password = password;
            this.lang = lang;
            this.clientname = clientname;
        }
    
        public String getRouter() {
            return router;
        }
    
        public void setRouter(String router) {
            this.router = router;
        }
    
        public String getAshost() {
            return ashost;
        }
    
        public void setAshost(String ashost) {
            this.ashost = ashost;
        }
    
        public String getSysnr() {
            return sysnr;
        }
    
        public void setSysnr(String sysnr) {
            this.sysnr = sysnr;
        }
    
        public String getClient() {
            return client;
        }
    
        public void setClient(String client) {
            this.client = client;
        }
    
        public String getUser() {
            return user;
        }
    
        public void setUser(String user) {
            this.user = user;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public String getLang() {
            return lang;
        }
    
        public void setLang(String lang) {
            this.lang = lang;
        }
    
        public String getClientname() {
            return clientname;
        }
    
        public void setClientname(String clientname) {
            this.clientname = clientname;
        }
    }
    

    2.2、基于 JCo3 + sapjco-spring-boot-starter

    2.2.1、依赖

    <dependency>
        <groupId>com.sap.jco3</groupId>
        <artifactId>sapjco</artifactId>
        <version>3.0.16</version>
    </dependency>
    <dependency>
        <groupId>com.github.virtualcry</groupId>
        <artifactId>sapjco-spring-boot-starter</artifactId>
        <version>3.1.4</version>
        <exclusions>
            <exclusion>
                <groupId>com.github.virtualcry</groupId>
                <artifactId>sapjco-spring-boot-starter-autoconfigure</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    

    2.2.2、RFC 函数执行器 RfcExecutor

    import cn.gitlab.virtualcry.sapjco.beans.factory.DefaultJCoConnectionFactory;
    import cn.gitlab.virtualcry.sapjco.beans.factory.JCoConnectionFactory;
    import cn.gitlab.virtualcry.sapjco.beans.factory.JCoConnectionFactoryProvider;
    import cn.gitlab.virtualcry.sapjco.client.JCoClient;
    import cn.gitlab.virtualcry.sapjco.client.handler.FunctionRequestHandler;
    import cn.gitlab.virtualcry.sapjco.config.JCoSettings;
    import cn.gitlab.virtualcry.sapjco.util.ObjectUtils;
    import cn.gitlab.virtualcry.sapjco.util.data.JCoDataUtils;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * RFC 函数执行器
     * 
     * @author wxhnyfy
     */
    public class RfcExecutor {
    
        /**
         * 调用 sap rfc
         *
         * @param sapConfig       sap配置
         * @param sapParameterMap 传入参数
         * @param rfc             rfc名称
         * @return 返回参数
         */
        public static Map<String, Object> callRfc(SapConfig sapConfig, Map<String, Object> sapParameterMap, String rfc) {
            JCoSettings jCoSettings = JCoSettings.builder()
                    //服务器
                    .ashost(sapConfig.getAshost())
                    //系统编号
                    .sysnr(sapConfig.getSysnr())
                    //SAP集团
                    .client(sapConfig.getClient())
                    //用户名
                    .user(sapConfig.getUser())
                    //密码
                    .password(sapConfig.getPassword())
                    //登录语言
                    .language(sapConfig.getLang())
                    .build();
    
            JCoConnectionFactory jCoConnectionFactory = null;
            JCoClient jCoClient = null;
            Map<String, Object> result = new HashMap<>();
    
            try {
                // 获取连接工厂
                jCoConnectionFactory = JCoConnectionFactoryProvider.getSingleton().getIfAvailable(DefaultJCoConnectionFactory::new);
                // 获取客户端连接
                jCoClient = jCoConnectionFactory.getOrCreateClient(sapConfig.getClientname(), jCoSettings);
                //设置传参,其中importParameter只作为输入参数,tableParameter和changingParameter可输入也可输出
                FunctionRequestHandler requestHandler = (importParameter, tableParameter, changingParameter) -> {
                    JCoDataUtils.setJCoParameterListValue(tableParameter, sapParameterMap);
                    JCoDataUtils.setJCoParameterListValue(importParameter, sapParameterMap);
                    JCoDataUtils.setJCoParameterListValue(changingParameter, sapParameterMap);
                };
                result = jCoClient.invokeSapFunc(rfc, requestHandler);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //关闭连接
                try {
                    if (!ObjectUtils.isEmpty(jCoClient)) {
                        jCoClient.release();
                    }
                    if (!ObjectUtils.isEmpty(jCoConnectionFactory)) {
                        jCoConnectionFactory.releaseClients();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return result;
        }
    }
    

    2.2.3、测试代码

    public class TestMain {
    
        private static final Logger logger = LoggerFactory.getLogger(TestMain.class);
    
        public static void main(String[] args) {
            //sapjco-spring-boot-starter必须要注册环境,否则连不上SAP服务器
            JCoDataProvider.registerInEnvironment();
            SapConfig config = new SapConfig("服务器IP",
                    "系统编号", "SAP集团号", "用户名", "密码",
                    "登录语言", "客户端名称");
    
    		//入参
            Map<String, Object> sapParameterMap = new HashMap<>();
            sapParameterMap.put("key1", "value1");
            sapParameterMap.put("key2", "value2");
            sapParameterMap.put("key3", "value3");
            sapParameterMap.put("key4", "value4");
            sapParameterMap.put("key5", "value5");
    
            Map<String, Object> result = RfcExecutor.callRfc(config, sapParameterMap, "RFC函数名");
            Object returnValue = result.get("returnValue");
            byte[] bytes = (byte[]) returnValue;
            logger.info("bytes:{}", bytes.length);
            logger.info("returnValue: {}", new String(bytes));
            List<Map<String, String>> ET_RETURN = (List<Map<String, String>>) result.get("ET_RETURN");
            logger.info("result:{}", JSON.toJSONString(result));
        }
    }
    

    2.3、基于 JCo3

    2.3.1、依赖

    <dependency>
        <groupId>com.sap.jco3</groupId>
        <artifactId>sapjco</artifactId>
        <version>3.0.16</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.2.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.2.2</version>
        <exclusions>
            <exclusion>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>2.12.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.11.0</version>
    </dependency>
    

    2.3.2、创建连接文件

    import com.sap.conn.jco.JCoDestination;
    import com.sap.conn.jco.JCoDestinationManager;
    import com.sap.conn.jco.ext.DestinationDataProvider;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.util.Properties;
    
    /**
     * 创建连接文件
     * 
     * @author wxhnyfy
     */
    public class CreateDestination {
    
        public static final String DESTINATION_NAME1 = "SAP客户端";
        public static final String ABAP_AS_WITH_POOL = "SAP客户端(连接池)";
    
        static {
            Properties connectProperties = new Properties();
            connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "服务器IP");
            connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "SAP系统编号");
            connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "集团编号");
            connectProperties.setProperty(DestinationDataProvider.JCO_USER, "用户名");
            connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "密码");
            connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "登录语言");
            connectProperties.setProperty(DestinationDataProvider.JCO_SAPROUTER, "路由");
            createDataFile(DESTINATION_NAME1, "jcoDestination", connectProperties);
            // 连接池属性
            connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "3");
            connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10");
            createDataFile(ABAP_AS_WITH_POOL, "jcoDestination", connectProperties);
        }
    
        /**
         * 获取连接
         *
         * @return JCoDestination
         */
        public static JCoDestination getDestination() {
            JCoDestination destination = null;
            try {
                destination = JCoDestinationManager.getDestination(DESTINATION_NAME1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return destination;
        }
    
        /**
         * 获取连接(使用连接池)
         *
         * @return JCoDestination
         */
        public static JCoDestination getDestinationUsingPool() {
            JCoDestination destination = null;
            try {
                destination = JCoDestinationManager.getDestination(ABAP_AS_WITH_POOL);
                destination.ping();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return destination;
        }
    
        /**
         * 创建连接文件
         *
         * @param name       文件名
         * @param suffix     后缀
         * @param properties 属性
         */
        static void createDataFile(String name, String suffix, Properties properties) {
            File cfg = new File(name + "." + suffix);
            cfg.deleteOnExit();
            if (!cfg.exists()) {
                try {
                    FileOutputStream fos = new FileOutputStream(cfg, false);
                    properties.store(fos, "for tests only !");
                    fos.close();
                } catch (Exception e) {
                    throw new RuntimeException("无法创建 destination 文件 " + cfg.getName(), e);
                }
            }
        }
    }
    

    2.3.3、RFC 函数执行器 RfcExecutor

    import com.sap.conn.jco.*;
    import org.apache.commons.codec.binary.Hex;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.*;
    import java.util.stream.Collectors;
    
    /**
     * RFC 函数执行器
     *
     * @author wxhnyfy
     */
    public class RfcExecutor {
    
        private static final Logger logger = LoggerFactory.getLogger(RfcExecutor.class);
    
        /**
         * 线程安全的 SimpleDateFormat
         */
        private static final ThreadLocal<DateFormat> THREAD_LOCAL = new ThreadLocal<>();
    
        /**
         * 获取 DateFormat
         *
         * @param pattern 格式化
         * @return DateFormat
         */
        public static DateFormat getDateFormat(String pattern) {
            DateFormat df = THREAD_LOCAL.get();
            if (df == null) {
                df = new SimpleDateFormat(pattern);
            }
            THREAD_LOCAL.set(df);
            return df;
        }
    
        /**
         * 无状态执行,执行一次RFC函数连接一次
         *
         * @param request     请求
         * @param destination 目标
         * @return 响应
         */
        public static Response statelessExecute(Request request, JCoDestination destination) {
            logger.info("开始连接...");
            Response response = new Response();
            try {
                // 调用SAP的sapRequestContent.getFuntionName()方法
                JCoFunction function = destination.getRepository().getFunction(request.getFunctionName());
                if (null == function) {
                    logger.error("SAP没有名称为:{} 的RFC函数!", request.getFunctionName());
                    return response;
                }
                logger.info("连接成功!");
                response = exec(request, function, destination);
            } catch (JCoException e) {
                logger.info("SAP调用RFC函数失败, 错误信息:" + e.getMessage());
                e.printStackTrace();
            }
            return response;
        }
    
        /**
         * 有状态执行,连接后不断开连接执行多个RFC函数
         *
         * @param requestList 请求(有顺序的列表)
         * @param destination 目标
         * @return 响应
         */
        public static Map<String, Response> statefulExecute(LinkedList<Request> requestList, JCoDestination destination) {
            logger.info("开始连接...");
            Map<String, Response> responseMap = new HashMap<>();
            try {
                JCoContext.begin(destination);
                for (int kk = 0; kk < requestList.size(); kk++) {
                    Request request = requestList.get(kk);
                    logger.info("开始执行第{}个RFC函数:{}", kk + 1, request.getFunctionName());
                    Response response = new Response();
                    JCoFunction function = destination.getRepository().getFunction(request.getFunctionName());
                    if (null == function) {
                        logger.error("SAP没有名称为:{} 的RFC函数!", request.getFunctionName());
                        responseMap.put(request.getFunctionName(), response);
                        continue;
                    }
                    logger.info("连接成功!");
                    response = exec(request, function, destination);
                    responseMap.put(request.getFunctionName(), response);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    JCoContext.end(destination);
                } catch (JCoException e) {
                    e.printStackTrace();
                }
            }
            return responseMap;
        }
    
        /**
         * 执行RFC函数
         *
         * @param request     请求
         * @param function    RFC函数
         * @param destination 目标
         * @return 响应
         */
        private synchronized static Response exec(Request request, JCoFunction function, JCoDestination destination) {
            Response response = new Response();
            try {
                //输入参数
                if (null != function.getImportParameterList()) {
                    setJCoParameterListValue(function.getImportParameterList(), request);
                }
                if (null != function.getTableParameterList()) {
                    setJCoParameterListValue(function.getTableParameterList(), request);
                }
                if (null != function.getChangingParameterList()) {
                    setJCoParameterListValue(function.getChangingParameterList(), request);
                }
                function.execute(destination);
                //输出参数
                JSONObject exportJson = new JSONObject();
                if (null != function.getExportParameterList()) {
                    getJCoParameterListValue(function.getExportParameterList(), exportJson);
                }
                if (null != function.getTableParameterList()) {
                    getJCoParameterListValue(function.getTableParameterList(), exportJson);
                }
                response.setExportJson(exportJson);
                JSONObject exceptionJson = new JSONObject();
                if (null != function.getExceptionList()) {
                    List<AbapException> exceptionList = Arrays.stream(function.getExceptionList()).collect(Collectors.toList());
                    exceptionList.forEach(exception -> exceptionJson.put(exception.getKey(), exception.getMessage()));
                }
                response.setExceptionJson(exceptionJson);
            } catch (JCoException e) {
                e.printStackTrace();
            }
            return response;
        }
    
        /**
         * 设置JCoParameterList的值
         *
         * @param parameterList 参数列表
         * @param request       参数
         */
        public static void setJCoParameterListValue(JCoParameterList parameterList, Request request) {
            if (parameterList == null || request == null) {
                return;
            }
            JCoFieldIterator fieldIterator = parameterList.getFieldIterator();
            while (fieldIterator.hasNextField()) {
                JCoField field = fieldIterator.nextField();
                if (field.getType() == JCoMetaData.TYPE_TABLE) {
                    setJCoFieldValue(field, request.getArrayListParams());
                } else if (field.getType() == JCoMetaData.TYPE_STRUCTURE) {
                    setJCoFieldValue(field, request.getObjectParams());
                } else {
                    setJCoFieldValue(field, request.getKeyValueParams());
                }
            }
        }
    
        /**
         * 设置JCoField的值
         *
         * @param field     JCoField
         * @param parameter 参数
         */
        public static void setJCoFieldValue(JCoField field, Object parameter) {
            List<Object> list = parameter instanceof List ? (List) parameter : new ArrayList<>();
            for (Object obj : list) {
                if (obj instanceof KeyValueParam) {
                    KeyValueParam keyValueParam = (KeyValueParam) obj;
                    if (field.getName().equals(keyValueParam.getName())) {
                        field.setValue(keyValueParam.getValue());
                    }
                } else if (obj instanceof ObjectParam) {
                    ObjectParam objectParam = (ObjectParam) obj;
                    if (field.getName().equals(objectParam.getName())) {
                        JCoStructure inStructure = field.getStructure();
                        Map<String, String> value = objectParam.getValue();
                        for (Map.Entry<String, String> entry : value.entrySet()) {
                            inStructure.setValue(entry.getKey(), entry.getValue());
                        }
                    }
                } else if (obj instanceof ArrayListParam) {
                    ArrayListParam arrayListParam = (ArrayListParam) obj;
                    if (field.getName().equals(arrayListParam.getName())) {
                        JCoTable inTable = field.getTable();
                        List<Map<String, String>> value = arrayListParam.getValue();
                        for (Map<String, String> map : value) {
                            inTable.appendRow();
                            for (Map.Entry<String, String> entry : map.entrySet()) {
                                logger.info("key:{}, value:{}", entry.getKey(), entry.getValue());
                                inTable.setValue(entry.getKey(), entry.getValue());
                            }
                        }
                    }
                }
            }
        }
    
        /**
         * 获取JCoParameterList的值
         *
         * @param parameterList 参数列表
         * @param exportJson    导出的JSON
         */
        public static void getJCoParameterListValue(JCoParameterList parameterList, JSONObject exportJson) {
            if (null == parameterList) {
                return;
            }
            //遍历参数
            JCoFieldIterator fieldIterator = parameterList.getFieldIterator();
            while (fieldIterator.hasNextField()) {
                //获取参数
                JCoField field = fieldIterator.nextField();
                //判断是否为Table
                if (field.isTable()) {
                    JCoTable jCoTable = field.getTable();
                    JSONArray tempTable = new JSONArray();
                    //遍历Table
                    for (int i = 0; i < jCoTable.getNumRows(); i++) {
                        JSONObject tempRow = new JSONObject();
                        jCoTable.setRow(i);
                        JCoRecordFieldIterator iterator = jCoTable.getRecordFieldIterator();
                        //遍历Table行
                        while (iterator.hasNextField()) {
                            JCoField field1 = iterator.nextField();
                            tempRow.put(field1.getName(), getJCoFieldValue(field1));
                        }
                        tempTable.add(tempRow);
                    }
                    exportJson.put(field.getName(), tempTable);
                }
                //判断是否为Structure
                else if (field.isStructure()) {
                    JCoStructure jCoStructure = field.getStructure();
                    JSONObject tempStruc = new JSONObject();
                    //遍历Structure
                    JCoRecordFieldIterator iterator = jCoStructure.getRecordFieldIterator();
                    while (iterator.hasNextField()) {
                        JCoField field1 = iterator.nextField();
                        tempStruc.put(field1.getName(), getJCoFieldValue(field1));
                    }
                    exportJson.put(field.getName(), tempStruc);
                }
                //普通参数
                else {
                    exportJson.put(field.getName(), getJCoFieldValue(field));
                }
            }
        }
    
        /**
         * 获取JCoField的值
         *
         * @param field JCoField
         * @return Object
         */
        public static Object getJCoFieldValue(JCoField field) {
            Object value;
            switch (field.getType()) {
                case JCoMetaData.TYPE_INT1:
                case JCoMetaData.TYPE_INT2:
                case JCoMetaData.TYPE_INT:
                    value = field.getInt();
                    break;
                case JCoMetaData.TYPE_BCD:
                case JCoMetaData.TYPE_DECF16:
                case JCoMetaData.TYPE_DECF34:
                    value = field.getBigDecimal();
                    break;
                case JCoMetaData.TYPE_DATE:
                    value = field.getDate();
                    if (null != value) {
                        //日期类型的值需要转换成yyyy-MM-dd格式
                        value = getDateFormat("yyyy-MM-dd").format((Date) value);
                    }
                    break;
                case JCoMetaData.TYPE_TIME:
                    value = field.getTime();
                    if (null != value) {
                        //时间类型的值需要转换成HH:mm:ss格式
                        value = getDateFormat("HH:mm:ss").format((Date) value);
                    }
                    break;
                case JCoMetaData.TYPE_FLOAT:
                    value = field.getFloat();
                    break;
                case JCoMetaData.TYPE_BYTE:
                case JCoMetaData.TYPE_XSTRING:
                    value = field.getByteArray();
                    if (null != value && ((byte[]) value).length > 0) {
                        //获取到的是字节数组,需要转换成16进制字符串
                        value = new String(Hex.encodeHex((byte[]) value)).toUpperCase();
                    }
                    break;
                case JCoMetaData.TYPE_CHAR:
                case JCoMetaData.TYPE_NUM:
                case JCoMetaData.TYPE_STRING:
                default:
                    value = field.getString();
                    break;
            }
            return value;
        }
    
    }
    

    2.3.4、测试代码

    2.3.4.1、无状态连接测试
    import com.sap.conn.jco.JCoDestination;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 无状态连接测试
     *
     * @author wxhnyfy
     */
    public class StatelessTest {
    
        private static final Logger logger = LoggerFactory.getLogger(StatelessTest.class);
    
        public static void main(String[] args) {
    
            JCoDestination destination = CreateDestination.getDestination();
            Request request = new Request();
            KeyValueParam kp1 = new KeyValueParam("key1", "value1");
            KeyValueParam kp2 = new KeyValueParam("key2", "value2");
            List<KeyValueParam> params = new ArrayList<>();
            params.add(kp1);
            params.add(kp2);
            request.setFunctionName("function1");
            request.setKeyValueParams(params);
            Response response = RfcExecutor.statelessExecute(request, destination);
            logger.info("返回结果:{}", response.getExportJson());
        }
    }
    
    2.3.4.2、有状态连接测试
    import com.sap.conn.jco.JCoDestination;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 有状态连接测试
     *
     * @author wxhnyfy
     */
    public class StatefulTest {
    
        private static final Logger logger = LoggerFactory.getLogger(StatefulTest.class);
    
        public static void main(String[] args) {
    
            JCoDestination destination = CreateDestination.getDestination();
    
            LinkedList<Request> requestList = new LinkedList<>();
    
            Request request = new Request();
            KeyValueParam kp1 = new KeyValueParam("key1", "value1");
            KeyValueParam kp2 = new KeyValueParam("key2", "value2");
            List<KeyValueParam> params = new ArrayList<>();
            params.add(kp1);
            params.add(kp2);
            request.setFunctionName("function1");
            request.setKeyValueParams(params);
    
            Request request2 = new Request();
            KeyValueParam kp3 = new KeyValueParam("key3", "value3");
            KeyValueParam kp4 = new KeyValueParam("key4", "value4");
            KeyValueParam kp5 = new KeyValueParam("key5", "value5");
            KeyValueParam kp6 = new KeyValueParam("key6", "value6");
            KeyValueParam kp7 = new KeyValueParam("key7", "value7");
            List<KeyValueParam> params2 = new ArrayList<>();
            params2.add(kp3);
            params2.add(kp4);
            params2.add(kp5);
            params2.add(kp6);
            params2.add(kp7);
            request2.setFunctionName("function2");
            request2.setKeyValueParams(params2);
    
            requestList.add(request);
            requestList.add(request2);
    
            Map<String, Response> responseList = RfcExecutor.statefulExecute(requestList, destination);
            logger.info("function1 返回结果:{}", responseList.get("function1").getExportJson());
            logger.info("function2 返回结果:{}", responseList.get("function2").getExportJson());
        }
    }
    

    2.3.5、将 RFC 函数的入参/出参导出为 Excel 文件

    2.3.5.1、POI 实体类 SheetData
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    /**
     * POI 实体类
     * 
     * @author wxhnyfy
     */
    public class SheetData {
        /**
         * 表头
         */
        private List<String> header = new ArrayList<>();
    
        /**
         * 表格数据
         */
        private List<Map<String, Object>> sheetDataList = new ArrayList<>();
    
        public SheetData() {
        }
    
        public SheetData(List<String> header, List<Map<String, Object>> sheetDataList) {
            this.header = header;
            this.sheetDataList = sheetDataList;
        }
    
        public List<String> getHeader() {
            return header;
        }
    
        public void setHeader(List<String> header) {
            this.header = header;
        }
    
        public List<Map<String, Object>> getSheetDataList() {
            return sheetDataList;
        }
    
        public void setSheetDataList(List<Map<String, Object>> sheetDataList) {
            this.sheetDataList = sheetDataList;
        }
    }
    
    2.3.5.2、POI 写文件
    import org.apache.commons.io.FileUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.poi.ss.usermodel.CellStyle;
    import org.apache.poi.ss.usermodel.Font;
    import org.apache.poi.ss.usermodel.HorizontalAlignment;
    import org.apache.poi.ss.usermodel.VerticalAlignment;
    import org.apache.poi.ss.util.CellRangeAddress;
    import org.apache.poi.xssf.usermodel.XSSFCell;
    import org.apache.poi.xssf.usermodel.XSSFRow;
    import org.apache.poi.xssf.usermodel.XSSFSheet;
    import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 写文件
     *
     * @author wxhnyfy
     */
    public class WriteExcelFile {
    
        private static final Logger log = LoggerFactory.getLogger(WriteExcelFile.class);
    
        /**
         * 写入Excel文件
         *
         * @param excelFile 待写入文件路径
         * @param sheetName sheet页签名称
         * @param sheetData 待写入数据
         */
        public static void writeFile(File excelFile, String sheetName, SheetData sheetData) {
    
            long start = System.currentTimeMillis();
            try {
                FileUtils.forceMkdirParent(excelFile);
                FileUtils.touch(excelFile);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            log.info("写入文件:{}", excelFile.getAbsolutePath());
            if (!excelFile.getName().toLowerCase().endsWith("xlsx")) {
                log.info("只支持 .xlsx 的文件类型写入!");
                return;
            }
            // 创建一个工作簿 03
            // HSSFWorkbook workbook = new HSSFWorkbook();
            // 创建一个工作簿 07
            XSSFWorkbook workbook = new XSSFWorkbook();
            // 创建一个工作表
            XSSFSheet sheet = workbook.createSheet(sheetName);
    
            List<String> header = sheetData.getHeader();
            // 创建第一行
            XSSFRow row1 = sheet.createRow(0);
            for (int i = 0; i < header.size(); i++) {
                // 创建一个单元格
                XSSFCell cell = row1.createCell(i);
                CellStyle cellStyle = workbook.createCellStyle();
                Font font = workbook.createFont();
                //设置字体
                font.setFontName("宋体");
                //设置字号
                font.setFontHeightInPoints((short) 13);
                cellStyle.setFont(font);
                //文本自动换行
                cellStyle.setWrapText(true);
                //左右居中
                cellStyle.setAlignment(HorizontalAlignment.CENTER);
                //上下居中
                cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
                cell.setCellStyle(cellStyle);
                cell.setCellValue(header.get(i));
            }
            log.info("写入标题行完成");
    
            // 调整列宽
            for (int colNum = 0; colNum < header.size(); colNum++) {
                //设置第几列列宽自适应
    //            sheet.autoSizeColumn(colNum, true);
    //            int width = sheet.getColumnWidth(colNum);
    //            // 设置最小列宽
    //            sheet.setColumnWidth(colNum, Math.max(width, 10 * 256));
    
                //固定列宽
                sheet.setColumnWidth(colNum, 20 * 256);
            }
            log.info("设置列宽完成");
    
            // 设置居中显示
            CellStyle style = workbook.createCellStyle();
            // 设置水平居中
            style.setAlignment(HorizontalAlignment.LEFT);
            // 设置垂直居中
            style.setVerticalAlignment(VerticalAlignment.CENTER);
    
            List<Map<String, Object>> sheetDataList = sheetData.getSheetDataList();
            for (int i = 0; i < sheetDataList.size(); i++) {
                // 创建第二行
                XSSFRow row2 = sheet.createRow(i + 1);
                Map<String, Object> rowDataMap = sheetDataList.get(i);
                for (int j = 0; j < header.size(); j++) {
                    // 创建一个单元格
                    XSSFCell cell = row2.createCell(j);
                    if (StringUtils.isNotEmpty(header.get(j))
                            && "序号".equals(header.get(j))
                            && rowDataMap.get(header.get(j)).toString().contains("参数")) {
                        // 设置单元格合并
                        CellRangeAddress region = new CellRangeAddress(
                                //开始行
                                i + 1,
                                //结束行
                                i + 1,
                                //开始列
                                0,
                                //结束列
                                header.size() - 1);
                        sheet.addMergedRegion(region);
                        cell.setCellStyle(style);
                    }
    
                    if (null == rowDataMap.get(header.get(j))) {
                        cell.setCellValue("");
                    } else {
                        cell.setCellValue(rowDataMap.get(header.get(j)).toString());
                    }
                }
            }
            log.info("写入数据行完成");
    
            //第一行开启筛选
            sheet.setAutoFilter(new CellRangeAddress(0, 0, 0, header.size() - 1));
            log.info("开启标题行筛选完成");
            /*
                四个参数分别代表:
                cellNum:表示要冻结的列数;
                rowNum:表示要冻结的行数;
                firstCellNum:表示被固定列右边第一列的列号;
                firstRollNum :表示被固定行下边第一列的行号;
                注意: 后2个参数均从0开始计算列号和行号,且firstCellNum>=cellNum &&firstRollNum >=cellNum
                sheet.createFreezePane(1,0,1,0);//就是固定了首列,列号的显示为:A,BCDEF...
                sheet.createFreezePane(1,0,3,0);//固定了首列,列号的显示为:A,DEF...
                //注意:BC列不是被隐藏,而是默认显示列为A,DEF,若想要看BC列,只需移动滚轮即可.行号同理
             */
            //这里是只冻结第一行
            sheet.createFreezePane(0, 1, 0, 1);
            log.info("冻结标题行完成");
    
            FileOutputStream fileOutputStream = null;
            try {
                // 创建文件
                fileOutputStream = new FileOutputStream(excelFile);
                // 写入文件
                workbook.write(fileOutputStream);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (null != fileOutputStream) {
                        fileOutputStream.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            long end = System.currentTimeMillis();
            log.info("写入文件完成,总耗时:{} 秒", (end - start) / 1000.0);
        }
    }
    
    2.3.5.3、将 RFC 函数的入参/出参导出为 Excel 文件
    import com.sap.conn.jco.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.File;
    import java.util.*;
    import java.util.stream.Collectors;
    
    /**
     * RFC执行
     *
     * @author chenwc
     * @date 2023/11/28 11:21
     */
    public class RfcExecutorExport {
    
        private static final Logger logger = LoggerFactory.getLogger(RfcExecutorExport.class);
    
        public static void main(String[] args) {
    
            File file = new File("1.txt");
            String path = file.getAbsolutePath().replace("1.txt", "");
            path = path + "outputExcel\\";
    
            JCoDestination destination = CreateDestination.getDestination();
            Request request = new Request();
            request.setFunctionName("ZMDG_UPDATE_VEN_CUS_ZFIELDS");
            Response response = statelessExecute(request, destination);
            logger.info("response:{}", response.getExportJson());
    
            JSONObject exportJson = response.getExportJson();
            JSONObject inputJson = exportJson.getJSONObject("传入参数");
            JSONObject outputJson = exportJson.getJSONObject("传出参数");
            JSONObject tableJson = exportJson.getJSONObject("表格参数");
    
            //写文件示例2
            List<String> header = new ArrayList<>();
            header.add("序号");
            header.add("参数名称");
            header.add("描述");
            header.add("字段类型");
            header.add("说明");
    
            List<Map<String, Object>> writeDataMapList = new ArrayList<>();
            int i = 0;
            Map<String, Object> row1 = new HashMap<>();
            row1.put("序号", "输入参数");
            writeDataMapList.add(row1);
    
            JSONObject kvJson = new JSONObject();
            JSONObject objJson = new JSONObject();
            if (null != inputJson && !inputJson.isEmpty()) {
                for (String key : inputJson.keySet()) {
                    Object param = inputJson.get(key);
                    if (param instanceof JSONObject) {
                        kvJson.put(key, param);
                    }
                    if (param instanceof JSONArray) {
                        objJson.put(key, param);
                    }
                }
            }
            Map<String, Object> row3334 = new HashMap<>();
            row3334.put("序号", "KeyValue输入参数");
            writeDataMapList.add(row3334);
            if (!kvJson.isEmpty()) {
                for (String key : kvJson.keySet()) {
                    i++;
                    JSONObject paramJson = kvJson.getJSONObject(key);
                    Map<String, Object> row = new HashMap<>();
                    row.put("序号", i);
                    row.put("参数名称", key);
                    row.put("描述", paramJson.getString("字段描述"));
                    row.put("字段类型", paramJson.getString("字段类型") + "(" + paramJson.getString("字段长度") + ")");
                    row.put("说明", "");
                    writeDataMapList.add(row);
                }
            }
    
            if (!objJson.isEmpty()) {
                for (String key : objJson.keySet()) {
                    i++;
                    JSONArray paramJson = objJson.getJSONArray(key);
                    Map<String, Object> row33 = new HashMap<>();
                    row33.put("序号", "对象输入参数名称:" + key);
                    writeDataMapList.add(row33);
                    int co = 0;
                    for (int j = 0; j < paramJson.size(); j++) {
                        co++;
                        JSONObject jsonObject = paramJson.getJSONObject(j);
                        Map<String, Object> row = new HashMap<>();
                        row.put("序号", co);
                        row.put("参数名称", jsonObject.getString("字段名"));
                        row.put("描述", jsonObject.getString("字段描述"));
                        row.put("字段类型", jsonObject.getString("字段类型") + "(" + jsonObject.getString("字段长度") + ")");
                        row.put("说明", "");
                        writeDataMapList.add(row);
                    }
                }
            }
            Map<String, Object> row2 = new HashMap<>();
            row2.put("序号", "表参数");
            writeDataMapList.add(row2);
            if (null != tableJson && !tableJson.isEmpty()) {
                for (String key : tableJson.keySet()) {
                    JSONArray paramJson = tableJson.getJSONArray(key);
                    Map<String, Object> row333 = new HashMap<>();
                    row333.put("序号", "表参数名称:" + key);
                    writeDataMapList.add(row333);
                    i = 0;
                    for (int j = 0; j < paramJson.size(); j++) {
                        i++;
                        JSONObject jsonObject = paramJson.getJSONObject(j);
                        Map<String, Object> row = new HashMap<>();
                        row.put("序号", i);
                        row.put("参数名称", jsonObject.getString("字段名"));
                        row.put("描述", jsonObject.getString("字段描述"));
                        row.put("字段类型", jsonObject.getString("字段类型") + "(" + jsonObject.getString("字段长度") + ")");
                        row.put("说明", "");
                        writeDataMapList.add(row);
                    }
                }
            }
    
            JSONObject kvOutJson = new JSONObject();
            JSONObject objOutJson = new JSONObject();
            if (null != outputJson && !outputJson.isEmpty()) {
                for (String key : outputJson.keySet()) {
                    Object param = outputJson.get(key);
                    if (param instanceof JSONObject) {
                        kvOutJson.put(key, param);
                    }
                    if (param instanceof JSONArray) {
                        objOutJson.put(key, param);
                    }
                }
            }
    
    
            Map<String, Object> row3 = new HashMap<>();
            row3.put("序号", "输出KeyValue参数");
            writeDataMapList.add(row3);
            i = 0;
            if (!kvOutJson.isEmpty()) {
                for (String key : kvOutJson.keySet()) {
                    i++;
                    JSONObject paramJson = kvOutJson.getJSONObject(key);
                    Map<String, Object> row = new HashMap<>();
                    row.put("序号", i);
                    row.put("参数名称", key);
                    row.put("描述", paramJson.getString("字段描述"));
                    row.put("字段类型", paramJson.getString("字段类型") + "(" + paramJson.getString("字段长度") + ")");
                    row.put("说明", "");
                    writeDataMapList.add(row);
                }
            }
            if (!objOutJson.isEmpty()) {
                for (String key : objOutJson.keySet()) {
                    i++;
                    JSONArray paramJson = objOutJson.getJSONArray(key);
                    Map<String, Object> row33 = new HashMap<>();
                    row33.put("序号", "对象输出参数名称:" + key);
                    writeDataMapList.add(row33);
                    int co = 0;
                    for (int j = 0; j < paramJson.size(); j++) {
                        co++;
                        JSONObject jsonObject = paramJson.getJSONObject(j);
                        Map<String, Object> row = new HashMap<>();
                        row.put("序号", co);
                        row.put("参数名称", jsonObject.getString("字段名"));
                        row.put("描述", jsonObject.getString("字段描述"));
                        row.put("字段类型", jsonObject.getString("字段类型") + "(" + jsonObject.getString("字段长度") + ")");
                        row.put("说明", "");
                        writeDataMapList.add(row);
                    }
                }
            }
    
            File newWriteFile = new File(path + request.getFunctionName() + ".xlsx");
            WriteExcelFile.writeFile(newWriteFile, request.getFunctionName(), new SheetData(header, writeDataMapList));
        }
    
        /**
         * 无状态执行,执行一次RFC函数连接一次
         *
         * @param request     请求
         * @param destination 目的地
         * @return 响应
         */
        public static Response statelessExecute(Request request, JCoDestination destination) {
    
            logger.info("开始连接...");
            Response response = new Response();
            try {
                // 调用SAP的sapRequestContent.getFuntionName()方法
                JCoFunction function = destination.getRepository().getFunction(request.getFunctionName());
                if (null == function) {
                    logger.error("SAP没有名称为:{} 的RFC函数!", request.getFunctionName());
                    return response;
                }
                logger.info("连接成功!");
                response = exec(request, function, destination);
            } catch (JCoException e) {
                logger.info("SAP调用RFC函数失败, 错误信息:" + e.getMessage());
                e.printStackTrace();
            }
            return response;
        }
    
        /**
         * 执行RFC函数
         *
         * @param request     请求
         * @param function    RFC函数
         * @param destination 目标
         * @return 响应
         */
        private synchronized static Response exec(Request request, JCoFunction function, JCoDestination destination) {
            Response response = new Response();
            JSONObject exportJson = new JSONObject();
            //输入参数
            if (null != function.getImportParameterList()) {
                JSONObject importJson = new JSONObject();
                getJCoParameterListValue(function.getImportParameterList(), importJson);
                exportJson.put("传入参数", importJson);
            }
            if (null != function.getTableParameterList()) {
                JSONObject tableJson = new JSONObject();
                getJCoParameterListValue(function.getTableParameterList(), tableJson);
                exportJson.put("表格参数", tableJson);
            }
            if (null != function.getChangingParameterList()) {
                JSONObject changingJson = new JSONObject();
                getJCoParameterListValue(function.getChangingParameterList(), changingJson);
                exportJson.put("传入修改参数", changingJson);
            }
            try {
                function.execute(destination);
            } catch (JCoException e) {
                e.printStackTrace();
            }
    
            if (null != function.getExportParameterList()) {
                JSONObject exportJson1 = new JSONObject();
                getJCoParameterListValue(function.getExportParameterList(), exportJson1);
                exportJson.put("传出参数", exportJson1);
            }
            if (null != function.getTableParameterList()) {
                JSONObject exportJson1 = new JSONObject();
                getJCoParameterListValue(function.getTableParameterList(), exportJson1);
                exportJson.put("表格参数", exportJson1);
            }
            response.setExportJson(exportJson);
    
            JSONObject exceptionJson = new JSONObject();
            if (null != function.getExceptionList()) {
                List<AbapException> exceptionList = Arrays.stream(function.getExceptionList()).collect(Collectors.toList());
                exceptionList.forEach(exception -> exceptionJson.put(exception.getKey(), exception.getMessage()));
            }
            response.setExceptionJson(exceptionJson);
    
            return response;
        }
    
        /**
         * 获取JCoParameterList的值
         *
         * @param parameterList 参数列表
         * @param exportJson    导出的JSON
         */
        public static void getJCoParameterListValue(JCoParameterList parameterList, JSONObject exportJson) {
            if (null == parameterList) {
                return;
            }
            //遍历参数
            JCoFieldIterator fieldIterator = parameterList.getFieldIterator();
            while (fieldIterator.hasNextField()) {
                //获取参数
                JCoField field = fieldIterator.nextField();
                //判断是否为Table
                if (field.isTable()) {
                    JCoTable jCoTable = field.getTable();
                    JSONArray tempTable = new JSONArray();
                    JCoRecordFieldIterator iterator = jCoTable.getRecordFieldIterator();
                    //遍历Table
                    while (iterator.hasNextField()) {
                        JSONObject tempRow = new JSONObject();
                        JCoField field1 = iterator.nextField();
                        tempRow.put("字段名", field1.getName());
                        tempRow.put("字段类型", field1.getTypeAsString());
                        tempRow.put("字段描述", field1.getDescription());
                        tempRow.put("字段长度", field1.getLength());
                        tempTable.add(tempRow);
                    }
                    exportJson.put(field.getName(), tempTable);
                }
                //判断是否为Structure
                else if (field.isStructure()) {
                    JCoStructure jCoStructure = field.getStructure();
                    JSONArray tempTable = new JSONArray();
                    //遍历Structure
                    JCoRecordFieldIterator iterator = jCoStructure.getRecordFieldIterator();
                    while (iterator.hasNextField()) {
                        JSONObject tempRow = new JSONObject();
                        JCoField field1 = iterator.nextField();
                        tempRow.put("字段名", field1.getName());
                        tempRow.put("字段类型", field1.getTypeAsString());
                        tempRow.put("字段描述", field1.getDescription());
                        tempRow.put("字段长度", field1.getLength());
                        tempTable.add(tempRow);
                    }
                    exportJson.put(field.getName(), tempTable);
                }
                //普通参数
                else {
                    JSONObject tempField = new JSONObject();
                    tempField.put("字段名", field.getName());
                    tempField.put("字段类型", field.getTypeAsString());
                    tempField.put("字段描述", field.getDescription());
                    tempField.put("字段长度", field.getLength());
                    exportJson.put(field.getName(), tempField);
                }
            }
        }
    
    }
    

    导出的 Excel 文件如下图所示:

    2.4、基于 JCo3 多线程调用 RFC 函数

    2.4.1、多步骤任务接口

    /**
     * 多步骤任务接口
     *
     * @author wxhnyfy
     */
    public interface MultiStepJob {
        //是否完成
        boolean isFinished();
    
        //运行下一步
        public JSONObject runNextStep();
    
        //获取名称
        String getName();
    
        //清理
        public void cleanUp();
    }
    

    2.4.2、无状态多步骤作业

    import com.sap.conn.jco.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * 无状态多步骤作业
     *
     * @author wxhnyfy
     */
    public class StatelessMultiStep implements MultiStepJob {
    
        private static final Logger logger = LoggerFactory.getLogger(StatelessMultiStep.class);
    
        //原子整数
        static AtomicInteger JOB_COUNT = new AtomicInteger(0);
        //增量计数器
        int jobID = JOB_COUNT.addAndGet(1);
        //调用数量
        int calls;
        //目标
        JCoDestination destination;
        //执行调用数量
        int executedCalls = 0;
        //异常
        Exception ex = null;
        //执行模板
        Request request;
    
        //json参数返回,返回所有类型
        JSONObject exportJson;
    
        /**
         * 无状态多步骤作业
         *
         * @param destination 目标
         * @param calls       调用数量
         * @param request     执行模板
         */
        public StatelessMultiStep(JCoDestination destination, int calls, Request request) {
            this.calls = calls;
            this.destination = destination;
            this.request = request;
        }
    
        /**
         * 是否完成
         *
         * @return 是否完成
         */
        @Override
        public boolean isFinished() {
            return executedCalls == calls || ex != null;
        }
    
        /**
         * 获取名称
         *
         * @return 名称
         */
        @Override
        public String getName() {
            return "stateless Job-" + jobID;
        }
    
        /**
         * 运行下一步
         */
        @Override
        public JSONObject runNextStep() {
            try {
                //获取计数器模板
                JCoFunction function = destination.getRepository().getFunction(request.getFunctionName());
                if (function == null) {
                    throw new RuntimeException("SAP 没有该【" + request.getFunctionName() + "】RFC 函数");
                }
                //输入参数
                if (null != function.getImportParameterList()) {
                    if (null != request.getKeyValueParams() && !request.getKeyValueParams().isEmpty()) {
                        logger.info("输入参数:{}", JSON.toJSONString(request.getKeyValueParams()));
                        request.getKeyValueParams().forEach(item -> function.getImportParameterList().setValue(item.getName(), item.getValue()));
                    }
                }
                if (null != function.getImportParameterList()) {
                    if (null != request.getObjectParams() && !request.getObjectParams().isEmpty()) {
                        request.getObjectParams().forEach(item -> {
                            JCoStructure inStructure = function.getImportParameterList().getStructure(item.getName());
                            Map<String, String> value = item.getValue();
                            for (Map.Entry<String, String> entry : value.entrySet()) {
                                inStructure.setValue(entry.getKey(), entry.getValue());
                            }
                        });
                    }
                    if (null != request.getArrayListParams() && !request.getArrayListParams().isEmpty()) {
                        request.getArrayListParams().forEach(item -> {
                            JCoTable inTable = function.getImportParameterList().getTable(item.getName());
                            List<Map<String, String>> value = item.getValue();
                            for (Map<String, String> map : value) {
                                inTable.appendRow();
                                for (Map.Entry<String, String> entry : map.entrySet()) {
                                    inTable.setValue(entry.getKey(), entry.getValue());
                                }
                            }
                        });
                    }
                }
                //执行目标
                function.execute(destination);
                //执行调用数量增加
                executedCalls++;
                if (null == exportJson) {
                    exportJson = new JSONObject();
                }
                //如果完成
                if (isFinished()) {
                    logger.info("RFC: {} 调用完成", request.getFunctionName());
                    //导出参数列表
                    if (null != function.getExportParameterList()) {
                        function.getExportParameterList().forEach(export -> {
                            if (export.isStructure()) {
                                JCoStructure jCoStructure = export.getStructure();
                                JSONObject tempStruc = new JSONObject();
                                JCoRecordMetaData strucMeta = jCoStructure.getRecordMetaData();
                                for (int i = 0; i < strucMeta.getFieldCount(); i++) {
                                    tempStruc.put(strucMeta.getName(i), jCoStructure.getString(strucMeta.getName(i)));
                                }
                                exportJson.put(export.getName(), tempStruc);
                            } else if (export.isTable()) {
                                JCoTable jCoTable = export.getTable();
                                JSONArray tempTable = new JSONArray();
                                for (int i = 0; i < jCoTable.getNumRows(); i++) {
                                    JSONObject tempRow = new JSONObject();
                                    jCoTable.setRow(i);
                                    JCoRecordMetaData tableMeta = jCoTable.getRecordMetaData();
                                    for (int j = 0; j < tableMeta.getFieldCount(); j++) {
                                        tempRow.put(tableMeta.getName(j), jCoTable.getString(tableMeta.getName(j)));
                                    }
                                    tempTable.add(tempRow);
                                }
                                exportJson.put(export.getName(), tempTable);
                            } else {
                                exportJson.put(export.getName(), export.getString());
                            }
                        });
                    }
                    //表参数列表
                    if (null != function.getTableParameterList()) {
                        function.getTableParameterList().forEach(table -> {
                            JSONArray tempTable = new JSONArray();
                            JCoTable jCoTable = table.getTable();
                            for (int i = 0; i < jCoTable.getNumRows(); i++) {
                                JSONObject tempRow = new JSONObject();
                                jCoTable.setRow(i);
                                JCoRecordMetaData tableMeta = jCoTable.getRecordMetaData();
                                for (int j = 0; j < tableMeta.getFieldCount(); j++) {
                                    tempRow.put(tableMeta.getName(j), jCoTable.getString(tableMeta.getName(j)));
                                }
                                tempTable.add(tempRow);
                            }
                            exportJson.put(table.getName(), tempTable);
                        });
                    }
                    //logger.info("exportJson:{}", exportJson.toJSONString());
                }
            } catch (JCoException | RuntimeException je) {
                je.printStackTrace();
                ex = je;
            }
            return exportJson;
        }
    
        /**
         * 清理
         */
        @Override
        public void cleanUp() {
            StringBuilder sb = new StringBuilder("任务 ").append(getName()).append(" 处理完成。 ");
            if (ex != null) {
                sb.append("出现异常:").append(ex);
            } else {
                sb.append("成功! ");
            }
            logger.info(sb.toString());
        }
    }
    

    2.4.3、有状态多步骤作业

    import com.sap.conn.jco.JCoContext;
    import com.sap.conn.jco.JCoDestination;
    import com.sap.conn.jco.JCoException;
    
    /**
     * 有状态多步骤作业
     *
     * @author wxhnyfy
     */
    public class StatefulMultiStep extends StatelessMultiStep {
    
        /**
         * 有状态多步骤作业
         *
         * @param destination 目标
         * @param calls       调用数量
         * @param request     执行模板
         */
        public StatefulMultiStep(JCoDestination destination, int calls, Request request) {
            super(destination, calls, request);
        }
    
        /**
         * 获取名称
         *
         * @return 名称
         */
        @Override
        public String getName() {
            return "stateful Job-" + jobID;
        }
    
        /**
         * 运行下一步
         */
        @Override
        public JSONObject runNextStep() {
            if (executedCalls == 0) {
                JCoContext.begin(destination);
            }
            return super.runNextStep();
        }
    
        /**
         * 清理
         */
        @Override
        public void cleanUp() {
            try {
                JCoContext.end(destination);
            } catch (JCoException je) {
                ex = je;
            }
            super.cleanUp();
        }
    }
    

    2.4.4、会话引用线程

    import com.sap.conn.jco.ext.JCoSessionReference;
    import com.sap.conn.jco.ext.SessionException;
    import com.sap.conn.jco.ext.SessionReferenceProvider;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.Collection;
    import java.util.Hashtable;
    import java.util.concurrent.*;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.function.Supplier;
    
    /**
     * 会话引用线程
     *
     * @author wxhnyfy
     */
    public class SessionReferenceThread {
    
        private static final Logger logger = LoggerFactory.getLogger(SessionReferenceThread.class);
    
        /**
         * 异步执行,能获取执行结果
         */
        public static class GetResultCompletableFuture implements Supplier<JSONArray> {
            //会话
            static Hashtable<MultiStepJob, MySessionReference> sessions = new Hashtable<>();
            //线程本地变量
            static ThreadLocal<MySessionReference> localSessionReference = new ThreadLocal<>();
            //计数器
            private final CountDownLatch doneSignal;
            //阻塞队列
            private BlockingQueue<MultiStepJob> queue = new LinkedBlockingQueue<>();
    
            public GetResultCompletableFuture(CountDownLatch doneSignal, BlockingQueue<MultiStepJob> queue) {
                this.doneSignal = doneSignal;
                this.queue = queue;
            }
    
            @Override
            public JSONArray get() {
                JSONArray jsonArray = new JSONArray();
                try {
                    //无限循环
                    for (; ; ) {
                        //从队列中取出任务
                        MultiStepJob job = queue.poll(10, TimeUnit.SECONDS);
                        //队列为空,结束循环
                        if (job == null) {
                            return jsonArray;
                        }
                        MySessionReference sesRef = sessions.get(job);
                        if (sesRef == null) {
                            sesRef = new MySessionReference();
                            sessions.put(job, sesRef);
                        }
                        localSessionReference.set(sesRef);
                        logger.info("任务 " + job.getName() + " 开始。");
                        try {
                            JSONObject export = job.runNextStep();
                            if (export != null) {
                                jsonArray.add(export);
                            }
                        } catch (Throwable th) {
                            th.printStackTrace();
                        }
                        if (job.isFinished()) {
                            logger.info("任务 " + job.getName() + " 结束。");
                            sessions.remove(job);
                            job.cleanUp();
                        } else {
                            logger.info("任务 " + job.getName() + " 激活。");
                            queue.add(job);
                        }
                        localSessionReference.set(null);
                    }
                } catch (InterruptedException e) {
                    //just leave
                } finally {
                    doneSignal.countDown();
                }
                return jsonArray;
            }
    
        }
    
        /**
         * 同步执行,能获取执行结果
         */
        public static class ReturnResultTaskCallable implements Callable<JSONArray> {
    
            //会话
            static Hashtable<MultiStepJob, MySessionReference> sessions = new Hashtable<>();
            //线程本地变量
            static ThreadLocal<MySessionReference> localSessionReference = new ThreadLocal<>();
            //计数器
            private final CountDownLatch doneSignal;
            //阻塞队列
            private BlockingQueue<MultiStepJob> queue = new LinkedBlockingQueue<>();
    
            public ReturnResultTaskCallable(CountDownLatch doneSignal, BlockingQueue<MultiStepJob> queue) {
                this.doneSignal = doneSignal;
                this.queue = queue;
            }
    
            @Override
            public JSONArray call() {
                JSONArray jsonArray = new JSONArray();
                try {
                    //无限循环
                    for (; ; ) {
                        //从队列中取出任务
                        MultiStepJob job = queue.poll(10, TimeUnit.SECONDS);
                        //队列为空,结束循环
                        if (job == null) {
                            return jsonArray;
                        }
                        MySessionReference sesRef = sessions.get(job);
                        if (sesRef == null) {
                            sesRef = new MySessionReference();
                            sessions.put(job, sesRef);
                        }
                        localSessionReference.set(sesRef);
                        logger.info("任务 " + job.getName() + " 开始。");
                        try {
                            JSONObject export = job.runNextStep();
                            if (export != null) {
                                jsonArray.add(export);
                            }
                        } catch (Throwable th) {
                            th.printStackTrace();
                        }
                        if (job.isFinished()) {
                            logger.info("任务 " + job.getName() + " 结束。");
                            sessions.remove(job);
                            job.cleanUp();
                        } else {
                            logger.info("任务 " + job.getName() + " 激活。");
                            queue.add(job);
                        }
                        localSessionReference.set(null);
                    }
                } catch (InterruptedException e) {
                    //just leave
                } finally {
                    doneSignal.countDown();
                }
                return jsonArray;
            }
        }
    
        /**
         * 同步执行,不需要获取执行结果
         */
        public static class WorkerThread extends Thread {
    
            //会话
            static Hashtable<MultiStepJob, MySessionReference> sessions = new Hashtable<>();
            //线程本地变量
            static ThreadLocal<MySessionReference> localSessionReference = new ThreadLocal<>();
            //计数器
            private final CountDownLatch doneSignal;
            //阻塞队列
            private BlockingQueue<MultiStepJob> queue = new LinkedBlockingQueue<>();
    
            /**
             * 工作线程
             *
             * @param doneSignal 计数器
             */
            WorkerThread(CountDownLatch doneSignal) {
                this.doneSignal = doneSignal;
            }
    
            public WorkerThread(CountDownLatch doneSignal,
                                BlockingQueue<MultiStepJob> queue) {
                this.doneSignal = doneSignal;
                this.queue = queue;
            }
    
            @Override
            public void run() {
                try {
                    //无限循环
                    for (; ; ) {
                        //从队列中取出任务
                        MultiStepJob job = queue.poll(10, TimeUnit.SECONDS);
                        //队列为空,结束循环
                        if (job == null) {
                            return;
                        }
                        MySessionReference sesRef = sessions.get(job);
                        if (sesRef == null) {
                            sesRef = new MySessionReference();
                            sessions.put(job, sesRef);
                        }
                        localSessionReference.set(sesRef);
                        logger.info("任务 " + job.getName() + " 开始。");
                        try {
                            JSONObject export = job.runNextStep();
                            if (export != null) {
                                logger.info("执行结果:" + export.toJSONString());
                            }
                        } catch (Throwable th) {
                            th.printStackTrace();
                        }
                        if (job.isFinished()) {
                            logger.info("任务 " + job.getName() + " 结束。");
                            sessions.remove(job);
                            job.cleanUp();
                        } else {
                            logger.info("任务 " + job.getName() + " 激活。");
                            queue.add(job);
                        }
                        localSessionReference.set(null);
                    }
                } catch (InterruptedException e) {
                    //just leave
                } finally {
                    doneSignal.countDown();
                }
            }
        }
    
        public static class MySessionReference implements JCoSessionReference {
    
            //原子整数
            static AtomicInteger atomicInt = new AtomicInteger(0);
            //ID
            private final String id = "session-" + atomicInt.addAndGet(1);
    
            /**
             * 上下文已完成
             */
            @Override
            public void contextFinished() {
                logger.debug("session " + id + " 上下文已完成");
            }
    
            /**
             * 上下文已开始
             */
            @Override
            public void contextStarted() {
                logger.debug("session " + id + " 上下文已开始");
            }
    
            /**
             * 获取ID
             *
             * @return ID
             */
            @Override
            public String getID() {
                return id;
            }
        }
    
        public static class MySessionReferenceProvider implements SessionReferenceProvider {
    
            /**
             * 获取当前会话参考
             *
             * @param scopeType 作用域类型
             * @return 会话参考
             */
            @Override
            public JCoSessionReference getCurrentSessionReference(String scopeType) {
                //没有返回结果的线程
                MySessionReference sesRef = WorkerThread.localSessionReference.get();
                //异步执行带返回结果的线程
                //MySessionReference sesRef = GetResultCompletableFuture.localSessionReference.get();
                //同步执行带返回结果的线程
                //MySessionReference sesRef = ReturnResultTaskCallable.localSessionReference.get();
                if (sesRef != null) {
                    return sesRef;
                }
                throw new RuntimeException("未知线程:" + Thread.currentThread().getId());
            }
    
            /**
             * 会话是否存活
             *
             * @param sessionId 会话ID
             * @return 是否存活
             */
            @Override
            public boolean isSessionAlive(String sessionId) {
                //没有返回结果的线程
                Collection<MySessionReference> availableSessions = WorkerThread.sessions.values();
                //异步执行带返回结果的线程
                //Collection<MySessionReference> availableSessions = GetResultCompletableFuture.sessions.values();
                //同步执行带返回结果的线程
                //Collection<MySessionReference> availableSessions = ReturnResultTaskCallable.sessions.values();
                for (MySessionReference ref : availableSessions) {
                    if (ref.getID().equals(sessionId)) {
                        return true;
                    }
                }
                return false;
            }
    
            /**
             * JCoServer会话继续
             *
             * @param sessionID 会话ID
             * @throws SessionException 会话异常
             */
            @Override
            public void jcoServerSessionContinued(String sessionID) throws SessionException {
                logger.debug("JCoServer会话继续, sessionID: " + sessionID);
            }
    
            /**
             * JCoServer会话完成
             *
             * @param sessionID 会话ID
             */
            @Override
            public void jcoServerSessionFinished(String sessionID) {
                logger.debug("JCoServer会话完成, sessionID: " + sessionID);
            }
    
            /**
             * JCoServer会话激活
             *
             * @param sessionID 会话ID
             * @throws SessionException 会话异常
             */
            @Override
            public void jcoServerSessionPassivated(String sessionID) throws SessionException {
                logger.debug("JCoServer会话激活, sessionID: " + sessionID);
            }
    
            /**
             * JCoServer会话开始
             *
             * @return 会话参考
             * @throws SessionException 会话异常
             */
            @Override
            public JCoSessionReference jcoServerSessionStarted() throws SessionException {
                logger.debug("JCoServer会话开始");
                return null;
            }
        }
    }
    

    2.4.5、测试代码

    import com.sap.conn.jco.JCoDestination;
    import com.sap.conn.jco.JCoDestinationManager;
    import com.sap.conn.jco.ext.DestinationDataProvider;
    import com.sap.conn.jco.ext.Environment;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Properties;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.LinkedBlockingQueue;
    
    /**
     * 多线程执行sap任务
     * 
     * @author wxhnyfy
     */
    public class TestMultipleThread {
    
        private static final Logger logger = LoggerFactory.getLogger(TestMultipleThread.class);
    
        private static final String DESTINATION_NAME1 = "SAP客户端";
        /**
         * 阻塞队列
         */
        private static final BlockingQueue<MultiStepJob> QUEUE = new LinkedBlockingQueue<>();
    
        static {
            Properties connectProperties = new Properties();
            connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "服务器	IP");
            connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "系统编号");
            connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "SAP集团");
            connectProperties.setProperty(DestinationDataProvider.JCO_USER, "用户名");
            connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "密码");
            connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "登录语言");
            connectProperties.setProperty(DestinationDataProvider.JCO_SAPROUTER, "路由");
            createDataFile(DESTINATION_NAME1, "jcoDestination", connectProperties);
            connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "3");
            connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10");
        }
    
        /**
         * 创建连接文件
         *
         * @param name       文件名
         * @param suffix     后缀
         * @param properties 属性
         */
        static void createDataFile(String name, String suffix, Properties properties) {
            File cfg = new File(name + "." + suffix);
            cfg.deleteOnExit();
            if (!cfg.exists()) {
                try {
                    FileOutputStream fos = new FileOutputStream(cfg, false);
                    properties.store(fos, "for tests only !");
                    fos.close();
                } catch (Exception e) {
                    throw new RuntimeException("无法创建 destination 文件 " + cfg.getName(), e);
                }
            }
        }
    
        /**
         * 开 threadCount 个线程,从阻塞队列中取出任务执行
         */
        public static void main(String[] args) {
            //注册sessionReferenceProvider
            Environment.registerSessionReferenceProvider(new SessionReferenceThread.MySessionReferenceProvider());
            //线程池实例
            ExecutorService executorService = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
    
            //线程数,开启多少个线程执行阻塞队列中的任务
            //一般要线程数要大于阻塞队列的长度,否则会有任务一直在队列中得不到执行
            int threadCount = 5;
    
            try {
                JCoDestination destination = JCoDestinationManager.getDestination(DESTINATION_NAME1);
    
                List<String> list = new ArrayList<>();
                list.add("1000004926");
                list.add("1000004927");
                list.add("1000004928");
                list.add("1000004929");
                list.add("1000004930");
                list.add("1000004931");
                list.add("1000004932");
    
                for (String num : list) {
                    KeyValueParam kp1 = new KeyValueParam("key1", "value1");
                    KeyValueParam kp2 = new KeyValueParam("key2", num);
                    List<KeyValueParam> params = new ArrayList<>();
                    params.add(kp1);
                    params.add(kp2);
                    Request request = new Request();
                    request.setFunctionName("function1");
                    request.setKeyValueParams(params);
                    //无状态的多步骤
                    QUEUE.add(new StatelessMultiStep(destination, 1, request));
                    //有状态的多步骤
                    //queue.add(new StatefulMultiStep(destination, 1, request));
                }
    
                logger.info(">>> Start");
    
                JSONArray allThreadResult = new JSONArray();
    
                //开线程
                CountDownLatch doneSignal = new CountDownLatch(threadCount);
                //这里开了10个线程,每个线程都会从阻塞队列中取任务执行,当阻塞队列中没有任务时,线程会结束
                for (int i = 0; i < threadCount; i++) {
                    //方法1
                    SessionReferenceThread.WorkerThread workerThread = new SessionReferenceThread.WorkerThread(doneSignal, QUEUE);
                    executorService.submit(workerThread);
                    //方法2
                    //new SessionReferenceThread.WorkerThread(doneSignal, queue).start();
                    //方法3,异步执行
    //                SessionReferenceThread.GetResultCompletableFuture completableFuture = new SessionReferenceThread.GetResultCompletableFuture(doneSignal, queue);
    //                CompletableFuture<JSONArray> result = CompletableFuture.supplyAsync(completableFuture, executorService)
    //                        .whenComplete((res, ex) -> {
    //                            logger.info(">>> 当前线程:" + Thread.currentThread().getName());
    //                            logger.info(">>> 结果:" + res);
    //                            if (ex != null) {
    //                                logger.error(">>> 异常:", ex);
    //                            }
    //                        });
                    //同步执行
    //                SessionReferenceThread.ReturnResultTaskCallable callable = new SessionReferenceThread.ReturnResultTaskCallable(doneSignal, queue);
    //                Future<JSONArray> future = executorService.submit(callable);
    //                //获取结果,阻塞线程。阻塞后会在一个线程中执行完队列中所有任务
    //                JSONArray result = future.get();
    //                allThreadResult.addAll(result);
                }
                //提交完任务后,关闭线程池,不再接受新的任务
                executorService.shutdown();
                logger.info(">>> Wait ... ");
                try {
                    doneSignal.await();
                } catch (InterruptedException ie) {
                    //just leave
                }
    //            logger.info(">>> 执行结果:" + allThreadResult.toJSONString());
                logger.info(">>> Done");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    }
    

    作者:菠萝蚊鸭

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用 JCo3 库实现 Java 与 SAP RFC 函数对接的详细代码指南

    发表回复