这几天貌似战斗力无穷,趁着有精力就多更新两篇。随着对Axis的研究加深,越感觉webservice是个很好玩的东西。这篇说一下如何传递一个JavaBean和你自己的一个special Object。
在第一篇介绍Axis的文章里,我们做了一个简单的webservice,我们client side传递了String和int类型的数据给service object。Service处理之后返回处理结果给Client。对于大多数需求,那个demo显然已经足够应付了。但是如果client端需要传输一个对象给server,那么那个demo就显得力不从心了。Axis中提供了远程传输对象的方法,通过那些方法我们同样可以随心的传递自己的对象。
我们先从传递一个JavaBean开始,首先编写一个JavaBean。
- package com.chnic.bean;
- public class OrderBean {
- private String name;
- private int age;
- private String[] items;
- private int[] price;
- private boolean checked;
- public OrderBean() {
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public boolean isChecked() {
- return checked;
- }
- public void setChecked(boolean checked) {
- this.checked = checked;
- }
- public String[] getItems() {
- return items;
- }
- public void setItems(String[] items) {
- this.items = items;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int[] getPrice() {
- return price;
- }
- public void setPrice(int[] price) {
- this.price = price;
- }
- }
package com.chnic.bean;
public class OrderBean {
private String name;
private int age;
private String[] items;
private int[] price;
private boolean checked;
public OrderBean() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isChecked() {
return checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
public String[] getItems() {
return items;
}
public void setItems(String[] items) {
this.items = items;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int[] getPrice() {
return price;
}
public void setPrice(int[] price) {
this.price = price;
}
}
这个JavaBean的前4个属性都很清楚,要解释一下最后一个。因为这个JavaBean被传递到Service端处理之后要接着被传回,用来示例webservce传进和传出。这个变量用来区别传进和传出的差别。解释完我们来看下service
- package com.chnic.webservice;
- import com.chnic.bean.OrderBean;
- public class AnalyzeOrder {
- public AnalyzeOrder(){
- }
- public OrderBean process(OrderBean order){
- order.setChecked(true);
- System.out.println("name: " + order.getName() + " age: " + order.getAge());
- for(int i=0; i<order.getItems().length; i++)
- System.out.println("Item " + (i+1) + order.getItems()[i] +
- " and price is " + order.getPrice()[i]);
- return order;
- }
- }
package com.chnic.webservice;
import com.chnic.bean.OrderBean;
public class AnalyzeOrder {
public AnalyzeOrder(){
}
public OrderBean process(OrderBean order){
order.setChecked(true);
System.out.println("name: " + order.getName() + " age: " + order.getAge());
for(int i=0; i<order.getItems().length; i++)
System.out.println("Item " + (i+1) + order.getItems()[i] +
" and price is " + order.getPrice()[i]);
return order;
}
}
Service Object的代码很简单,就不解释了。惯例,我们来编写发布文件。
- <deployment xmlns="http://xml.apache.org/axis/wsdd/"
- xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
- <service name="CheckOrder" provider="java:RPC">
- <parameter name="className" value="com.chnic.webservice.AnalyzeOrder"/>
- <parameter name="allowedMethods" value="process"/>
- <beanMapping qname="myNS:Order" xmlns:myNS="urn:AnalyzeOrder"
- languageSpecificType="java:com.chnic.bean.OrderBean"/>
- </service>
- </deployment>
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="CheckOrder" provider="java:RPC">
<parameter name="className" value="com.chnic.webservice.AnalyzeOrder"/>
<parameter name="allowedMethods" value="process"/>
<beanMapping qname="myNS:Order" xmlns:myNS="urn:AnalyzeOrder"
languageSpecificType="java:com.chnic.bean.OrderBean"/>
</service>
</deployment>
唯一不同的就是多了<beabMapping>这个节点。qname 表示 XML 规范中定义的限定名称,他由名称空间 URI、本地部分和前缀组成。除了本地部分其他都不是必须的另外QName是不可变的。xmlns后面的myNS是必须的。具体根据前面所指定的qname来决定。之后可以随意命名一个namespace。最后的languageSpecificType指定的是你传递的对象类型。第一个属性的本地部分和第二个节点你自定义的命名空间会组成一个新的QName,并将你要传输的对象mapping是上去。
发布这个webservice,编写测试代码
- String targetEendPoint = "http://localhost:8080/axis/services/CheckOrder";
- OrderBean order = new OrderBean();
- order.setName("Beckham");
- order.setAge(32);
- String [] items = new String[] { "Ipod", "ThinkPad" };
- int [] price = new int [] { 999, 5000 };
- order.setItems(items);
- order.setPrice(price);
- order.setChecked(false);
- System.out.println(order.isChecked());
- Service service = new Service();
- Call call = (Call) service.createCall();
- QName qn = new QName("urn:AnalyzeOrder", "Order" );
- call.registerTypeMapping(OrderBean.class, qn,
- new org.apache.axis.encoding.ser.BeanSerializerFactory(OrderBean.class, qn),
- new org.apache.axis.encoding.ser.BeanDeserializerFactory(OrderBean.class, qn));
- call.setTargetEndpointAddress( new java.net.URL(targetEendPoint) );
- call.setOperationName( new QName("CheckOrder", "process") );
- call.addParameter( "arg1", qn, ParameterMode.IN );
- call.setReturnClass(OrderBean.class);
- OrderBean result = (OrderBean) call.invoke( new Object[] {order} );
- System.out.println("Success...");
- System.out.println(result.isChecked())
String targetEendPoint = "http://localhost:8080/axis/services/CheckOrder";
OrderBean order = new OrderBean();
order.setName("Beckham");
order.setAge(32);
String [] items = new String[] { "Ipod", "ThinkPad" };
int [] price = new int [] { 999, 5000 };
order.setItems(items);
order.setPrice(price);
order.setChecked(false);
System.out.println(order.isChecked());
Service service = new Service();
Call call = (Call) service.createCall();
QName qn = new QName("urn:AnalyzeOrder", "Order" );
call.registerTypeMapping(OrderBean.class, qn,
new org.apache.axis.encoding.ser.BeanSerializerFactory(OrderBean.class, qn),
new org.apache.axis.encoding.ser.BeanDeserializerFactory(OrderBean.class, qn));
call.setTargetEndpointAddress( new java.net.URL(targetEendPoint) );
call.setOperationName( new QName("CheckOrder", "process") );
call.addParameter( "arg1", qn, ParameterMode.IN );
call.setReturnClass(OrderBean.class);
OrderBean result = (OrderBean) call.invoke( new Object[] {order} );
System.out.println("Success...");
System.out.println(result.isChecked())
从控制台输出一些信息以便测试,里面大多代码都应该见过。new QName和之后的registerTypeMapping方法也是在实现我上面那段黑体字的内容。之后注册完参数和返回值类型运行。
会发现在tomcat控制台和本地控制台都会输出测试结果,值得注意的是checked这个属性在传入之前是false属性,传入之后我们改变了他的属性变为true。返回之后在本地控制台打印出来也为true。
事实上Axis除了可以传输JavaBean之外还可以传输一些自定义的类型。比如List、Map和时间日期类型。Axis也为他们提供了专门的SerializerFactory和DeserializerFactory。这些工厂类会产生串行化工具去序列化相应的对象。更多的Factory Object可以在org.apache.axis.encoding.ser下面找到。
对于自定义序列化,Axis也提供了相对性的配置节点。具体配置如下:
- <typeMapping qname="ns:local" xmlns:ns="someNamespace"
- languageSpecificType="java:my.java.thingy"
- serializer="my.java.Serializer"
- deserializer="my.java.DeserializerFactory"
- encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
<typeMapping qname="ns:local" xmlns:ns="someNamespace"
languageSpecificType="java:my.java.thingy"
serializer="my.java.Serializer"
deserializer="my.java.DeserializerFactory"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
typeMapping的前三个属性和上面讲的beanMapping都一样。不一样的是后三个。serializer指定的是串行化类,dserializer指定的是反串行化类。最后一个指定的编码方式。其实对于typeMapping来说beanMapping只不过是他的一个简化版而已。因为beanMapping的串行化和反串行化工厂类都是固定的,而编码方式也是固定的。
因为typemapping和beanMapping很相似,在这里就不再写demo了。 有些人也许会问,既然能串行化对象那能不能“串行化”文件呢?这个问题留着下次再说吧。今天米动力了。
小白