WebService(2) JAX-WS、CXF、Spring3.0+

来源:互联网 发布:淘宝客服需要什么软件 编辑:程序博客网 时间:2024/05/22 21:36

引自:http://www.cnblogs.com/NF-CHH/archive/2013/02/19/WebService.html?utm_source=tuicool&utm_medium=referral

前言:

          面对工作的需要,web服务这一块一直都在身边转悠着。既然工作中需要这些,作为程序员就应该去了解和学习。下面主要简述采用CXF+Spring+JAX-WS来发布WebService服务,以及创建客户端调用服务。

     准备工作:

         1、先了解关于WebService的相关概念以及一些专有名词的解释:

     WEBSERVICE 

         W3C的定义是webservice是一个软件系统,用以支持网络间不同机器的互动操作。

     受外部环境和实现技术影响,目前普遍认为webservice的技术核心是

     soap,wsdl(一个XML格式文档,用以描述服务端口访问方式和使用协议的细节。通常用来辅助生成服务器和客户端代码及配置信息),uddi(一个用来发布和搜索WEB服务的协议,应用程序可借由   此协议在设计或运行时找到目标WEB服务)

     这些标准由这些组织制订:W3C负责XML、SOAP及WSDL;OASIS负责UDDI。

         JAX-WS

    JAX-WS规范是一组XML web services的JAVA API。JAX-WS允许开发者可以选择RPC-oriented或者message-oriented 来实现自己的web services。

         CXF

         Apache CXF 是一个开源的 Services 框架,主要是帮助开发者来快速构建web服务。

 

   webservice三种最普遍的实现方式是:

   远程过程调用(RPC)

   面向服务架构(SOA)

   表述性状态转移(REST)

      我在这里说的实现方式并不是说 这三种方式是包含于webservice,个人理解它们之间应该是存在交集,即它们是有联系的同时它们也是有不同的,应该不是从属的关系。

 

       2、相关的开发环境与依赖的jar()    
          A、CXF官方网址:http://cxf.apache.org/
          B、Jar包下载地址:http://www.apache.org/dyn/closer.cgi?path=/cxf/2.3.3/apache-cxf-2.3.3.zip
           将下来的jar包解压后,目录大概就这样
           bin目录提供的是常用的dos控制台命令工具
           docs 帮助文档
           lib jar包、依赖库
           lib-samples 也是jar包,有jetty、httpclients、junit等jar包
           modules 打包好的WebService模块
           samples示例demo
          C、源码下载:http://www.apache.org/dyn/closer.cgi?path=/cxf/2.3.3/apache-cxf-2.3.3-src.zip
            有时候你可以看看源码,对你了解和学习CXF WebService都会有作用。
          D、CXF的特性
           有代码生成工具:Java to WSDL;WSDL to Java;XSD to WSDL;WSDL to XML;WSDL to SOAP;WSDL to Service;
           支持 JAX-WS、 JAX-WSA、JSR-181 和 SAAJ;支持 SOAP 1.1、1.2、WS-I BasicProfile、WS-Security、WS-Addressing、WS-RM 和 WS-Policy;支持 WSDL 1.1 、2.0;支持 MTOM;通过 Yoko 支持 CORBA;通过 Tuscany 支持 SCA;通过 ServiceMix 支持 JBI;内置Jetty应用服务器(Jetty服务器也是当今web开发的一款比较好用的服务器);

 

      开发:

         开发需要的jar如下:

         

              1、首先创建一个web项目,将得到的包拷贝到lib目录下

               既然是想发布自己的服务,首先创建一个接口

复制代码
 1 package com.chh.service; 2  3 import javax.jws.WebParam; 4 import javax.jws.WebService; 5 import javax.jws.soap.SOAPBinding; 6 import javax.jws.soap.SOAPBinding.Style; 7 import com.chh.entity.User; 8  9 /**10  * 定制客户端请求WebService所需要的接口11  * @author chh12  *13  */14 @WebService15 @SOAPBinding(style=Style.RPC)16 public interface IComplexUserService {17     18     public User getUserByName(@WebParam(name = "name") String name);19 20     public void setUser(User user);21 22 }
复制代码

           接口只是用来定义,具体操作要在它下面的实现类中得以体现

复制代码
 1 package com.chh.service; 2  3 import java.util.Date; 4  5 import javax.jws.WebParam; 6 import javax.jws.WebService; 7 import javax.jws.soap.SOAPBinding; 8 import javax.jws.soap.SOAPBinding.Style; 9 10 import com.chh.entity.User;11 /**12  * WebService传递复杂对象,如JavaBean、Array、List、Map等13  * @author chh14  *15  */16 @WebService17 @SOAPBinding(style=Style.RPC)18 @SuppressWarnings("deprecation")19 public class ComplexUserService implements IComplexUserService {20 21     @Override22     public User getUserByName(@WebParam(name = "name") String name) {23         User user = new User();24 25         user.setId(new Date().getSeconds());26         user.setName(name);27         user.setAddress("china");28         user.setEmail(name + "@hoo.com");29 30         return user;31     }32 33     @Override34     public void setUser(User user) {35         System.out.println("############Server setUser###########");36         System.out.println("setUser:" + user);37     }38 39 }
