JAX-WS傳遞自定義的Java類型

在以前的文章中,有實現一個圖書館的WebService。能夠在這篇文章中http://my.oschina.net/xpbug/blog/224912 找到。java

然而,以前的圖書館系統接口所接收的參數和返回的類型,都很是簡單,只是int和String兩種類型。若是我想讓接口接收和返回自定義的複雜類型,該如何作?這篇文章將展現如何將以前的圖書館系統改造爲更復雜的實現。c++

圖書館服務接口

首先定義圖書館提供了哪些服務,讓我用接口表示:web

@WebService(name="Library", targetNamespace="http://library.mycompany.com")
public interface Library {
    @WebResult(name="result",targetNamespace="http://library.mycompany.com")
    public Book addBook(@WebParam(name="book", targetNamespace="http://library.mycompany.com")Book book);
    @WebResult(name="result",targetNamespace="http://library.mycompany.com")
    public Book getBook(@WebParam(name="id")int id);
    @WebResult(name="bookArray")
    public Book[] getBooksArray();
    @WebResult(name="bookList")
    public List<Book> getBookList();
    @WebResult(name="bookMap")
    public Map<Integer, Book> getBookMap();
    @WebResult(name="result")
    public boolean deleteBook(@WebParam(name="id")int id);
}

由上能夠看到,新的圖書館系統所提供的服務,接收和返回的均是封裝好的Book類型或者Book的集合。這須要參數和返回類型符合JAXB的規範,JAVA類型和XML能夠經過JAXB相互轉換。tomcat

實現Book類型

在JAXB2.0的時候,List和Array能夠被轉爲XML,但Map不能夠,但在2.1中,Map已經能夠被轉爲XML。Array型的XML在被轉爲Java時,會封裝成List。eclipse

因爲Array,List和Map都可以被JAXB轉爲XML,只剩下Book類型,須要作一些設計,才能夠被JAXB轉爲XML。maven

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

@XmlRootElement(name="book", namespace="library.mycompany.com")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name="book", namespace="library.mycompany.com")
public class Book {
    @XmlElement(name = "id", namespace = "")
    private int id;
    @XmlElement(name = "name", namespace = "")
    private String name;
    @XmlElement(name = "author", namespace = "")
    private String author;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
}

咱們的Book類型還算簡單,有時候須要更加複雜的自定義類型,這時候可能須要@XmlJavaTypeAdapter的支持,詳細內容請學習JAXB。ide

實現圖書館SEI

@WebService(endpointInterface="com.mycompany.Library")
public class LibraryImpl implements Library {
    private static Map<Integer, Book> store = new HashMap<Integer, Book>();
    private static int currentId=0;

    @Override
    public Book addBook(Book book) {
        book.setId(++currentId);
        store.put(book.getId(), book);
        return book;
    }

    @Override
    public Book getBook(int id) {
        return store.get(id);
    }

    @Override
    public Book[] getBooksArray() {
        List<Book> l = new ArrayList<Book>();
        Iterator<Integer> it = store.keySet().iterator();
        while(it.hasNext()) {
            l.add(store.get(it.next()));
        }
        Book[] r = l.toArray(new Book[1]);
        System.out.println(r.length);
        return r;
    }
    
    @Override
    public List<Book> getBookList() {
        List<Book> l = new ArrayList<Book>();
        Iterator<Integer> it = store.keySet().iterator();
        while(it.hasNext()) {
            l.add(store.get(it.next()));
        }
        return l;
    }
    
    @Override
    public Map<Integer, Book> getBookMap() {
        return store;
    }

    @Override
    public boolean deleteBook(int id) {
        if (store.containsKey(id)) {
            store.remove(id);
            return true;
        } else {
            return false;
        }
    }
}

sun-jaxws.xml

在WEB-INF下建立sun-jaxws.xml文件:函數

<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns='http://java.sun.com/xml/ns/jax-ws/ri/runtime' version='2.0'>
    <endpoint
        name='library'
        implementation='com.mycompany.LibraryImpl'
        url-pattern='/service'/>
</endpoints>

部署

使用wsgen命令,產生WSDL,XSD和相應的Java文件。我建立的是Maven project,因此使用的是Maven中的wsgen插件。學習

      <plugin>
        <groupId>org.jvnet.jax-ws-commons</groupId>
        <artifactId>jaxws-maven-plugin</artifactId>
        <version>2.3</version>
        <executions>
          <execution>
            <id>wsgen-from-jdk</id>
            <phase>process-classes</phase>
            <goals>
              <goal>wsgen</goal>
            </goals>
            <configuration>
              <executable>${tool.wsgen}</executable>
              <sei>com.mycompany.LibraryImpl</sei>
              <genWsdl>true</genWsdl>
            </configuration>
          </execution>
        </executions>
      </plugin>

運行命令: mvn packagethis

獲得可部署的war包library.war. War包的內部結構如圖:

最後將產生的library.war丟到tomcat下。驗證webservice已經產生: http://localhost:8080/library/service

生成客戶端

由於客戶端也是用Maven建立的項目,因此wsimport命令使用的是Maven中的插件。在pom.xml中:

      <plugin>
        <groupId>org.jvnet.jax-ws-commons</groupId>
        <artifactId>jaxws-maven-plugin</artifactId>
        <version>2.3</version>
        <executions>
          <execution>
            <id>wsimport-from-jdk</id>
            <goals>
              <goal>wsimport</goal>
            </goals>
            <configuration>
              <executable>${tool.wsimport}</executable>
              <wsdlUrls>
                <wsdlUrl>http://localhost:8080/library/service?wsdl</wsdlUrl>
              </wsdlUrls>
              <verbose>true</verbose>
              <xdebug>true</xdebug>
            </configuration>
          </execution>
        </executions>
      </plugin>

運行mvn generate-sources, 獲得wsdl生成的java文件。將java文件copy到項目中:

上面紅色框中,除了AuthorHandler和LoggerHandler是本身寫的,其它的都是wsimport產生的。

最後填寫App.java中的main函數

public class App {
    public static void main( String[] args ) {
        Book newBook = new Book();
        newBook.setAuthor("xpbug");
        newBook.setName("java");
        Book rBook = createPort().addBook(newBook);
        printBook(rBook);
        
        newBook = new Book();
        newBook.setAuthor("cat");
        newBook.setName("c++");
        rBook = createPort().addBook(newBook);
        printBook(rBook);
        
        System.out.println(createPort().deleteBook(rBook.getId()));
        
        rBook = createPort().getBook(1);
        printBook(rBook);
        
        List<Book> list = createPort().getBooksArray();
        System.out.println(list.size());
        for (Book i : list) {
            printBook(i);
        }
        
        list = createPort().getBookList();
        System.out.println(list.size());
        for (Book i : list) {
            printBook(i);
        }
        
        BookMap map = createPort().getBookMap();
        for (Entry i : map.getEntry()) {
            System.out.println(i.getKey());
            printBook(i.getValue());
        }
    }
    
    public static Library createPort() {
        Library port = new LibraryImplService().getLibraryImplPort();
        return port;
    }
    
    public static void printBook(Book book) {
        System.out.println("[id="+book.getId()+"; name="+book.getName()+"; author="+book.getAuthor()+"]");
    }
}

能夠直接在eclipse中運行App。

常見問題

在編寫webservice的過程當中,明明邏輯正確,參數也正確,但後臺老是報NullPointException, 這種時候,就須要注意namespace了。查看client端發出的參數的namespace是否跟server端接收方參數類型的namespace一致。若是不一致,接收方只會接到一個null參數。

相關文章
相關標籤/搜索