Web Service笔记(二):利用CXF开发Web Service

3 篇文章 0 订阅
2 篇文章 0 订阅

一、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上查看代码片 派生到我的代码片
  1. package com.ws;  
  2.   
  3. import java.util.List;  
  4.   
  5. import javax.jws.WebService;  
  6.   
  7.   
  8. import com.ws.bean.Cat;  
  9. import com.ws.bean.User;  
  10.   
  11. @WebService  
  12. public interface HelloWorld {  
  13.       
  14.     public String sayHi(String name);  
  15.       
  16. }  

2、实现类

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.ws.impl;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Date;  
  5. import java.util.List;  
  6.   
  7. import javax.jws.WebService;  
  8.   
  9. import com.service.UserService;  
  10. import com.service.impl.UserServiceImp;  
  11. import com.ws.HelloWorld;  
  12. import com.ws.bean.Cat;  
  13. import com.ws.bean.User;  
  14.   
  15. /** 
  16.  * endpointInterface,是他实现的接口,记得写全包名 serviceName,服务器名称 
  17.  *  
  18.  * @author SAM 
  19.  *  
  20.  */  
  21.   
  22. // 实现类需要标明 WebService  
  23. // 标明实现的接口,endpointInterface 含包名  
  24. // serviceName 自定义名称  
  25. @WebService(endpointInterface = "com.ws.HelloWorld", serviceName = "HelloSAM")  
  26. public class HelloWorldImpl implements HelloWorld {  
  27.   
  28.     public String sayHi(String name) {  
  29.   
  30.         return name + ",您好!您现在访问的是简单的WS服务端,时间为:" + new SimpleDateFormat().format(new Date());  
  31.     }  
  32.   
  33.   
  34. }  

3、发布

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 发布简单的WebService 
  3.  */  
  4. public void deployService() {  
  5.   
  6.     System.out.println("Server start ……");  
  7.   
  8.     HelloWorldImpl service = new HelloWorldImpl();  
  9.     String address = "http://localhost:8080/helloWorld";  
  10.   
  11.     // 调用Endpoint的publish方法  
  12.     Endpoint.publish(address, service);  
  13.   
  14.     System.out.println("server ready ……");  
  15.   
  16. }  


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上查看代码片 派生到我的代码片
  1. /** 
  2.  * 简单客户端访问 
  3.  */  
  4. private void visitServer() {  
  5.   
  6.     HelloSAM helloFactory = new HelloSAM();// HelloSAM是客户端生成的继承了 service的类  
  7.     HelloWorld hw = helloFactory.getHelloWorldImplPort();// 返回远程ws对象的代理,不是服务器中远程对象  
  8.     System.out.println(hw.sayHi("SAM-SHO"));  
  9.   
  10. }  

4、这边服务器和客户端启动都是依赖main方法,需要jetty包的支持,到此为止,一次启动服务和客户端,就可以再后台看到如下输出,即简单的WS发布和访问成功。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. SAM-SHO,您好!您现在访问的是简单的WS服务端,现在的时间是:14-11-16 下午10:41  

5、另一种方式:利用 JaxWsProxyFactoryBean

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 另一种方式访问 
  3.  */  
  4. private void visitServer2() {  
  5.     // 调用WebService  
  6.     JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();  
  7.     factory.setServiceClass(HelloWorld.class);  
  8.     factory.setAddress("http://localhost:8080/Java_WS_Server/soap/helloWorld");  
  9.   
  10.     HelloWorld service = (HelloWorld) factory.create();  
  11.   
  12.     System.out.println("#############Client sayHi##############");  
  13.     System.out.println(service.sayHi("SAM-SAM"));  
  14.   
  15. }  


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


二、带javaBean 和 集合的WS


(一)、服务器端

