在以前的文章中,有實現一個圖書館的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
在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
@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; } } }
在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參數。