介绍
在之前的文章中,有一篇关于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);
}
}