1、在服务器端增加方法:然后创建javaBean 以及其业务类。代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.ws;  
  2.   
  3. import java.util.List;  
  4.   
  5. import javax.jws.WebService;  
  6.   
  7.   
  8. import com.ws.bean.Cat;  
  9. import com.ws.bean.User;  
  10.   
  11. @WebService  
  12. public interface HelloWorld {  
  13.       
  14.     public String sayHi(String name);  
  15.       
  16.     public List<Cat> getCatsByUser(User user);  
  17. }  

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.ws.impl;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Date;  
  5. import java.util.List;  
  6.   
  7. import javax.jws.WebService;  
  8.   
  9. import com.service.UserService;  
  10. import com.service.impl.UserServiceImp;  
  11. import com.ws.HelloWorld;  
  12. import com.ws.bean.Cat;  
  13. import com.ws.bean.User;  
  14.   
  15. /** 
  16.  * endpointInterface,是他实现的接口,记得写全包名 serviceName,服务器名称 
  17.  *  
  18.  * @author SAM 
  19.  *  
  20.  */  
  21.   
  22. // 实现类需要标明 WebService  
  23. // 标明实现的接口,endpointInterface 含包名  
  24. // serviceName 自定义名称  
  25. @WebService(endpointInterface = "com.ws.HelloWorld", serviceName = "HelloSAM")  
  26. public class HelloWorldImpl implements HelloWorld {  
  27.   
  28.     /** 
  29.      * 简单方法 
  30.      */  
  31.     public String sayHi(String name) {  
  32.   
  33.         return name + ",您好!您现在访问的是简单的WS服务端,时间为:" + new SimpleDateFormat().format(new Date());  
  34.     }  
  35.   
  36.     /** 
  37.      * 复杂方法 含javabean 和 集合 
  38.      */  
  39.     public List<Cat> getCatsByUser(User user) {  
  40.   
  41.         UserService tUserService = new UserServiceImp();  
  42.         return tUserService.getCatsByUser(user);  
  43.     }  
  44. }  
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.ws.bean;  
  2. /** 
  3.  * User类 
  4.  * @author SAM 
  5.  * 
  6.  */  
  7. public class User {  
  8.       
  9.     private Integer  id;  
  10.     private String name;  
  11.     private String pass;  
  12.     private String address;  
  13.       
  14.     public User() {  
  15.         super();  
  16.     }  
  17.       
  18.     public User(Integer id, String name, String pass, String address) {  
  19.         super();  
  20.         this.id = id;  
  21.         this.name = name;  
  22.         this.pass = pass;  
  23.         this.address = address;  
  24.     }  
  25.   
  26.     public Integer getId() {  
  27.         return id;  
  28.     }  
  29.     public void setId(Integer id) {  
  30.         this.id = id;  
  31.     }  
  32.     public String getName() {  
  33.         return name;  
  34.     }  
  35.     public void setName(String name) {  
  36.         this.name = name;  
  37.     }  
  38.     public String getPass() {  
  39.         return pass;  
  40.     }  
  41.     public void setPass(String pass) {  
  42.         this.pass = pass;  
  43.     }  
  44.     public String getAddress() {  
  45.         return address;  
  46.     }  
  47.     public void setAddress(String address) {  
  48.         this.address = address;  
  49.     }  
  50.   
  51.     @Override  
  52.     public int hashCode() {  
  53.         final int prime = 31;  
  54.         int result = 1;  
  55.         result = prime * result + ((name == null) ? 0 : name.hashCode());  
  56.         result = prime * result + ((pass == null) ? 0 : pass.hashCode());  
  57.         return result;  
  58.     }  
  59.   
  60.     @Override  
  61.     public boolean equals(Object obj) {  
  62.         if (this == obj)  
  63.             return true;  
  64.         if (obj == null)  
  65.             return false;  
  66.         if (getClass() != obj.getClass())  
  67.             return false;  
  68.         User other = (User) obj;  
  69.         if (name == null) {  
  70.             if (other.name != null)  
  71.                 return false;  
  72.         } else if (!name.equals(other.name))  
  73.             return false;  
  74.         if (pass == null) {  
  75.             if (other.pass != null)  
  76.                 return false;  
  77.         } else if (!pass.equals(other.pass))  
  78.             return false;  
  79.         return true;  
  80.     }  
  81.       
  82. }  

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.ws.bean;  
  2. /** 
  3.  * Cat类 
  4.  * @author SAM 
  5.  * 
  6.  */  
  7. public class Cat {  
  8.     private Integer id;  
  9.     private String name;  
  10.     private String color;  
  11.       
  12.     public Cat() {  
  13.         super();  
  14.     }  
  15.       
  16.     public Cat(Integer id, String name, String color) {  
  17.         super();  
  18.         this.id = id;  
  19.         this.name = name;  
  20.         this.color = color;  
  21.     }  
  22.       
  23.     public Integer getId() {  
  24.         return id;  
  25.     }  
  26.     public void setId(Integer id) {  
  27.         this.id = id;  
  28.     }  
  29.     public String getName() {  
  30.         return name;  
  31.     }  
  32.     public void setName(String name) {  
  33.         this.name = name;  
  34.     }  
  35.     public String getColor() {  
  36.         return color;  
  37.     }  
  38.     public void setColor(String color) {  
  39.         this.color = color;  
  40.     }  
  41.   
  42.     @Override  
  43.     public String toString() {  
  44.         return "Cat [color=" + color + ", id=" + id + ", name=" + name + "]";  
  45.     }  
  46. }  
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.service;  
  2.   
  3. import java.util.List;  
  4.   
  5. import com.ws.bean.Cat;  
  6. import com.ws.bean.User;  
  7.   
  8. public interface UserService {  
  9.   
  10.     List<Cat> getCatsByUser(User user);  
  11.   
  12. }  

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.service.impl;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. import com.service.UserService;  
  9. import com.ws.bean.Cat;  
  10. import com.ws.bean.User;  
  11. /** 
  12.  *  
  13.  * UserServiceImp.java 
  14.  * 
  15.  * @title User业务类 
  16.  * @description 
  17.  * @author SAM-SHO  
  18.  * @Date 2014-11-16 
  19.  */  
  20. public class UserServiceImp implements UserService {  
  21.   
  22.     //模拟数据库  
  23.     static Map <User,List<Cat>> catDB = new HashMap<User,List<Cat>>();  
  24.     //静态初始化  
  25.     static{  
  26.         List<Cat> catList1 = new ArrayList<Cat>();  
  27.         catList1.add(new Cat(1"加菲猫""黄色"));  
  28.         catList1.add(new Cat(2"蓝胖子""蓝色"));  
  29.         catDB.put(new User(1"Sam-Sho""1234""soochow"), catList1);  
  30.           
  31.         List<Cat> catList2 = new ArrayList<Cat>();  
  32.         catList1.add(new Cat(3"hello kitty""粉色"));  
  33.         catList1.add(new Cat(4"熊猫""黑白色"));  
  34.         catDB.put(new User(2"赵小妞""4567""soochow"), catList2);  
  35.           
  36.     }  
  37.       
  38.     public List<Cat> getCatsByUser(User user) {  
  39.           
  40.         return catDB.get(user);  
  41.     }  
  42.   
  43. }  

