Apache CXF 整合 Map

jopen 10年前發布 | 37K 次閱讀 Apache CXF WEB服務/RPC/SOA

上一篇 《Apache CXF 整合Spring》中提到當接口方法返回 Map 數據類型在 CXF 中不能直接支持,本文就是介紹如何整合,項目是以上一篇為基礎,所以讀者最好先閱讀上一篇。

在進行編碼前有必要對一些基本的認識進行介紹,以便后面的講解。

1、JAXB:

    JAXB能夠使用Jackson對JAXB注解的支持實現(jackson-module-jaxb-annotations),既方便生成XML,也方便生成JSON,這樣一來可以更好的標志可以轉換為JSON對象的JAVA類。JAXB允許JAVA人員將JAVA類映射為XML表示方式,常用的注解包括:@XmlRootElement,@XmlElement等等。

    JAXB(Java Architecture for XML Binding) 是一個業界的標準,是一項可以根據XML Schema產生Java類的技術。該過程中,JAXB也提供了將XML實例文檔反向生成Java對象樹的方法,并能將Java對象樹的內容重新寫到XML實例文檔。從另一方面來講,JAXB提供了快速而簡便的方法將XML模式綁定到Java表示,從而使得Java開發者在Java應用程序中能方便地結合XML數據和處理函數。

2、Java SE中的JAXB

    JAXB 2.0是JDK 1.6的組成部分。JAXB 2.2.3是JDK 1.7的組成部分。


   2.1 JDK中JAXB相關的重要Class和Interface:
    JAXBContext類,是應用的入口,用于管理XML/Java綁定信息。
    Marshaller接口,將Java對象序列化為XML數據。
    Unmarshaller接口,將XML數據反序列化為Java對象。


   2.2 JDK中JAXB相關的重要Annotation:
    @XmlType,將Java類或枚舉類型映射到XML模式類型
    @XmlAccessorType(XmlAccessType.FIELD) ,控制字段或屬性的序列化。FIELD表示JAXB將自動綁定Java類中的每個非靜態的(static)、非瞬態的(由@XmlTransient標注)字段到XML。其他值還有XmlAccessType.PROPERTY和XmlAccessType.NONE。
    @XmlAccessorOrder,控制JAXB 綁定類中屬性和字段的排序。
    @XmlJavaTypeAdapter,使用定制的適配器(即擴展抽象類XmlAdapter并覆蓋marshal()和unmarshal()方法),以序列化Java類為XML。
    @XmlElementWrapper ,對于數組或集合(即包含多個元素的成員變量),生成一個包裝該數組或集合的XML元素(稱為包裝器)。
    @XmlRootElement,將Java類或枚舉類型映射到XML元素。
    @XmlElement,將Java類的一個屬性映射到與屬性同名的一個XML元素。
    @XmlAttribute,將Java類的一個屬性映射到與屬性同名的一個XML屬性。

3、解組和編組

    解組:( unmarshalling )把數據從存儲媒介上轉化到內存中的過程,正好與編組相反。因此需要把 xml 文檔解組到 Java VM 中。這里的復雜性不是在扁平數據中,因為這不是必需的,而在于從正確的數據到正確 Java 代碼變量的映射。如果映射是錯誤的,就不可能正確的訪問數據。當然,如果再嘗試重新編組還會造成更大的問題,并且問題傳播的很快。
    編組:( marshalling )是把內存中的數據轉化到存儲媒介上的過程。因此在 java 和 XML 環境中,編組就是把一些 Java 對象轉換成一個或多個 XML 文檔。在數據庫環境中,則是把 Java 表示的數據存入數據庫。顯然,編組的秘密在于把 Java 實例中的面向對象結構轉化成適用于 XML 的扁平結構,或者 RDBMS 中的關系結構

    好的,下面開始編碼了。工程以上一篇的為基礎。

一、創建Person類

Apache CXF 整合 Map

    其代碼為:

package com.yao.spring.bean;

import java.io.Serializable;

public class Person implements Serializable{

    private static final long serialVersionUID = -283567759187941425L;

    private String name;

    private int age;

    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


}
二、因為我們其中要返回一個Map<String,Person>的類型,所以我們要實現一個解組和編組的適配器工具。

    2.1 創建Map轉換器類:MapConvertor,@XmlType注釋標明該類可以轉化為xml類型,@XmlAccessorType(XmlAccessType.FIELD) ,控制字段或屬性的序列化。

package com.yao.spring.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

@XmlType(name = "MapConvertor")
@XmlAccessorType(XmlAccessType.FIELD)
public class MapConvertor {
    private List<MapEntry> entries = new ArrayList<MapEntry>();

    public void addEntry(MapEntry entry) {
        entries.add(entry);
    }

    public List<MapEntry> getEntries() {
        return entries;
    }

    public static class MapEntry {

        private String key;

        private Object value;

        public MapEntry() {
            super();
        }

        public MapEntry(Map.Entry<String, Object> entry) {
            super();
            this.key = entry.getKey();
            this.value = entry.getValue();
        }

        public MapEntry(String key, Object value) {
            super();
            this.key = key;
            this.value = value;
        }

        public String getKey() {
            return key;
        }

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

        public Object getValue() {
            return value;
        }

        public void setValue(Object value) {
            this.value = value;
        }
    }
}
    2.2 創建Map適配器類 MapAdapter,用于編組與解組,重寫XmlAdapter的 編組(marshal )與解組(unmarshal)方法
package com.yao.spring.util;

import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.annotation.adapters.XmlAdapter;

