本文主要描述了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) 取每条记录。