2、服务端发布如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 发布javaBean 和集合 的WS 
  3.  */  
  4. private void deployComplexService() {  
  5.     System.out.println("Server start ……");  
  6.     HelloWorldImpl service = new HelloWorldImpl();  
  7.     String address = "http://localhost:8080/helloWorld";  
  8.   
  9.     // 调用Endpoint的publish方法  
  10.     Endpoint.publish(address, service);  
  11.     System.out.println("server ready ……");  
  12. }  

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



(二)、客户端

1、使用 wsdl2java ,方法与上面创建客户端一致。

2、客户端调用服务端代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 访问复杂客户端 
  3.  */  
  4. private void visitComplexServer() {  
  5.   
  6.     HelloSAM helloFactory = new HelloSAM();// HelloSAM是客户端生成的继承了 service的类  
  7.     HelloWorld hw = helloFactory.getHelloWorldImplPort();// 返回远程ws对象的代理,不是服务器中远程对象  
  8.       
  9.     //1, "Sam-Sho", "1234", "soochow"  
  10.     User user = new User();  
  11.     user.setId(1);  
  12.     user.setName("Sam-Sho");  
  13.     user.setPass("1234");  
  14.     user.setAddress("soochow");  
  15.     System.out.println(hw.getCatsByUser(user));//[com.ws.Cat@1aaf0b3, com.ws.Cat@1a082e2, com.ws.Cat@f0c85e, com.ws.Cat@1f297e7]  
  16.     System.out.println(hw.getCatsByUser(user).get(0).getName());//加菲猫  
  17. }  

3、【输出】

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


