JAVA Hibersap 框架调用 SAP
In this example we will create a simple Maven project which uses Hibersap to call a function in SAP and print the result to the command line.
Download and install the SAP Java Connector
Download SAP Java Connector 3 from http://service.sap.com/connectors and extract the sapjco3.jar and the sapjco3 native library.
The native library implements the underlying communication protocol (SAP RFC, Remote Function Call) and is needed by the sapjco3.jar at runtime. Since native libraries are different for each operating system and processor architecture, there are different distributions for the JCo, e.g. Windows on Intel x86, 64 bit JVM or Mac, 32 bit JVM. Make sure to download the correct distribution for the OS/architecture combination on which your application will be running. |
Install the sapjco3 jar to your local Maven repository from the command line. In the example we assume you use version 3.0.12, if not so, replace to version number with the correct value:
mvn install:install-file -DgroupId=org.hibersap -DartifactId=sapjco3 -Dversion=3.0.12 \\
-Dpackaging=jar -Dfile=/path/to/sapjco3.jar
Create a Maven project with the required dependencies
Create a Maven project with the following dependencies:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany</groupId>
<artifactId>hibersap-example</artifactId>
<version>1.0.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.hibersap</groupId>
<artifactId>hibersap-core</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.hibersap</groupId>
<artifactId>hibersap-jco</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>org.hibersap</groupId>
<artifactId>sapjco3</artifactId>
<version>3.0.12</version>
</dependency>
</dependencies>
</project>
Implement the application
Our little application will call the SAP function BAPI_SFLIGHT_GETLIST. This function is part of a demo application in SAP that implements a simplified flight-booking system.
Examine the function module
First, we will take a look at the SAP function module we will call. The following is the function module’s interface. The function is written in SAP’s programming language ABAP.
FUNCTION BAPI_SFLIGHT_GETLIST.
IMPORTING
VALUE(FROMCOUNTRYKEY) LIKE BAPISFDETA-COUNTRYFR
VALUE(FROMCITY) LIKE BAPISFDETA-CITYFROM
VALUE(TOCOUNTRYKEY) LIKE BAPISFDETA-COUNTRYTO
VALUE(TOCITY) LIKE BAPISFDETA-CITYTO
VALUE(AIRLINECARRIER) LIKE BAPISFDETA-CARRID DEFAULT SPACE
VALUE(AFTERNOON) LIKE BAPI_AUX-AFTERNOON DEFAULT SPACE
VALUE(MAXREAD) LIKE BAPI_AUX-MAXREAD DEFAULT 0
EXPORTING
VALUE(RETURN) LIKE BAPIRET2 STRUCTURE BAPIRET2
TABLES
FLIGHTLIST STRUCTURE BAPISFLIST
The function’s interface defines some parameters that represent search criteria to look up flights in SAP’s database. The matching flights are returned in the FLIGHTLIST table, which contains information such as the airline carrier id, a flight connection code and departure / destination data. In the RETURN structure the function may return extra messages like errors, warnings, etc.
In this function, the import parameters are simple types, whereas the export and table parameter are complex data types (ABAP structures). The RETURN parameter is of type BAPIRET2, which is a standard structure that can be found in many function modules' interfaces and is not specific to this BAPI. This are the individual elements:
Component name | Type | Description |
---|---|---|
TYPE |
Character |
Message type: S Success, E Error, W Warning, I Info, A Abort |
ID |
Character |
Messages, message class |
NUMBER |
Numeric character |
Messages, message number |
MESSAGE |
Character |
Message text |
LOG_NO |
Character |
Application log: log number |
LOG_MSG_NO |
Numeric character |
Application log: Internal message serial number |
MESSAGE_V1 |
Character |
Messages, message variables |
MESSAGE_V2 |
Character |
Messages, message variables |
MESSAGE_V3 |
Character |
Messages, message variables |
MESSAGE_V4 |
Character |
Messages, message variables |
PARAMETER |
Character |
Parameter name |
ROW |
4-byte integer |
Lines in parameter |
FIELD |
Character |
Field in parameter |
SYSTEM |
Character |
Logical system from which message originates |
The FLIGHTLIST table’s lines are of type BAPISFLIST which contains the following elements:
Component name | Type | Description |
---|---|---|
CARRID |
Character |
Airline carrier ID |
CONNID |
Numerical character |
Flight connection code |
FLDATE |
Date |
Flight date |
AIRPFROM |
Character |
Airport of departure |
AIRPTO |
Character |
Destination airport |
DEPTIME |
Time |
Departure time |
SEATSMAX |
4-byte integer |
Maximum capacity |
SEATSOCC |
4-byte integer |
Occupied seats |
Our goal is to map all those parameters to Java classes and their fields which we will achieve using Java annotations defined by Hibersap.
Implement the BAPI class
Next, we will write a BAPI class that acts as an adapter to the JCo function. The BAPI class is a simple Java class with a number of fields representing the BAPI’s import, export and table parameters. In case the BAPI parameter being a scalar parameter, the Java field itself is of a simple Java type. In the case of a structure parameter, the Java field’s type is of a complex type. A table parameter maps to an Array or a Collection of a complex type.
All setup related to the function module’s interface is done via Java annotations. A BAPI class is defined using the Hibersap class annotation @Bapi
, which has an argument specifying the name of the SAP function module we want to call. (All Hibersap annotations can be found in the package org.hibersap.annotations
.)
package org.hibersap.examples.flightlist;
import java.util.List;
import org.hibersap.*;
@Bapi("BAPI_SFLIGHT_GETLIST")
public class FlightListBapi {
// ...
}
The Java fields that will be mapped to the function module’s parameters are annotated with the @Import
, @Export
or @Table
annotations to tell Hibersap which kind of parameter it shall handle. Additionally, we have to specify the function module’s field name to which it relates, using the @Parameter
annotation. The @Parameter
's second argument, type
, tells Hibersap if the parameter is mapped to a simple or complex type. The enumeration ParameterType
defines possible values, the default type for element type being SIMPLE
. In most cases we have to specify a parameter’s name only. In case of table parameters the type
argument will be ignored by Hibersap since tables always have a complex type for each table line.
@Import
@Parameter("FROMCOUNTRYKEY")
private final String fromCountryKey;
@Import
@Parameter("FROMCITY")
private final String fromCity;
@Import
@Parameter("TOCOUNTRYKEY")
private final String toCountryKey;
@Import
@Parameter("TOCITY")
private final String toCity;
@Import
@Parameter("AIRLINECARRIER")
private final String airlineCarrier;
@Import
@Parameter("AFTERNOON")
@Convert(converter = BooleanConverter.class)
private final boolean afternoon;
@Import
@Parameter("MAXREAD")
private final int maxRead;
@Export
@Parameter(value="RETURN", type = ParameterType.STRUCTURE)
private BapiRet2 returnData;
@Table
@Parameter("FLIGHTLIST")
private List<Flight> flightList;
The Java type of each simple field is related to the SAP field’s data type. Hibersap relies on the Java Connector’s conversion scheme.
The @Convert
annotation on the field afternoon
in the listing above tells Hibersap to use a Converter of type BooleanConverter
to convert the parameter AFTERNOON (which is a character field of length 1 in SAP) to a Java boolean value. See section Type Conversion in the Hibersap Reference Manual for a deeper discussion of custom converters.
To conclude the example, we write a constructor which has all the import parameters as arguments, initializing the corresponding fields:
public FlightListBapi(String fromCountryKey,
String fromCity,
String toCountryKey,
String airlineCarrier,
String toCity,
boolean afternoon,
int maxRead) {
this.fromCountryKey = fromCountryKey;
this.fromCity = fromCity;
this.toCountryKey = toCountryKey;
this.toCity = toCity;
this.airlineCarrier = airlineCarrier;
this.afternoon = afternoon;
this.maxRead = maxRead;
}
Finally, we add a getter method for each field. Hibersap itself does not need setter methods, because all fields are set using reflection. Additional fields and methods may of course be added.
public boolean getAfternoon() {
return this.afternoon;
}
// ...
There is one constraint in the current version of Hibersap you should take into account: The mapping between SAP parameters and Java classes works as expected only if the SAP function module complies to the BAPI standard. As of now, this means: Deep tables (i. e. tables in tables or tables in structures) are not supported. Changing parameters can not be mapped. |
Implement structure classes for complex parameters
There are two more classes we need to write: One for the complex export parameter RETURN, which is named BapiRet2
, after the SAP data type. It is another annotated simple Java class with fields related to some of the function module’s parameter. To keep the example simple, we do not map all the fields of the RETURN parameter.
package org.hibersap.bapi;
import org.hibersap.annotations.*;
@BapiStructure
public class BapiRet2 {
@Parameter("TYPE")
@Convert(converter = CharConverter.class)
private char type;
@Parameter("ID")
private String id;
@Parameter("NUMBER")
private String number;
@Parameter("MESSAGE")
private String message;
public char getType() { return this.type; }
public String getId() { return this.id; }
public String getNumber() { return this.number; }
public String getMessage() { return this.message; }
}
The class is annotated with @BapiStructure
to tell Hibersap that it maps to a complex parameter on the SAP side. Each particular field is annotated with the already known @Parameter
annotation that defines the name of the corresponding structure field. The BapiRet2
class is already part of Hibersap, since this structure is used by a lot of SAP function modules. This means, you don’t have to implement it yourself.
The second class we need to implement is a Java class that Hibersap will map to each row in the table parameter FLIGHTLIST, which in our example is simply called Flight
. The table FLIGHTLIST will be filled by SAP with the flight information matching our request.
package org.hibersap.examples.flightlist;
import java.util.Date;
import org.hibersap.*;
@BapiStructure
public class Flight {
@Parameter("CARRID")
private String carrierId;
@Parameter("CONNID")
private String connectionId;
@Parameter("AIRPFROM")
private String airportFrom;
@Parameter("AIRPTO")
private String airportTo;
@Parameter("FLDATE")
private Date flightDate;
@Parameter("DEPTIME")
private Date departureTime;
@Parameter("SEATSMAX")
private int seatsMax;
@Parameter("SEATSOCC")
private int seatsOccupied;
public String getAirportFrom() { return this.airportFrom; }
public String getAirportTo() { return this.airportTo; }
public String getCarrierId() { return this.carrierId; }
public String getConnectionId() { return this.connectionId; }
public Date getDepartureTime() {
return DateUtil.joinDateAndTime( flightDate, departureTime );
}
public Date getFlightDate() { return flightDate; }
public int getSeatsMax() { return this.seatsMax; }
public int getSeatsOccupied() { return this.seatsOccupied; }
}
Please note that the method getDepartureTime()
does not simply return the field departureTime
but calls a utility method DateUtil.joinDateAndTime()
. This is done here because ABAP — unlike Java — does not have a data type that contains date and time. In ABAP such a timestamp is separated into two fields, one of type Date, the other of type Time. Therefore the Java Connector returns a java.util.Date
for the SAP date field containing the date fraction (date at 00:00:00,000) and another java.util.Date for the time field containing the time fraction (i.e. Jan. 1st, 1970 plus time). The utility method joins those two dates into one.
Configure Hibersap
To configure Hibersap, we create an XML file named hibersap.xml
in the project’s src/main/resources/META-INF
folder. The configuration file contains information for Hibersap itself, plus properties for the SAP Java Connector.
In the example we use a minimal set of JCo properties to be able to connect to the SAP system. All valid JCo properties are specified in the interface com.sap.conn.jco.ext.DestinationDataProvider
of th JCo library (for details see javadoc provided with JCo).
The values of the JCo client, user, passwd, ashost and sysnr properties must match the SAP system we are connecting to. This means, you need to adopt the values to your specific SAP system and user account.
<?xml version="1.0" encoding="UTF-8"?>
<hibersap xmlns="urn:hibersap:hibersap-configuration:1.0">
<session-manager name="A12">
<properties>
<property name="jco.client.client" value="800" />
<property name="jco.client.user" value="sapuser" />
<property name="jco.client.passwd" value="password" />
<property name="jco.client.lang" value="en" />
<property name="jco.client.ashost" value="10.20.30.40" />
<property name="jco.client.sysnr" value="00" />
<property name="jco.destination.pool_capacity" value="5" />
</properties>
<annotatedClasses>
<class>org.hibersap.examples.flightlist.FlightListBapi</class>
</annotatedClasses>
</session-manager>
</hibersap>
Call the function module and show the results
To interact with Hibersap, an instance of type SessionManager
must be aquired. For each SAP system which the application interacts with a SessionManager
is needed. The SessionManager
should only be created once in an application because it is rather expensive to create.
The SessionManager is responsible for creating Sessions
. A Session
represents a connection to the SAP system. The first time we call a function module on a Session, Hibersap aquires a connection from the underlying connection pool. When closing a session, the connection is returned to the pool. The application has to take care of closing the session whenever it is not needed anymore, preferably in a finally block. If the application keeps open too many sessions, the connection pool may get exhausted sooner or later. Any further attempt of opening another session would thus fail.
The following function configures a Hibersap SessionManager
. First, an instance of type AnnotationConfiguration is created for the named SessionManager, as specified in hibersap.xml. Finally, the SessionManager
is built. In a real application this should be done once, reusing the SessionManager throughout the application’s lifetime.
public class HibersapTest {
public SessionManager createSessionManager() {
AnnotationConfiguration configuration = new AnnotationConfiguration("A12");
return configuration.buildSessionManager();
}
}
Now it is time to call the function module in SAP. After creating the SessionManager
and opening a new Session
, we create an instance of our BAPI Class, passing all parameters needed to execute the function. Then we simply call the Session.execute()
method, passing the BAPI class which actually performs the call to SAP. Now the flightListBapi
object is enriched with all the values returned by the function module which we have mapped to Java fields in our BAPI Class.
public void showFlightList() {
SessionManager sessionManager = createSessionManager();
Session session = sessionManager.openSession();
try {
FlightListBapi flightList = new FlightListBapi( "DE", "Frankfurt",
"DE", "Berlin",
null, false, 10 );
session.execute( flightList );
showResult( flightList );
}
finally {
session.close();
}
}
To see the result of the function call, we simply print the BAPI class' fields to the console in the showResult()
method. Finally, we create a main method that calls the showFlightList() method.
private void showResult( FlightListBapi flightList ) {
System.out.println( "AirlineId: " + flightList.getFromCountryKey() );
System.out.println( "FromCity: " + flightList.getFromCity() );
System.out.println( "ToCountryKey: " + flightList.getToCountryKey() );
System.out.println( "ToCity: " + flightList.getToCity() );
System.out.println( "AirlineCarrier: " + flightList
.getAirlineCarrier() );
System.out.println( "Afternoon: " + flightList.getAfternoon() );
System.out.println( "MaxRead: " + flightList.getMaxRead() );
System.out.println( "\nFlightData" );
List<Flight> flights = flightList.getFlightList();
for ( Flight flight : flights ) {
System.out.print( "\t" + flight.getAirportFrom() );
System.out.print( "\t" + flight.getAirportTo() );
System.out.print( "\t" + flight.getCarrierId() );
System.out.print( "\t" + flight.getConnectionId() );
System.out.print( "\t" + flight.getSeatsMax() );
System.out.print( "\t" + flight.getSeatsOccupied() );
System.out.println( "\t" + flight.getDepartureTime() );
}
System.out.println( "\nReturn" );
BapiRet2 returnStruct = flightList.getReturnData();
System.out.println( "\tMessage: " + returnStruct.getMessage() );
System.out.println( "\tNumber: " + returnStruct.getNumber() );
System.out.println( "\tType: " + returnStruct.getType() );
System.out.println( "\tId: " + returnStruct.getId() );
}
public static void main( String[] args ) {
new HibersapTest().showFlightList();
}
Run the application
Build the project with maven on the command-line using mvn compile
and run the main class, or run it directly from your IDE.
Make sure the application can access the JCo native library. The folder in which the native lib file is located must be on the application’s library path. The library path is defined by the Java system property java.library.path
which can be passed as a JVM option with the -D command line switch.
-Djava.library.path=/path/to/sapjco-native-lib/
When running from an IDE like IntelliJ or Eclipse, you can add the JVM option by editing the run configuration. When running from the command line you can directly add it to the java
command.
In the example, we are looking for all flights from Frankfurt to Berlin. The result should look like follows, in this example, there were two flights found.
AirlineId: DE
FromCity: Frankfurt
ToCountryKey: DE
ToCity: Berlin
AirlineCarrier:
Afternoon: false
MaxRead: 10
FlightData
FRA SXF LH 2402 220 191 Thu Dec 30 10:30:00 CET 2010
FRA SXF LH 2402 220 207 Fri Dec 31 10:30:00 CET 2010
Return
Message:
Number: 000
Type: S
Id:
If there were no flights found which is usually the case when you didn’t create test data in SAP yet, SAP will return something like the following:
Return
Message: No corresponding flights found
Number: 150
Type: E
Id: BC_BOR
Further examples can be found in the Hibersap Github repository, including a Java EE application using Hibersap with the Cuckoo Resource Adapter for SAP.
JAVA Hibersap 框架调用 SAP的更多相关文章
- java使用JNA框架调用dll动态库
这两天了解了一下java调用dll动态库的方法,总的有三种:JNI.JNA.JNative.其中JNA调用DLL是最方便的. ·JNI ·JNA ·JNative java使用 JNI来调用dll动态 ...
- (二)通过JAVA调用SAP接口 (增加一二级参数)
(二)通过JAVA调用SAP接口 (增加一二级参数) 一.建立sap连接 请参考我的上一篇博客 JAVA连接SAP 二.测试项目环境准备 在上一篇操作下已经建好的环境后,在上面的基础上新增类即可 三. ...
- Android平台dalvik模式下java Hook框架ddi的分析(2)--dex文件的注入和调用
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/77942585 前面的博客<Android平台dalvik模式下java Ho ...
- java 调用SAP RFC函数错误信息
RFC接口调用SAP如果有异常会通过com.sap.mw.jco.JCO$Exception: 抛出异常 在开发中遇到的异常有如下 用户名密码可能是错误或者用户无权限,确认用户,必要时联系SAP负责人 ...
- Java集合框架List,Map,Set等全面介绍
Java集合框架的基本接口/类层次结构: java.util.Collection [I]+--java.util.List [I] +--java.util.ArrayList [C] +- ...
- Java三大框架 介绍
三大框架:Struts+hibernate+spring Java三大框架主要用来做WEN应用. Struts主要负责表示层的显示 Spring利用它的IOC和AOP来处理控制业务(负责对数据库的操作 ...
- 【集合框架】Java集合框架综述
一.前言 现笔者打算做关于Java集合框架的教程,具体是打算分析Java源码,因为平时在写程序的过程中用Java集合特别频繁,但是对于里面一些具体的原理还没有进行很好的梳理,所以拟从源码的角度去熟悉梳 ...
- Java集合框架实现自定义排序
Java集合框架针对不同的数据结构提供了多种排序的方法,虽然很多时候我们可以自己实现排序,比如数组等,但是灵活的使用JDK提供的排序方法,可以提高开发效率,而且通常JDK的实现要比自己造的轮子性能更优 ...
- (转)Java集合框架:HashMap
来源:朱小厮 链接:http://blog.csdn.net/u013256816/article/details/50912762 Java集合框架概述 Java集合框架无论是在工作.学习.面试中都 ...
随机推荐
- POJ 3494 Largest Submatrix of All 1’s(最大子图形)
[题目链接] http://poj.org/problem?id=3494 [题目大意] 在01矩阵中求最大全1子矩形 [题解] 在处理每个点的时候,继承上一个点等高度下的左右最大扩展, 计算在该层的 ...
- 【尺取法】【Multiset】bzoj1342 [Baltic2007]Sound静音问题
O(n)地枚举所有长度为k的段,每次暴力转移. 转移的时候只是从最后插入一个数,从前面删去一个数. 计算的时候要取当前的max和min. 用multiset(∵元素是可重的)以上这些操作都是O(log ...
- 【莫比乌斯反演+分块】BZOJ1101-[POI2007]Zap
[题目大意] 对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d. [思路] 前面的思路同HDU1695 不过不同的是这道题中(a,b)和(b ...
- 【整体二分+莫比乌斯函数+容斥原理】BZOJ2440
[题目大意] 求第k个不是完全平方数或完全平方数整数倍的数. [思路] 由于μ(i)*(n/i^2)=n,可以直接从1开始,得出非完全平方数/完全平方数倍数的数的个数 注意一下二分的写法,这里用的是我 ...
- opencv在vc2010 express下环境搭建方法笔记+空白通用工程(已编译测试通过)(提供下载)
opencv在VC2010 express版本下的环境搭建可以参见下面的wiki,这里面讲的非常清楚. http://wiki.opencv.org.cn/index.php/VC_2010_Expr ...
- Ubuntu安装“启动引导器”的设备选哪一项,选默认还是选/boot分区?
如果你要用Ubuntu的引导器代替Windows的引导器,就选 /dev/sda. 如果你要保留Windows的引导器,就选 /boot分区,但这样一来,装完Ubuntu重启后,只能启动Windows ...
- VS2017安装错误:工作负荷不完整,未能安装包“sqlcmdlnutils,version=15.1.61703.130,chip=x64,language=zh-CN”。
场景:已安装的VS2017维护安装MVC4时出现如下错误: 看问题描述是由于sqlcmdlnutils安装失败影响到其它组件的安装,于是单独下载此安装包进行安装,发现安装一切正常,继续维护VS2017 ...
- SpringMVC——redirect重定向跳转传值
原文:https://my.oschina.net/u/2273085/blog/398374 spring MVC框架controller间跳转,需重定向.有几种情况:不带参数跳转,带参数拼接url ...
- 1、Android项目框架搭建 (分析需求、整理资料)
闲来无事.想搭个框架试试 分析一般应用 将资料整理整理 粗略统计 须要下面资料 1.android-pulltorefresh 一个强大的拉动刷新开源项目,支持各种控件下拉刷新 ListView.Vi ...
- Shell--nl命令
nl命令在linux系统中用来计算文件中行号.nl 可以将输出的文件内容自动的加上行号!其默认的结果与 cat -n 有点不太一样, nl 可以将行号做比较多的显示设计,包括位数与是否自动补齐 0 等 ...