复制代码

          实体

复制代码
 1 package com.chh.entity; 2  3 import java.io.Serializable; 4 /** 5  * 序列化user实体 6  * @author chh 7  *  8  */ 9 public class User implements Serializable {10 11     private static final long serialVersionUID = 677484458789332877L;12     private int id;13     private String name;14     private String email;15     private String address;16 17     public int getId() {18         return id;19     }20 21     public void setId(int id) {22         this.id = id;23     }24 25     public String getName() {26         return name;27     }28 29     public void setName(String name) {30         this.name = name;31     }32 33     public String getEmail() {34         return email;35     }36 37     public void setEmail(String email) {38         this.email = email;39     }40 41     public String getAddress() {42         return address;43     }44 45     public void setAddress(String address) {46         this.address = address;47     }48 49     public static long getSerialversionuid() {50         return serialVersionUID;51     }52     53     @Override54     public String toString() {55         return this.id + "#" + this.name + "#" + this.email + "#" + this.address;56     }57 58 }
复制代码
复制代码
 1 package com.chh.entity; 2  3 import java.util.HashMap; 4 import java.util.List; 5  6 /** 7  *  8  * @author chh 9  * 10  */11 public class Users {12     private List<User> users;13     private User[] userArr;14     private HashMap<String, User> map;15 16     public List<User> getUsers() {17         return users;18     }19 20     public void setUsers(List<User> users) {21         this.users = users;22     }23 24     public User[] getUserArr() {25         return userArr;26     }27 28     public void setUserArr(User[] userArr) {29         this.userArr = userArr;30     }31 32     public HashMap<String, User> getMap() {33         return map;34     }35 36     public void setMap(HashMap<String, User> map) {37         this.map = map;38     }39 40 }
复制代码

         自定义消息拦截器(如果在你的项目中不需要用到拦截器的时候,可以撤掉不用)

