本文主要描述了android客户端与PC服务器端,利用webservice和ksoap2插件进行网络通信的传递实体类的方法。网上有好多文章都描述了将android客户端的自定义实体类作为参数传递给webservice中方法的步骤,能够正常的运行。但是当android客户端接收自定义类型时,却不能强制类型转换为自定义类型(附注:好像用dotNet实现的webservice可以,但是用JAX-WS的不行)。本文自定义了一个parseToObject方法,来处理该问题,并以此为基础,处理了自定义类型List的返回值。
首先在服务端创建自定义类Person,详细代码如下:
public class Person { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } } |
然后创建服务的接口和实现方法,详细代码如下:
public interface HelloWorldService { public List<Person> sayHelloOne(Person person); public Person sayHelloTwo(Person person); public Boolean sayHelloThree(Boolean isRight); public Date sayHelloFour(Date date); } |
import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.jws.WebMethod; import javax.jws.WebService; @Stateless @Remote(HelloWorldService.class) @WebService(name = "HelloWorldService", serviceName = "HelloWorldServiceImpl", targetNamespace = "http://cn.edu.nju.software", portName = "HelloWorldPort") public class HelloWorldServiceImpl implements HelloWorldService { @WebMethod(exclude = true) public String getHelloWorld(String content){ return "Hello World: "+content; } @Override public List<Person> sayHelloOne(Person person) { // TODO Auto-generated method stub Person personA = new Person(); personA.setName(person.getName()+"Hello"); personA.setAge(person.getAge()+4); List<Person> list = new ArrayList<Person>(); list.add(person); list.add(personA); return list; } @Override public Person sayHelloTwo(Person person) { // TODO Auto-generated method stub Person personA = new Person(); personA.setName(person.getName()+"Hello"); personA.setAge(person.getAge()+4); return personA; } @Override public Boolean sayHelloThree(Boolean isRight) { // TODO Auto-generated method stub if(isRight){ return false; } return true; } @Override public Date sayHelloFour(Date date) { // TODO Auto-generated method stub System.out.println(date.toString()); return new Date(0); } } |
标记好注释之后,利用myeclipse自带的工具生成webservice以及wsdl文件。
-------------------------------------------------------------------------------------------------------------------------------
在客户端创建自定义实体类Person,属性(名称,类型)都要和服务端的相同,该实体类还需要实现KvmSerializable接口,以便顺利地将其传输给JAX-WS服务端的webservice,详细代码如下:
import java.util.Hashtable; import org.ksoap2.serialization.KvmSerializable; import org.ksoap2.serialization.PropertyInfo; public class Person implements KvmSerializable{ private String name; private Integer age; public Person(){ } public Person(String name, Integer age){ this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public Object getProperty(int arg0) { // TODO Auto-generated method stub switch(arg0){ case 0: return name; case 1: return age; } return null; } @Override public int getPropertyCount() { // TODO Auto-generated method stub return 2; } @Override public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) { // TODO Auto-generated method stub switch(index) { case 0: info.type = PropertyInfo.STRING_CLASS; info.name = "name"; break; case 1: info.type = PropertyInfo.INTEGER_CLASS; info.name = "age"; break; default: break; } } @Override public void setProperty(int index, Object value) { // TODO Auto-generated method stub switch(index) { case 0: name = value.toString(); break; case 1: age = Integer.parseInt(value.toString()); break; default: break; } } } |
接下来是android端利用ksoap2与webservice进行通信的详细介绍(最主要的部分),先贴上详细代码:
//首先创建自定义对象并包装到PropertyInfo 中;也可以直接被request.addProperty,注意第一个设置参数名的参数内容 必须和服务端方法的wsdl中参数名相同,这里是arg0 Person person = new Person(); person.setName("Android;Android:Android"); person.setAge(7); PropertyInfo pi = new PropertyInfo (); pi.setType(Person.class); pi.setValue(person); pi.setName("arg0"); //必须和服务端方法的wsdl中参数名相同 String wsdl = "http://IPAddress:8080/HelloWorldService/HelloWorldServiceImplPort?wsdl"; String namespace = "http://software.nju.edu.cn/"; String webmethod = "sayHelloOne"; String soapAction = namespace+webmethod; SoapObject request = new SoapObject(namespace, webmethod); request.addProperty(pi); SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.dotNet = false; //由于不是用dotNet做服务端,需设置为false。 envelope.setOutputSoapObject(request); envelope.addMapping(namespace, "Person", Person.class); //ksoap2传递自定义类型对象的属性中如果有除了Boolean、Integer和String以外类型的属性时,需要在envelope中注册相应的Marshal //Marshal dateMarshal = new MarshalDate(); //dateMarshal.register(envelope); HttpTransportSE ht = new HttpTransportSE(wsdl); String response = ""; //设置为true,方便之后读取信息,如 ht.requestDump和ht.responseDump ht.debug = true; try { ht.call(soapAction, envelope); if(envelope.getResponse()!=null){ List<Person> list = new ArrayList<Person>(); SoapObject rpsObject = (SoapObject) envelope.bodyIn; int numOfList = rpsObject.getPropertyCount(); for(int i=0;i<numOfList;i++){ SoapObject tmpSoapObject = (SoapObject)rpsObject.getProperty(i); list.add((Person)CastObject.parseToObject(tmpSoapObject, Person.class)); } for(Person obj:list){ response += "name: "+obj.getName()+" age: "+obj.getAge()+"\n"; } }catch (IOException e){ // TODO Auto-generated catch block response += e.getMessage(); } catch (XmlPullParserException e){ // TODO Auto-generated catch block response += e.getMessage(); }catch (Exception e){ // TODO Auto-generated catch block response += e.getMessage(); } response += "\nRequest: "; response += ht.requestDump; response += "\nResponse: "; response += ht.responseDump; |
自定义方法parseToObject,详细代码如下:
public class CastObject { public static KvmSerializable parseToObject(SoapObject soapObject, Class objectClass) throws IllegalAccessException, InstantiationException{ KvmSerializable result = (KvmSerializable) objectClass.newInstance(); int numOfAttr = result.getPropertyCount(); for(int i=0; i<numOfAttr; i++){ PropertyInfo info = new PropertyInfo(); result.getPropertyInfo(i, null, info); //处理property不存在的情况 try{ result.setProperty(i, soapObject.getProperty(info.name)); }catch(Exception e){ continue; } } return result; } } |
在经过多次试验之后还发现了envelope.getResponse()和envelope.bodyIn的区别,请读者注意:
envelope.getResponse()是取单条记录;当遇到多条记录时,用envelope.bodyIn,然后用(SoapObject)object.getProperty(i) 取每条记录。