/**
 * 對Map類型做轉換的類和適配器類
 * @author Kangjun
 *
 */
public class MapAdapter extends XmlAdapter<MapConvertor, Map<String, Object>> {

    @Override
    public MapConvertor marshal(Map<String, Object> map) throws Exception {
        MapConvertor convertor = new MapConvertor();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            MapConvertor.MapEntry e = new MapConvertor.MapEntry(entry);
            convertor.addEntry(e);
        }
        return convertor;
    }

    @Override
    public Map<String, Object> unmarshal(MapConvertor map) throws Exception {
        Map<String, Object> result = new HashMap<String, Object>();
        for (MapConvertor.MapEntry e : map.getEntries()) {
            result.put(e.getKey(), e.getValue());
        }
        return result;
    }
}

這時的類結構如下:

Apache CXF 整合 Map

三、創建要調用的接口:PersonService。注意到public Map<String, Person> getPersonMap()方法有注釋@XmlJavaTypeAdapter(MapAdapter.class),此處注釋的XmlJavaTypeAdapter是對自定義編組使用實現XmlAdapter的適配器,即MapAdapter這個類,該類實現了XmlAdapter適配器,因此要實現解組和編組兩個方法。可能有的初學讀者會提到:為什么我們要實現編組和解組呢?原因很簡單,CXF不能直接支持Map。

package com.yao.spring.service;

import java.util.Map;

import javax.jws.WebService;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import com.yao.spring.bean.Person;
import com.yao.spring.util.MapAdapter;

@WebService
public interface PersonService {

    public Person getPerson();

    @XmlJavaTypeAdapter(MapAdapter.class)
    public Map<String, Person> getPersonMap();
}

這時的類結構如下:

Apache CXF 整合 Map

四、實現接口的方法類PersonServiceImpl:
package com.yao.spring.service;

import java.util.HashMap;
import java.util.Map;

import javax.jws.WebService;

import com.yao.spring.bean.Person;

@WebService(endpointInterface="com.yao.spring.service.PersonService")
public class PersonServiceImpl implements PersonService {

    @Override
    public Person getPerson() {
        Person p = new Person();
        p.setAge(22);
        p.setName("yaokj");
        return p;
    }

    @Override
    public Map<String, Person> getPersonMap() {
        Person p = new Person();
        p.setAge(25);
        p.setName("yaokj");
        Map<String, Person> map = new HashMap<String, Person>();
        map.put("yaokj", p);
        return map;
    }

}
五、修改cxf-servlet.xml文件,添加:<jaxws:endpoint id="personService" implementor="com.yao.spring.service.PersonServiceImpl" address="/PersonService"/>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    <jaxws:endpoint id="helloWorld" implementor="com.yao.spring.service.HelloWorldImpl" address="/HelloWorld"/>
    <jaxws:endpoint id="personService" implementor="com.yao.spring.service.PersonServiceImpl" address="/PersonService"/>
</beans>
六、修改client-beans.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd">
    <bean id="client" class="com.yao.spring.service.HelloWorld" factory-bean="clientFactory" factory-method="create"/>
    <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
        <property name="serviceClass" value="com.yao.spring.service.HelloWorld"/>
        <property name="address" value="http://localhost:8080/HelloSpringCXF/services/HelloWorld"/>
    </bean>

    <bean id="personClient" class="com.yao.spring.service.PersonService" factory-bean="personFactory" factory-method="create" />
    <bean id="personFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
        <property name="serviceClass" value="com.yao.spring.service.PersonService"/>
        <property name="address" value="http://localhost:8080/HelloSpringCXF/services/PersonService" />
    </bean>
</beans>
七、編寫客戶端代碼:PersonClient
package com.yao.spring.client;

import java.util.Map;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.yao.spring.bean.Person;
import com.yao.spring.service.PersonService;

public class PersonClient {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"client-beans.xml"});

        PersonService personService = (PersonService)ctx.getBean("personClient");

        Person p =  personService.getPerson();
        System.out.println(p);

        Map<String,Person> map = personService.getPersonMap();
        System.out.println("map: "+map.get("yaokj"));

        ctx.close();
        System.exit(0);
    }

}

這時的類結構如下:

Apache CXF 整合 Map

八、啟動Tomcat

Apache CXF 整合 Map

九、運行PersonClient,并打印,成功。

2014-8-21 2:12:02 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@735cda3f: startup date [Thu Aug 21 02:12:02 CST 2014]; root of context hierarchy
2014-8-21 2:12:02 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [client-beans.xml]
2014-8-21 2:12:03 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@28e70e30: defining beans [client,clientFactory,personClient,personFactory]; root of factory hierarchy
2014-8-21 2:12:03 org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
信息: Creating Service {http://service.spring.yao.com/}HelloWorldService from class com.yao.spring.service.HelloWorld
2014-8-21 2:12:04 org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean buildServiceFromClass
信息: Creating Service {http://service.spring.yao.com/}PersonServiceService from class com.yao.spring.service.PersonService
Person [age=22, name=yaokj]
map: Person [age=25, name=yaokj]
2014-8-21 2:12:04 org.springframework.context.support.AbstractApplicationContext doClose
信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@735cda3f: startup date [Thu Aug 21 02:12:02 CST 2014]; root of context hierarchy
2014-8-21 2:12:04 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
信息: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@28e70e30: defining beans [client,clientFactory,personClient,personFactory]; root of factory hierarchy

來自:http://my.oschina.net/jamaly/blog/304958

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!