webService开发的问题一览:
前提:本人采用xfile框架进行开发,xfile相比axis来说,xfile更方便支持复杂类型,xfile能支持List、map以及用户自定义的类型。
问题1:在发布的服务器类我只提供了一个带有参数(参数类型是自己定义的一种类型)的构造方法,结果在客户端调用webService时报错:
Could not invoke service.. Nested exception is org.codehaus.xfire.fault.XFireFault: Couldn't instantiate service object.
解答:A.在服务器端中要进行webService接口发布的类,如果提供一个带了形参的构造函数,就报上面的错误。这是因为java的规定:
一个类在实例化时,如果没有构造函数,那么就执行其父类的构造函数,如果自己定义了构造函数,则就执行自己的构造函数。
正是因为如此,一个发布的类提供了带参数的构造函数,而在webService的客户端实例化该类的时候没有提供该构造函数所需的
实参,所以就不能实例化,报异常。
B.如果该类中要发布的接口方法使用了类初始化时初始化的数据,那么必须提供一个无参的构造方法。不然就报空指针异常。
问题2:对于返回类型用到了List、map、自定义的类型时,部署解析的xml问题?
解答:对于发布接口的方法中的参数涉及到List、Map或自定义的类时,必须提供一个解析的xml,告诉服务器你接口方法的参数是什么类型。
该xml文件的命名及xml文件的放置位置都有规定。
xml文件命名:<发布的类名>.aegis.xml
xml文件放置的位置:和发布的类在同一个文件目录下面
xml文件的格式:
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<mapping >
<method name="getAllUsers(发布的接口方法名)">
<return-type componentType="com.example.webservice.servicepackage.User(自定义的类)"/>
</method>
</mapping>
</mappings>
com.example.webservice.servicepackage.User(自定义的类)参见如下:
package com.example.webservice.servicepackage;
public class User {
private String userId;
private String password;
private String userName;
/**
* @return the userId
*/
public String getUserId() {
return userId;
}
/**
* @param userId the userId to set
*/
public void setUserId(String userId) {
this.userId = userId;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return the userName
*/
public String getUserName() {
return userName;
}
/**
* @param userName the userName to set
*/
public void setUserName(String userName) {
this.userName = userName;
}
}
问题3:客户端如何取得webservice方法返回的List<自定义类型>的值?
解答:详见如下代码,可以看得更加清楚。
try {
/** 如果返回值为List,webService在生成客户端代码时,会生成一个包含了List的类,如:ArrayOfUser
* ArrayOfUser就是一个包含List<User>的类,且你调用服务器方法 【public List getAllUsers(String fromIndex,String endIndex)】
* 时,得到的并不是一个List,webService都要封装一层,得到的是webService定义的ArrayOfUser。
**/
ArrayOfUser users = service.getAllUsers("1", "5"); //取得list返回值
System.err.println("users="+users.getUser().size());
for (int i = 0; i < users.user.size(); i++) {
User user = (User) users.user.get(i);
System.err.print(user.getUserId().getValue()); //取自定义的类,还必须getValue()才能取得真正的值。webService封装了一层(正如上面所讲的那样)
System.err.print(user.getPassword().getValue());
System.err.println(user.getUserName().getValue());
}
} catch (Exception e) {
e.printStackTrace();
}
问题4:在真正发布webService的接口时,尽量不要使用这种复杂数据类型,而是采用符合xml文档规则的字符串。这是为什么呢?
解答:因为服务器端修改已经发布的接口及xml文档,服务器端和客户端都要重新生成,这对于项目开发来说无疑是不允许的。所以发布接口时,就应该把接口的入参和返回类型
都定义好,最好都是采用符合xml规则的字符串。所以以后不管接口业务发生什么变化,只要服务器和客户端统一xml的内容规则就行,接口
方法不需要变化,因此增强了代码的健壮性。
前提:本人采用xfile框架进行开发,xfile相比axis来说,xfile更方便支持复杂类型,xfile能支持List、map以及用户自定义的类型。
问题1:在发布的服务器类我只提供了一个带有参数(参数类型是自己定义的一种类型)的构造方法,结果在客户端调用webService时报错:
Could not invoke service.. Nested exception is org.codehaus.xfire.fault.XFireFault: Couldn't instantiate service object.
解答:A.在服务器端中要进行webService接口发布的类,如果提供一个带了形参的构造函数,就报上面的错误。这是因为java的规定:
一个类在实例化时,如果没有构造函数,那么就执行其父类的构造函数,如果自己定义了构造函数,则就执行自己的构造函数。
正是因为如此,一个发布的类提供了带参数的构造函数,而在webService的客户端实例化该类的时候没有提供该构造函数所需的
实参,所以就不能实例化,报异常。
B.如果该类中要发布的接口方法使用了类初始化时初始化的数据,那么必须提供一个无参的构造方法。不然就报空指针异常。
问题2:对于返回类型用到了List、map、自定义的类型时,部署解析的xml问题?
解答:对于发布接口的方法中的参数涉及到List、Map或自定义的类时,必须提供一个解析的xml,告诉服务器你接口方法的参数是什么类型。
该xml文件的命名及xml文件的放置位置都有规定。
xml文件命名:<发布的类名>.aegis.xml
xml文件放置的位置:和发布的类在同一个文件目录下面
xml文件的格式:
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<mapping >
<method name="getAllUsers(发布的接口方法名)">
<return-type componentType="com.example.webservice.servicepackage.User(自定义的类)"/>
</method>
</mapping>
</mappings>
com.example.webservice.servicepackage.User(自定义的类)参见如下:
package com.example.webservice.servicepackage;
public class User {
private String userId;
private String password;
private String userName;
/**
* @return the userId
*/
public String getUserId() {
return userId;
}
/**
* @param userId the userId to set
*/
public void setUserId(String userId) {
this.userId = userId;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* @return the userName
*/
public String getUserName() {
return userName;
}
/**
* @param userName the userName to set
*/
public void setUserName(String userName) {
this.userName = userName;
}
}
问题3:客户端如何取得webservice方法返回的List<自定义类型>的值?
解答:详见如下代码,可以看得更加清楚。
try {
/** 如果返回值为List,webService在生成客户端代码时,会生成一个包含了List的类,如:ArrayOfUser
* ArrayOfUser就是一个包含List<User>的类,且你调用服务器方法 【public List getAllUsers(String fromIndex,String endIndex)】
* 时,得到的并不是一个List,webService都要封装一层,得到的是webService定义的ArrayOfUser。
**/
ArrayOfUser users = service.getAllUsers("1", "5"); //取得list返回值
System.err.println("users="+users.getUser().size());
for (int i = 0; i < users.user.size(); i++) {
User user = (User) users.user.get(i);
System.err.print(user.getUserId().getValue()); //取自定义的类,还必须getValue()才能取得真正的值。webService封装了一层(正如上面所讲的那样)
System.err.print(user.getPassword().getValue());
System.err.println(user.getUserName().getValue());
}
} catch (Exception e) {
e.printStackTrace();
}
问题4:在真正发布webService的接口时,尽量不要使用这种复杂数据类型,而是采用符合xml文档规则的字符串。这是为什么呢?
解答:因为服务器端修改已经发布的接口及xml文档,服务器端和客户端都要重新生成,这对于项目开发来说无疑是不允许的。所以发布接口时,就应该把接口的入参和返回类型
都定义好,最好都是采用符合xml规则的字符串。所以以后不管接口业务发生什么变化,只要服务器和客户端统一xml的内容规则就行,接口
方法不需要变化,因此增强了代码的健壮性。