Web Service笔记(二):利用CXF开发Web Service(转别人的)

前言:
1、wsdl与soap详解 或 wsdl文件结构分析
2、jax-ws详解
3、jax-rs详解

一、CXF开发简单的WS服务与客户端

(一)、要求的jar 包
1、CXF版本为 cxf-2.7.8.jar ,其他版本可能会有出入。
2、需要的jar包为:

3、因为使用main函数启动发布,所以需要 jetty 包。
4、出现Cannot create a secure XMLInputFactory异常提示时通常是少了woodstox-core-asl-4.2.0.jar或stax2-api这两个包,少这两个包服务能够启动成功,且浏览器访问wsdl正常;但客户端连接web service时就出现错误提示了。加入后可能还需要重启下eclipse。

(二)、服务器端
1、接口:
[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.ws; 
 
import java.util.List; 
 
import javax.jws.WebService; 
 
 
import com.ws.bean.Cat; 
import com.ws.bean.User; 
 
@WebService 
public interface HelloWorld { 
     
    public String sayHi(String name); 
     


2、实现类
[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.ws.impl; 
 
import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.List; 
 
import javax.jws.WebService; 
 
import com.service.UserService; 
import com.service.impl.UserServiceImp; 
import com.ws.HelloWorld; 
import com.ws.bean.Cat; 
import com.ws.bean.User; 
 
/**
* endpointInterface,是他实现的接口,记得写全包名 serviceName,服务器名称

* @author SAM

*/ 
 
// 实现类需要标明 WebService 
// 标明实现的接口,endpointInterface 含包名 
// serviceName 自定义名称 
@WebService(endpointInterface = "com.ws.HelloWorld", serviceName = "HelloSAM") 
public class HelloWorldImpl implements HelloWorld { 
 
    public String sayHi(String name) { 
 
        return name + ",您好!您现在访问的是简单的WS服务端,时间为:" + new SimpleDateFormat().format(new Date()); 
    } 
 
 


3、发布
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/**
* 发布简单的WebService
*/ 
public void deployService() { 
 
    System.out.println("Server start ……"); 
 
    HelloWorldImpl service = new HelloWorldImpl(); 
    String address = "http://localhost:8080/helloWorld"; 
 
    // 调用Endpoint的publish方法 
    Endpoint.publish(address, service); 
 
    System.out.println("server ready ……"); 
 



4、分析
1)实现类需要标明 @WebService
2)标明实现的哪个接口,关键字,endpointInterface 含包名。如 endpointInterface = "com.ws.HelloWorld"
3)serviceName 自定义服务器的名称,这个名字随便取,用 wsdl2java 生成客户端时,生成的继承 service的类,就会是这个名字。如我这边取名为  serviceName = "HelloSAM" 。
4)使用 Endpoint.publish(address, service) 方法发布WS的服务端。这时,只要访问 http://localhost:8080/helloWorld?wsdl 地址就可以看到WS服务成功发布了。如


(三)、客户端
1、自动生成客户端,在dos窗口,进入eclipse的客户端工程下,使用 wsdl2java + 服务器端的 wsdl 地址。如


2、CXF会根据自动生成 http://localhost:8080/helloWorld?wsdl 的wsdl文件自动生成客户端需要的文件。
3、客户端调用服务器端代码:需要使用自动生成的继承了Service 类的那个类,这边就是 HelloSAM 即在服务端的那个 serviceName = "HelloSAM" 指定的名称。代码如下:
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/**
* 简单客户端访问
*/ 
private void visitServer() { 
 
    HelloSAM helloFactory = new HelloSAM();// HelloSAM是客户端生成的继承了 service的类 
    HelloWorld hw = helloFactory.getHelloWorldImplPort();// 返回远程ws对象的代理,不是服务器中远程对象 
    System.out.println(hw.sayHi("SAM-SHO")); 
 


4、这边服务器和客户端启动都是依赖main方法,需要jetty包的支持,到此为止,一次启动服务和客户端,就可以再后台看到如下输出,即简单的WS发布和访问成功。
[java] view plain copy 在CODE上查看代码片派生到我的代码片
SAM-SHO,您好!您现在访问的是简单的WS服务端,现在的时间是:14-11-16 下午10:41 

5、另一种方式:利用 JaxWsProxyFactoryBean
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/**
* 另一种方式访问
*/ 
private void visitServer2() { 
    // 调用WebService 
    JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); 
    factory.setServiceClass(HelloWorld.class); 
    factory.setAddress("http://localhost:8080/Java_WS_Server/soap/helloWorld"); 
 
    HelloWorld service = (HelloWorld) factory.create(); 
 
    System.out.println("#############Client sayHi##############"); 
    System.out.println(service.sayHi("SAM-SAM")); 
 



6、分析详见:Web Service笔记(三):wsdl 与 soap协议详解

二、带javaBean 和 集合的WS

(一)、服务器端
1、在服务器端增加方法:然后创建javaBean 以及其业务类。代码如下:
[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.ws; 
 
import java.util.List; 
 
import javax.jws.WebService; 
 
 
import com.ws.bean.Cat; 
import com.ws.bean.User; 
 
@WebService 
public interface HelloWorld { 
     
    public String sayHi(String name); 
     
    public List<Cat> getCatsByUser(User user); 


[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.ws.impl; 
 
import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.List; 
 
import javax.jws.WebService; 
 
import com.service.UserService; 
import com.service.impl.UserServiceImp; 
import com.ws.HelloWorld; 
import com.ws.bean.Cat; 
import com.ws.bean.User; 
 
/**
* endpointInterface,是他实现的接口,记得写全包名 serviceName,服务器名称

* @author SAM

*/ 
 
// 实现类需要标明 WebService 
// 标明实现的接口,endpointInterface 含包名 
// serviceName 自定义名称 
@WebService(endpointInterface = "com.ws.HelloWorld", serviceName = "HelloSAM") 
public class HelloWorldImpl implements HelloWorld { 
 
    /**
     * 简单方法
     */ 
    public String sayHi(String name) { 
 
        return name + ",您好!您现在访问的是简单的WS服务端,时间为:" + new SimpleDateFormat().format(new Date()); 
    } 
 
    /**
     * 复杂方法 含javabean 和 集合
     */ 
    public List<Cat> getCatsByUser(User user) { 
 
        UserService tUserService = new UserServiceImp(); 
        return tUserService.getCatsByUser(user); 
    } 

[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.ws.bean; 
/**
* User类
* @author SAM
*
*/ 
public class User { 
     
    private Integer  id; 
    private String name; 
    private String pass; 
    private String address; 
     
    public User() { 
        super(); 
    } 
     
    public User(Integer id, String name, String pass, String address) { 
        super(); 
        this.id = id; 
        this.name = name; 
        this.pass = pass; 
        this.address = address; 
    } 
 
    public Integer getId() { 
        return id; 
    } 
    public void setId(Integer id) { 
        this.id = id; 
    } 
    public String getName() { 
        return name; 
    } 
    public void setName(String name) { 
        this.name = name; 
    } 
    public String getPass() { 
        return pass; 
    } 
    public void setPass(String pass) { 
        this.pass = pass; 
    } 
    public String getAddress() { 
        return address; 
    } 
    public void setAddress(String address) { 
        this.address = address; 
    } 
 
    @Override 
    public int hashCode() { 
        final int prime = 31; 
        int result = 1; 
        result = prime * result + ((name == null) ? 0 : name.hashCode()); 
        result = prime * result + ((pass == null) ? 0 : pass.hashCode()); 
        return result; 
    } 
 
    @Override 
    public boolean equals(Object obj) { 
        if (this == obj) 
            return true; 
        if (obj == null) 
            return false; 
        if (getClass() != obj.getClass()) 
            return false; 
        User other = (User) obj; 
        if (name == null) { 
            if (other.name != null) 
                return false; 
        } else if (!name.equals(other.name)) 
            return false; 
        if (pass == null) { 
            if (other.pass != null) 
                return false; 
        } else if (!pass.equals(other.pass)) 
            return false; 
        return true; 
    } 
     


[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.ws.bean; 
/**
* Cat类
* @author SAM
*
*/ 
public class Cat { 
    private Integer id; 
    private String name; 
    private String color; 
     
    public Cat() { 
        super(); 
    } 
     
    public Cat(Integer id, String name, String color) { 
        super(); 
        this.id = id; 
        this.name = name; 
        this.color = color; 
    } 
     
    public Integer getId() { 
        return id; 
    } 
    public void setId(Integer id) { 
        this.id = id; 
    } 
    public String getName() { 
        return name; 
    } 
    public void setName(String name) { 
        this.name = name; 
    } 
    public String getColor() { 
        return color; 
    } 
    public void setColor(String color) { 
        this.color = color; 
    } 
 
    @Override 
    public String toString() { 
        return "Cat [color=" + color + ", id=" + id + ", name=" + name + "]"; 
    } 

[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.service; 
 
import java.util.List; 
 
import com.ws.bean.Cat; 
import com.ws.bean.User; 
 
public interface UserService { 
 
    List<Cat> getCatsByUser(User user); 
 


[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.service.impl; 
 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
 
import com.service.UserService; 
import com.ws.bean.Cat; 
import com.ws.bean.User; 
/**

* UserServiceImp.java
*
* @title User业务类
* @description
* @author SAM-SHO 
* @Date 2014-11-16
*/ 
public class UserServiceImp implements UserService { 
 
    //模拟数据库 
    static Map <User,List<Cat>> catDB = new HashMap<User,List<Cat>>(); 
    //静态初始化 
    static{ 
        List<Cat> catList1 = new ArrayList<Cat>(); 
        catList1.add(new Cat(1, "加菲猫", "黄色")); 
        catList1.add(new Cat(2, "蓝胖子", "蓝色")); 
        catDB.put(new User(1, "Sam-Sho", "1234", "soochow"), catList1); 
         
        List<Cat> catList2 = new ArrayList<Cat>(); 
        catList1.add(new Cat(3, "hello kitty", "粉色")); 
        catList1.add(new Cat(4, "熊猫", "黑白色")); 
        catDB.put(new User(2, "赵小妞", "4567", "soochow"), catList2); 
         
    } 
     
    public List<Cat> getCatsByUser(User user) { 
         
        return catDB.get(user); 
    } 
 


2、服务端发布如下:
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/**
* 发布javaBean 和集合 的WS
*/ 
private void deployComplexService() { 
    System.out.println("Server start ……"); 
    HelloWorldImpl service = new HelloWorldImpl(); 
    String address = "http://localhost:8080/helloWorld"; 
 
    // 调用Endpoint的publish方法 
    Endpoint.publish(address, service); 
    System.out.println("server ready ……"); 


3、在浏览器中调用 http://localhost:8080/helloWorld?wsdl



(二)、客户端
1、使用 wsdl2java ,方法与上面创建客户端一致。
2、客户端调用服务端代码如下:
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/**
* 访问复杂客户端
*/ 
private void visitComplexServer() { 
 
    HelloSAM helloFactory = new HelloSAM();// HelloSAM是客户端生成的继承了 service的类 
    HelloWorld hw = helloFactory.getHelloWorldImplPort();// 返回远程ws对象的代理,不是服务器中远程对象 
     
    //1, "Sam-Sho", "1234", "soochow" 
    User user = new User(); 
    user.setId(1); 
    user.setName("Sam-Sho"); 
    user.setPass("1234"); 
    user.setAddress("soochow"); 
    System.out.println(hw.getCatsByUser(user));//[com.ws.Cat@1aaf0b3, com.ws.Cat@1a082e2, com.ws.Cat@f0c85e, com.ws.Cat@1f297e7] 
    System.out.println(hw.getCatsByUser(user).get(0).getName());//加菲猫 


3、【输出】
[java] view plain copy 在CODE上查看代码片派生到我的代码片
SAM-SHO,您好!您现在访问的是简单的WS服务端,时间为:14-11-16 下午11:29 
[com.ws.Cat@1aaf0b3, com.ws.Cat@1a082e2, com.ws.Cat@f0c85e, com.ws.Cat@1f297e7] 
加菲猫 


三、CXF处理Map等不支持的类型
(一)服务端实现
1、使用 @XmlJavaTypeAdapter 注解修饰 CXF 不支持的类型。并且通过其value属性指定特定的类型转换器。
2、这个类型转换器必须继承抽象类 XmlAdapter<ValueType,BoundType>,其中 BoundType 为CXF不支持的类型,而 ValueType 为我们即将把 BoundType  转换为的支持的类型。一般需要自己定义。
3、定义 ValueType 这个转换对象类型,且为CXF 支持的类型。其本质就是模拟实现一个Map即可。

4、服务端涉及的代码如下
1)服务的接口与实现类代码:
[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.ws; 
 
import java.util.List; 
import java.util.Map; 
 
import javax.jws.WebService; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 
 
import com.adapter.TypeAdapter; 
import com.ws.bean.Cat; 
import com.ws.bean.User; 
 
@WebService 
public interface HelloWorld { 
     
    public String sayHi(String name); 
     
    public List<Cat> getCatsByUser(User user); 
     
    //value属性指定一个转换器,为自定义的转换器 
    @XmlJavaTypeAdapter(value = TypeAdapter.class)  
    public Map<String,Cat> getAllCats(); 
     
     

[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.ws.impl; 
 
import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.List; 
import java.util.Map; 
 
import javax.jws.WebService; 
 
import com.service.UserService; 
import com.service.impl.UserServiceImp; 
import com.ws.HelloWorld; 
import com.ws.bean.Cat; 
import com.ws.bean.User; 
 
/**
* endpointInterface,是他实现的接口,记得写全包名 serviceName,服务器名称

* @author SAM

*/ 
 
// 实现类需要标明 WebService 
// 标明实现的接口,endpointInterface 含包名 
// serviceName 自定义名称 
@WebService(endpointInterface = "com.ws.HelloWorld", serviceName = "HelloSAM") 
public class HelloWorldImpl implements HelloWorld { 
 
    /**
     * 简单方法
     */ 
    public String sayHi(String name) { 
 
        return name + ",您好!您现在访问的是简单的WS服务端,时间为:" + new SimpleDateFormat().format(new Date()); 
    } 
 
    /**
     * 复杂方法 含javabean 和 集合
     */ 
    public List<Cat> getCatsByUser(User user) { 
 
        UserService tUserService = new UserServiceImp(); 
        return tUserService.getCatsByUser(user); 
    } 
 
    /**
     * 处理Map
     */ 
    public Map<String, Cat> getAllCats() { 
        UserService tUserService = new UserServiceImp(); 
        return tUserService.getAllCats(); 
    } 
 


[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.service; 
 
import java.util.List; 
import java.util.Map; 
 
import com.ws.bean.Cat; 
import com.ws.bean.User; 
 
public interface UserService { 
 
    List<Cat> getCatsByUser(User user); 
 
    Map<String, Cat> getAllCats(); 
 


[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.service.impl; 
 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
 
import com.service.UserService; 
import com.ws.bean.Cat; 
import com.ws.bean.User; 
/**

* UserServiceImp.java
*
* @title User业务类
* @description
* @author SAM-SHO 
* @Date 2014-11-16
*/ 
public class UserServiceImp implements UserService { 
 
    //模拟数据库 
    static Map <User,List<Cat>> catDB = new HashMap<User,List<Cat>>(); 
    //静态初始化 
    static{ 
        List<Cat> catList1 = new ArrayList<Cat>(); 
        catList1.add(new Cat(1, "加菲猫", "黄色")); 
        catList1.add(new Cat(2, "蓝胖子", "蓝色")); 
        catDB.put(new User(1, "Sam-Sho", "1234", "soochow"), catList1); 
         
        List<Cat> catList2 = new ArrayList<Cat>(); 
        catList1.add(new Cat(3, "hello kitty", "粉色")); 
        catList1.add(new Cat(4, "熊猫", "黑白色")); 
        catDB.put(new User(2, "赵小妞", "4567", "soochow"), catList2); 
         
    } 
     
    public List<Cat> getCatsByUser(User user) { 
         
        return catDB.get(user); 
    } 
 
    /**
     * 返回Map
     */ 
    public Map<String, Cat> getAllCats() { 
        Map<String, Cat> catMap = new HashMap<String, Cat>(); 
        int i = 1; 
        for(List<Cat> cats: catDB.values()){ 
            for( Cat cat: cats){ 
                catMap.put("第"+ i++ + "个", cat); 
            } 
        } 
        return catMap; 
    } 
 


2)自定义转换器代码如下:TypeAdapter.class
[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.adapter; 
 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
 
import javax.xml.bind.annotation.adapters.XmlAdapter; 
 
import com.adapter.StringCat.Entry; 
import com.ws.bean.Cat; 
/**

* TypeAdapter.java
*
* @title 类型转换器
* @description
* XmlAdapter<ValueType,BoundType>:
* 1、BoundType为不支持的类型,即 Map<String,Cat>
* 2、ValueType 为map即将转换成的支持的类型。自定义即可。
* @author SAM-SHO 
* @Date 2014-11-19
*/ 
public class TypeAdapter extends XmlAdapter<StringCat, Map<String,Cat>> { 
 
    // 即 Map<String, Cat> 转换为 StringCat 
    @Override 
    public StringCat marshal(Map<String, Cat> v) throws Exception { 
         
        StringCat tStringCat = new StringCat(); 
        for (String key : v.keySet()) { 
            tStringCat.getEntries().add(new Entry(key,v.get(key))); 
        } 
         
        return tStringCat; 
    } 
 
    // StringCat 即 转换为 Map<String, Cat>  
    @Override 
    public Map<String, Cat> unmarshal(StringCat v) throws Exception { 
         
        Map<String, Cat> catMap = new HashMap<String, Cat>(); 
         
        List<Entry> entryLists = v.getEntries();// 
        for (Entry entry : entryLists) { 
            catMap.put(entry.getKey(), entry.getValue()); 
        } 
         
        return catMap; 
    } 
 


3)自定义转换的支持类型如下:StringCat.class
[java] view plain copy 在CODE上查看代码片派生到我的代码片
package com.adapter; 
 
import java.util.ArrayList; 
import java.util.List; 
 
import com.ws.bean.Cat; 
 
/**
* StringCat.java
*
* @title  自定义CXF支持的类型
* @description
* @author SAM-SHO 
* @Date 2014-11-19
*/ 
public class StringCat { 
     
    // 把Map<String,Cat> 转换 Entry 
    // 然后把Entry放入List 
    private List<Entry> entries = new ArrayList<Entry>(); 
     
     
    //内部类 即 Map<String,Cat>  
    public static class Entry{ 
        private String key; 
        private Cat value; 
         
        public Entry() { 
             
        } 
        public Entry(String key, Cat value) { 
            this.key = key; 
            this.value = value; 
        } 
        public String getKey() { 
            return key; 
        } 
        public void setKey(String key) { 
            this.key = key; 
        } 
        public Cat getValue() { 
            return value; 
        } 
        public void setValue(Cat value) { 
            this.value = value; 
        } 
    } 
 
 
    public List<Entry> getEntries() { 
        return entries; 
    } 
 
 
    public void setEntries(List<Entry> entries) { 
        this.entries = entries; 
    } 



5、这时启动服务就可以访问了:http://localhost:8080/helloWorld?wsdl
[java] view plain copy 在CODE上查看代码片派生到我的代码片
/**
* 发布含有Map的ws
*/ 
private void deployMapService() { 
     
    System.out.println("Server start ……"); 
    HelloWorldImpl service = new HelloWorldImpl(); 
    String address = "http://localhost:8080/helloWorld"; 
 
    // 调用Endpoint的publish方法 
    Endpoint.publish(address, service); 
    System.out.println("server ready ……"); 
     


6、传入传出的消息(xml片段)为如下:分析wsdl文件得出
[html] view plain copy 在CODE上查看代码片派生到我的代码片
<!--传入--> 
<getAllCats> 
</getAllCats> 
 
 
<!--传出--> 
<getAllCatsResponse> 
    <return> 
        <entries>--出现0-N次 
            <key></key> 
            <value> 
                <color></color> 
                <id></id> 
                <name></name> 
            </value> 
        </entries> 
        <entries> 
            <key></key> 
            <value> 
                <color></color> 
                <id></id> 
                <name></name> 
            </value> 
        </entries> 
    </return> 
</getAllCatsResponse> 

(二)、客户端实现
1、wsdl2java,重新生成客户端。
2、实现服务端方法getAllCats()的调用
[html] view plain copy 在CODE上查看代码片派生到我的代码片
/** 
* 访问CXF不支持的客户端 
*/ 
private void visitMapServer() { 
    HelloSAM helloFactory = new HelloSAM();// HelloSAM是客户端生成的继承了 service的类 
    HelloWorld hw = helloFactory.getHelloWorldImplPort();// 返回远程ws对象的代理,不是服务器中远程对象 
     
    StringCat tStringCat = hw.getAllCats(); 
    for (Entry entry : tStringCat.getEntries()) { 
        System.out.println(entry.getKey()+" : " + entry.getValue().getName()); 
    } 



3【输出】
[html] view plain copy 在CODE上查看代码片派生到我的代码片
第4个 : 熊猫 
第3个 : hello kitty 
第1个 : 加菲猫 
第2个 : 蓝胖子 



原博客地址: http://blog.csdn.net/u012228718/article/details/41077187

猜你喜欢

转载自lfc-jack.iteye.com/blog/2365953