三、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上查看代码片 派生到我的代码片
  1. package com.ws;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5.   
  6. import javax.jws.WebService;  
  7. import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;  
  8.   
  9. import com.adapter.TypeAdapter;  
  10. import com.ws.bean.Cat;  
  11. import com.ws.bean.User;  
  12.   
  13. @WebService  
  14. public interface HelloWorld {  
  15.       
  16.     public String sayHi(String name);  
  17.       
  18.     public List<Cat> getCatsByUser(User user);  
  19.       
  20.     //value属性指定一个转换器,为自定义的转换器  
  21.     @XmlJavaTypeAdapter(value = TypeAdapter.class)   
  22.     public Map<String,Cat> getAllCats();  
  23.       
  24.       
  25. }  
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.ws.impl;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Date;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. import javax.jws.WebService;  
  9.   
  10. import com.service.UserService;  
  11. import com.service.impl.UserServiceImp;  
  12. import com.ws.HelloWorld;  
  13. import com.ws.bean.Cat;  
  14. import com.ws.bean.User;  
  15.   
  16. /** 
  17.  * endpointInterface,是他实现的接口,记得写全包名 serviceName,服务器名称 
  18.  *  
  19.  * @author SAM 
  20.  *  
  21.  */  
  22.   
  23. // 实现类需要标明 WebService  
  24. // 标明实现的接口,endpointInterface 含包名  
  25. // serviceName 自定义名称  
  26. @WebService(endpointInterface = "com.ws.HelloWorld", serviceName = "HelloSAM")  
  27. public class HelloWorldImpl implements HelloWorld {  
  28.   
  29.     /** 
  30.      * 简单方法 
  31.      */  
  32.     public String sayHi(String name) {  
  33.   
  34.         return name + ",您好!您现在访问的是简单的WS服务端,时间为:" + new SimpleDateFormat().format(new Date());  
  35.     }  
  36.   
  37.     /** 
  38.      * 复杂方法 含javabean 和 集合 
  39.      */  
  40.     public List<Cat> getCatsByUser(User user) {  
  41.   
  42.         UserService tUserService = new UserServiceImp();  
  43.         return tUserService.getCatsByUser(user);  
  44.     }  
  45.   
  46.     /** 
  47.      * 处理Map 
  48.      */  
  49.     public Map<String, Cat> getAllCats() {  
  50.         UserService tUserService = new UserServiceImp();  
  51.         return tUserService.getAllCats();  
  52.     }  
  53.   
  54. }  

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.service;  
  2.   
  3. import java.util.List;  
  4. import java.util.Map;  
  5.   
  6. import com.ws.bean.Cat;  
  7. import com.ws.bean.User;  
  8.   
  9. public interface UserService {  
  10.   
  11.     List<Cat> getCatsByUser(User user);  
  12.   
  13.     Map<String, Cat> getAllCats();  
  14.   
  15. }  

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.service.impl;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7.   
  8. import com.service.UserService;  
  9. import com.ws.bean.Cat;  
  10. import com.ws.bean.User;  
  11. /** 
  12.  *  
  13.  * UserServiceImp.java 
  14.  * 
  15.  * @title User业务类 
  16.  * @description 
  17.  * @author SAM-SHO  
  18.  * @Date 2014-11-16 
  19.  */  
  20. public class UserServiceImp implements UserService {  
  21.   
  22.     //模拟数据库  
  23.     static Map <User,List<Cat>> catDB = new HashMap<User,List<Cat>>();  
  24.     //静态初始化  
  25.     static{  
  26.         List<Cat> catList1 = new ArrayList<Cat>();  
  27.         catList1.add(new Cat(1"加菲猫""黄色"));  
  28.         catList1.add(new Cat(2"蓝胖子""蓝色"));  
  29.         catDB.put(new User(1"Sam-Sho""1234""soochow"), catList1);  
  30.           
  31.         List<Cat> catList2 = new ArrayList<Cat>();  
  32.         catList1.add(new Cat(3"hello kitty""粉色"));  
  33.         catList1.add(new Cat(4"熊猫""黑白色"));  
  34.         catDB.put(new User(2"赵小妞""4567""soochow"), catList2);  
  35.           
  36.     }  
  37.       
  38.     public List<Cat> getCatsByUser(User user) {  
  39.           
  40.         return catDB.get(user);  
  41.     }  
  42.   
  43.     /** 
  44.      * 返回Map 
  45.      */  
  46.     public Map<String, Cat> getAllCats() {  
  47.         Map<String, Cat> catMap = new HashMap<String, Cat>();  
  48.         int i = 1;  
  49.         for(List<Cat> cats: catDB.values()){  
  50.             for( Cat cat: cats){  
  51.                 catMap.put("第"+ i++ + "个", cat);  
  52.             }  
  53.         }  
  54.         return catMap;  
  55.     }  
  56.   
  57. }  

2)自定义转换器代码如下:TypeAdapter.class

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.adapter;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.List;  
  5. import java.util.Map;  
  6.   
  7. import javax.xml.bind.annotation.adapters.XmlAdapter;  
  8.   
  9. import com.adapter.StringCat.Entry;  
  10. import com.ws.bean.Cat;  
  11. /** 
  12.  *  
  13.  * TypeAdapter.java 
  14.  * 
  15.  * @title 类型转换器 
  16.  * @description 
  17.  * XmlAdapter<ValueType,BoundType>: 
  18.  * 1、BoundType为不支持的类型,即 Map<String,Cat> 
  19.  * 2、ValueType 为map即将转换成的支持的类型。自定义即可。 
  20.  * @author SAM-SHO  
  21.  * @Date 2014-11-19 
  22.  */  
  23. public class TypeAdapter extends XmlAdapter<StringCat, Map<String,Cat>> {  
  24.   
  25.     // 即 Map<String, Cat> 转换为 StringCat  
  26.     @Override  
  27.     public StringCat marshal(Map<String, Cat> v) throws Exception {  
  28.           
  29.         StringCat tStringCat = new StringCat();  
  30.         for (String key : v.keySet()) {  
  31.             tStringCat.getEntries().add(new Entry(key,v.get(key)));  
  32.         }  
  33.           
  34.         return tStringCat;  
  35.     }  
  36.   
  37.     // StringCat 即 转换为 Map<String, Cat>   
  38.     @Override  
  39.     public Map<String, Cat> unmarshal(StringCat v) throws Exception {  
  40.           
  41.         Map<String, Cat> catMap = new HashMap<String, Cat>();  
  42.           
  43.         List<Entry> entryLists = v.getEntries();//  
  44.         for (Entry entry : entryLists) {  
  45.             catMap.put(entry.getKey(), entry.getValue());  
  46.         }  
  47.           
  48.         return catMap;  
  49.     }  
  50.   
  51. }  

