什么是web service
web service(以下简称ws)是服务与服务,机器与机器之间交流沟通的技术,可以保证不同平台间的服务相互操作,很多不同语言开发的平台服务之前可以通过ws相互通信,这一方式使得ws可以跨平台和跨语言使用。
ws有三个重要的组成部件
-
UDDI
UDDI是Universal Description,Discovery,Integration的缩写,是一个基于XML的框架,可以发现,描述和集成ws服务。 -
WSDL
WSDL全称Web Service Description Language,其基于XML文件对ws服务进行描述,可以从WSDL文件中获取到服务名称、参数、服务地址等访问服务的信息,WSDL属于UDDI的一部分。 -
SOAP
SOAP全称Simple Object Access Protocol,是ws服务之间访问的协议,此协议基于xml。
ws服务基于SOAP协议通信,也是w3c推荐的服务通信方式,SOAP定义自己的安全特性使用上安全性较高,因为服务间是通过统一的协议通信,所以也有可以跨平台和跨语言的优点,但是因为这种协议定义了比较多标准,通信时比较消耗带宽和资源,会有比较慢的缺陷,而且也只有WSDL支持SOAP协议的服务发现。
ws除了基于SOAP协议,还有RESTful风格的实践,这章节主要介绍SOAP协议的方式。
Java实现
Java中ws api分为两类JAX-WS(SOAP)和JAX-RS(RESTful),而JAX-WS也可分为两种风格分别是RPC风格和Document风格,这两种风格之间最大的不同就是RPC风格每次会发送尽量多的元素,只有复杂参数类型时候RPC风格才会对参数进行xml格式的解释,而Document风格是每次以单独一个文件发送,无论参数是否复杂类型都会以xml格式进行解释。java中主要使用javax.jws包中的注解对ws服务进行实现。
复杂类型的xml格式的解释可以通过访问types下的schemaLocation查看。
<types>
<xsd:schema>
<xsd:import namespace="http://server.rpc.ws.clo.com/" schemaLocation="http://localhost:7999/ws/rpc/hello?xsd=1"/>
</xsd:schema>
</types>
首先需要创建一个ws服务接口
@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface HelloWorldRpc {
@WebMethod
@WebResult(name = "helloStr")
String getHelloWorldString(@WebParam(name = "name") String name);
@WebMethod
@WebResult(name = "fruitResp")
Response getFruit(@WebParam(name = "name") String name, @WebParam(name = "color") Fruit.Color color);
}
接着为这个ws服务接口实现服务方法
@WebService(endpointInterface = "com.clo.ws.rpc.server.HelloWorldRpc")
public class HelloWorldRpcImpl implements HelloWorldRpc {
@Override
public String getHelloWorldString(String name) {
return "Hello WS RPC " + name;
}
@Override
public Response getFruit(String name, Fruit.Color color) {
Fruit fruit = new Fruit(name, color);
return new Response<Fruit>().getSuccessResp(fruit);
}
}
最后将服务注册
public class WsPublisher {
public static void main(String[] args) {
Endpoint.publish("http://localhost:7999/ws/rpc/hello", new HelloWorldRpcImpl());
}
}
@WebService标识了ws服务的接口和实现,@WebMethod标识ws服务下的操作,@SOAPBinding(style = SOAPBinding.Style.RPC)表示使用SOAP的RPC风格,如果想使用Document风格将style的值替换为SOAPBinding.Style.DOCUMENT
即可,启动服务之后,可以访问http://localhost:7999/ws/rpc/hello?wsdl
查看该服务生成的相应wsdl的xml文件。
接下来创建一个客户端与服务端进行通信
先创建一个客户端基类
public class BaseClient<T extends HelloWorldRpc> {
protected String url;
protected Class<T> serviceClazz;
private T service;
public BaseClient(String url, Class<T> serviceClazz) {
this.url = url;
this.serviceClazz = serviceClazz;
}
protected T createService() throws MalformedURLException {
if(url == null || "".equals(url)) {
return null;
}
URL serviceUrl = new URL(url);
QName qName = new QName("http://server.rpc.ws.clo.com/", "HelloWorldRpcImplService");
Service service = Service.create(serviceUrl, qName);
this.service = service.getPort(serviceClazz);
return this.service;
}
protected T getService() throws MalformedURLException {
return service != null ? service : createService();
}
}
实现基类,并进行相应的服务操作调用
public class HelloWorldRpcClient extends BaseClient<HelloWorldRpc> {
private HelloWorldRpc helloWorldRpc;
public HelloWorldRpcClient(String url, Class helloWorldRpcClazz) {
super(url, helloWorldRpcClazz);
}
public String getHelloWorldString(String name) throws MalformedURLException {
return getService().getHelloWorldString(name);
}
}
最后在ws服务启动后使用客户端调用服务端
public class HelloWorldRpcClientTest {
public static void main(String[] args) {
HelloWorldRpcClient helloWorldRpcClient = new HelloWorldRpcClient("http://localhost:7999/ws/rpc/hello?wsdl", HelloWorldRpc.class);
try {
System.out.println(helloWorldRpcClient.getHelloWorldString("cloneable"));
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
对于ws服务的访问主要使用javax.xml.namespace.QName
访问相应的服务命名空间和服务,再通过javax.xml.ws.Service
类将服务对应到客户端根据服务创建的服务接口,最后客户端就可以对过这个服务接口访问ws服务了,需要注意的是此处代码中客户端和服务端使用的是同一个服务接口类,事实上客户端应该根据wsdl的服务描述创建自己的服务接口类。
关于ws服务中的SOAP先介绍到此处。
如需要查看完整代码可以点击此处查看。
文章参考java point网站的web service及java实现SOAP部分,可点击此处查看。
网友评论