实现一个Web服务的过程,大概有3个基本的过程:
- Web服务提供者设计并开发Web服务
- Web服务提供者发布Web服务
- Web服务请求者调用Web服务
下面,我通过一个例子,来实现上述过程:
假设一个Web服务提供者提供一个对域名进行探测解析的服务,给定一个域名,可以给出改域名解析后对应的IP地址列表。Web服务提供者设计并开发这个Web服务,然后将服务发布出去,并可以让Web服务请求者进行调用。
开发Web服务
服务接口文件DetectionService.java代码如下所示:
1 |
package org.shirdrn.server.webservices.jaxws; |
2 |
|
3 |
public interface DetectService { |
4 |
DetectedResult detect(String domain); |
5 |
} |
对应的实现类DomainDetectionService.java,如下所示:
01 |
package org.shirdrn.server.webservices.jaxws; |
02 |
|
03 |
import java.net.InetAddress; |
04 |
import java.net.UnknownHostException; |
05 |
import java.util.Date; |
06 |
|
07 |
import javax.jws.WebMethod; |
08 |
import javax.jws.WebService; |
09 |
import javax.jws.soap.SOAPBinding; |
10 |
|
11 |
import org.xbill.DNS.Address; |
12 |
|
13 |
@WebService (serviceName = "DomainDetector" ,portName = "DomainDetectorPort" , |
14 |
targetNamespace = "http://ws.shirdrn.org/jaxws/WSDomainDetector" ) |
15 |
@SOAPBinding (style=SOAPBinding.Style.DOCUMENT,use=SOAPBinding.Use.LITERAL, |
16 |
parameterStyle=SOAPBinding.ParameterStyle.WRAPPED) |
17 |
public class DomainDetectService implements DetectService { |
18 |
|
19 |
@WebMethod |
20 |
public DetectedResult detect(String domain) { |
21 |
DetectedResult result = new DetectedResult(); |
22 |
result.setStartTime( new Date()); |
23 |
try { |
24 |
InetAddress[] addresses = Address.getAllByName(domain); |
25 |
for (InetAddress addr : addresses) { |
26 |
result.getIpAddresses().add(addr.getHostAddress()); |
27 |
} |
28 |
} catch (UnknownHostException e) { |
29 |
e.printStackTrace(); |
30 |
} finally { |
31 |
result.setFinishTime( new Date()); |
32 |
result.setTimeTaken(result.getFinishTime().getTime() - result.getStartTime().getTime()); |
33 |
} |
34 |
return result; |
35 |
} |
36 |
|
37 |
} |
上面用到一个DtectedResult类,如下所示:
01 |
package org.shirdrn.server.webservices.jaxws; |
02 |
|
03 |
import java.util.ArrayList; |
04 |
import java.util.Date; |
05 |
import java.util.List; |
06 |
|
07 |
public class DetectedResult { |
08 |
|
09 |
private Date startTime; |
10 |
private Date finishTime; |
11 |
private long timeTaken; |
12 |
private List<String> ipAddresses = new ArrayList<String>(); |
13 |
|
14 |
public Date getStartTime() { |
15 |
return startTime; |
16 |
} |
17 |
|
18 |
public void setStartTime(Date startTime) { |
19 |
this .startTime = startTime; |
20 |
} |
21 |
|
22 |
public Date getFinishTime() { |
23 |
return finishTime; |
24 |
} |
25 |
|
26 |
public void setFinishTime(Date finishTime) { |
27 |
this .finishTime = finishTime; |
28 |
} |
29 |
|
30 |
public long getTimeTaken() { |
31 |
return timeTaken; |
32 |
} |
33 |
|
34 |
public void setTimeTaken( long timeTaken) { |
35 |
this .timeTaken = timeTaken; |
36 |
} |
37 |
|
38 |
public List<String> getIpAddresses() { |
39 |
return ipAddresses; |
40 |
} |
41 |
|
42 |
public void setIpAddresses(List<String> ipAddresses) { |
43 |
this .ipAddresses = ipAddresses; |
44 |
} |
45 |
|
46 |
} |
生成Web Service描述文件(WSDL),如下所示:
1 |
shirdrn@SYJ:~$ cd ~/programs/eclipse-java-juno/workspace/self_practice/bin |
2 |
shirdrn@SYJ:~/programs/eclipse-java-juno/workspace/self_practice/bin$ wsgen - cp . org.shirdrn.server.webservices.jaxws.DomainDetectService -wsdl |
3 |
shirdrn@SYJ:~/programs/eclipse-java-juno/workspace/self_practice/bin$ ls |
4 |
com DomainDetector_schema1.xsd DomainDetector.wsdl log4j.properties main org server.xml test |
5 |
shirdrn@SYJ:~/programs/eclipse-java-juno/workspace/self_practice/bin$ cp DomainDetect* /home/shirdrn/programs/eclipse-java-juno/workspace/self_practice/src/org/shirdrn/server/webservices/jaxws/wsdl |
经过上面步骤,生成了两个文件:DomainDetect_schema1.xsd和DomainDetect.wsdl,内容分别如下所示:
- DomainDetector_schema1.xsd内容
01 |
<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?> |
02 |
< xs:schema version = "1.0" targetNamespace = "http://ws.shirdrn.org/jaxws/WSDomainDetector" |
03 |
xmlns:tns = "http://ws.shirdrn.org/jaxws/WSDomainDetector" xmlns:xs = "http://www.w3.org/2001/XMLSchema" > |
04 |
|
05 |
< xs:element name = "detect" type = "tns:detect" /> |
06 |
|
07 |
< xs:element name = "detectResponse" type = "tns:detectResponse" /> |
08 |
|
09 |
< xs:complexType name = "detect" > |
10 |
< xs:sequence > |
11 |
< xs:element name = "arg0" type = "xs:string" minOccurs = "0" /> |
12 |
</ xs:sequence > |
13 |
</ xs:complexType > |
14 |
|
15 |
< xs:complexType name = "detectResponse" > |
16 |
< xs:sequence > |
17 |
< xs:element name = "return" type = "tns:detectedResult" minOccurs = "0" /> |
18 |
</ xs:sequence > |
19 |
</ xs:complexType > |
20 |
|
21 |
< xs:complexType name = "detectedResult" > |
22 |
< xs:sequence > |
23 |
< xs:element name = "finishTime" type = "xs:dateTime" minOccurs = "0" /> |
24 |
< xs:element name = "ipAddresses" type = "xs:string" nillable = "true" |
25 |
minOccurs = "0" maxOccurs = "unbounded" /> |
26 |
< xs:element name = "startTime" type = "xs:dateTime" minOccurs = "0" /> |
27 |
< xs:element name = "timeTaken" type = "xs:long" /> |
28 |
</ xs:sequence > |
29 |
</ xs:complexType > |
30 |
</ xs:schema > |
- DomainDetector.wsdl内容
01 |
<? xml version = "1.0" encoding = "UTF-8" standalone = "yes" ?> |
02 |
<!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS |
03 |
RI 2.1.6 in JDK 6. --> |
04 |
< definitions targetNamespace = "http://ws.shirdrn.org/jaxws/WSDomainDetector" |
05 |
name = "DomainDetector" xmlns = "http://schemas.xmlsoap.org/wsdl/" xmlns:tns = "http://ws.shirdrn.org/jaxws/WSDomainDetector" |
06 |
xmlns:xsd = "http://www.w3.org/2001/XMLSchema" xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/" > |
07 |
< types > |
08 |
< xsd:schema > |
09 |
< xsd:import namespace = "http://ws.shirdrn.org/jaxws/WSDomainDetector" |
10 |
schemaLocation = "DomainDetector_schema1.xsd" /> |
11 |
</ xsd:schema > |
12 |
</ types > |
13 |
< message name = "detect" > |
14 |
< part name = "parameters" element = "tns:detect" /> |
15 |
</ message > |
16 |
< message name = "detectResponse" > |
17 |
< part name = "parameters" element = "tns:detectResponse" /> |
18 |
</ message > |
19 |
< portType name = "DomainDetectService" > |
20 |
< operation name = "detect" > |
21 |
< input message = "tns:detect" /> |
22 |
< output message = "tns:detectResponse" /> |
23 |
</ operation > |
24 |
</ portType > |
25 |
< binding name = "DomainDetectorPortBinding" type = "tns:DomainDetectService" > |
26 |
< soap:binding transport = "http://schemas.xmlsoap.org/soap/http" |
27 |
style = "document" /> |
28 |
< operation name = "detect" > |
29 |
< soap:operation soapAction = "" /> |
30 |
< input > |
31 |
< soap:body use = "literal" /> |
32 |
</ input > |
33 |
< output > |
34 |
< soap:body use = "literal" /> |
35 |
</ output > |
36 |
</ operation > |
37 |
</ binding > |
38 |
< service name = "DomainDetector" > |
39 |
< port name = "DomainDetectorPort" binding = "tns:DomainDetectorPortBinding" > |
40 |
< soap:address location = "REPLACE_WITH_ACTUAL_URL" /> |
41 |
</ port > |
42 |
</ service > |
43 |
</ definitions > |
可以看到,在wsdl文件中通过import引用了前面的schema文件,这个schema文件用于定义类型。
发布Web服务
我们可以发布我们上面开发的Web服务,代码如下所示:
01 |
package org.shirdrn.server.webservices.jaxws; |
02 |
|
03 |
import javax.xml.ws.Endpoint; |
04 |
|
05 |
public class PublishingServer { |
06 |
|
07 |
|
08 |
public static void main(String[] args) { |
09 |
String address = "http://172.0.8.212:9033/ws/services/DomainDetectService" ; |
10 |
DetectService domainDetectService = new DomainDetectService(); |
11 |
|
12 |
Endpoint.publish(address, domainDetectService); |
13 |
} |
14 |
|
15 |
} |
可以查看本地运行的Web服务进程:
1 |
shirdrn@SYJ:~/programs/eclipse-java-juno/workspace/self_practice/src/org/shirdrn/server/webservices/jaxws$ sudo netstat -nap | grep 9033 |
2 |
tcp6 0 0 172.0.8.212:9033 :::* LISTEN 8302/java |
3 |
shirdrn@SYJ:~/programs/eclipse-java-juno/workspace/self_practice/src/org/shirdrn/server/webservices/jaxws$ jps |
4 |
8302 PublishingServer |
5 |
8358 Jps |
可见,服务发布成功。
也可以在浏览器中打开链接:http://172.0.8.212:9033/ws/services/DomainDetectService?wsdl,就能看到发布的WSDL,内容如下所示:
01 |
<!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.6 in JDK 6. --> |
02 |
<!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.1.6 in JDK 6. --> |
03 |
< definitions xmlns:soap = "http://schemas.xmlsoap.org/wsdl/soap/" |
04 |
xmlns:tns = "http://ws.shirdrn.org/jaxws/WSDomainDetector" xmlns:xsd = "http://www.w3.org/2001/XMLSchema" |
05 |
xmlns = "http://schemas.xmlsoap.org/wsdl/" targetNamespace = "http://ws.shirdrn.org/jaxws/WSDomainDetector" |
06 |
name = "DomainDetector" > |
07 |
< types > |
08 |
< xsd:schema > |
09 |
< xsd:import namespace = "http://ws.shirdrn.org/jaxws/WSDomainDetector" |
10 |
schemaLocation = "http://172.0.8.212:9033/ws/services/DomainDetectService?xsd=1" /> |
11 |
</ xsd:schema > |
12 |
</ types > |
13 |
< message name = "detect" > |
14 |
< part name = "parameters" element = "tns:detect" /> |
15 |
</ message > |
16 |
< message name = "detectResponse" > |
17 |
< part name = "parameters" element = "tns:detectResponse" /> |
18 |
</ message > |
19 |
< portType name = "DomainDetectService" > |
20 |
< operation name = "detect" > |
21 |
< input message = "tns:detect" /> |
22 |
< output message = "tns:detectResponse" /> |
23 |
</ operation > |
24 |
</ portType > |
25 |
< binding name = "DomainDetectorPortBinding" type = "tns:DomainDetectService" > |
26 |
< soap:binding transport = "http://schemas.xmlsoap.org/soap/http" |
27 |
style = "document" /> |
28 |
< operation name = "detect" > |
29 |
< soap:operation soapAction = "" /> |
30 |
< input > |
31 |
< soap:body use = "literal" /> |
32 |
</ input > |
33 |
< output > |
34 |
< soap:body use = "literal" /> |
35 |
</ output > |
36 |
</ operation > |
37 |
</ binding > |
38 |
< service name = "DomainDetector" > |
39 |
< port name = "DomainDetectorPort" binding = "tns:DomainDetectorPortBinding" > |
40 |
< soap:address |
41 |
location = "http://172.0.8.212:9033/ws/services/DomainDetectService" /> |
42 |
</ port > |
43 |
</ service > |
44 |
</ definitions > |
调用Web服务
首先要根据服务提供者发布的Web服务,生成服务请求者客户端代码,如下所示:
01 |
shirdrn@SYJ:~/programs/eclipse-java-juno/workspace/self_practice/bin$ wsimport -keep -p org.shirdrn.client.webservices.jaxwshttp://172.0.8.212:9033/ws/services/DomainDetectService?wsdl |
02 |
parsing WSDL... |
03 |
04 |
generating code... |
05 |
06 |
compiling code... |
07 |
shirdrn@SYJ:~/programs/eclipse-java-juno/workspace/self_practice/bin$ cd org/shirdrn/client/webservices/jaxws/ |
08 |
shirdrn@SYJ:~/programs/eclipse-java-juno/workspace/self_practice/bin/org/shirdrn/client/webservices/jaxws$ cp *.java /home/shirdrn/programs/eclipse-java-juno/workspace/self_practice/src/org/shirdrn/client/webservices/jaxws |
09 |
shirdrn@SYJ:~/programs/eclipse-java-juno/workspace/self_practice/bin/org/shirdrn/client/webservices/jaxws$ cd ~/programs/eclipse-java-juno/workspace/self_practice/src/org/shirdrn/client/webservices/jaxws/ |
10 |
shirdrn@SYJ:~/programs/eclipse-java-juno/workspace/self_practice/src/org/shirdrn/client/webservices/jaxws$ ls |
11 |
DetectedResult.java DetectResponse.java DomainDetector.java ObjectFactory.java |
12 |
Detect.java DomainDetectService.java package-info.java |
上面自动生成了客户端代码的骨架,如下几个文件:
- DetectedResult.java
- DetectResponse.java
- DomainDetector.java
- ObjectFactory.java
- Detect.java
- DomainDetectService.java
- package-info.java
基于这些代码,就可以实现服务请求者对服务提供者发布服务的调用。我们实现了一个简单的调用,代码如下所示:
01 |
package org.shirdrn.client.webservices.jaxws; |
02 |
|
03 |
public class DomainDetectClient { |
04 |
|
05 |
public static void main(String[] args) { |
06 |
DomainDetector detector = new DomainDetector(); |
07 |
String domain = "baidu.com" ; |
08 |
DetectedResult result = detector.getDomainDetectorPort().detect(domain); |
09 |
System.out.println(result.getIpAddresses()); |
10 |
} |
11 |
|
12 |
} |
调用后可以返回对域名进行解析后得到的IP地址列表,结果如下所示:
1 |
[220.181.111.86, 123.125.114.144, 220.181.111.85] |
到此为止,我们完成了一个简单的Web Service的开发、发布、调用的过程。