因为即将在项目中使用到web service,所以,我提前学习了下这个东西。
不看不知道,一看吓一跳。
好久以前学习并使用过的XFire竟然已经和Celtix合并成了CXF,还出了几个版本。
看来,人还是需要经常关注技术发展的,否则,还真是要掉队了。
(废话太多了?那好吧,我开始演示我的小实验。)
首先,下载CXF,官网(http://cxf.apache.org/ ),解压后,得到以下目录。
其中,lib为jar包,在接下来的工作中需要用到。
下面,我们开始建立工程。
一、组建提供WebService的服务器端项目。
1. 在eclipse/myEclipse中建立web工程cxf2,将CXF_HOME/lib下的所有jar复制到工程的lib中,并添加到buildpath中。
2. 新建一个新POJO,为User.Java。
 package server;
 
 public class User {
     String first;
     String last;
     public String getFirst() {
     return first;
     }
     public void setFirst(String first) {
     this.first = first;
     }
     public String getLast() {
     return last;
     }
     public void setLast(String last) {
     this.last = last;
     }
 }
3. 因为CXF提供的所有webservice都基于接口,所以,新建一个接口UserService。如下:
 package server;
 
 import javax.jws.WebService;
 
 @WebService
 public interface UserService {
     
     void add(User user);
     
     User[] findAllUsers();
 }
其中,@WebService注解是CXF必须的,照搬吧。
4. 新建一个类UserServiceImpl.java,并实现接口UserService。如下:
 package server;
 
 import java.util.List;
 import java.util.Vector;
 
 import javax.jws.WebService;
 
 import org.apache.log4j.Logger;
 
 @WebService(endpointInterface = "server.UserService",serviceName = "UserService",portName="UserServicePort")
 public class UserServiceImpl implements UserService {
     static List<User> UserRepository= new Vector<User>();
     private static Logger log = Logger.getLogger(UserServiceImpl.class);
     {
         log.info("CXF正在初始化 UserServiceImpl.");
     }
     public void add(User user) {
         log.info("CXF正在添加一个用户: "+user.getFirst()+"."+user.getLast());
         UserRepository.add(user);
     }
     
     public User[] findAllUsers() {
         User[] users= new User[UserRepository.size()];
         UserRepository.toArray(users);
         return users;
     }
 }
这里,注解@WebService(endpointInterface = "server.UserService",serviceName = "UserService",portName="UserServicePort")与上面不一样,可以省略。
但在复杂的应用中,不能省略,如指定哪些方法可供远程调用时,需要用到注解。(个人愚见)
5.配置web.xml。
(1)在web.xml中添加CXF的配置文件定义。
 <context-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>WEB-INF/beans.xml</param-value>
  </context-param>
(2)在web.xml中添加如下监听器和servlet。
 <!-- 因为CXF3.0依赖于spring,需要添加这个listener-->
     <listener>
         <listener-class>
             org.springframework.web.context.ContextLoaderListener
         </listener-class>
     </listener>
     
     <servlet>
         <servlet-name>CXFServlet</servlet-name>
         <servlet-class>
             org.apache.cxf.transport.servlet.CXFServlet
         </servlet-class>
         <load-on-startup>1</load-on-startup>
     </servlet>
     
     <servlet-mapping>
         <servlet-name>CXFServlet</servlet-name>
         <url-pattern>/webServices/*</url-pattern>
     </servlet-mapping>
6.建立CXF的配置文件,存放路径要与web.xml中定义的一致。
 <?xml version="1.0" encoding="UTF-8"?>
 
 <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:jaxws="http://cxf.apache.org/jaxws"
         xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
         http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
 
     <import resource="classpath:META-INF/cxf/cxf.xml" />
     <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
     <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
 
     <jaxws:endpoint id="userService" implementor="server.UserServiceImpl" address="/userService" />
 
 </beans>
经过上面步骤,我们已经完成配置了一个提供webservice的服务器。
启动tomcat,在浏览器中输入地址:http://localhost:8880/cxf2/webServices/userService,将返回一个wsdl文件(xml)。
(如果是IE,需要查看源文件来查看。如果是firefox,可以直接看到xml代码。)
更详细的访问地址为:http://localhost:8880/cxf2/webServices/userService?wsdl。
工程目录如图:
二、上面,我们已经成功配置了一个webservice服务器。接下来,我们建立另一个工程来模拟远程调用webservice。
1.新建一个工程testCxf,将上面服务器工程中的User.java和UserService.java复制到工程testCxf中。
2.新建一个类Client.java,代码如下:
 package server;
 
 import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
 
 public class Client {
     public static void main(String[] arg){
 
         JaxWsProxyFactoryBean soapFactoryBean = new JaxWsProxyFactoryBean();
         soapFactoryBean.setAddress("http://localhost:8880/cxf2/webServices/userService");    // 这个就是第一个工程完成后所测试的地址。
         soapFactoryBean.setServiceClass(UserService.class);
         Object o = soapFactoryBean.create();
         UserService userService = (UserService) o;
         User user= new User();
         user.setFirst("James");
         user.setLast("Bond");
         userService.add(user);
         User[] users= userService.findAllUsers();
         for(User u : users){
             System.out.println(u.getFirst()+"."+u.getLast());
         }
     }
 }
执行这个java类,我们会看到控制台输出了相应信息。
CXF正在添加一个用户: James.Bond (这个信息为第一个工程输出)
James.Bond (这个信息为第二个工程输出)
如果运行多次,在最后一次运行后,将会看到有多个“James.Bond ”被输出。
由此,我们可以看到,服务器所提供的webservice已经被成功调用。
到此,两者的通信已经建立,你想做什么就做什么吧,尽情发挥你天马行空的创意。
工程目录如图:
需要两个工程的朋友,可以从这里下载。
http://download.csdn.net/source/2775877 (服务器端)
http://download.csdn.net/source/2775884 (客户端)
后记:
三、由于我们通常不知道提供Web Service的服务器接口及其相关类的代码,我们也不可能从他人那里获得。
对此,CXF提供了一些命令行工具,在CXF_HOME/bin下。
使用wsdl2java,可以根据从服务器返回的wsdl文件生成我们所需要的java接口和相关类。
在上面的工程中,我们可以用以下命令生成JAVA代码,而不是从第一个工程中复制过来。
wsdl2java -p client http://localhost:8880/cxf2/webServices/userService?wsdl (需要在cmd窗口中将路径切换至CXF_HOME/bin下)
(解释:wsdljava –p 包路径 –d 目标文件夹 wsdl 的url地址)
 
 
四、需要注意的是,对于接口类和相关类的包路径,一定要和服务器的一样,(可以通过第三个步骤知道包路径)
否则,会出现Unexpected wrapper element {****}addResponse found.……错误。
