之前说过,对于当形参、返回值的类型是String、基本数据类型、JavaBean式的复合类,List集合,数组的时候,CXF可以很好的处理。但是像Map、非JavaBean式的复合类,CXF是处理不了的。 我们
我们先用之前编写的示例实验一下。
我们在服务端的HelloWorld接口中增加一个getAllCats()方法,返回一个Map集合:
package org.java.cxf.ws; import java.util.List; import java.util.Map; import javax.jws.WebService; import org.java.cxf.domain.Cat; import org.java.cxf.domain.User; @WebService public interface HelloWorld { public String sayHi(String name); public List<Cat> getCatsByUser(User user); public Map<String,Cat> getAllCats(); }
在实现类中编写该方法:
package org.java.cxf.ws.impl; import java.util.Date; import java.util.List; import java.util.Map; import javax.jws.WebService; import org.java.cxf.domain.Cat; import org.java.cxf.domain.User; import org.java.cxf.ws.HelloWorld; import org.java.cxf.ws.UserService; @WebService(endpointInterface="org.java.cxf.ws.HelloWorld" ,serviceName="HelloworldWs") public class HelloworldWs implements HelloWorld{ @Override public String sayHi(String name) { return name+",您好" +"现在的时间是:"+new Date(); } @Override public List<Cat> getCatsByUser(User user) { //在实际项目中,Web Service组件自己并不会去实现业务功能 //它只是调用业务逻辑组件的方法来暴露Web Service UserService us=new UserServiceImpl(); return us.getCatsByUser(user); } @Override public Map<String, Cat> getAllCats() { UserService us=new UserServiceImpl(); return us.getAllCats(); } }
然后在UserService接口声明该方法
package org.java.cxf.ws; import java.util.List; import java.util.Map; import org.java.cxf.domain.Cat; import org.java.cxf.domain.User; public interface UserService { public List<Cat> getCatsByUser(User user); public Map<String, Cat> getAllCats(); }
实现类UserServiceImpl中实现getAllCats()方法:
package org.java.cxf.ws.impl; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.java.cxf.domain.Cat; import org.java.cxf.domain.User; import org.java.cxf.ws.UserService; public class UserServiceImpl implements UserService { //用一个HashMap来模拟内存中的数据库 static Map<User,List<Cat>> catDb=new HashMap<>(); //初始化数据 static{ List<Cat> CatList1=new ArrayList<Cat>(); CatList1.add(new Cat(1,"花花","黑色")); CatList1.add(new Cat(2,"毛球","白色")); catDb.put(new User(1,"zhangsan","1122","河南"), CatList1); List<Cat> CatList2=new ArrayList<Cat>(); CatList2.add(new Cat(3,"丁丁","黄色")); CatList2.add(new Cat(4,"咪咪","灰色")); catDb.put(new User(1,"lisi","3344","广州"), CatList2); } public List<Cat> getCatsByUser(User user) { return catDb.get(user); } @Override public Map<String, Cat> getAllCats() { Map<String ,Cat> result =new HashMap<String,Cat>(); int i=1; for(List<Cat> cats:catDb.values()){ for(Cat cat:cats){ result.put("第"+ i++ +"个", cat); } } return result; } }
我们重新启动服务端:
发现分别报了javax.xml.ws.WebServiceException和 javax.xml.bind.JAXBException这两个错误。也就是说Map这种类型是CXF接受不了的数据格式。
那么,在CXF开发中,如果遇到系统无法自动处理的类型,就需要开发人员自行处理了。
处理思路:提供一个转换器,该转换器负责把CXF搞不定的类型,转换成其搞的定的类型。
处理步骤:
(1)使用@XmlJavaTypeAdapter(Java类型适配器注解)修饰CXF无法自动处理的类型。使用该注解时,需要给注解指定一个适配器值。
package org.java.cxf.ws; import java.util.List; import java.util.Map; import javax.jws.WebService; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import org.java.cxf.domain.Cat; import org.java.cxf.domain.User; @WebService public interface HelloWorld { public String sayHi(String name); public List<Cat> getCatsByUser(User user); //CXF不能处理这种类型,所以采用XmlJavaTypeAdapter来处理 public @XmlJavaTypeAdapter(value = WSXmlAdapter.class) Map<String,Cat> getAllCats(); }
(2)实现自己的适配器,然后编写一个CXF识别的数据类型:
package org.java.cxf.ws; import java.util.HashMap; import java.util.Map; import javax.xml.bind.annotation.adapters.XmlAdapter; import org.java.cxf.domain.Cat; import org.java.cxf.ws.StringCat.Entry; //XmlAdapter<ValueType, BoundType>接口参数中ValueType是CXF可以解析的类型 //BoundType是CXF搞不定的类型 public class WSXmlAdapter extends XmlAdapter<StringCat, Map<String,Cat>>{ @Override public Map<String, Cat> unmarshal(StringCat v) throws Exception { Map<String,Cat> result=new HashMap<>(); for(Entry entry:v.getEntries()){ result.put(entry.getKey(), entry.getValue()); } return result; } @Override public StringCat marshal(Map<String, Cat> v) throws Exception { StringCat cCat=new StringCat(); for(String key:v.keySet()){ cCat.getEntries().add(new Entry(key,v.get(key))); } return cCat; } }
其中StringCat类为:
package org.java.cxf.ws; import java.util.ArrayList; import java.util.List; import org.java.cxf.domain.Cat; public class StringCat { //静态内部类 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; } } private List<Entry> entries=new ArrayList<Entry>(); public List<Entry> getEntries() { return entries; } public void setEntries(List<Entry> entries) { this.entries = entries; } }
然后我们的程序就完成了,我们重启服务端看一下:
我们的服务重启成功。
我们分析一下发布成功时的WSDL文档:
整个wsdl文档没有什么变化,只是比之前多了一个getAllCats的operation。
我们去看一下import标签中的location的路径,之前说过,这个是引入的接口的定义文档:
我们看到这里也没有什么大的变化,仅仅是多了getAllCats的message。
我们去看一下types标签对的import标签中的schemaLocation,这是引入的类型的定义文档:
从中我们可以看出我们定义的StringCat数据类型的定义,证明我们对外发布的getAllCats方法的返回类型是StringCat。
即是,对于getAllCats操作来说,
传入的消息是
<getAllCats> </getAllCats>
传出的消息是
<getAllCatsResponse> <return> <entries> <key>字符串</key> <value> <color>字符串</color> <id>整数值</id> <name>字符串</name> </value> </entries> </return> </getAllCatsResponse>
我们在客户端的源代码文件夹重新生成WebService相关代码:
然后我们刷新客户端工程:
我们在客户端的主类中调用getAllCats方法,获取所有的Cat:
package show; import org.java.cxf.ws.Entry; import org.java.cxf.ws.HelloWorld; import org.java.cxf.ws.StringCat; import org.java.cxf.ws.impl.HelloworldWs; public class ClientMain { public static void main(String[] args) { HelloworldWs factory=new HelloworldWs(); //此处返回的只是远程Web Service的代理 HelloWorld hw=factory.getHelloworldWsPort(); System.out.println(hw.sayHi("孙悟空")); StringCat cCat=hw.getAllCats(); for (Entry entry: cCat.getEntries()) { System.out.println(entry.getKey()+entry.getValue().getName()); } } }
运行结果:
孙悟空,您好现在的时间是:Sun Jul 31 17:52:52 CST 2016
第4个毛球
第3个花花
第1个丁丁
第2个咪咪
注:不是顺序的原因是,hashMap是通过Hash值排序的而不是通过Key排序。
至此我们使用适配器,解决了所有CXF解决不了的数据结构类型。
转载请注明出处:http://www.voidcn.com/article/p-eqqmdopj-bbb.html