Java连接SAP ————JCO 3.0技术详解

SAP的ERP平台很强大,这是毋庸置疑的,它被运用于个个行业领域,也正因如此,所以公司上线SAP后,总需要花费很多时间去培养用户,有时候,在SAP上,用户的操作需求很简单,但在SAP平台上,却不得不进行许多复杂的操作。

=======================================================================================

在我们公司,许多Sales和“老大们”都是电脑白痴,SAP虽然很强大,但是在他们自己用来,却觉得很复杂繁琐,他们想查看一下报表、操作一些功能,总要记住各种T-CODE,随着开发人员开发的T-CODE越来越多,用户要记住的也就越多。 SAP虽然很强大,但是也有不少不方便的地方,因为它不是针对某个公司去设计的,所以它也有很多不完善和不能满足公司需求的地方。

随着公司的用户越来越多,公司SAP购买的帐号分配和权限分配也不断被需求,很多时候几十个用户,虽然他们有很多时候对SAP的操作需求是一样的,但是公司却不得不为他们购买和分配SAP帐号...基于公司内部的需求,我们希望能把SAP上一些简单的功能模块抽取出来, 架设 一个Web平台,该平台旨在:打造一个更加符合本公司需求、提高用户效率、便捷、主流的接口平台。

经过比较和分析,我们决定使用 JCO技术,我作为一个Java出身的ABAP开发员,从来没有真正去了解过JCO技术,上网才发现,JCO技术早已经更新到了3.0版本了,可是在中文网上(百度、360搜索)的许多资料却都是关于 JCO 2.0 技术的,关于JCO3.0的资料寥寥无几,谷歌上虽然也有不少,可是在开发过程遇到的许多问题,在谷歌上回答的人也不多。但是为了与时俱进,我还是花了一段时间认真的研究了JCO 3.0的API,和查找了不少的资料。终于给我研究出来了,经过不断的开发和对JCO 3.0的不断渗透了解,现在已经能很好的驾驭它。

废话少说,就和大家一起分享一下啊JCO 3.0的实现技术吧。

<!--[if !supportLists]--> 1、 <!--[endif]--> 首先,如果不知道JCO是什么?和JCO能干什么的?自己去谷歌吧,这里就不解释了。我们先来看一下JCO 3.0是如何连接SAP Netweaver  的。

  JCO 3.0与2.0有许多的不同,它对SAP的连接更加的快捷、稳定和高效,不相信的,可以在学完3.0技术后,再去看看2.0的技术吧。

  JCO 3.0对SAP的接口操作一般有两种方式:一种是以Web服务器作为客户端,SAP Netweaver为服务端,传输和接收数据;另一种是作为Server端,但是这种方式我没怎么了解,只是测试过,在Web端stop和start Web Server后,SAP会产生什么样的反应;而且在网上大量的资料也都是关于第一种的连接方式。

     所以,在此,我就只介绍第一种连接方式吧,第一种连接SAP方式的原理是:

    以Web Server(Tomcat)作为客户端,JCO技术作为中间接口桥梁,SAP作为服务的,用户在Web端所有的操作数据最终将通过RFC回滚到SAP上去维护,SAP会自动处理这些数据,这和BAPI原理是一样的。 许多公司,上线了SAP后,需要将原来公司内部的ERP软件上的数据写入SAP,也是通过JCO技术作为桥梁来处理的。

  

<!--[if !supportLists]--> 2、 <!--[endif]--> 连接第一步:

   JCO连接SAP时,先要创建一个连接池,它的连接信息保存在一个Properties文件里。

   /**

* 创建属性文件



*  @param  filename

*            文件名

*  @param  stuffix

*            後綴名

*  @param  host

*            主機地址

*  @param  sysnr

*            系統ID

*  @param  client

*            客戶端

*  @param  user

*            用戶名

*  @param  pass

*            密碼

*  @param  lang

*            語言

*  @param  pool_capacity  最大空閒連接

*  @param  peak_limit 最大活動鏈接數

*  @return

*/

public   static   boolean   creatSapPros (String filename, String stuffix,

String host, String sysnr, String client, String user, String pass,

String lang, String pool_capacity, String peak_limit) {

Properties pros =  new  Properties();

boolean  iscreate =  false ;

String sysno =  "" ;

if  (sysnr.equals( "AFD" )) {

sysno =  "00" ;

}

if  (sysnr.equals( "AFQ" )) {

sysno =  "00" ;

}

if  (sysnr.equals( "AFP" )) {

sysno =  "01" ;

}

if  (lang.equals( "" )) {

lang =  "ZF" ;

}

pros.clear();  // 先清空

pros.setProperty(DestinationDataProvider. JCO_ASHOST , host);

pros.setProperty(DestinationDataProvider. JCO_SYSNR , sysno);

pros.setProperty(DestinationDataProvider. JCO_CLIENT , client);

pros.setProperty(DestinationDataProvider. JCO_USER , user);

pros.setProperty(DestinationDataProvider. JCO_PASSWD , pass);

pros.setProperty(DestinationDataProvider. JCO_LANG , lang);

pros.setProperty(DestinationDataProvider. JCO_POOL_CAPACITY ,

pool_capacity);

pros.setProperty(DestinationDataProvider. JCO_PEAK_LIMIT , peak_limit);

iscreate =  createFiles (filename, stuffix, pros);

if  (iscreate) {

return   true ;

}  else  {

return   false ;

}

}