复制代码
 1 package com.chh.interceptor; 2  3 import org.apache.cxf.interceptor.Fault; 4 import org.apache.cxf.message.Message; 5 import org.apache.cxf.phase.AbstractPhaseInterceptor; 6  7 /** 8  * 自定义消息拦截器 9  * @author chh10  *11  */12 public class MessageInterceptor extends AbstractPhaseInterceptor<Message> {13 14     //至少要有一个带参的构造方法15     public MessageInterceptor(String phase) {16         super(phase);17     }18     19     public void handleMessage(Message message) throws Fault {20         System.out.println("############handleMessage##########");21         System.out.println(message);22         23         if(message.getDestination() != null){24              System.out.println(message.getId() + "#" + message.getDestination().getMessageObserver());25         }26         27         if(message.getExchange() != null){28             System.out.println(message.getExchange().getInMessage() + "#" + message.getExchange().getInFaultMessage());29             System.out.println(message.getExchange().getOutMessage() + "#" + message.getExchange().getOutFaultMessage());30         }31         32     }33 34 }
复制代码

         用xml配置服务端(applicationContext-service.xml)

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3     xmlns:context="http://www.springframework.org/schema/context" 4     xmlns:jaxws="http://cxf.apache.org/jaxws" 5     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 6     xsi:schemaLocation="http://www.springframework.org/schema/beans  7     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 8     http://www.springframework.org/schema/context 9     http://www.springframework.org/schema/context/spring-context-3.0.xsd10     http://cxf.apache.org/jaxws 11     http://cxf.apache.org/schemas/jaxws.xsd">12     13     <import resource="classpath:META-INF/cxf/cxf.xml"/>14     <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>15     <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>16     17     <bean id="userServiceBean" class="com.chh.service.ComplexUserService"/>18 19     <bean id="inMessageInterceptor" class="com.chh.interceptor.MessageInterceptor">20         <constructor-arg  value="receive"/>21     </bean>22 23     <bean id="outLoggingInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>24     25     <!-- 注意下面的address,这里的address的名称就是访问的WebService的name -->26     <jaxws:server id="userService" serviceBean="#userServiceBean" address="/Users">27         <jaxws:inInterceptors>28             <ref bean="inMessageInterceptor"/>29         </jaxws:inInterceptors>30     31         <jaxws:outInterceptors>32             <ref bean="outLoggingInterceptor"/>33         </jaxws:outInterceptors>34     </jaxws:server>35     36 </beans>
复制代码

        注意于此同时web.xml中要加在Spring容器

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> 3   <display-name>CXFWebService</display-name> 4        5   <!-- 加载Spring容器配置 --> 6     <listener> 7         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 8     </listener> 9     10     <!-- 设置Spring容器加载配置文件路径 -->11     <context-param>12         <param-name>contextConfigLocation</param-name>13         <param-value>classpath*:applicationContext-server.xml</param-value>14     </context-param>15     16     <listener>17         <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>18     </listener>19 20     <servlet>21         <servlet-name>CXFService</servlet-name>22         <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>23     </servlet>24 25     <servlet-mapping>26         <servlet-name>CXFService</servlet-name>27         <url-pattern>/*</url-pattern>28     </servlet-mapping>    29 </web-app>
复制代码

到这一步为止,我们web服务端开发完成!可以启动项目测试一下自己的web服务有没有发布成功,其中成功与否第一要看项目启动时是否报错,如果报错看具体报什么错误,是包冲突,还是包的版本太低等。启动项目不报错,那么输入地址查看你的这个web服务的wsdl信息:http://localhost:8080/CXFWebService/Users,如果能够看到看到xml格式的信息,则说明你成功发布了web服务。

有了web服务端,但是如果我在程序中想通过别人提供的web服务地址得到自己想要的数据,这一步又该怎么做呢?下面将继续采用CXF+Spring3.0+ 定制开发web服务客户端。其实到这一步已经很简单了,我们可以通过wsdl中的信息来定制客户端(具体有怎样的规则与细节,可以参看http://blog.csdn.net/qjyong/article/details/2148558   这篇博客下面的几个段落)。

       根据服务端定制客户端

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3  4     xmlns:context="http://www.springframework.org/schema/context" 5     xmlns:jaxws="http://cxf.apache.org/jaxws" 6     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 7     xsi:schemaLocation="http://www.springframework.org/schema/beans  8     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 9     http://www.springframework.org/schema/context10     http://www.springframework.org/schema/context/spring-context-3.0.xsd11     http://cxf.apache.org/jaxws 12     http://cxf.apache.org/schemas/jaxws.xsd">13 14     <import resource="classpath:META-INF/cxf/cxf.xml"/>15     <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>16     <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>17 18     <!-- serviceClass写定制客户接口的全路径 -->19     <jaxws:client id="userWsClient" serviceClass="com.chh.service.IComplexUserService" 20         address="http://localhost:8080/CXFWebService/Users"/>21     22 </beans>
复制代码

      利用客户端得到服务端的数据。值得说的是,以前发布WebService是用Endpoint的push方法。这里用的是JaxWsServerFactoryBean和客户端调用的代码JaxWsProxyFactoryBean有点不同。

复制代码
 1 package com.chh.client; 2  3 import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6  7 import com.chh.entity.User; 8 import com.chh.service.IComplexUserService; 9 10 /**11  * 请求Spring整合CXF的WebService客户端12  * @author chh13  *14  */15 public class SpringUsersWsClient {16     17     public static void clientFirst(){18         JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();19         factory.setServiceClass(IComplexUserService.class);20         factory.setAddress("http://localhost:8080/CXFWebService/Users");21         22         IComplexUserService service = (IComplexUserService) factory.create();23         24         System.out.println("#############Client getUserByName##############");25         User user = service.getUserByName("chh");26         System.out.println(user);27 28         user.setAddress("China-Guangzhou");29         service.setUser(user);30     }31     32     public static void clientToXML(){33         ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext-client.xml");34 35         IComplexUserService service = ctx.getBean("userWsClient", IComplexUserService.class);36         37         System.out.println("#############Client getUserByName##############");38         User user = service.getUserByName("chh");39         System.out.println(user);40 41         user.setAddress("China-Guangzhou");42         service.setUser(user);43     }44 45     public static void main(String[] args) {46         clientToXML();47     }48 }
复制代码

      这样下来,只要项目还启动着web服务还没有停,我们可以运行SpringUserWsClient这个文件的main方法就可以调用到服务端的数据。

    项目目录结构图:

   

整个服务的发布与调用都是采用xml形式开发的,其实如果你不习惯用的话可以文件中用代码实现,这样也是可以的。

到这里,让我想起了公司里面的那套框架的发布服务与调用服务,如果一个web服务想要加密以及MAC校验、设置访问的最大数、超时时间、描述等等,采用现在

这种发布服务的方式那该如何实现,客户端又该如何调用?或者说有没有更加简单的方式来实现这一切功能呢?这样的一些想法还都在摸索着前进,如果有那位热

心肠有高见的话,希望大家知识共享!


原创粉丝点击