J2EE 7 SDK
Eclipse
Tomcat
Maven
SEI,全称Service Endpoint Interface或Service Endpoint Implemention。是服务器端和客户端开发真正要接触的类。
JAX-WS RI,全称JAX-WS Reference Implementation。这是JAX-WS的实现。与之相对立的应该是JAX-WS和JAXB API。
JAXB,全称Java Architecture for XML Binding。这是将Java类和XML schema相互映射的标准,此标准可以将Java实例转为XML,也可以将XML转为Java实例。
SAAJ,全称SOAP with Attachment API for Java。这是用于解析和生成SOAP协议数据的类库。
SEI中的方法中的参数,是由JAXB从SOAP中的XML数据转变而来,方法返回值,则由JAXB转为XML数据,然后通过SAAJ封装在SOAP消息中传回。所以,SEI中的方法参数和返回值,必须符合JAVA和XML Type的对应关系。
这里有一张映射表 http://docs.oracle.com/javaee/7/tutorial/doc/jaxws002.htm
用图表示,JAX-WS的工作原理就是
SEI成功工作所依赖的自定义java类,都可以使用JEE SDK所提供的工具,自动产生。
一般存在两种开发流程,从开发SEI开始,另一种是从开发WSDL开始。
这种方式适合Java程序猿。
首先开发SEI。
使用JEE SDK中的工具wsgen,生成运行所依赖的所有Java类,class以及WSDL,XSD。
例如:wsgen -wsdl -r resource -s src -d stock -cp myclasspath stock.StockService
-wsdl 表示产生wsdl xsd文件
-r 表示wsdl产生在那个目录
-s 表示source放在哪个目录
-d 表示生成的最终文件放在哪个目录
编写配置文件
打包成WAR并发布。
这种方式适合跨平台
开发,或者从其它平台获取WSDL文件。
使用JEE SDK中的工具wsimport,生成SEI接口以及所有Java文件。
例如: wsimport -p stockquote http://stockquote.xyz/quote?wsdl
为SEI接口编写SEI实现类。
打包并发布。
JAX-WS提供了Maven plugin,可以使用Maven简化上面的流程。详细过程请看后面的实例。
下面我将一步一步的开发一个实例。
添加图书。
根据编号查询图书。
删除图书。
在eclipse中,创建一个webApp的maven项目。JAXWS的Maven Plugin使用方法,可以在https://jax-ws-commons.java.net/jaxws-maven-plugin/ 找到。Plugin中包含了最重要的两个goal, wsimport和wsgen。
由于JRE的lib中已经包含了JAXWS的所有包,但其版本可能不是你想要的。所以,在开发开发部署JAXWS的时候,存在着两种依赖方式:
使用JDK中自带的JAXWS版本。
使用其它版本。这需要Java Endorsed Standards Override Mechanism .
本实验对JAXWS的版本要求不高,所以使用JDK自带的即可。
修改pom.xml,引入plugin。请加入以下代码:
<build> <pluginManagement> <plugins> <plugin> <groupId>org.eclipse.m2e</groupId> <artifactId>lifecycle-mapping</artifactId> <version>1.0.0</version> <configuration> <lifecycleMappingMetadata> <pluginExecutions> <pluginExecution> <pluginExecutionFilter> <groupId>org.jvnet.jax-ws-commons</groupId> <artifactId>jaxws-maven-plugin</artifactId> <versionRange>[1.0,)</versionRange> <goals> <goal>wsgen</goal> </goals> </pluginExecutionFilter> <action> <execute /> </action> </pluginExecution> </pluginExecutions> </lifecycleMappingMetadata> </configuration> </plugin> </plugins> </pluginManagement> <plugins> <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.Library</sei> <genWsdl>true</genWsdl> </configuration> </execution> </executions> </plugin> </plugins> </build> <!-- setup corresponding executables on win --> <profiles> <profile> <id>win</id> <activation> <os> <family>windows</family> </os> </activation> <properties> <tool.wsgen>D:/sts/jdk1.7.0_10/bin/wsgen.exe</tool.wsgen> <tool.wsimport>D:/sts/jdk1.7.0_10/bin/wsimport.exe</tool.wsimport> </properties> </profile> </profiles>
以上POM中的代码,将wsgen goal挂到process-classes phase上。其中PluginManagement部分是专门为eclipse m2e写的,因为execution无法在m2e中被cover。如果是独立maven环境,则不需要写PluginManagement.
创建完Maven项目以后,接下来,我们就可以创建WebService SEI了。
Library.java
package com.mycompany; import java.util.ArrayList; import java.util.List; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebResult; import javax.jws.WebService; @WebService(targetNamespace="http://library.mycompany.com") public class Library { private static List<Book> bookList = new ArrayList<Book>(); private static int currentId = 0; public Library() { } @WebMethod @WebResult(name="id") public int addRawBook(@WebParam(name="name") String name, @WebParam(name="author") String author) { Book book = new Book(); book.setId(++currentId); book.setName(name); book.setAuthor(author); bookList.add(book); return currentId; } @WebMethod @WebResult(name="rawBook") public String getRawBook(@WebParam(name="id") int id) { Book goal=null; for(Book b: bookList) { if (id == b.getId()) { goal = b; break; } } StringBuilder result = new StringBuilder(); if (goal == null) { result.append("No Book Found"); } else { result.append("[id=").append(goal.getId()).append(";name=").append(goal.getName()).append(";author=").append(goal.getAuthor()); } return result.toString(); } @WebMethod public void deleteBook(@WebParam(name="id") int id) throws LibraryException { Book goal=null; for(Book b: bookList) { if (id == b.getId()) { goal = b; break; } } if(goal == null) { throw new LibraryException("Fail to delete", "Id not exist."); } else { bookList.remove(goal); } } }
另外还有Book和Exception的实现:
Book.java
package com.mycompany; public class Book { 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; } private int id; private String name; private String author; }
LibraryException.java
package com.mycompany; public class LibraryException extends Exception { private String detail; public LibraryException(String message, String detail) { super(message); this.detail=detail; } public String getDetail() { return detail; } }
在servlet3.0容器中,并不需要web.xml,请忽略下面。如果部署在2.5中,则需要声明webservice的servlet。
<listener> <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class> </listener> <servlet> <servlet-name>Library</servlet-name> <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Library</servlet-name> <url-pattern>/service</url-pattern> </servlet-mapping>
如果是glassfish,则不需要sun-jaxws.xml,自从java跟了oracle,oracle对java的各种规范极力支持,glassfish就是一个极度遵循j2ee规范的server。如果部署在tomcat及其它server上,则需要在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.Library' url-pattern='/service'/> </endpoints>
运行maven package命令,将得到的library.war复制到tomcat的目录下。访问页面http://127.0.0.1:8080/library/service?wsdl
创建一个Maven project。在pom.xml中加入wsimport的命令。跟上面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://127.0.0.1:8080/library/service?wsdl</wsdlUrl> </wsdlUrls> </configuration> </execution> </executions> </plugin>
在eclipse中,运行命令maven jaxws:wsimport,然后在target下面找到产生的java文件。将这些文件导入到src/main/java中。
public class App { public static void main( String[] args ) throws LibraryException_Exception { int id; String rawBook; id = createPort().addRawBook("java", "Tom"); System.out.println("Add id="+id); id=createPort().addRawBook("C", "Sam"); System.out.println("Add id="+id); rawBook = createPort().getRawBook(2); System.out.println("find"+rawBook); createPort().deleteBook(2); rawBook = createPort().getRawBook(2); System.out.println("find"+rawBook); createPort().deleteBook(2); } public static Library createPort() { Library port = new LibraryService().getLibraryPort(); return port; } }
https://jax-ws.java.net