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

博主个人教程地址

前言

之前说完了JavaBean的传递 今天来说一下Map类型的传递

Map类型传递

其实主要的还是针对的服务端的类型转换 所以主要修改的代码时在服务端的 我们还是按照正常的思路在扩充方法 来看一下会出现什么错误吧

还是在我们的接口中新增一个方法 返回一个Map类型的结构

代码如下

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

然后在实现类实现对应的方法

 @Override
    public Map<String, List<Role>> getAllUserRole() {
        // 声明Map存储用户角色信息
        Map<String,List<Role>> myMap = new HashMap<>();

        // 创建第一个用户角色列表
        List<Role> list1 = new ArrayList<>();
        list1.add(new Role(1,"root"));
        list1.add(new Role(1,"guest"));
        myMap.put("lwx",list1);

        // 创建第二个用户角色列表
        List<Role> 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.<init>(JAXBContextImpl.java:273)
	at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(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<String,List<Role>> 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<Role> value;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public List<Role> getValue() {
        return value;
    }

    public void setValue(List<Role> value) {
        this.value = 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<MyRole[], Map<String, List<Role>>> {

    /**
     * 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<String, List<Role>> unmarshal(MyRole[] v) throws Exception {
        Map<String, List<Role>> 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<String, List<Role>> 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;
    }
}

编写完毕之后呢 再次去发布咱们的服务端服务就成功了

接下来还是去生成咱们的客户端代码 和之前一样

执行对应命令
WebService开发 - CXF(4) - 服务端返回Map类型数据_第1张图片
生成完毕之后编写客户端代码 对应的类都会生成出来

WebService开发 - CXF(4) - 服务端返回Map类型数据_第2张图片
客户端代码

通过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<MyRole> item = allUserRole.getItem();
        System.out.println(item);
    }
}

输出结果

[top.liwenxiang.server.service.MyRole@6a6824be, top.liwenxiang.server.service.MyRole@5c8da962]

结语

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

你可能感兴趣的:(Web,服务,CXF)