3)自定义转换的支持类型如下:StringCat.class

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.adapter;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import com.ws.bean.Cat;  
  7.   
  8. /** 
  9.  * StringCat.java 
  10.  * 
  11.  * @title  自定义CXF支持的类型 
  12.  * @description 
  13.  * @author SAM-SHO  
  14.  * @Date 2014-11-19 
  15.  */  
  16. public class StringCat {  
  17.       
  18.     // 把Map<String,Cat> 转换 Entry  
  19.     // 然后把Entry放入List  
  20.     private List<Entry> entries = new ArrayList<Entry>();  
  21.       
  22.       
  23.     //内部类 即 Map<String,Cat>   
  24.     public static class Entry{  
  25.         private String key;  
  26.         private Cat value;  
  27.           
  28.         public Entry() {  
  29.               
  30.         }  
  31.         public Entry(String key, Cat value) {  
  32.             this.key = key;  
  33.             this.value = value;  
  34.         }  
  35.         public String getKey() {  
  36.             return key;  
  37.         }  
  38.         public void setKey(String key) {  
  39.             this.key = key;  
  40.         }  
  41.         public Cat getValue() {  
  42.             return value;  
  43.         }  
  44.         public void setValue(Cat value) {  
  45.             this.value = value;  
  46.         }  
  47.     }  
  48.   
  49.   
  50.     public List<Entry> getEntries() {  
  51.         return entries;  
  52.     }  
  53.   
  54.   
  55.     public void setEntries(List<Entry> entries) {  
  56.         this.entries = entries;  
  57.     }  
  58. }  


5、这时启动服务就可以访问了:http://localhost:8080/helloWorld?wsdl

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 发布含有Map的ws 
  3.  */  
  4. private void deployMapService() {  
  5.       
  6.     System.out.println("Server start ……");  
  7.     HelloWorldImpl service = new HelloWorldImpl();  
  8.     String address = "http://localhost:8080/helloWorld";  
  9.   
  10.     // 调用Endpoint的publish方法  
  11.     Endpoint.publish(address, service);  
  12.     System.out.println("server ready ……");  
  13.       
  14. }  

6、传入传出的消息(xml片段)为如下:分析wsdl文件得出

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <!--传入-->  
  2. <getAllCats>  
  3. </getAllCats>  
  4.   
  5.   
  6. <!--传出-->  
  7. <getAllCatsResponse>  
  8.     <return>  
  9.         <entries>--出现0-N次  
  10.             <key></key>  
  11.             <value>  
  12.                 <color></color>  
  13.                 <id></id>  
  14.                 <name></name>  
  15.             </value>  
  16.         </entries>  
  17.         <entries>  
  18.             <key></key>  
  19.             <value>  
  20.                 <color></color>  
  21.                 <id></id>  
  22.                 <name></name>  
  23.             </value>  
  24.         </entries>  
  25.     </return>  
  26. </getAllCatsResponse>  

(二)、客户端实现

1、wsdl2java,重新生成客户端。

2、实现服务端方法getAllCats()的调用

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /**  
  2.  * 访问CXF不支持的客户端  
  3.  */  
  4. private void visitMapServer() {  
  5.     HelloSAM helloFactory = new HelloSAM();// HelloSAM是客户端生成的继承了 service的类  
  6.     HelloWorld hw = helloFactory.getHelloWorldImplPort();// 返回远程ws对象的代理,不是服务器中远程对象  
  7.       
  8.     StringCat tStringCat = hw.getAllCats();  
  9.     for (Entry entry : tStringCat.getEntries()) {  
  10.         System.out.println(entry.getKey()+" : " + entry.getValue().getName());  
  11.     }  
  12. }  


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


四、带拦截器的WS

(一)、WS的拦截器简介:

1、WS的拦截器示意图:



2、服务端与客户端都有 In 与 Out 拦截器。顺序为 客户端Out --> 服务端In --> 服务端Out --> 客户端In 。


(二)、CXF的日志拦截器 LoggingInInterceptor 、LoggingOutInterceptor

1、服务端添加拦截器:

1)利用 EndpointImpl 类的 getInInterceptors() 或  getOutInterceptors() 方法 返回一个拦截器集合,往拦截器集合中add() 添加随意多个拦截器。

2)getInInterceptors().add() 添加的为 In 拦截器;getOutInterceptors().add() 添加的为 Out 拦截器。

