XFire的介绍另见学习资料。
该文档包含了多种Web服务的发布,主要演示复杂对象的传递——网上很多有关Web Services的发布教程讲到的都只是简单的Hello World,在调用Web Service的时候,返回值都是以字符串做演示,都没有涉及到复杂对象的传递。通过该文档,应该可以应付所有的传递值类型了,除了java.util.Map类型 的对象。具体原因,据网上所说,是因为XFire还是什么咚咚与WSDL的xsd:anyType的映射有缺陷引起的。
1.发布Web Service的接口
言归正传,下面是用来发布Web Services的接口及实现类:
package demo;
import java.util.Collection;
import java.util.List;
/**
* 用于发布Web Service的接口
* @author dreava Nov 10, 2008
*/
public interface IHelloService {
/**
* @param ttt
* @return
*/
public String sayHello(String ttt);
/**
* @param u
* @return
*/
public Course choose(User u);
/**
* @param t
* @return
*/
public List<Course> getList(List<String> paramList);
/**
* @return
*/
public Collection<User> getCollection();
}
package demo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
/**
* @author dreava Nov 10, 2008
*/
public class HelloServiceImpl implements IHelloService {
public String sayHello(String ttt) {
return "Hello, " + ttt;
}
public Course choose(User user) {
System.out.println(user.getName());
Course course = new Course();
course.setName("choose: Eee");
List<User> userList = new ArrayList<User>();
userList.add(user);
course.setUserList(userList);
return course;
}
public List<Course> getList(List<String> paramList) {
for (int i = 0; i < paramList.size(); i++) {
System.out.println((String) paramList.get(i));
}
List<Course> courseList = new ArrayList<Course>();
Course course = new Course();
course.setName("getList: EeeDDDDDD");
User user = new User();
user.setName("getList: liaokun");
List<User> userList = new ArrayList<User>();
userList.add(user);
course.setUserList(userList);
courseList.add(course);
return courseList;
}
public Collection<User> getCollection(){
Collection<User> collection = new HashSet<User>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setName("user"+i);
collection.add(user);
}
return collection;
}
}
下面是上述接口和实现类涉及到的POJO类:
package demo;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author dreava Nov 10, 2008
*/
public class Course {
private String name;
private List<User> userList;
public Collection<User> collection;
public Collection<User> getCollection() {
return collection;
}
public void setCollection(Collection<User> collection) {
this.collection = collection;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
}
package demo;
/**
* @author dreava Nov 10, 2008
*/
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
3.客户端编程测试
下面我们再看看如何对其进行客户端编程。
客户端调用方式有两种,一种为使用服务端的窄接口类,XFire根据Service模型对象及Web Service的URL地址就可以构造出Web Service的调用实例。在服务端Tomcat启动的情况下,运行以下的客户 代码,将可以获得正确的输出。
package demo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.codehaus.xfire.client.Client;
import org.codehaus.xfire.client.XFireProxyFactory;
import org.codehaus.xfire.service.Service;
import org.codehaus.xfire.service.binding.ObjectServiceFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
/**
* @author dreava
* Nov 12, 2008
*/
public class ServiceTest {
public void invokeService() throws Exception{
//根据窄接口创建Service模型
Service serviceModel = new ObjectServiceFactory()
.create(IHelloService.class);
//服务对应的URL地址
String serviceURL = "http://localhost:8080/springxfire/service/HelloServiceUT";
IHelloService service = null;
try {
//创建一个Web Service的访问实例,并将其转换为窄接口类型。
service = (IHelloService) new XFireProxyFactory().create(
serviceModel, serviceURL);
} catch (Exception e) {
throw new RuntimeException(e);
}
//以下为调用各个Web Service方法
//Test sayHello
String str = service.sayHello("dreava");
System.out.println("sayHello(): " + str);
//Test getList
List<String> list = new ArrayList<String>();
for(int i = 0; i < 5; i ++){
list.add("this is: " + i);
}
List<Course> courseList = (List<Course>)service.getList(list);
System.out.println("getList(): ");
for (Course course : courseList) {
System.out.println(course.getName());
}
//Test choose
User user = new User();
user.setName("dreava");
Course course = service.choose(user);
System.out.println("choose(): ");
System.out.println(course.getName());
//Test getCollection
Collection<User> collection = service.getCollection();
System.out.println("getCollection(): ");
for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
User user2 = (User) iterator.next();
System.out.println(user2.getName());
}
}
public static void main(String[] args) throws Exception{
ServiceTest client = new ServiceTest();
client.invokeService();
}
}
另一种调用方式是,用户可以通过WSDL文件生成客户端调用程序,用户可以直接通过URL指定WSDL,也可以将WSDL保存在本地系统中,通过InputStream的方式获取WSDL内容。代码如下:
String wsdl = "test/HelloServiceUT.wsdl";
Resource resource = new ClassPathResource(wsdl);
Client client = new Client(resource.getInputStream(), null);
//Test sayHello
Object[] helloResults = client.invoke("sayHello", new Object[]{"dreava"});
System.out.println("Test sayHello: " + helloResults[0]);
//Test choose
User user = new User();
user.setName("liaokun");
Object[] chooseResults = client.invoke("choose", new Object[]{user});
if(chooseResults != null){
//以下代码将抛出类型转换异常
Course course = (Course) chooseResul
System.out.println("Test choose, the result course is " + course.getName());
}
//Test getList
List<String> list = new ArrayList<String>();
for(int i = 0; i < 5; i ++){
list.add("this is: " + i);
}
//以下代码将抛出异常,该问题的解决还有待进一步上网查找解决办法。
//Object[] testResults = client.invoke("getList", new Object[]{list});
对于涉及到复杂对象的Web Service,必须要配置一个映射文件,比如IHelloService.aegis.xml,该文件必须放在与发布Web Service的接口文件相同的目录下,映射配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<mapping>
<method name="choose">
<parameter index="0" componentType="java.lang.String" />
<return-type componentType="demo.Course" />
</method>
<method name="getList">
<parameter index="0" componentType="java.lang.String" />
<return-type componentType="demo.Course" />
</method>
<method name="getCollection">
<parameter index="0" componentType="java.lang.String" />
<return-type componentType="demo.User" />
</method>
</mapping>
</mappings>
通过上面的例子,在实际项目当中只需要稍加扩展即可,这个例子应该能够应付Web Service项目的开发或改造了。
2.配置文件及发布
下面就可以配置Spring和XFire,以及Web.xml等配置文件了。XFire发布Web Service有两种方式,一种是利用XFire的导出器,一种是利用在发布接口和实现类的相应位置添加注释,这种注释的标准是由BEA提出来的——JSR181,两者各有利弊,利用导出器无需对原有代码进行修改;而利用第二种方法,不适用改造现有系统,似乎只适合新开发Web Services的项目。本文暂时只讲第一种方法。
先看一下Web.xml文件的配置,重要代码添加了注释:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<!-- Spring配置文件 -->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- 配合Spring容器中XFire一起工作的Servlet -->
<servlet>
<servlet-name>xfireServlet</servlet-name>
<servlet-class>
org.codehaus.xfire.spring.XFireSpringServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>xfireServlet</servlet-name>
<url-pattern>/service/*</url-pattern><!-- 在这个URI下开放Web Service服务 -->
</servlet-mapping>
</web-app>
接着我们来看一看Spring的配置文件,相关处有注释:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<!--引入XFire的预配置文件-->
<import resource="classpath:org/codehaus/xfire/spring/xfire.xml" />
<bean id="HelloServiceImpl" class="demo.HelloServiceImpl" />
<!-- 使用导出器导出Web Service -->
<bean id="HelloService"
class="org.codehaus.xfire.spring.remoting.XFireExporter"><!-- XFire导出器 -->
<!-- 引用XFire.xml中定义工作 -->
<property name="serviceFactory" ref="xfire.serviceFactory" />
<!-- 引用XFire.xml中定义的XFire实例 -->
<property name="xfire" ref="xfire" />
<!-- 业务服务Bean -->
<property name="serviceBean" ref="HelloServiceImpl" />
<!-- 业务服务Bean的窄接口类 -->
<property name="serviceClass"
value="demo.IHelloService" />
<!-- Web Service名称 -->
<property name="name" value="HelloServiceUT"/>
</bean>
</beans>
这样,将项目部署到tomcat下,启动容器,在浏览器中输入http://localhost:8080/springxfire/service/HelloServiceUT?wsdl,可看见该发布的Web Service的WSDL文件。