Web|WebService开发 - CXF(4) - 服务端返回Map类型数据

博主个人教程地址
前言 【Web|WebService开发 - CXF(4) - 服务端返回Map类型数据】之前说完了JavaBean的传递 今天来说一下Map类型的传递
Map类型传递 其实主要的还是针对的服务端的类型转换 所以主要修改的代码时在服务端的 我们还是按照正常的思路在扩充方法 来看一下会出现什么错误吧
还是在我们的接口中新增一个方法 返回一个Map类型的结构
代码如下

/* 获取所有用户角色 */ Map,List> getAllUserRole();

然后在实现类实现对应的方法
@Override public Map, List> getAllUserRole() { // 声明Map存储用户角色信息 Map,List> myMap = new HashMap<>(); // 创建第一个用户角色列表 List list1 = new ArrayList<>(); list1.add(new Role(1,"root")); list1.add(new Role(1,"guest")); myMap.put("lwx",list1); // 创建第二个用户角色列表 List list2 = new ArrayList<>(); list1.add(new Role(1,"guest")); myMap.put("jack",list2); return myMap; }

然后呢 我们还是 开心的去发布我们的服务端代码
会发现报如下错误
Exception in thread "main" org.apache.cxf.service.factory.ServiceConstructionException at org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:354) at org.apache.cxf.service.factory.AbstractServiceFactoryBean.initializeDataBindings(AbstractServiceFactoryBean.java:86) at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.buildServiceFromClass(ReflectionServiceFactoryBean.java:469) at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.buildServiceFromClass(JaxWsServiceFactoryBean.java:693) at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.initializeServiceModel(ReflectionServiceFactoryBean.java:529) at org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean.create(ReflectionServiceFactoryBean.java:262) at org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean.create(JaxWsServiceFactoryBean.java:199) at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:103) at org.apache.cxf.frontend.ServerFactoryBean.create(ServerFactoryBean.java:168) at org.apache.cxf.jaxws.JaxWsServerFactoryBean.create(JaxWsServerFactoryBean.java:211) at top.liwenxiang.server.main.main.main(main.java:20) Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions java.util.List是接口, 而 JAXB 无法处理接口。 this problem is related to the following location: at java.util.List at private java.util.Map top.liwenxiang.server.service.jaxws_asm.GetAllUserRoleResponse._return at top.liwenxiang.server.service.jaxws_asm.GetAllUserRoleResponse at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:76) at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:441) at com.sun.xml.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:273) at com.sun.xml.bind.v2.runtime.JAXBContextImpl.(JAXBContextImpl.java:109) at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1126) at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:135) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:247) at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:234) at javax.xml.bind.ContextFinder.find(ContextFinder.java:441) at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:641) at org.apache.cxf.common.jaxb.JAXBContextCache$2.run(JAXBContextCache.java:345) at org.apache.cxf.common.jaxb.JAXBContextCache$2.run(JAXBContextCache.java:343) at java.security.AccessController.doPrivileged(Native Method) at org.apache.cxf.common.jaxb.JAXBContextCache.createContext(JAXBContextCache.java:343) at org.apache.cxf.common.jaxb.JAXBContextCache.getCachedContextAndSchemas(JAXBContextCache.java:245) at org.apache.cxf.jaxb.JAXBDataBinding.createJAXBContextAndSchemas(JAXBDataBinding.java:497) at org.apache.cxf.jaxb.JAXBDataBinding.initialize(JAXBDataBinding.java:352) ... 10 more

这个错误就是不能够识别我们接口对应方法的返回类型 而抛出的错误信息 我们需要解决 并且让cxf能够识别这个类型 所以我们需要进行一个适配的操作
首先我们在我们对应返回map的方法上面加上一个注解 @XmlJavaTypeAdapter(MyMapAdapter.class)
MyMapAdapter 这个类使我们一会自己需要新建的
/* 获取所有用户角色 */ @XmlJavaTypeAdapter(MyMapAdapter.class) Map,List> getAllUserRole();

新建MyMapAdapter类并继承XmlAdapter类 实现其中的方法 并编写对应代码 进行转换
XmlAdapter 第一个是转换的类 第二个是绑定的参数类型
实现两个方法 进行相互转换 一个是 从 Map 转换到 MyRole 一个是从MyRole转换到Map
我们的MyRole是需要进行创建的 借助这么一个中间实体类进行值得设置
  • MyRole 代码
package top.liwenxiang.server.entity; import java.util.List; public class MyRole {private String key; private List value; public String getKey() { return key; }public void setKey(String key) { this.key = key; }public List getValue() { return value; }public void setValue(List value) { this.value = https://www.it610.com/article/value; } }

  • MyMapAdapter 代码
package top.liwenxiang.server.adapter; import top.liwenxiang.server.entity.MyRole; import top.liwenxiang.server.entity.Role; import javax.xml.bind.ValidationEventHandler; import javax.xml.bind.annotation.adapters.XmlAdapter; import java.util.HashMap; import java.util.List; import java.util.Map; public class MyMapAdapter extends XmlAdapter>> {/** * Convert a value type to a bound type. * * @param v The value to be converted. Can be null. * @throws Exception if there's an error during the conversion. The caller is responsible for *reporting the error to the user through {@link ValidationEventHandler}. *//* 这里通过遍历得到Map并返回 */ @Override public Map, List> unmarshal(MyRole[] v) throws Exception { Map, List> map = new HashMap<>(); for (int i = 0 ; i < v.length ; i++){ map.put(v[i].getKey(),v[i].getValue()); } return map; }/** * Convert a bound type to a value type. * * @param v The value to be convereted. Can be null. * @throws Exception if there's an error during the conversion. The caller is responsible for *reporting the error to the user through {@link ValidationEventHandler}. */ /* 通过遍历得到MyRole数组并返回 */ @Override public MyRole[] marshal(Map, List> v) throws Exception { MyRole[] roles = new MyRole[v.size()]; int i = 0; for(String key : v.keySet()){ MyRole m = new MyRole(); roles[i] = m; roles[i].setKey(key); roles[i].setValue(v.get(key)); i++; } return roles; } }

编写完毕之后呢 再次去发布咱们的服务端服务就成功了
接下来还是去生成咱们的客户端代码 和之前一样
执行对应命令
Web|WebService开发 - CXF(4) - 服务端返回Map类型数据
文章图片

生成完毕之后编写客户端代码 对应的类都会生成出来
Web|WebService开发 - CXF(4) - 服务端返回Map类型数据
文章图片

客户端代码
通过getItem方法就可以得到一个List集合 返回我们的MyRole实体 在里面遍历可以获取到对应的用户名称和角色
package client; import top.liwenxiang.server.service.*; import java.io.UnsupportedEncodingException; import java.util.List; public class invoke { public static void main(String[] args) throws UnsupportedEncodingException, UnsupportedEncodingException_Exception { HelloWebServiceService helloWebServiceService = new HelloWebServiceService(); HelloWebService helloWebServicePort = helloWebServiceService.getHelloWebServicePort(); MyRoleArray allUserRole = helloWebServicePort.getAllUserRole(); List item = allUserRole.getItem(); System.out.println(item); } }

输出结果
[top.liwenxiang.server.service.MyRole@6a6824be, top.liwenxiang.server.service.MyRole@5c8da962]

结语 本篇主要是针对服务端的改进 以使其能够支持Map类型的返回~ 记得自己动手编写一下哦 ~

    推荐阅读