3)服务端代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 发布带拦截器的WS 
  3.  */  
  4. private void deployInterceptorService() {  
  5.     System.out.println("Server start ……");  
  6.     HelloWorldImpl service = new HelloWorldImpl();  
  7.     String address = "http://localhost:8080/helloWorld";  
  8.   
  9.     // 调用Endpoint的publish方法  
  10.     EndpointImpl ep = (EndpointImpl) Endpoint.publish(address, service);  
  11.   
  12.   
  13.     // 添加默认拦截器(LoggingInInterceptor 和 LoggingOutInterceptor)  
  14.     ep.getInInterceptors().add(new LoggingInInterceptor());//in 拦截器  
  15.     ep.getOutInterceptors().add(new LoggingOutInterceptor());// out 拦截器  
  16.   
  17.     System.out.println("server ready ……");  
  18.   
  19. }  

3)客户端访问代码:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 简单客户端访问 
  3.  */  
  4. private void visitServer() {  
  5.   
  6.     HelloSAM helloFactory = new HelloSAM();// HelloSAM是客户端生成的继承了 service的类  
  7.     HelloWorld hw = helloFactory.getHelloWorldImplPort();// 返回远程ws对象的代理,不是服务器中远程对象  
  8.     System.out.println(hw.sayHi("SAM-SHO"));  
  9.   
  10. }  

4)客户端显示:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. SAM-SHO,您好!您现在访问的是简单的WS服务端,时间为:14-11-20 下午1:28  

5)服务端显示:主要是LoggingInInterceptor 和 LoggingOutInterceptor 输出的soap消息。

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

[html]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 2014-11-20 13:28:17 org.apache.cxf.services.HelloSAM.HelloWorldImplPort.HelloWorld  
  2. 信息: Inbound Message  
  3. ----------------------------  
  4. ID: 1  
  5. Address: http://localhost:8080/helloWorld?wsdl  
  6. Http-Method: GET  
  7. Content-Type:   
  8. Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[localhost:8080], User-Agent=[Java/1.6.0_10-rc2]}  
  9. --------------------------------------  
  10. 2014-11-20 13:28:17 org.apache.cxf.services.HelloSAM.HelloWorldImplPort.HelloWorld  
  11. 信息: Inbound Message  
  12. ----------------------------  
  13. ID: 2  
  14. Address: http://localhost:8080/helloWorld?wsdl=HelloWorld.wsdl  
  15. Http-Method: GET  
  16. Content-Type:   
  17. Headers: {Accept=[text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Type=[null], Host=[localhost:8080], User-Agent=[Java/1.6.0_10-rc2]}  
  18. --------------------------------------  
  19. 2014-11-20 13:28:18 org.apache.cxf.services.HelloSAM.HelloWorldImplPort.HelloWorld  
  20. 信息: Inbound Message  
  21. ----------------------------  
  22. ID: 3  
  23. Address: http://localhost:8080/helloWorld  
  24. Encoding: UTF-8  
  25. Http-Method: POST  
  26. Content-Type: text/xml; charset=UTF-8  
  27. Headers: {Accept=[text/xml, multipart/related, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2], connection=[keep-alive], Content-Length=[186], content-type=[text/xml; charset=UTF-8], Host=[localhost:8080], SOAPAction=[""], User-Agent=[Java/1.6.0_10-rc2]}  
  28. Payload: <?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:sayHi xmlns:ns2="http://ws.com/"><arg0>SAM-SHO</arg0></ns2:sayHi></S:Body></S:Envelope>  
  29. --------------------------------------  
  30. 2014-11-20 13:28:18 org.apache.cxf.services.HelloSAM.HelloWorldImplPort.HelloWorld  
  31. 信息: Outbound Message  
  32. ---------------------------  
  33. ID: 3  
  34. Response-Code: 200  
  35. Encoding: UTF-8  
  36. Content-Type: text/xml  
  37. Headers: {}  
  38. Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHiResponse xmlns:ns2="http://ws.com/"><return>SAM-SHO,您好!您现在访问的是简单的WS服务端,时间为:14-11-20 下午1:28</return></ns2:sayHiResponse></soap:Body></soap:Envelope>  
  39. --------------------------------------  

2、客户端添加拦截器:使用 ClientProxy 与 Client 类。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 带拦截器的客户端访问 
  3.  */  
  4. private void visitInterceptorServer() {  
  5.   
  6.     HelloSAM helloFactory = new HelloSAM();// HelloSAM是客户端生成的继承了 service的类  
  7.     HelloWorld hw = helloFactory.getHelloWorldImplPort();// 返回远程ws对象的代理,不是服务器中远程对象  
  8.     System.out.println(hw.sayHi("SAM-SHO"));  
  9.   
  10.     // 客户端 增加拦截器  
  11.     Client client = ClientProxy.getClient(hw);  
  12.     client.getInInterceptors().add(new LoggingInInterceptor());  
  13.     client.getOutInterceptors().add(new LoggingOutInterceptor());  
  14.   
  15.   
  16. }  


(三)、自定义拦截器

1、自定义拦截器

1)自定义的拦截器需要继承 AbstractPhaseInterceptor<SoapMessage> 类,参数 SoapMessage 为请求的 soap消息。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public class MyIntecepter extends AbstractPhaseInterceptor<SoapMessage> {}  

