WebService之JAX-WS、CXF、Spring3.0+

标签: webservice jax ws | 发表时间:2013-02-19 00:02 | 作者:鼠标CHH
出处:http://www.cnblogs.com/

  前言:

          面对工作的需要,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 chh
12 *
13 */
14 @WebService
15 @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 chh
14 *
15 */
16 @WebService
17 @SOAPBinding(style=Style.RPC)
18 @SuppressWarnings("deprecation")
19 public class ComplexUserService implements IComplexUserService {
20
21 @Override
22 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 @Override
34 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 @Override
54 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 chh
10 *
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.xsd
10 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/context
10 http://www.springframework.org/schema/context/spring-context-3.0.xsd
11 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 chh
13 *
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校验、设置访问的最大数、超时时间、描述等等,采用现在

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

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

     

本文链接

相关 [webservice jax ws] 推荐:

WebService之JAX-WS、CXF、Spring3.0+

- - 博客园_首页
          面对工作的需要,web服务这一块一直都在身边转悠着. 既然工作中需要这些,作为程序员就应该去了解和学习. 下面主要简述采用CXF+Spring+JAX-WS来发布WebService服务,以及创建客户端调用服务.          1、先了解关于WebService的相关概念以及一些专有名词的解释:.

利用JAX-WS开发Web服务

- - CSDN博客推荐文章
利用JAX-WS开发Web服务.        Web服务是一种经由HTTP与其他软件进行通信的软件. Java最激动人心的一个特性是用于XML Web服务的Java API(JAX-WS). JAX-WS是一组Java类和包,他可以创建对Web服务发出请求的客户端,以及接受这些请求的服务.        JAX-WS支持使用简单对象访问协议(SimpleObject Access Protocol,SOAP)和表述性状态转移(Representational State Transfer,REST)实现的Web服务.

SOAP WebService以CXF实现WS-Security之xml签名及加密

- - 编程语言 - ITeye博客
接上篇,记录一下使用apache cxf和spring使用自签名数字证书实现WebService服务端及客户端的xml签名、加密以及解密和签名验证;. 这里仅针对客户端加密和签名并在服务端实现解密及签名验证的单向认证的情形,双向认证可以参照官方sample改进;. 客户端使用客户端私钥进行消息签名、客户端使用服务端公钥消息加密;.

SOAP Webservice和RESTful Webservice

- - 人月神话的BLOG
REST是一种架构风格,其核心是面向资源,REST专门针对网络应用设计和开发方式,以降低开发的复杂性,提高系统的可伸缩性. REST提出设计概念和准则为:. 1.网络上的所有事物都可以被抽象为资源(resource). 2.每一个资源都有唯一的资源标识(resource identifier),对资源的操作不会改变这些标识.

webservice认证

- - 行业应用 - ITeye博客
1、服务器端,增加拦截认证--ServerPasswordCallback.java.                 throw new WSSecurityException("用户不匹配.                 throw new WSSecurityException("密码不匹配.

cxf + spring 的WS Security示例

- - RSS - IT博客云
WSPasswordCallback的 passwordType属性和 password属性都为null,你只能获得用户名(identifier),一般这里的逻辑是使用这个用户名到数据库中查询其密码,然后再设置到 password属性,WSS4J会自动比较客户端传来的值和你设置的这个值. 你可能会问为什么这里CXF不把客户端提交的密码传入让我们在 ServerPasswordCallbackHandler中比较呢.

WebService性能测试

- - ImportNew
(本文也会在最下面通俗的介绍). 这里给一个站内大哥的讲解: http://www.cnblogs.com/Leo_wl/archive/2010/05/20/1740205.html. 简单点就是测试WebService的一个工具. 官网地址: http://www.soapui.org/. ps:官网是英语的,如果你英语不好的话可以使用谷歌浏览器或360极速浏览器,它可以自动把英文转换成中文.

webservice编程基础—cxf

- - ITeye博客
最近研究了一下cxf的使用,主要的步骤如下:. 下载最新的cxf包apache-cxf-2.6.2.tar.zip,并解压,有一个lib文件,里面的jar包,就是webservice需要的(不完全需要,看你的应用,但是懒的分),加载进你的webservice的工程即可. 配置两个配置文件,为beans.xml和web.xml,内容如下:.

[转]JMeter进行WebService测试

- - 小鸥的博客
1. Building a WebService Test Plan参考. 1.   建立WebServiceTest Plan. 参考 http://jmeter.apache.org/usermanual/build-ws-test-plan.html. 1)      添加ThreadGroup.

CXF WEBSERVICE 安全验证

- - 企业架构 - ITeye博客
CXF 封装的接口,不希望对外暴露 WSDL结构,找到的CXF安全认证技术都是基于拦截器,在调用的时候返回认证错误信息, 不能保护WSDL不被看到,后来看到别人的一个实现方式最简单有效,基于URL拦截的安全保护,用FILTER. 现在把这2种安全保护都记录下来,备用. 参考: http://www.myexception.cn/open-source/1505475.html.