最近接到一任务,需求是SAP将采购请求发送给第三方EDI程序,我的任务是将第三方EDI接口封装好,然后供本公司SAP程序调用。之前都是JAVA通过JCO来调用SAP的RFC程序,这已经很熟悉了,没有任何问题。现在反过来调用,还是头一回,查阅了大量资料,终于搞定。现将研究成果与大家分享,避免大家走许多弯路。项目框架采用的是springmvc,spring初始化的时候加载该服务。
准备工作
安装JCo3
JCo有32位和64为之分,32位的JVM选择32位的JCO, 64位的JVM选择64位的JCO, 在windows环境,选择相应的 sapjco3.dll, Unix和Linux环境选择合适的 sapjco3.so,这里不多做介绍。如果服务器是window操作系统,见博客 no sapjco3 in java.library.path,如果服务器是linux操作系统,具体安装方法见博客 linux配置sapjco3。
JCo有32位和64为之分,32位的JVM选择32位的JCO, 64位的JVM选择64位的JCO, 在windows环境,选择相应的 sapjco3.dll, Unix和Linux环境选择合适的 sapjco3.so,这里不多做介绍。如果服务器是window操作系统,见博客 no sapjco3 in java.library.path,如果服务器是linux操作系统,具体安装方法见博客 linux配置sapjco3。
ABAP访问Java服务
1、ABAP端
ABAP(作为Clint端),调用JAVA(作为服务器端)。SAP通过JCO反向调用JAVA的RFC服务其实也是相对简单的,只是在JAVA端需要使用JCO创建一个RFC服务,然后在SAP端注册这个服务程序。
首先,JCo服务器程序需在网关中进行注册,在SM59中,定义一个连接类型为T的远程目标。
RFC目标系统:是ABAP RFC调用Java时,需指定的目标系统名。
Program ID:是JAVA程序中使用的。
Gateway Host与Gateway service值来自以下界面(Tcode:SMGW):
所有配置好且Java服务器代码跑起来后,点击“Connection Test”按钮,如不出现红色文本,则表示链接成功(注:此时需要ServerDataProvider.JCO_PROGID设置的Program ID要与SM59中设置的相同,否则测试不成功。另要注意的是:即使Java服务器设置的Program ID乱设置,Java服务端还是能启起来,但ABAP测试连接时会不成功,也就代表ABAP不能调用Java):
此时可以通过SMGW来观测连接:
如果出现如下异常:
连接异常registrationnot allowed
Java服务启动时,如出现以下异常,则需在SAP中修改网关参数:
com.sap.conn.jco.JCoException: (113) JCO_ERROR_REGISTRATION_DENIED: CPIC-CALL: SAP_CMACCPTP3 on convId:
LOCATION SAP-Gateway on host LRP-ERP / sapgw00
ERROR registration of tp JCOTEST from host JIANGZHENGJUN not allowed
TIME Wed Apr 16 21:25:39 2014
RELEASE 720
COMPONENT SAP-Gateway
VERSION 2
RC 720
MODULE gwxxrd.c
LINE 3612
COUNTER 275
代码如下:
*&---------------------------------------------------------------------*
*& Report ZRMMLQ_REQUEST_OUT
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT zrmmlq_request_out.
TABLES: zmmlqpo_d,
zmmlqpo_h.
DATA: requesth TYPE zslq_request_out OCCURS 0 WITH HEADER LINE,
requestd TYPE zslq_request_out_item OCCURS 0 WITH HEADER LINE.
DATA: i_h LIKE zmmlqpo_h OCCURS 0 WITH HEADER LINE,
i_d LIKE zmmlqpo_d OCCURS 0 WITH HEADER LINE.
DATA: message TYPE char100.
DATA: v_p(6) TYPE c.
DATA: v_q(6) TYPE c.
DATA: v_string TYPE string.
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE text-001.
SELECT-OPTIONS: s_ebeln FOR zmmlqpo_h-ebeln,
s_aedat FOR zmmlqpo_h-aedat.
SELECTION-SCREEN END OF BLOCK b1.
START-OF-SELECTION.
SELECT * FROM zmmlqpo_h INTO TABLE i_h
WHERE ebeln IN s_ebeln
AND aedat IN s_aedat
AND status = '02'.
IF sy-subrc EQ 0.
SELECT * FROM zmmlqpo_d INTO TABLE i_d
FOR ALL ENTRIES IN i_h
WHERE ebeln = i_h-ebeln.
LOOP AT i_h.
MOVE i_h-aedat TO requesth-porchasedate.
MOVE i_h-ebeln TO requesth-pono.
MOVE i_h-thirdparty TO requesth-thirdparty.
* request-others
requesth-signtype = 'B'.
* request-purchasecontact
* request-contactareatel
* request-contacttel
** CLEAR orderitem.
** CLEAR orderitem[].
*
*
** request-orderitem = orderitem[].
SELECT SINGLE province
city
district
county
street
segment
tunnel
znum
FROM zmd_sqxx1
INTO (requesth-province,
requesth-city,
requesth-area,
requesth-village,
requesth-road,
requesth-section,
requesth-lane,
requesth-oddeven
)
WHERE zzmd_mdbm = requesth-shiptocust.
READ TABLE i_d WITH KEY ebeln = i_h-ebeln.
IF sy-subrc EQ 0.
MOVE i_d-werks TO requesth-shiptocust.
ENDIF.
APPEND requesth.
CLEAR requesth.
ENDLOOP.
LOOP AT i_d .
MOVE i_d-ebeln TO requestd-pono.
* requestd-POCOMMENTS
MOVE i_d-ebelp TO requestd-polineno.
MOVE i_d-matnr TO requestd-stockcode.
*requestd-UNITPRICE
MOVE i_d-menge TO v_string.
SPLIT v_string AT '.' INTO v_p v_q.
MOVE v_p TO requestd-orderqty.
*requestd-DISCOUNT
*requestd-PROMOTION
APPEND requestd.
ENDLOOP.
CALL FUNCTION 'ZFM_LQ_REQUEST_OUT' DESTINATION 'ZLQTEST'
IMPORTING
message = message
TABLES
requesth = requesth
requestd = requestd.
IF message = 'SUCCESS'.
LOOP AT i_h.
i_h-status = '01'.
MODIFY i_h.
ENDLOOP.
ELSE.
LOOP AT i_h.
i_h-status = '00'.
MODIFY i_h.
ENDLOOP.
ENDIF.
MODIFY zmmlqpo_h FROM TABLE i_h.
* CALL FUNCTION 'ZFM_LQ_REQUEST_OUT' DESTINATION 'ZLQTEST'
* TABLES
* requesth = requesth
* requestd = requestd.
ENDIF.
对应的RFC结构如下:
2、JAVA端
采购单头代码如下:
package com.pcmall.domain.vo;
import java.util.Date;
import java.util.List;
public class SapPo {
private String PorchaseDate;
private String PoNo;
private String ThirdParty;
private String ShipToCust;
private String Province;
private String City;
private String Area;
private String Village;
private String Road;
private String Section;
private String Lane;
private String Oddeven;
private String Others;
private String SignType;
private String PurchaseContact;
private String ContactAreaTel;
private String ContactTel;
private List<SapPod> pods;
public String getPorchaseDate() {
return PorchaseDate;
}
public void setPorchaseDate(String porchaseDate) {
PorchaseDate = porchaseDate;
}
public String getPoNo() {
return PoNo;
}
public void setPoNo(String poNo) {
PoNo = poNo;
}
public String getThirdParty() {
return ThirdParty;
}
public void setThirdParty(String thirdParty) {
ThirdParty = thirdParty;
}
public String getShipToCust() {
return ShipToCust;
}
public void setShipToCust(String shipToCust) {
ShipToCust = shipToCust;
}
public String getProvince() {
return Province;
}
public void setProvince(String province) {
Province = province;
}
public String getCity() {
return City;
}
public void setCity(String city) {
City = city;
}
public String getArea() {
return Area;
}
public void setArea(String area) {
Area = area;
}
public String getVillage() {
return Village;
}
public void setVillage(String village) {
Village = village;
}
public String getRoad() {
return Road;
}
public void setRoad(String road) {
Road = road;
}
public String getSection() {
return Section;
}
public void setSection(String section) {
Section = section;
}
public String getLane() {
return Lane;
}
public void setLane(String lane) {
Lane = lane;
}
public String getOddeven() {
return Oddeven;
}
public void setOddeven(String oddeven) {
Oddeven = oddeven;
}
public String getOthers() {
return Others;
}
public void setOthers(String others) {
Others = others;
}
public String getSignType() {
return SignType;
}
public void setSignType(String signType) {
SignType = signType;
}
public String getPurchaseContact() {
return PurchaseContact;
}
public void setPurchaseContact(String purchaseContact) {
PurchaseContact = purchaseContact;
}
public String getContactAreaTel() {
return ContactAreaTel;
}
public void setContactAreaTel(String contactAreaTel) {
ContactAreaTel = contactAreaTel;
}
public String getContactTel() {
return ContactTel;
}
public void setContactTel(String contactTel) {
ContactTel = contactTel;
}
public List<SapPod> getPods() {
return pods;
}
public void setPods(List<SapPod> pods) {
this.pods = pods;
}
}
采购单行代码如下:
package com.pcmall.domain.vo;
public class SapPod {
private String PoComments;
private String PoLineNo;
private String StockCode;
private String UnitPrice;
private String OrderQty;
private String Discount;
private String Promotion;
public String getPoComments() {
return PoComments;
}
public void setPoComments(String poComments) {
PoComments = poComments;
}
public String getPoLineNo() {
return PoLineNo;
}
public void setPoLineNo(String poLineNo) {
PoLineNo = poLineNo;
}
public String getStockCode() {
return StockCode;
}
public void setStockCode(String stockCode) {
StockCode = stockCode;
}
public String getUnitPrice() {
return UnitPrice;
}
public void setUnitPrice(String unitPrice) {
UnitPrice = unitPrice;
}
public String getOrderQty() {
return OrderQty;
}
public void setOrderQty(String orderQty) {
OrderQty = orderQty;
}
public String getDiscount() {
return Discount;
}
public void setDiscount(String discount) {
Discount = discount;
}
public String getPromotion() {
return Promotion;
}
public void setPromotion(String promotion) {
Promotion = promotion;
}
}
SAPJCO连接类代码如下:
package com.pcmall.common.sap;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import com.sap.conn.jco.JCo;
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.ServerDataProvider;
public class SapjcoConnector {
private static Logger logger = LoggerFactory
.getLogger(SapjcoConnector.class);
static Hashtable<String, JCoDestination> destinations = new Hashtable<String, JCoDestination>();
public static String SERVER_NAME = "SANPOWER_SERVER";
public static String DESTINATION_NAME = "ABAP_AS_WITH_POOL";
static {
try {
doInitialize();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 初始化SAP连接
*
* @param fdPoolName
* @return
* @throws Exception
*/
public static synchronized void doInitialize() throws Exception {
JCo.setTrace(4, null);// 打开调试
Properties connectProperties = new Properties();
InputStream is = SapjcoConnector.class
.getResourceAsStream("/properties/sap-config.properties");
connectProperties.load(is);
createDataFile(DESTINATION_NAME, "jcoDestination", connectProperties);
// ******JCo sever
Properties servertProperties = new Properties();
InputStream isServer = SapjcoConnector.class
.getResourceAsStream("/properties/sap-config-server.properties");
servertProperties.load(isServer);
/*servertProperties.setProperty(ServerDataProvider.JCO_GWHOST,
"xxx.xxx.xxx.xxx");
// TCP服务sapgw是固定的,后面的00就是SAP实例系统编号,也可直接是端口号(端口号可以在
// etc/server文件中找sapgw00所对应的端口号)
servertProperties.setProperty(ServerDataProvider.JCO_GWSERV, "sapgw30");
// 这里的程序ID来自于SM59中设置的Program ID,必须相同
servertProperties
.setProperty(ServerDataProvider.JCO_PROGID, "JCO_SANPOWER_LQ");
servertProperties.setProperty(ServerDataProvider.JCO_REP_DEST,
DESTINATION_NAME);
servertProperties.setProperty(ServerDataProvider.JCO_CONNECTION_COUNT,
"2");*/
createDataFile(SERVER_NAME, "jcoServer", servertProperties);
}
/**
* 创建连接文件(必须)
*
* @param name
* @param suffix
* @param properties
*/
private static void createDataFile(String name, String suffix,
Properties properties) {
File cfg = new File(name + "." + suffix);
if (cfg.exists()) {
cfg.deleteOnExit();
}
try {
FileOutputStream fos = new FileOutputStream(cfg, false);
properties.store(fos, "for connection");
fos.close();
logger.info("createDataFile: " + name + "." + suffix);
} catch (Exception e) {
throw new RuntimeException(
"Unable to create the destination file "
+ cfg.getName(), e);
}
}
/**
* 获取连接池,利用JCoDestinationManager创建连接池放到表中
*
* @param fdPoolName
* @return
* @throws Exception
*/
public static JCoDestination getDestination(String fdPoolName)
throws Exception {
JCoDestination destination = null;
if (destinations.containsKey(fdPoolName)) {
destination = destinations.get(fdPoolName);
} else {
destination = JCoDestinationManager.getDestination(fdPoolName);
destinations.put(fdPoolName, destination);
}
return destination;
}
}
Service层代码如下:
package com.pcmall.service.sap.impl;
import java.io.ByteArrayOutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.stereotype.Service;
import com.pcmall.common.sap.SapConnector;
import com.pcmall.common.sap.SapjcoConnector;
import com.pcmall.common.utils.XmlConverUtil;
import com.pcmall.domain.vo.ResponseVO;
import com.pcmall.domain.vo.SapPo;
import com.pcmall.domain.vo.SapPod;
import com.pcmall.domain.vo.SapPurchaseAttachDetailVO;
import com.pcmall.domain.vo.SapPurchaseAttachVO;
import com.pcmall.service.sap.ISapService;
import com.pcmall.service.sap.impl.SapRfc.StfcConnectionHandler;
import com.sap.conn.jco.JCo;
import com.sap.conn.jco.JCoCustomRepository;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoDestinationManager;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoFunctionTemplate;
import com.sap.conn.jco.JCoListMetaData;
import com.sap.conn.jco.JCoMetaData;
import com.sap.conn.jco.JCoParameterList;
import com.sap.conn.jco.JCoRecord;
import com.sap.conn.jco.JCoRepository;
import com.sap.conn.jco.JCoTable;
import com.sap.conn.jco.server.DefaultServerHandlerFactory;
import com.sap.conn.jco.server.JCoServer;
import com.sap.conn.jco.server.JCoServerContext;
import com.sap.conn.jco.server.JCoServerContextInfo;
import com.sap.conn.jco.server.JCoServerErrorListener;
import com.sap.conn.jco.server.JCoServerExceptionListener;
import com.sap.conn.jco.server.JCoServerFactory;
import com.sap.conn.jco.server.JCoServerFunctionHandler;
import com.sap.conn.jco.server.JCoServerState;
import com.sap.conn.jco.server.JCoServerStateChangedListener;
@Service
public class SapServiceImpl implements ISapService {
@Override
public ResponseVO submitPurchaseAttach(SapPurchaseAttachVO attach)
throws Exception {
ResponseVO responseVO = new ResponseVO();
String sParam[] = null;
JCoDestination foo = SapConnector
.getDestination(SapConnector.fdPoolName);
JCoRepository mRepository = foo.getRepository();
JCoFunctionTemplate ft = mRepository.getFunctionTemplate("ZFMHK_ORDER");
JCoFunction function = ft.getFunction();
JCoParameterList input = function.getImportParameterList();
// 设置输入参数
// 设置输入参数
JCoTable tableDataH = function.getTableParameterList().getTable(
"I_ZTHK0001H");
tableDataH.appendRow();
tableDataH.setValue("MANDT", attach.getMANDT());
tableDataH.setValue("ZERPNO", attach.getZERPNO());
tableDataH.setValue("ZTYPE", attach.getZTYPE());
tableDataH.setValue("BUKRS_F", attach.getBUKRS_F());
tableDataH.setValue("KOSTL_F", attach.getKOSTL_F());
tableDataH.setValue("PRCTR_F", attach.getPRCTR_F());
tableDataH.setValue("PRCTR_F", attach.getPRCTR_F());
tableDataH.setValue("ZFROMNO", attach.getZFROMNO());
tableDataH.setValue("BUKRS_T", attach.getBUKRS_T());
tableDataH.setValue("KOSTL_T", attach.getKOSTL_T());
tableDataH.setValue("PRCTR_T", attach.getPRCTR_T());
tableDataH.setValue("ZTONO", attach.getZTONO());
tableDataH.setValue("ZSTATUS", attach.getZSTATUS());
tableDataH.setValue("EKORG", attach.getEKORG());
tableDataH.setValue("LIFNR", attach.getLIFNR());
tableDataH.setValue("LIFNR_TXT", attach.getLIFNR_TXT());
tableDataH.setValue("ZBEIZHU", attach.getZBEIZHU());
tableDataH.setValue("BUDAT", attach.getBUDAT());
tableDataH.setValue("ZOUTIN", attach.getZOUTIN());
tableDataH.setValue("BELNR1", attach.getBELNR1());
tableDataH.setValue("BELNR2", attach.getBELNR2());
tableDataH.setValue("ERDAT", attach.getERDAT());
tableDataH.setValue("ZCRE_DATE", attach.getZCRE_DATE());
tableDataH.setValue("ZCRE_TIME", attach.getZCRE_TIME());
tableDataH.setValue("ZCRE_USER", attach.getZCRE_USER());
tableDataH.setValue("ZUP_DATE", attach.getZUP_DATE());
tableDataH.setValue("ZUP_TIME", attach.getZUP_TIME());
tableDataH.setValue("ZUP_USER", attach.getZUP_USER());
tableDataH.setValue("NETWR2", attach.getNETWR2());
JCoTable tableData = function.getTableParameterList().getTable(
"I_ZTHK0001D");
for (SapPurchaseAttachDetailVO detail : attach.getDetails()) {
tableData.appendRow();
tableData.setValue("MANDT", detail.getMANDT());
tableData.setValue("ZERPNO", detail.getZERPNO());
tableData.setValue("POSNUM", detail.getPOSNUM());
tableData.setValue("MATNR", detail.getMATNR());
tableData.setValue("MAKTX", detail.getMAKTX());
tableData.setValue("MENGE", detail.getMENGE());
tableData.setValue("NETPR", detail.getNETPR());
tableData.setValue("NETWR", detail.getNETWR());
// tableData.setValue("NETWR2",detail.getNETWR2());
tableData.setValue("MWSBP", detail.getMWSBP());
tableData.setValue("ZOUTIN", detail.getZOUTIN());
}
// 执行function
function.execute(foo);
// 得到输出参数TABLE
// JCoTable tableExport =
// function.getTableParameterList().getTable("RETURN");
String result = function.getExportParameterList().getString("RETCODE");
String message = function.getExportParameterList().getString("RETMSG");
if (result.equals("E")) {
responseVO.setSuccess(false);
responseVO.setErrorMsg(message);
} else {
responseVO.setSuccess(true);
}
return responseVO;
}
@Override
public ResponseVO submitPo2Lq() {
// TODO Auto-generated method stub
return null;
}
// 在Java服务端定义远程函数(不需要在ABAP端进行函数的签名定义)
@PostConstruct
static void startPo2LqRfc() {
/*
* JCoListMetaData impList = JCo.createListMetaData("IMPORT");
* impList.add("REQUTEXT", JCoMetaData.TYPE_CHAR, 100, 50, 0, null,
* null, JCoListMetaData.IMPORT_PARAMETER, null, null);
* impList.lock();// 锁住,不允许再修改
*/
JCoListMetaData expList = JCo.createListMetaData("EXPORT");
expList.add("MESSAGE", JCoMetaData.TYPE_CHAR, 100, 50, 0, null, null,
JCoListMetaData.EXPORT_PARAMETER, null, null);
expList.lock();
JCoListMetaData tblList = JCo.createListMetaData("TABLE");
tblList.add("REQUESTH", JCoMetaData.TYPE_TABLE, 1000, 500, 0, null, null,
JCoListMetaData.OPTIONAL_PARAMETER, "ZSLQ_REQUEST_OUT", null);
tblList.add("REQUESTD", JCoMetaData.TYPE_TABLE, 1000, 500, 0, null, null,
JCoListMetaData.OPTIONAL_PARAMETER, "ZSLQ_REQUEST_OUT_ITEM", null);
tblList.lock();
// 注:ZSTFC_CONNECTION函数不必要在ABAP端时行定义了(只定义签名,不需要实现),因为在这里(Java)
// 进行了动态的函数对象创建的创建与注册,这与上面simpleServer方法示例是不一样的
JCoFunctionTemplate fT = JCo.createFunctionTemplate("ZFM_LQ_REQUEST_OUT",
null, expList, null, tblList, null);
JCoCustomRepository cR = JCo
.createCustomRepository("MyCustomRepository");
cR.addFunctionTemplateToCache(fT);
JCoServer server;
try {
server = JCoServerFactory.getServer(SapjcoConnector.SERVER_NAME);
} catch (JCoException ex) {
throw new RuntimeException("Unable to create the server "
+ SapjcoConnector.SERVER_NAME + " because of "
+ ex.getMessage(), ex);
}
String repDest = server.getRepositoryDestination();
if (repDest != null) {
try {
cR.setDestination(JCoDestinationManager.getDestination(repDest));
} catch (JCoException e) {
e.printStackTrace();
System.out
.println(">>> repository contains static function definition only");
}
}
server.setRepository(cR);
JCoServerFunctionHandler requestHandler = new StfcConnectionHandler();
DefaultServerHandlerFactory.FunctionHandlerFactory factory = new DefaultServerHandlerFactory.FunctionHandlerFactory();
factory.registerHandler(fT.getName(), requestHandler);
server.setCallHandlerFactory(factory);
server.start();
}
// 处理来自ABAP端的调用请求,实现注册过的虚拟函数真正功能
static class StfcConnectionHandler implements JCoServerFunctionHandler {
public void handleRequest(JCoServerContext serverCtx,
JCoFunction function) {// 处理远程调用请求
printServerInfo(serverCtx, function);
JCoTable poTable = function.getTableParameterList().getTable(
"REQUESTH");
JCoTable podTable = function.getTableParameterList().getTable(
"REQUESTD");
List<SapPo> listPo = new ArrayList<SapPo>();
for(int i=0;i<poTable.getNumRows();i++){
poTable.setRow(i);
SapPo po = new SapPo();
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
Date date = null;
try {
date = formatter.parse(poTable.getString("PORCHASEDATE"));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String dateString = formatter.format(date);
po.setPorchaseDate(dateString);
po.setPoNo(poTable.getString("PONO"));
po.setThirdParty(poTable.getString("THIRDPARTY"));
po.setShipToCust(poTable.getString("SHIPTOCUST"));
po.setProvince(poTable.getString("PROVINCE"));
po.setCity(poTable.getString("CITY"));
po.setArea(poTable.getString("AREA"));
po.setVillage(poTable.getString("VILLAGE"));
po.setRoad(poTable.getString("ROAD"));
po.setSection(poTable.getString("SECTION"));
po.setLane(poTable.getString("LANE"));
po.setOddeven(poTable.getString("ODDEVEN"));
po.setOthers(poTable.getString("OTHERS"));
po.setSignType(poTable.getString("SIGNTYPE"));
po.setPurchaseContact(poTable.getString("PURCHASECONTACT"));
po.setContactAreaTel(poTable.getString("CONTACTAREATEL"));
po.setContactTel(poTable.getString("CONTACTTEL"));
List<SapPod> listPod = new ArrayList<SapPod>();
for(int j=0;j<podTable.getNumRows();j++){
podTable.setRow(j);
if(podTable.getString("PONO").equals(poTable.getString("PONO"))){
SapPod pod = new SapPod();
pod.setPoComments(podTable.getString("POCOMMENTS"));
pod.setPoLineNo(podTable.getString("POLINENO"));
pod.setStockCode(podTable.getString("STOCKCODE"));
pod.setUnitPrice(podTable.getString("UNITPRICE"));
pod.setOrderQty(podTable.getString("ORDERQTY"));
pod.setDiscount(podTable.getString("DISCOUNT"));
pod.setPromotion(podTable.getString("PROMOTION"));
listPod.add(pod);
}
}
po.setPods(listPod);
listPo.add(po);
}
try {
System.out.println(listtoXml(listPo));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
function.getExportParameterList().setValue("MESSAGE", "SUCCESS");
}
public void printServerInfo(JCoServerContext serverCtx,
JCoFunction function) {
System.out
.println("----------------------------------------------------------------");
System.out.println("call : " + function.getName());// ABAP调用的是哪个函数
System.out.println("ConnectionId : "
+ serverCtx.getConnectionID());
System.out.println("SessionId : "
+ serverCtx.getSessionID());
System.out.println("TID : " + serverCtx.getTID());
System.out.println("repository name : "
+ serverCtx.getRepository().getName());
System.out.println("is in transaction : "
+ serverCtx.isInTransaction());
System.out.println("is stateful : "
+ serverCtx.isStatefulSession());
System.out
.println("----------------------------------------------------------------");
System.out.println("gwhost: "
+ serverCtx.getServer().getGatewayHost());
System.out.println("gwserv: "
+ serverCtx.getServer().getGatewayService());
System.out.println("progid: "
+ serverCtx.getServer().getProgramID());
System.out
.println("----------------------------------------------------------------");
System.out.println("attributes : ");
System.out.println(serverCtx.getConnectionAttributes().toString());
System.out
.println("----------------------------------------------------------------");
System.out.println("CPIC conversation ID: "
+ serverCtx.getConnectionAttributes()
.getCPICConversationID());
System.out
.println("----------------------------------------------------------------");
}
}
static class MyThrowableListener implements JCoServerErrorListener,
JCoServerExceptionListener {// 服务异常监听器
public void serverErrorOccurred(JCoServer jcoServer,
String connectionId, JCoServerContextInfo serverCtx, Error error) {
System.out.println(">>> Error occured on "
+ jcoServer.getProgramID() + " connection " + connectionId);
error.printStackTrace();
}
public void serverExceptionOccurred(JCoServer jcoServer,
String connectionId, JCoServerContextInfo serverCtx,
Exception error) {
System.out.println(">>> Error occured on "
+ jcoServer.getProgramID() + " connection " + connectionId);
error.printStackTrace();
}
}
static class MyStateChangedListener implements
JCoServerStateChangedListener {// 服务状态改变监听器
public void serverStateChangeOccurred(JCoServer server,
JCoServerState oldState, JCoServerState newState) {
// Defined states are: STARTED启动, DEAD死, ALIVE活, STOPPED停止;
// see JCoServerState class for details.
// Details for connections managed by a server instance
// are available via JCoServerMonitor.
System.out.println("Server state changed from "
+ oldState.toString() + " to " + newState.toString()
+ " on server with program id " + server.getProgramID());
}
}
/**
*
* @param document
* @return
*/
public static String doc2String(Document document) {
String s = "";
try {
// 使用输出流来进行转化
ByteArrayOutputStream out = new ByteArrayOutputStream();
// 使用UTF-8编码
OutputFormat format = new OutputFormat(" ", true, "UTF-8");
XMLWriter writer = new XMLWriter(out, format);
writer.write(document);
s = out.toString("UTF-8");
} catch (Exception ex) {
ex.printStackTrace();
}
return s;
}
public static String listtoXml(List<SapPo> listSapPo) throws Exception{
//创建文档及设置根元素节点的方式
Element root = DocumentHelper.createElement("PurchaseOrdersRequest");
Document document = DocumentHelper.createDocument(root);
Element baseID = root.addElement("BaseID").addText("10321");
Element purchaseOrderList = root.addElement("PurchaseOrderList");
for(SapPo po : listSapPo){
Element purchaseOrder = purchaseOrderList.addElement("PurchaseOrder");
Element porchaseDate = purchaseOrder.addElement("PorchaseDate").addText(po.getPorchaseDate());
Element poNo = purchaseOrder.addElement("PoNo").addText(po.getPoNo());
Element thirdParty = purchaseOrder.addElement("ThirdParty").addText(po.getThirdParty());
Element shipToCust = purchaseOrder.addElement("shipToCust").addText(po.getShipToCust());
Element province = purchaseOrder.addElement("Province").addText(po.getProvince());
Element city = purchaseOrder.addElement("City").addText(po.getCity());
Element area = purchaseOrder.addElement("Area").addText(po.getArea());
Element village = purchaseOrder.addElement("Village").addText(po.getVillage());
Element road = purchaseOrder.addElement("Road").addText(po.getRoad());
Element section = purchaseOrder.addElement("Section").addText(po.getSection());
Element lane = purchaseOrder.addElement("Lane").addText(po.getLane());
Element oddeven = purchaseOrder.addElement("Oddeven").addText(po.getOddeven());
Element others = purchaseOrder.addElement("Others").addText(po.getOthers());
Element signType = purchaseOrder.addElement("SignType").addText(po.getSignType());
Element purchaseContact = purchaseOrder.addElement("PurchaseContact").addText(po.getPurchaseContact());
Element contactAreaTel = purchaseOrder.addElement("contactAreaTel").addText(po.getContactAreaTel());
Element contactTel = purchaseOrder.addElement("contactTel").addText(po.getContactTel());
Element orderItemList = purchaseOrder.addElement("OrderItemList");
for(SapPod pod : po.getPods()){
Element orderItem = orderItemList.addElement("OrderItem");
Element poComments = orderItem.addElement("PoComments").addText(pod.getPoComments());
Element poLineNo = orderItem.addElement("PoLineNo").addText(pod.getPoLineNo());
Element stockCode = orderItem.addElement("StockCode").addText(pod.getStockCode());
Element unitPrice = orderItem.addElement("UnitPrice").addText(pod.getUnitPrice());
Element orderQty = orderItem.addElement("OrderQty").addText(pod.getOrderQty());
Element discount = orderItem.addElement("Discount").addText(pod.getDiscount());
Element promotion = orderItem.addElement("Promotion").addText(pod.getPromotion());
}
}
String strXml = doc2String(document);
return strXml;
}
}
3、ABAP端调用
ABAP端调用后,JAVA根据采购单列表进行拼接XML,生成的XML文件如下,供第三方EDI做为入参。<?xml version="1.0" encoding="utf-8"?>
<PurchaseOrdersRequest>
<BaseID>10321</BaseID>
<PurchaseOrderList>
<PurchaseOrder>
<PorchaseDate>2017-04-17</PorchaseDate>
<PoNo>4500004860</PoNo>
<ThirdParty>N</ThirdParty>
<shipToCust/>
<Province/>
<City/>
<Area/>
<Village/>
<Road/>
<Section/>
<Lane/>
<Oddeven/>
<Others/>
<SignType>B</SignType>
<PurchaseContact/>
<contactAreaTel/>
<contactTel/>
<OrderItemList/>
</PurchaseOrder>
<PurchaseOrder>
<PorchaseDate>2017-05-03</PorchaseDate>
<PoNo>4500004863</PoNo>
<ThirdParty>N</ThirdParty>
<shipToCust>D000</shipToCust>
<Province/>
<City/>
<Area/>
<Village/>
<Road/>
<Section/>
<Lane/>
<Oddeven/>
<Others/>
<SignType>B</SignType>
<PurchaseContact/>
<contactAreaTel/>
<contactTel/>
<OrderItemList>
<OrderItem>
<PoComments/>
<PoLineNo>00001</PoLineNo>
<StockCode>000000000000106261</StockCode>
<UnitPrice/>
<OrderQty>10</OrderQty>
<Discount/>
<Promotion/>
</OrderItem>
</OrderItemList>
</PurchaseOrder>
<PurchaseOrder>
<PorchaseDate>2017-05-03</PorchaseDate>
<PoNo>4500004864</PoNo>
<ThirdParty>N</ThirdParty>
<shipToCust>D000</shipToCust>
<Province/>
<City/>
<Area/>
<Village/>
<Road/>
<Section/>
<Lane/>
<Oddeven/>
<Others/>
<SignType>B</SignType>
<PurchaseContact/>
<contactAreaTel/>
<contactTel/>
<OrderItemList>
<OrderItem>
<PoComments/>
<PoLineNo>00001</PoLineNo>
<StockCode>000000000000106261</StockCode>
<UnitPrice/>
<OrderQty>10</OrderQty>
<Discount/>
<Promotion/>
</OrderItem>
<OrderItem>
<PoComments/>
<PoLineNo>00002</PoLineNo>
<StockCode>000000000000106262</StockCode>
<UnitPrice/>
<OrderQty>2</OrderQty>
<Discount/>
<Promotion/>
</OrderItem>
</OrderItemList>
</PurchaseOrder>
</PurchaseOrderList>
</PurchaseOrdersRequest>
4、常见问题
开发完毕之后,我就将程序发布到Linux测试服务器上,结果SAP端通过SMGW是可以连接的,但是通过SM59测试连接,死活连接不通。一直报如下错误:
后来想是不是Linux服务器问题啊,我们领导就让我在Windows服务器上再部署试一下,结果还是不行,不过它报错了,一直报"sapgw30 service unknow...",后来一想我机器上是安装了SAP客户端,目录“C:\Windows\System32\drivers\etc"下的services文件中有sapgw30服务,这样我们在services文件中加入sapgw30服务,就可以了。
同理,我们在Linux服务器上
/etc/services也添加sapgw30服务,
sapgw30 3330/tcp
这下就能成功连接了。
注:
/etc/services文件包含了服务名和端口号之间的映射,很多的系统程序要使用这个文件。一般情况下,不要修改该文件的内容,因为这些设置都是Internet标准的设置。一旦修改,可能会造成系统冲突,使用户无法正常访问资源。Linux系统的端口号的范围为0–65535,不同范围有不同的意义。
0 不使用
1--1023 系统保留,只能由root用户使用
1024---4999 由客户端程序自由分配
5000---65535 由服务器端程序自由分配
0 不使用
1--1023 系统保留,只能由root用户使用
1024---4999 由客户端程序自由分配
5000---65535 由服务器端程序自由分配
至此大功告成!