java要调用 SAP RFC接口时,需要用到sapjco3.jar 架包;
网上说的乱八七糟的windows将sapjco3.dll 文件放到system32的目录下.............我嫌弃麻烦没用;
本人经历亲测可用的简单粗暴的方式:
先说windows下还需要将文件sapjco3.dll 和 sapjco3.jar文件放到项目下WEB-INF/lib 下直接就可以用。
此时tomcat/bin下面会生成一个文件【*****.jcoDestination】如果测试-正式切换的时候,这个不会变,要手动更改。
【Java 调用sap 切换正式怎么还是测试的问题】{ 后面会讲解到!}
Linux别急下面再详细说一下Linux的配置,坑的要死。。。(各种百度各种查)
下载链接:链接:https://pan.baidu.com/s/1dFKyvldScvXxIXP18nmtpA
提取码:cvde
不乐意挣这个csdn币 直接放百度云,有用的话给个双击就行。
java项目下直接把sapjco3.jar 和sapjco3.dll 两个文件da放到 项目lib下
直接上代码:连接sap
package com.jeecg.sapjco;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoDestinationManager;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.ext.DestinationDataProvider;
import org.jeecgframework.core.annotation.JAuth;
import org.jeecgframework.core.enums.Permission;import java.io.File;
import java.io.FileOutputStream;
import java.util.Properties;@JAuth(auth= Permission.SKIP_AUTH) //跳过外部调用拦截
public class GetSapConn {static String ABAP_AS_POOLED = "SAP-RFC"; //所属异构系统 【找sap要】private static void createDataFile() {Properties properties = new Properties();//测试properties.setProperty(DestinationDataProvider.JCO_ASHOST, "**.**.**.***");//sap服务器地址properties.setProperty(DestinationDataProvider.JCO_SYSNR, "02");//系统编号,找SAP核对写00就可以了properties.setProperty(DestinationDataProvider.JCO_CLIENT, "6**");//集团号,不知道就问你们的sap basisproperties.setProperty(DestinationDataProvider.JCO_USER, "***");//帐号properties.setProperty(DestinationDataProvider.JCO_PASSWD, "****");//密码properties.setProperty(DestinationDataProvider.JCO_LANG, "zh");//语言String name = ABAP_AS_POOLED;String suffix = "jcoDestination";File cfg = new File(name + "." + suffix);if (!cfg.exists()) {try {FileOutputStream fos = new FileOutputStream(cfg, false);properties.store(fos, "for tests only !");fos.close();} catch (Exception e) {throw new RuntimeException("Unable to create the destination file " + cfg.getName(), e);}}}public static JCoDestination getJcoConnection() throws JCoException {createDataFile();return JCoDestinationManager.getDestination(ABAP_AS_POOLED);}}
测试案例【传入参数调用sap函数返回结果】
package com.jeecg.sapjco;import com.jeecg.roomRecord.entity.TAWorkroomRecordEntity;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoParameterList;
import com.sap.conn.jco.JCoTable;
import org.jeecgframework.core.annotation.JAuth;
import org.jeecgframework.core.common.controller.BaseController;
import org.jeecgframework.core.common.model.json.AjaxJson;
import org.jeecgframework.core.constant.Globals;
import org.jeecgframework.core.enums.Permission;
import org.jeecgframework.minidao.annotation.Param;
import org.jeecgframework.web.cgform.exception.BusinessException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;@Controller
@RequestMapping("/SapTest")
@JAuth(auth= Permission.SKIP_AUTH)
public class SapTest extends BaseController {/**** @param request* @return** Sap 函数:ZFI_FM_009*/@RequestMapping(params = "test")@ResponseBodypublic AjaxJson test(HttpServletRequest request) {String message = null;AjaxJson j = new AjaxJson();try {JCoDestination jCoDestination = null;// 连接对象JCoFunction function = null;// 调用rfc函数对象try {jCoDestination=GetSapConn.getJcoConnection();调用rfc-sap【ZFI_FM_009】函数对象--指的是调用sap 那边的函数名function = jCoDestination.getRepository().getFunctionTemplate("ZFI_FM_009").getFunction();if (null == function) {throw new RuntimeException("get function not found in sap");} else {JCoParameterList paramList = function.getImportParameterList();//【sap系统传入参数,有多个的话就写多行 LV_BANKA sap定义的函数参数名 有多个的话就写多行】paramList.setValue("LV_BANKA","参数值");paramList.setValue("LV_BANKL","参数值");//如果传如参数是内表的形式的话就以如下代码传入sap系统// JCoTable table1 = function.getTableParameterList().getTable("I_EKPO");// for (int i = 0; i < purchaseNo.size(); i++) {// table1.setRow(i);// table1.appendRow();// table1.setValue("EBELN", purchaseNo.get(i)[0]);// table1.setValue("EBELP", purchaseNo.get(i)[1]);// }function.execute(jCoDestination);//执行调用函数JCoTable table2 = function.getTableParameterList().getTable("ES_DATA");//[ES_DATA 是SAP返回 数据的“表名字”]得到sap返回的参数,你就把他当作c语言的结构体理解就可以了//有时候sap那边只是返回一个输出参数,sap比方说你这边输入一个物料号,想得到sap那边的物料描述,这是sap方是不会返回一个内表给你的//而是只是返回一个输出参数给你这时你就要用到下面的方法来得到输出参数//paramList = function.getExportParameterList();//paramList.getString("rfc返回字段字段名称");for (int i = 0; i < table2.getNumRows(); i++) {table2.setRow(i);//这里获取sap函数传出内表结构的字段 【传入的字符串为调用函数需要传入的参数名,必须为大写】String BANKL = table2.getString("BANKL");//【表结果里面的字段】记住这里BANKL一定是大写的,不然得不到值String BANKA = table2.getString("BANKA");//【表结果里面的字段】记住这里BANKA一定是大写的,不然得不到值System.out.println("BANKL:"+BANKL +"------"+ "BANKA"+BANKA);//得到了sap数据,然后下面就是你java擅长的部分了,想封装成什么类型的都由你}}} catch (Exception e1) {// TODO Auto-generated catch blocke1.printStackTrace();} finally {jCoDestination = null;}} catch (Exception e) {e.printStackTrace();message = "失败";throw new org.jeecgframework.core.common.exception.BusinessException(e.getMessage());}j.setMsg(message);return j;}
}
执行结果:
如果是 普通参数(相当于java 方法传入一个字符串 ) + 结构参数的话 说白了结构类型就相当于java传入一个Map
/*** IV_TYPE* IV_IS_COMMIT* IS_DATA [结构类型]* OA存储主数据存储接口--结构类型* ZSD_FM_CREATE_CUSTOMER* chufangbo 2020-04-11*/@RequestMapping(params = "get***SAP***Function")@ResponseBodypublic AjaxJson getSapBackFunction(HttpServletRequest request) {//TDingOaInfoEntity entity = JSONObject.parseObject(jsonObject, TDingOaInfoEntity.class);String message = null;AjaxJson j = new AjaxJson();try {JCoDestination destination = JCoDestinationManager.getDestination(ABAP_AS);//所属异构系统OA或者SAP提供JCoFunction function = destination.getRepository().getFunction("ZSD_FM_*******");//从对象仓库中获取 RFM 函数if (function == null)throw new RuntimeException("RFC_SYSTEM_INFO not found in SAP.");try {function.execute(destination);} catch (AbapException e) {System.out.println(e.toString());}JCoParameterList is_data_sum = function.getImportParameterList();is_data_sum.setValue("IV_TYPE","1");// 普通参数is_data_sum.setValue("IV_IS_COMMIT","X");// 普通参数//IS_DATA 是SAP 结构名称 类是与JAVA Map当参数传入Funtion的参数封装JCoStructure is_data = function.getImportParameterList().getStructure("IS_DATA");is_data.setValue("KTOKD","***");// KTOKD 是结构中的名称类似于java 传入一个map,在此处通过key赋值value进行封装//.............继续添加is_data_sum.setValue("IS_DATA",is_data);function.execute(destination);//执行调用函数JCoTable table2 = function.getTableParameterList().getTable("MESSTAB");//[MESSTAB 是SAP返回 数据的“表名字”]得到sap返回的参数,你就把他当作c语言的结构体理解就可以了//有时候sap那边只是返回一个输出参数,sap比方说你这边输入一个物料号,想得到sap那边的物料描述,这是sap方是不会返回一个内表给你的//而是只是返回一个输出参数给你这时你就要用到下面的方法来得到输出参数//获取sap回执编号JCoParameterList exportParameterList = function.getExportParameterList();Object ev_kunnr = exportParameterList.getValue("EV_KUNNR");System.out.println("获取SAP回传客户编号: "+ev_kunnr);for (int i = 0; i < table2.getNumRows(); i++) {table2.setRow(i);//这里获取sap函数传出内表结构的字段 【传入的字符串为调用函数需要传入的参数名,必须为大写】String TYPE = table2.getString("TYPE");//[消息类型:S 成功 E 错误 W警告 I信息 A 中断]记住这里参数一定是大写的,不然得不到值【如果报错说明你参数传的不对】String MESSAGE = table2.getString("MESSAGE");//记住这里一定是大写的,不然得不到值System.out.println("TYPE:"+TYPE +"MESSAGE:"+MESSAGE);}} catch (Exception e1) {// TODO Auto-generated catch blocke1.printStackTrace();}j.setMsg(message);return j;}
开始Linux :
首先不要依靠以上配置,和百度所说的去Linux去配置环境变量什么的。。。都没用。。。害我南辕北辙,ca踩了一个坑,跳出来又踩进去,又跳出来,又踩进去。。。。。
开始正文
找到Linux项目中的Tomcat /home/...../apache-tomcat-dd/webapps/项目名称/WEB-INF/lib
第一步 把以下三个文件丢进去。sapjcorfc 这两个文件,看网上说的天花乱坠的我是没用到。
第二步:找到 /home/......./apache-tomcat-dd/bin
把这两个文件丢进去,然后重新启动项目
然后你会发现 在bin目录下面生成一个 类是与 SAP-RFC.jcoDestination 。
注释:SAP-RFC是我调用sap那边定义的所属异构系统的名字,不用管,你们可能生成的别的名字
另外【如果本地测试之后没问题,或者到服务器上测试没问题的话,切换到正式连接之后发现数据还是测试库的,憋着急,此时请查看本地Tomcat 和服务器上tomcat/bin 目录下的SAP-RFC.jcoDestination ,的地址配置的还是测试库的,修改保存一下就OK了】
如果你们没生成,等会我在文章最开始的百度云放一个,你们模仿写一下你们自己的配置。添加进去。这个东西很重要,如果没有就会调用失败。
大致就是:(你们可以自己写一个方进去SAP-RFC是我调用sap那边定义的 你们用你们自己的)
#for tests only !
#Mon Apr 20 11:03:50 CST 2020
jco.client.lang=zh
jco.client.client=***
jco.client.passwd=***
jco.client.user=*****
jco.client.sysnr=0*
jco.client.ashost=2*.2*.2*.2**
大功告成:
注释:如果SAP那边报错
可能就是通过JAVA传输的时候 sap 那边不支持 Null,此时你可以debug 查看一下 然后用三元运算符赋值为 空串。