/**

* 判斷文件是否存在



*  @param  filename

*  @param  stuffix

*  @return

*/

public   static   boolean  isFileExist(String filename, String stuffix) {

File file =  new  File(filename +  "."  + stuffix);

if  (file.exists()) {

try  {

System. out .println( "路徑:"  + file.getCanonicalPath());

}  catch  (IOException e) {

e.printStackTrace();

}

return   true ;

}  else  {

return   false ;

}

}   

/**

* 創建新文件



*  @param  filename

*            文件名

*  @param  suffix

*            後綴名

*  @param  pros

*            Properties

*  @return

*/

public   static   boolean   createFiles (String filename, String suffix,

Properties pros) {

File file =  new  File(filename +  "."  + suffix);

FileOutputStream fos =  null ;

if  (!file.exists()) {

try  {

System. out .println( "********* 正在寫入文件 **********" );

fos =  new  FileOutputStream(file,  false );

pros.store(fos,  "Author: EthanLiang" );

fos.close();

return   true ;

}  catch  (FileNotFoundException e) {

System. out .println( "-------- 找不到文件! ---------" );

e.printStackTrace();

return   false ;

}  catch  (IOException e) {

System. out .println( "-------- 內容寫入失敗! ---------" );

e.printStackTrace();

return   false ;

}  finally  {

try  {

fos.close();

}  catch  (IOException e) {

e.printStackTrace();

}

}

}  else  {

return   false ;

}

}

上面我写了一个创建Property文件的方法,这样的话,这个文件是保存在Web服务器里面的,至于在什么位置,自己创建后,有兴趣可以去找找看。    

<!--[if !supportLists]--> 3、 <!--[endif]--> 第二步:开始连接SAP:

   这一步,我们也可以叫它“登录SAP”,其实JCO实现的原理是和SAP的客户端原理是一样的,你要登录到SAP,首先是要先登录,第一步是创建了一个连接池,接下来咱们就要把用户的登录信息写在这个文件里,SAP会通过RFC自己去调用的。

    public   synchronized   JCoDestination  getJCoDestination(String filename,

String stuffix, String host, String sysnr, String client,

String user, String pass, String lang) {

boolean  isexist =  false ;  // 判断文件是否存在

boolean  isCreate =  false ;  // 穿件pro文件

JCoDestination destination;

isexist = FileUtil. isFileExist (filename, stuffix);

if  (isexist ==  true ) {

System. out .println( "-------- 文件已經存在 -----------" );

try  {

destination = JCoDestinationManager. getDestination (filename);

return  destination;

}  catch  (JCoException e) {

System. out

.println( "---------- 獲取JCoDestination失敗! -----------" );

e.printStackTrace();

return   null ;

}

}  else  {

isCreate = FileUtil. creatSapPros (filename, stuffix, host, sysnr,

client, user, pass, lang,  "3000" ,  "500" );

if  (isCreate ==  true ) {

try  {

destination = JCoDestinationManager

. getDestination (filename);

System. out

.println( "---------- 獲取JCoDestination!成功,正在返回數據 -----------" );

return  destination;

}  catch  (JCoException e) {

System. out

.println( "---------- 無法獲取JCoDestination! -----------" );

e.printStackTrace();

return   null ;

}

}  else  {  // 如果文件不存在

return   null ;

}

}

}

  ===================================================================

上面的连接SAP代码,我设计了一个非常人性化的代码,我写了一个 getJCoDestination 的方法,该方法用来连接 SAP ,连接成功后会返回远程连接目标信息,也就是  JCoDestination 。代码中, 去登录前,先判断property文件是否已经创建好了,如果创建好了,就直接取出文件登录信息去连接SAP,如果没有,就先去创建一次,创建的代码请看 第2步 。

JCoDestinationManager. getDestination (filename);

这代码就是根据你创建的property文件的命名去获取里面的登录信息;

这里的 filename 是你自己随机定义命名的,你创建property文件时,是用什么名字,你 getDestination 也要用什么名字 ,这个filename是不包含property后缀名的,一定要切记 。比如: createFiles ( “ filetest ” ,  “ pros ” ,Properties pros)   ; 这个方法是【   第 2 步   】创建 property 文件的方法,我们以上假设了创建一个 property 文件, filename 是【 filetest 】 , 后缀名是【 pros 】,创建成功后,你会看服务器上多出了个【 filetest.pros 】的文件,这个文件就是保存 SAP 登录信息的文件; 