2)实现自己的拦截器时,需要实现handleMessage方法, handleMessage方法中的形参就是被拦截到的SOAP消息,一旦程序获得了这个soap消息,剩下的事情就可以解析soap消息,或修改soap消息

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void handleMessage(SoapMessage msg) throws Fault {}  

3)拦截器拦截的阶段:通过PhaseInterceptor,可以指定拦截器在哪个阶段起作用。定义无参的构造器,调用父类有参构造器。Phase 定义了阶段。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /* 
  2.  * 一定要自己定义一个构造器 
  3.  */  
  4. public MyIntecepter() {  
  5.       
  6.     /* 
  7.      * 父类构造器中参数String phase,为在哪个阶段调用拦截器 
  8.      * Phase.PRE_INVOKE在调用之前调用拦截器 
  9.      */       
  10.     super(Phase.PRE_INVOKE);  
  11. }  

2、解析Soap消息的header信息。soap消息的body是固定遵守 wsdl。header部分可以自定义数据,用于一些数据的校验。一个soap消息可以有多个header。

3、服务端完整的自定义拦截器代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.intecepter;  
  2.   
  3. import java.util.List;  
  4.   
  5. import org.apache.cxf.binding.soap.SoapMessage;  
  6. import org.apache.cxf.headers.Header;  
  7. import org.apache.cxf.interceptor.Fault;  
  8. import org.apache.cxf.phase.AbstractPhaseInterceptor;  
  9. import org.apache.cxf.phase.Phase;  
  10. import org.w3c.dom.Element;  
  11. import org.w3c.dom.NodeList;  
  12.   
  13. /** 
  14.  * 自定义拦截器,需要继承 AbstractPhaseInterceptor 
  15.  * 通过PhaseInterceptor,可以指定拦截器在哪个阶段起作用 
  16.  * @author SAM 
  17.  * 
  18.  */  
  19. public class MyIntecepter extends AbstractPhaseInterceptor<SoapMessage> {  
  20.       
  21.     /* 
  22.      * 一定要自己定义一个构造器 
  23.      */  
  24.     public MyIntecepter() {  
  25.           
  26.         /* 
  27.          * 父类构造器中参数String phase,为在哪个阶段调用拦截器 
  28.          * Phase.PRE_INVOKE在调用之前调用拦截器 
  29.          */       
  30.         super(Phase.PRE_INVOKE);  
  31.     }  
  32.       
  33.     /* 实现自己的拦截器时,需要实现handleMessage方法 
  34.      * handleMessage方法中的形参就是被拦截到的SOAP消息 
  35.      * 一旦程序获得了这个soap消息,剩下的事情就可以解析soap消息,或修改soap消息 
  36.     */  
  37.     public void handleMessage(SoapMessage msg) throws Fault {  
  38.         System.out.println("++++拦++++截++++器++++开++++始++++调++++用++++");        
  39.           
  40. //      System.out.println("=========================== \n"+ msg+"\n ========================");      
  41.           
  42.         List<Header> headers = msg.getHeaders();  
  43.         if(headers==null || headers.size()<1) {  
  44.             throw new Fault(new IllegalArgumentException("根本没有Header,别想调用"));  
  45.         }  
  46.           
  47.         //假如要求第一个Header携带了用户名、密码信息  
  48.         Header firstHeader = headers.get(0);  
  49.         Element element = (Element) firstHeader.getObject();  
  50.           
  51.         NodeList userids = element.getElementsByTagName("userId");  
  52.         NodeList userPasses = element.getElementsByTagName("userPass");  
  53.           
  54.         if(userids.getLength()!=1) {  
  55.             throw new Fault(new IllegalArgumentException("用户名格式不对"));  
  56.         }  
  57.           
  58.         if(userPasses.getLength()!=1) {  
  59.             throw new Fault(new IllegalArgumentException("密码格式不对"));  
  60.         }  
  61.           
  62.         //得到第一个userId元素的文本内容,以该内容作为用户名字  
  63.         String userId = userids.item(0).getTextContent();  
  64.         String userPass = userPasses.item(0).getTextContent();  
  65.           
  66.         //实际项目中,应该去查询数据库,该用户名、密码是否被授权  
  67.         if(!userId.equals("邵小宝")) {  
  68.             throw new Fault(new IllegalArgumentException("---------用---户----名---不----正-----确---------!!!!"));  
  69.         }  
  70.         if(!userPass.equals("sammy999")) {  
  71.             throw new Fault(new IllegalArgumentException("--------密---码-----不-----正------确-------!!!!!"));  
  72.         }  
  73.           
  74.         System.out.println("拦++++截++++器++++结===============束++++");   
  75.     }  
  76.   
  77. }  

