在之前的文章中,有一篇关于HandlerChain的介绍。当时HandlerChain使用的是Java Annotation方式注册到WebService上的。我们也可以使用JAX-WS提供的针对WSDL的customization,来配置HandlerChain。JAX-WS的规范中,定义了针对WSDL的customization,可以对以下内容进行定制:
Package name
Wrapper style
Asynchrony
Provider interface
Class
Java method
Java parameter
Java doc
XML schema
Handler chain
这些customization,可以对wsimport产生影响。wsimport会根据WSDL+Customization产生出定制化的实现类。
Customization有两种声明方式:
External, 即脱离WSDL文件,单独放在一个外部文件中。
Embedded,内嵌在WSDL文件中。
Embedded方式跟External方式均必须放置在如下XML节点中:
<jaxws:bindings xmlns:jaxws=""> </jaxws:bindings>
不同的是,在外部声明方式中,需要指明wsdl的位置,也需要指明customization所针对的wsdl中的节点。embedded方式就没有这种烦恼了。
外部声明示例:
<jaxws:bindings wsdlLocation="http://127.0.0.1:8080/library/service?wsdl" jaxws:xmlns="http://java.sun.com/xml/ns/jaxws"> <jaxws:bindings node="wsdl:definitions" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <jaxws:package name="external_customize.client"/> ... </jaxws:bindings> </jaxws:bindings>
接下来,我将给出一个实例。下面的实例。
在JAXWS的官方网站中,提供了一个配置Provider的实例。实例对客户端接口进行了定制,修改各种名字,以表现的像本地API。我以此为例做解释。
在服务端,提供了一个加法服务。只对正数提供服务,负数会抛异常。
@WebService (serviceName = "AddNumbersService", targetNamespace = "http://duke.example.org") public class AddNumbersImpl { /** * @param number1 must be > 0 * @param number2 must be > 0 * @return The sum * @throws AddNumbersException * if any of the numbers to be added is negative. */ public int addNumbers (int number1, int number2) throws AddNumbersException { if(number1 < 0 || number2 < 0){ throw new AddNumbersException ("Negative number cant be added!", "Numbers: "+number1+", "+number2); } return number1 + number2; } }
异常
@javax.xml.ws.WebFault(name = "AddNumbersException", targetNamespace = "http://duke.example.org") public class AddNumbersException extends Exception { String info; public AddNumbersException(String message, String detail) { super(message); this.info = detail; } public String getFaultInfo() { return info; } }
首先,使用wsgen命令,生成相应的WSDL文件和一系列的JAXB所需类文件。
然后创建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='numbers' implementation='com.mycompany.AddNumbersImpl' url-pattern='/addNumbers'/> </endpoints>
然后打包部署到tomcat中。
在使用wsimport生成客户端之前,先创建customization文件,将原SEI重命名。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <bindings xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" wsdlLocation="http://localhost:8080/library/addNumbers?wsdl" xmlns="http://java.sun.com/xml/ns/jaxws"> <package name="external_customize.client"/> <!-- default settings --> <enableWrapperStyle>true</enableWrapperStyle> <enableAsyncMapping>false</enableAsyncMapping> <!-- wsdl:portType customization --> <bindings node="wsdl:definitions/wsdl:portType[@name='AddNumbersImpl']"> <!-- change the generated SEI class --> <class name="MathUtil"/> <!-- you can also override the following customization settings --> <enableWrapperStyle>true</enableWrapperStyle> <enableAsyncMapping>false</enableAsyncMapping> </bindings> <!-- wsdl:portType operation customization --> <bindings node="wsdl:definitions/wsdl:portType[@name='AddNumbersImpl']/wsdl:operation[@name='addNumbers']"> <!-- change java method name from addNumbers() to add() --> <method name="add"/> <!-- rename method parameters--> <parameter part="wsdl:definitions/wsdl:message[@name='addNumbers']/wsdl:part[@name='parameters']" childElementName="tns:number1" name="num1"/> <parameter part="wsdl:definitions/wsdl:message[@name='addNumbers']/wsdl:part[@name='parameters']" childElementName="tns:number2" name="num2"/> <!-- you can also override the following customization settings --> <enableWrapperStyle>true</enableWrapperStyle> <enableAsyncMapping>false</enableAsyncMapping> </bindings> <!-- change the generated exception class name --> <bindings node="wsdl:definitions/wsdl:portType[@name='AddNumbersImpl']/wsdl:operation[@name='addNumbers']/wsdl:fault[@name='AddNumbersException']"> <class name="MathUtilException"/> </bindings> <!-- wsdl:service customization --> <bindings node="wsdl:definitions/wsdl:service[@name='AddNumbersService']"> <!-- change the generated service class --> <class name="MathUtilService"/> </bindings> <!-- change the port accessor method --> <bindings node="wsdl:definitions/wsdl:service[@name='AddNumbersService']/wsdl:port[@name='AddNumbersImplPort']"> <method name="getMathUtil"/> </bindings> </bindings>
然后使用wsimport命令创建客户端实现类:
在maven中,命令如下:
<execution> <id>wsimport-from-jdk</id> <goals> <goal>wsimport</goal> </goals> <configuration> <executable>${tool.wsimport}</executable> <wsdlUrls> <wsdlUrl>http://localhost:8080/library/addNumbers?wsdl</wsdlUrl> </wsdlUrls> <bindingFiles> <bindingFile>/pathTo/custom-client.xml</bindingFile> </bindingFiles> <verbose>true</verbose> <xdebug>true</xdebug> </configuration> </execution>
运行maven命令 mvn generate-sources, 可以生成所有的java文件。
引入生成的java文件,编写client,调用client端的service。
public class AddNumbersClient { private MathUtil port; public AddNumbersClient () { port = new MathUtilService().getMathUtil (); } public static void main (String[] args) { try { AddNumbersClient client = new AddNumbersClient (); //invoke synchronous method client.invoke (); } catch(MathUtilException e){ System.out.println ("\tException detail: "+ e.getMessage ()+", "+e.getFaultInfo ()); } } private void invoke () throws MathUtilException{ int number1 = 10; int number2 = 20; System.out.printf ("Invoking addNumbers(%d, %d)\n", number1, number2); int result = port.add (number1, number2); System.out.printf ("The result of adding %d and %d is %d.\n\n", number1, number2, result); //lets make endpoint throw exception number1 = -10; System.out.printf ("Invoking addNumbers(%d, %d) and expect exception.\n", number1, number2); result = port.add (number1, number2); } }