然后登录时就应该是:

JCoDestinationManager. getDestination ( “ filetest ” );

成功连接了 SAP 后,可以测试一下  有没连接成功,可以打印一下连接信息:

// getJCoDestination 要传的参数自己去写吧,我自己做个范例而已。

Destination   dest =  getJCoDestination(String filename,

String stuffix, String host, String sysnr, String client,

String user, String pass, String lang) ;

System.out.println( destination.getAttributes( ) );

<!--[if !supportLists]--> 4、 <!--[endif]--> 当成功连接了SAP后,开始与SAP交互了:

   Java同JCO技术与SAP进行交互的时候,主要是通过SAP 的RFC进行操作,也就SAP的Function,这个Function可以是SAP任何的Function,当然要成功连接Function前,请记得先去SAPFunction的【属性】设置里,选择【 Remote-Enable Module立即开始 】,要切记啊,不然连接不到Function,如果是自己开发的Function,还要激活它这个Function才能用。

首先我们通过上面的第三部连接成功后:

  Destination   dest =  getJCoDestination(String filename,

String stuffix, String host, String sysnr, String client,

String user, String pass, String lang) ;

// 开始连接 function 

try  {

JCoFunction  fun  = dest.getRepository()

    .getFunction( “ ZRFC_PRICE_STATUS ” );

}  catch  (JCoException e) {

   fun =  null ;

System. out .println( "JCO異常,無法獲取Function" );

e.printStackTrace();

}

有没连接成功,可以打印一下 function.getName () 来看看;

<!--[if !supportLists]--> 5、 <!--[endif]--> 获取接口参数:

   做ABAP开发的都知道,ABAP的Functionz主要有四个接口:Export、Import、Changing和Table;

   Function连接成功后,我们就开始获取这四个接口的参数;首先是获取到这个三个接口:

JCoParameterList  imlist = function.getImportParameterList();

JCoParameterList  e mlist = function.getExportParameterList();

JCoParameterList  t mlist = function.getTableParameterList();

JCoParameterList  c mlist = function.getChangingParameterList();

接着我们可以开始向SAP传数据,如果不需要传递数据,可以直接跳过以下的步骤。我们来往function的import接口里的参数传,其他的三个接口也类似,其它三个借口的传法,可以去参考API的案例或者去百度。

imlist .setValue( "STATUS" ,  "D" );  // 傳入參數

imlist .setValue( "VBELN_LOW" ,  vbeln .trim());  // 傳入參數

<!--[if !supportLists]--> 6、 <!--[endif]--> 开始调用function:

    try  {

      JCoParameterList  imlist = function.getImportParameterList();

      JCoParameterList  t mlist = function.getTableParameterList();

       imlist .setValue( "STATUS" ,  "D" );  // 傳入參數

       imlist .setValue( "VBELN_LOW" ,  vbeln .trim());  // 傳入參數

JCoContext . begin ( destination );     // 开启一个事务 

       // 开始执行 function 

function .execute( destination );    

    // 获取 function 返回的数据,因为我的 function 执行成功后, abap 返回的数据是存放在 table 接口,所以我以上是这样去获得数据,如果你想返回在 export 里面,那就用 export 的方式去获取 

    JCoTable tab =  t mlist .getTable( "IT_RETURN" );   

    for  ( int  i = 0; i <  tab  .getNumRows(); i++) {

tab .setRow(i);     // 设置指针位置,这个很重要 

     // 获取出 table 接口里名为“  IT_RETURN ”的表的数据

      tab .getString( "VBELN" );    //訂單號 

  tab .getString( "NAME1" );    //買 方 

  tab .getString( "NAME2" );   //付款人 

  tab .getString( "NAME3" );   //收貨人

   }

        try  {

JCoContext. end ( destination );    // 远程调用结束后可以关闭 

}  catch  (JCoException e1) {

e1.printStackTrace();

}

    catch  (JCoException e1) {

e1.printStackTrace();

}

<!--[if !supportLists]--> 7、 <!--[endif]--> 最后:

   好了,Java与SAP的交互已经说完了,中间还有很多的细节和功能,你在自己按着这个思路去摸索吧。

   当然,使用JCO首先要去下载JCO 3.0的JAR文件,这里我就不提供,网上也有,想要的话,也可以问我要。JCO 3.0的压缩包里,除了有Jar包,还有API和Demo,你可以慢慢去看Demo。

    最后声明,要想成功连接SAP, JCO 3.0包里面还有一个重要“sapjco3.dll”这个文件,你必须把这个文件放在你的项目WEB-INF/lib 文件夹下面,或者放在你本地的哪个位置来的?我忘了,自己去搜索一下吧,反正我不是放在本地的目录下的。这点要切记啊!

猜你喜欢

转载自comtoexe.iteye.com/blog/2289454
今日推荐