4、客户端自定义拦截器代码如下:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.intecepter;  
  2.   
  3. import java.util.List;  
  4.   
  5. import javax.xml.namespace.QName;  
  6.   
  7. import org.apache.cxf.binding.soap.SoapMessage;  
  8. import org.apache.cxf.headers.Header;  
  9. import org.apache.cxf.helpers.DOMUtils;  
  10. import org.apache.cxf.interceptor.Fault;  
  11. import org.apache.cxf.phase.AbstractPhaseInterceptor;  
  12. import org.apache.cxf.phase.Phase;  
  13. import org.w3c.dom.Document;  
  14. import org.w3c.dom.Element;  
  15. /** 
  16.  *  
  17.  * MyClientIntecepter.java 
  18.  * 
  19.  * @title 客户端的拦截器 
  20.  * @description 
  21.  * @author SAM-SHO  
  22.  * @Date 2014-11-22 
  23.  */  
  24. public class MyClientIntecepter extends AbstractPhaseInterceptor<SoapMessage> {  
  25.       
  26.     private String userId;  
  27.     private String userPass;  
  28.       
  29.     //构造器  
  30.     public MyClientIntecepter(String userId, String userPass) {  
  31.         super(Phase.PREPARE_SEND);//发送消息前调用  
  32.         this.userId = userId;  
  33.         this.userPass = userPass;  
  34.     }  
  35.       
  36.     // 实现的方法  
  37.     public void handleMessage(SoapMessage msg) throws Fault {  
  38.         List<Header> headers = msg.getHeaders();//得到soap消息的header  
  39.           
  40.         //创建document对象  
  41.         Document document = DOMUtils.createDocument();  
  42.         Element header = document.createElement("MyHeader");  
  43.           
  44.         //创建一个header元素与服务器一致  
  45.         Element userIdEle = document.createElement("userId");  
  46.         Element userPassEle = document.createElement("userPass");         
  47.         userIdEle.setTextContent(userId);  
  48.         userPassEle.setTextContent(userPass);         
  49.         header.appendChild(userIdEle);  
  50.         header.appendChild(userPassEle);  
  51.           
  52.         headers.add(new Header(new QName("HelloSAM"), header));//把header放入soap的  
  53.           
  54.     }  
  55.   
  56.     public String getUserId() {  
  57.         return userId;  
  58.     }  
  59.     public void setUserId(String userId) {  
  60.         this.userId = userId;  
  61.     }  
  62.     public String getUserPass() {  
  63.         return userPass;  
  64.     }  
  65.     public void setUserPass(String userPass) {  
  66.         this.userPass = userPass;  
  67.     }  
  68.   
  69. }  


5、把自定义的拦截器装载在服务端,方法与添加CXF的拦截器一致。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 发布带拦截器的WS 
  3.  */  
  4. private void deployInterceptorService() {  
  5.     System.out.println("Server start ……");  
  6.     HelloWorldImpl service = new HelloWorldImpl();  
  7.     String address = "http://localhost:8080/helloWorld";  
  8.   
  9.     // 调用Endpoint的publish方法  
  10.     EndpointImpl ep = (EndpointImpl) Endpoint.publish(address, service);  
  11.   
  12.     // 添加自定义拦截器  
  13.     ep.getInInterceptors().add(new MyIntecepter());  
  14.       
  15.     System.out.println("server ready ……");  
  16.   
  17. }  

6、客户端装载拦截器。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.     /** 
  2.      * 带拦截器的客户端访问 
  3.      */  
  4.     private void visitInterceptorServer() {  
  5.   
  6.         HelloSAM helloFactory = new HelloSAM();// HelloSAM是客户端生成的继承了 service的类  
  7.         HelloWorld hw = helloFactory.getHelloWorldImplPort();// 返回远程ws对象的代理,不是服务器中远程对象  
  8. //      System.out.println(hw.sayHi("SAM-SHO"));  
  9.   
  10.         // 客户端 增加拦截器  
  11.         Client client = ClientProxy.getClient(hw);  
  12.   
  13.         client.getOutInterceptors().add(new MyClientIntecepter("邵小宝","sammy999"));  
  14.         System.out.println(hw.sayHi("SAM"));  

7、运行,调用。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 2014-11-22 14:26:33 org.apache.cxf.service.factory.ReflectionServiceFactoryBean buildServiceFromWSDL  
  2. 信息: Creating Service {http://impl.ws.com/}HelloSAM from WSDL: http://localhost:8080/helloWorld?wsdl  
  3. Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: --------密---码-----不-----正------确-------!!!!!  
  4.     at org.apache.cxf.jaxws.JaxWsClientProxy.inv
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值