1. Web 服务示例:订单处理我之所以选择“订单处理”作为示例,是因为它比较接近实际的商业用例。该Web服务能够处理,更新一个给定的订单。为了达到这个目的,它必须具有两个方法:processOrder和updateOrder。方法processOrder具有一个IN参数orderID和一个作为OUT参数的Order(订单)对象。processOrder方法返回一个状态字符串。方法updateOrder把一个Order(订单)对象作为INOUT参数,它更新orderDate,并且把Order对象返回给客户端。由于这两个方法都用到了一个复杂数据类型Order,更确切的说,它被用作为OUT/INOUT参数,所以需要开发一个Holder类。下面的清单1和清单2分别给出了Order类和相应的Holder类(为了说明,全部代码都放在sample包中): 清单 1:Order类package sample; public class Order { // ID for order private String orderID = null; // date of order private String orderDate= null; // getter methodspublic String getOrderID() { return orderID; } public String getOrderID() { return orderID; } // setter methods public void setOrderID(String orderID) { this.orderID = orderID; } public void setOrderDate(String orderDate) { this. orderDate = orderDate; } } 清单 2:Order类相应的Holder类 // Note that holder class is in the holders package and its name // is derived by adding Holder as a suffix to ''Order'', as per // the JAX-RPC specification. package sample.holders; public class OrderHolder { // Order''s object public Order value = null; // default constructor public void OrderHolder () { } // constructor, which takes value as a parameter public void OrderHolder (Order value) { this.value=value; } } 现在,我们来开发具有上述功能的Web服务。清单3给出了相应的代码。 清单3:订单处理Web服务 package sample; public class OrderProcessingService { // Method 1: processes a order given ID as input and // return status and Order object as an OUT parameter public String processOrder(String orderID, OrderHolder orderHolder ) { String status = "pending"; // perform business logic here // for simplicity just filling the Order object Order order = new Order(); order.setOrderID(orderID); order.setOrderDate("03 March 2003"); // set the Holder value to the order. orderHolder.value = order; //set the status status = "complete" ; return status; } // Method 2: updates a order given Order as an INOUT // parameter and returns status. public String updateOrder(OrderHolder orderHolder) { String status = "pending"; // perform update here Order order = orderHolder.value; order.setOrderDate("03 April 2003"); // Note that orderID is not changed. // It will be same as the passed one. // set the Holder value to the order. orderHolder.value = order; //set the status status = "complete" ; return status; } } 至此,我们已经完成Web服务的开发,下一步就是编译,把它部署到Tomcat-Axis平台上去。编译后,我们需要用部署描述文件把上述的Web服务部署到Tomcat-Axis。 清单4:部署文件deploy.wsdd <deployment xmlns="http://xml.apache.org/Axis/wsdd/" xmlns:java="http://xml.apache.org/Axis/wsdd/providers/java"> <service name=" OrderProcessingService" provider="java:RPC"> <parameter name="className" value="sample.OrderProcessingService "/> <parameter name="allowedMethods" value="*"/> <operation name="processOrder"> <parameter name="arg1" mode="IN"/> <parameter name="arg2" mode="OUT"/> </operation> <operation name="updateOrder"> <parameter name="arg1" mode="INOUT"/> </operation> </service> </deployment> 上述的部署描述文件实际上是让服务器知道有关该Web服务的一些信息,例如公开的方法,期望的参数以及返回值类型等。部署OrderProcessingService,我们需要传递参数“deploy.wsdd”,调用Axis admin服务。运行在同一服务器上的admin服务将处理描述文件,部署该Web服务,至此,它可以被客户端调用了。 在与deploy.wsdd文件相同的目录下运行下列命令: java -cp %AxisCLASSPATH% org.apache.Axis.client.AdminClient -lhttp://localhost:8080/Axis/services/AdminService deploy.wsdd 其中,AxisCLASSPATH用于设置Axis环境(详情请参考Axis/" target=new>Axis installation guide )。可以通过下面的地址来访问OrderProcessing服务:http://<your_machine_name>:<port-num>/<contextURI>/<serviceURI> .对我们的示例来说,地址如下: Axis/services/OrderProcessing">http://localhost:8080/Axis/services/OrderProcessing 2. Web 服务OrderProcessing的客户端动态客户端 动态客户端类似于用反射APIs(reflection APIs)查找,调用Java类的方法. 这里,所有的信息,例如目标端点(target endpoint),方法参数等等都必须明确的设定。清单5所列出的代码展示了怎样编写一个调用Web服务OrderProcessing的updateOrder方法的动态客户端。 清单 5:动态客户端package sample.client; import org.apache.Axis.client.Call; import org.apache.Axis.client.Service; import org.apache.Axis.encoding.XMLType; import javax.xml.RPC.ParameterMode; import javax.xml.RPC.encoding.*; import javax.xml.namespace.QName; import java.util.*; import sample.*; /** * This class illustrates how to use the JAX-RPC API to invoke * the Order Processing Web service dynamically */ public class DynamicClient { public static void main(String[] args) throws Exception { // create service factory ServiceFactory factory = ServiceFactory.newInstance(); // define qnames String targetNamespace = "OrderProcessingService"; QName serviceName = new QName(targetNamespace, "OrderProcessingService"); QName portName = new QName(targetNamespace, "OrderProcessingService"); QName operationName = new QName(targetNamespace, "updateOrder"); // create service Service service = new Service(); Call call = (Call) service.createCall(); Qname qn = new Qname(targetNamespace, "OrderHolder"); call.registerTypeMapping(OrderHolder.class, qn, new org.apache.Axis.encoding.ser.BeanSerializerFactory (OrderHolder.class, qn), new org.apache.Axis.encoding.ser.BeanDeserializerFactory (TicketHolder.class, qn)); // set port and operation name call.setPortTypeName(portName); call.setOperationName(operationName); // add parameters call.addParameter( "arg1", serviceName, ParameterMode.INOUT ); call.setReturnType( XMLType.XSD_STRING ); Order order = new Order (); order.setOrderID("Order001"); order.setOrderDate("03 March 2003"); // set end point address call.setTargetEndpointAddress( "http://localhost:8080/Axis/services/OrderProcessing"); // Invoke the WebService String result = (String) call.invoke( new Object[] { order } ); System.out.println("result : " +result); Map outparams = call.getOutputParams(); System.out.println("Got the outparams"); } 3. 运行客户端用下列命令运行客户端: <Prompt>java -cp %AxisCLASSPATH% sample.client.DynamicClient 结果如下: 得到输出参数(如在开发客户端时所提到的一样)。 4. 结论本文试图揭开Web服务的神秘面纱,表达一种使用Apache开放源代码的Axis工具开发基于JAX-RPC的Web服务是多么的简单和经济适用。该文还详细阐述了一种“怎样开发”基于JAX-RPC的Web服务的方式。这种开发方式给开发者充分的自由去编写Web服务和客户端,隐藏了以有线XML(on-the-wire XML)格式序列化对象的所有复杂细节。对开发人员来说,它看起来只不过是Java方法调用。本文系列的下一部分,我将讲解Web服务的其他方法和技术。 5. 参考资料l http://jakarta.apache.org/tomcat/index.html l Axis/" target=new>http://ws.apache.org/Axis/ l JAXRPC" target=new>http://java.sun.com/xml/JAXRPC
|