290.14. SAP 示例
290.14.1. 示例 1:从 SAP 读取数据
概述
本例展示了从 SAP 读取 FlightCustomer
业务对象数据的路由。路由调用 FlightCustomer
BAPI 方法 BAPI_FLCUST_GETLIST
,使用 SAP 同步 RFC 目标端点来检索数据。
用于路由的 Java DSL
示例路由的 Java DSL 如下:
from("direct:getFlightCustomerInfo") .to("bean:createFlightCustomerGetListRequest") .to("sap-srfc-destination:nplDest:BAPI_FLCUST_GETLIST") .to("bean:returnFlightCustomerInfo");
路由的 XML DSL
同一路由的 Spring DSL 如下:
<route> <from uri="direct:getFlightCustomerInfo"/> <to uri="bean:createFlightCustomerGetListRequest"/> <to uri="sap-srfc-destination:nplDest:BAPI_FLCUST_GETLIST"/> <to uri="bean:returnFlightCustomerInfo"/> </route>
createFlightCustomerGetListRequest bean
createFlightCustomerGetListRequest
bean 负责在后续 SAP 端点的 RFC 调用中使用的交换方法中构建 SAP 请求对象。以下代码片段演示了构建请求对象的操作序列:
public void create(Exchange exchange) throws Exception { // Get SAP Endpoint to be called from context. SapSynchronousRfcDestinationEndpoint endpoint = exchange.getContext().getEndpoint("sap-srfc-destination:nplDest:BAPI_FLCUST_GETLIST", SapSynchronousRfcDestinationEndpoint.class); // Retrieve bean from message containing Flight Customer name to // look up. BookFlightRequest bookFlightRequest = exchange.getIn().getBody(BookFlightRequest.class); // Create SAP Request object from target endpoint. Structure request = endpoint.getRequest(); // Add Customer Name to request if set if (bookFlightRequest.getCustomerName() != null && bookFlightRequest.getCustomerName().length() > 0) { request.put("CUSTOMER_NAME", bookFlightRequest.getCustomerName()); } } else { throw new Exception("No Customer Name"); } // Put request object into body of exchange message. exchange.getIn().setBody(request); }
returnFlightCustomerInfo bean
returnFlightCustomerInfo
bean 负责从 SAP 响应对象提取数据,在其从以前的 SAP 端点接收的交换方法中提取数据。以下代码片段演示了从响应对象中提取数据的操作序列:
public void createFlightCustomerInfo(Exchange exchange) throws Exception { // Retrieve SAP response object from body of exchange message. Structure flightCustomerGetListResponse = exchange.getIn().getBody(Structure.class); if (flightCustomerGetListResponse == null) { throw new Exception("No Flight Customer Get List Response"); } // Check BAPI return parameter for errors @SuppressWarnings("unchecked") Table<Structure> bapiReturn = flightCustomerGetListResponse.get("RETURN", Table.class); Structure bapiReturnEntry = bapiReturn.get(0); if (bapiReturnEntry.get("TYPE", String.class) != "S") { String message = bapiReturnEntry.get("MESSAGE", String.class); throw new Exception("BAPI call failed: " + message); } // Get customer list table from response object. @SuppressWarnings("unchecked") Table<? extends Structure> customerList = flightCustomerGetListResponse.get("CUSTOMER_LIST", Table.class); if (customerList == null || customerList.size() == 0) { throw new Exception("No Customer Info."); } // Get Flight Customer data from first row of table. Structure customer = customerList.get(0); // Create bean to hold Flight Customer data. FlightCustomerInfo flightCustomerInfo = new FlightCustomerInfo(); // Get customer id from Flight Customer data and add to bean. String customerId = customer.get("CUSTOMERID", String.class); if (customerId != null) { flightCustomerInfo.setCustomerNumber(customerId); } ... // Put bean into body of exchange message. exchange.getIn().setHeader("flightCustomerInfo", flightCustomerInfo); }
290.14.2. 示例 2:将数据写入 SAP
概述
本例演示了在 SAP 中创建 FlightTrip
业务对象实例的路由。路由调用 FlightTrip
BAPI 方法 BAPI_FLTRIP_CREATE
,使用目标端点来创建对象。
用于路由的 Java DSL
示例路由的 Java DSL 如下:
from("direct:createFlightTrip") .to("bean:createFlightTripRequest") .to("sap-srfc-destination:nplDest:BAPI_FLTRIP_CREATE?transacted=true") .to("bean:returnFlightTripResponse");
路由的 XML DSL
同一路由的 Spring DSL 如下:
<route> <from uri="direct:createFlightTrip"/> <to uri="bean:createFlightTripRequest"/> <to uri="sap-srfc-destination:nplDest:BAPI_FLTRIP_CREATE?transacted=true"/> <to uri="bean:returnFlightTripResponse"/> </route>
事务支持
SAP 端点的 URL 将 transacted
选项设置为 true
。如 第 290.11 节 “事务支持” 所述,当启用此选项时,端点可确保在调用 RFC 调用前启动 SAP 事务会话。由于此端点的 RFC 在 SAP 中创建新数据,因此此选项需要在 SAP 中永久进行路由更改。
填充请求参数
createFlightTripRequest
和 returnFlightTripResponse
beans 负责将请求参数填充到 SAP 请求中,并根据上例中所示的相同操作序列来提取响应参数。
290.14.3. 示例 3:处理 SAP 的请求
概述
本例演示了处理从 SAP 请求到 BOOK_FLIGHT
RFC (由路由实施)的路由。此外,它演示了组件的 XML 序列化支持,使用 JAXB 到 unmarshal 和 marshal SAP 请求对象,并将对象响应到自定义 Bean。
此路由代表旅行代理 FlightCustomer
创建 FlightTrip
业务对象。路由首先将 SAP 服务器端点收到的 SAP 请求对象加载到自定义 JAXB bean 中。然后,这个自定义 Bean 在交换中被多播到三个子路由,它会收集创建动态行程所需的旅行代理、flight 连接和乘客信息。最后的子路由会在 SAP 中创建 flight trip 对象,如上例中所示。最终的子路由还会创建并返回自定义 JAXB bean,该 Bean 会被 marshaled 到 SAP 响应对象,并由服务器端点返回。
用于路由的 Java DSL
示例路由的 Java DSL 如下:
DataFormat jaxb = new JaxbDataFormat("org.fusesource.sap.example.jaxb"); from("sap-srfc-server:nplserver:BOOK_FLIGHT") .unmarshal(jaxb) .multicast() .to("direct:getFlightConnectionInfo", "direct:getFlightCustomerInfo", "direct:getPassengerInfo") .end() .to("direct:createFlightTrip") .marshal(jaxb);
路由的 XML DSL
同一路由的 XML DSL 如下:
<route> <from uri="sap-srfc-server:nplserver:BOOK_FLIGHT"/> <unmarshal> <jaxb contextPath="org.fusesource.sap.example.jaxb"/> </unmarshal> <multicast> <to uri="direct:getFlightConnectionInfo"/> <to uri="direct:getFlightCustomerInfo"/> <to uri="direct:getPassengerInfo"/> </multicast> <to uri="direct:createFlightTrip"/> <marshal> <jaxb contextPath="org.fusesource.sap.example.jaxb"/> </marshal> </route>
BookFlightRequest bean
以下列表演示了一个 JAXB bean,它来自 SAP BOOK_FLIGHT
请求对象的序列化形式:
@XmlRootElement(name="Request", namespace="http://sap.fusesource.org/rfc/nplServer/BOOK_FLIGHT") @XmlAccessorType(XmlAccessType.FIELD) public class BookFlightRequest { @XmlAttribute(name="CUSTNAME") private String customerName; @XmlAttribute(name="FLIGHTDATE") @XmlJavaTypeAdapter(DateAdapter.class) private Date flightDate; @XmlAttribute(name="TRAVELAGENCYNUMBER") private String travelAgencyNumber; @XmlAttribute(name="DESTINATION_FROM") private String startAirportCode; @XmlAttribute(name="DESTINATION_TO") private String endAirportCode; @XmlAttribute(name="PASSFORM") private String passengerFormOfAddress; @XmlAttribute(name="PASSNAME") private String passengerName; @XmlAttribute(name="PASSBIRTH") @XmlJavaTypeAdapter(DateAdapter.class) private Date passengerDateOfBirth; @XmlAttribute(name="CLASS") private String flightClass; ... }
BookFlightResponse bean
以下列表演示了一个 JAXB bean,它被处理到 SAP BOOK_FLIGHT
响应对象的序列化形式:
@XmlRootElement(name="Response", namespace="http://sap.fusesource.org/rfc/nplServer/BOOK_FLIGHT") @XmlAccessorType(XmlAccessType.FIELD) public class BookFlightResponse { @XmlAttribute(name="TRIPNUMBER") private String tripNumber; @XmlAttribute(name="TICKET_PRICE") private BigDecimal ticketPrice; @XmlAttribute(name="TICKET_TAX") private BigDecimal ticketTax; @XmlAttribute(name="CURRENCY") private String currency; @XmlAttribute(name="PASSFORM") private String passengerFormOfAddress; @XmlAttribute(name="PASSNAME") private String passengerName; @XmlAttribute(name="PASSBIRTH") @XmlJavaTypeAdapter(DateAdapter.class) private Date passengerDateOfBirth; @XmlElement(name="FLTINFO") private FlightInfo flightInfo; @XmlElement(name="CONNINFO") private ConnectionInfoTable connectionInfo; ... }
响应对象的复杂参数字段被序列化为响应的子元素。
FlightInfo bean
以下列表演示了一个 JAXB bean,它被处理到复杂结构参数 FLTINFO
的序列化形式:
@XmlRootElement(name="FLTINFO", namespace="http://sap.fusesource.org/rfc/nplServer/BOOK_FLIGHT") @XmlAccessorType(XmlAccessType.FIELD) public class FlightInfo { @XmlAttribute(name="FLIGHTTIME") private String flightTime; @XmlAttribute(name="CITYFROM") private String cityFrom; @XmlAttribute(name="DEPDATE") @XmlJavaTypeAdapter(DateAdapter.class) private Date departureDate; @XmlAttribute(name="DEPTIME") @XmlJavaTypeAdapter(DateAdapter.class) private Date departureTime; @XmlAttribute(name="CITYTO") private String cityTo; @XmlAttribute(name="ARRDATE") @XmlJavaTypeAdapter(DateAdapter.class) private Date arrivalDate; @XmlAttribute(name="ARRTIME") @XmlJavaTypeAdapter(DateAdapter.class) private Date arrivalTime; ... }
ConnectionInfoTable bean
以下列表演示了一个 JAXB bean,它将对复杂表参数 CONNINFO
的序列化形式 marshals。
JAXB bean 的 root 元素类型的名称对应于带有 _TABLE
后缀的行结构类型的名称,bean 包含行元素列表。
@XmlRootElement(name="CONNINFO_TABLE", namespace="http://sap.fusesource.org/rfc/nplServer/BOOK_FLIGHT") @XmlAccessorType(XmlAccessType.FIELD) public class ConnectionInfoTable { @XmlElement(name="row") List<ConnectionInfo> rows; ... }
ConnectionInfo bean
以下列表演示了一个 JAXB bean,它被处理到上述表行元素的序列化形式:
@XmlRootElement(name="CONNINFO", namespace="http://sap.fusesource.org/rfc/nplServer/BOOK_FLIGHT") @XmlAccessorType(XmlAccessType.FIELD) public class ConnectionInfo { @XmlAttribute(name="CONNID") String connectionId; @XmlAttribute(name="AIRLINE") String airline; @XmlAttribute(name="PLANETYPE") String planeType; @XmlAttribute(name="CITYFROM") String cityFrom; @XmlAttribute(name="DEPDATE") @XmlJavaTypeAdapter(DateAdapter.class) Date departureDate; @XmlAttribute(name="DEPTIME") @XmlJavaTypeAdapter(DateAdapter.class) Date departureTime; @XmlAttribute(name="CITYTO") String cityTo; @XmlAttribute(name="ARRDATE") @XmlJavaTypeAdapter(DateAdapter.class) Date arrivalDate; @XmlAttribute(name="ARRTIME") @XmlJavaTypeAdapter(DateAdapter.class) Date arrivalTime; ... }