您的位置:首页 > 编程语言 > Java开发

WebService在java中的简单应用

2019-04-12 15:12 260 查看
版权声明:如需转载,请注明出处! https://blog.csdn.net/qq_34609889/article/details/85338253

一、WebService简介

1、什么是WebService

WebService即web服务,w3C组织对其的定义如下,它是一个软件系统,为了支持跨网络的机器间相互操作交互而设计。Web Service服务通常被定义为一组模块化的API,它们可以通过网络进行调用,来执行远程系统的请求服务。简而言之,WebService就是一种跨编程语言和跨操作系统平台的远程调用技术

2、WebService技术支持

(1)XML和XSD
XML(Extensible Markup Language) 扩展性标记语言,XML主要的优点在于它既与平台无关,又与厂商无关。XML是由万维网协会(W3C)创建,W3C制定的XML SchemaXSD 定义了一套标准的数据类型,并给出了一种语言来扩展这套数据类型。Web Service平台是用XSD来作为数据类型系统的。为了符合Web Service标准,所有你使用的数据类型都必须被转换为XSD类型。如想让它使用在不同平台和不同软件的不同组织间传递,还需要用某种东西将它包装起来。这种东西就是一种协议,如 SOAP。
(2)SOAP
SOAP (Simple Object Access Protocol):简易对象访问协议,它是用来来描述传递数据的格式的。SOAP是基于HTTP的,发送请求和接收结果时,数据内容是采用XML格式封装,然后加上特定的HTTP消息头,以说明 HTTP消息的内容格式。HTTP消息头加上XML数据就是SOAP协议。所以可以认为SOAP = HTTP+XML数据。
(3)WSDL
WSDL(WebService Description Language)WebService描述语言。它用来描述如何访问具体的接口,通过xml形式说明服务地址以及如何调用。客户端要调用一个WebService服务之前,要知道该服务的WSDL文件的地址。 WebService服务提供商可以通过两种方式来暴露它的WSDL文件地址:1.注册到UDDI服务器,以便被人查找;2.直接告诉给客户端调用者。
(4)UDDI
UDDI(Universal Description Discovery and Integration):通用描述、发现及整合。用来管理、分发、查询webService。UDDI是一套基于Web的、分布式的、为Web Service提供的、信息注册中心的实现标准规范,同时也包含一组使企业能将自身提供的Web Service注册,以使别的企业能够发现的访问协议的实现标准。

二、WebService Java代码实现

1、WebService服务端代码实现

(1)创建简单java工程。
(2)创建服务接口SEI(Service Endpoint Interface),SEI在WSDL中就是portType,在java中其实就是普通接口

/**
*
* @author dmf
* WebService 服务接口SEI(Service Endpoint Interface),在wsdl中就是portType
*
*/
@WebService
public interface UserService {

public String saveUserInfo(String name,int age);
public String getUserInfoById(String id);
}

(3)创建接口的实现类,加上@WebService注解
注意:
1、给类添加上@WebService注解后,类中所有的非静态方法都将会对外公布。
2、如果希望某个方法不对外公开,可以在方法上添加@WebMethod(exclude=true),阻止对外公开。
3、如果一个类上,被添加了@WebService注解,则必须此类至少有一个可以公开的方法,否则将会启动失败。protected、private、final、static方法不能对外公开

@WebService    //@WebService注解表示该类是一个服务类,需要发布其中的public的方法
public class UserServiceImpl implements UserService{

@Override
public String saveUserInfo(String name, int age) {
System.out.println("姓名:"+name+" 年龄:"+age);
return "success";
}

@Override
public String getUserInfoById(String id) {
// TODO Auto-generated method stub
System.out.println("用户id:"+id);
return "张三";
}
}

(4)发布服务

public class UserServicePublish {

public static void main(String[] args) {
// WebService的发布地址,地址格式为:http://ip:端口号/xxxx,IP为本机IP地址
String address = "http://localhost:8888/UserServer/Webservice";

// 使用Endpoint类提供的publish方法发布WebService,发布时要保证使用的端口号没有被其他应用程序占用,第二个参数为是服务实现类
Endpoint.publish(address, new UserServiceImpl());
System.out.println("webservice成功发布!");
//验证是否发布成功:直接把address复制到浏览器访问,或者用address?wsdl也可以

}

}

(5)验证是否发布成功。
在浏览器地址栏输入http://localhost:8888/UserServer/Webservice或者http://localhost:8888/UserServer/Webservice?wsdl 即可

如果是web项目的话,可以在servlet或者监听器中的初始化方法中编写发布代码用来发布WebService服务

2、WebService客户端代码实现

Webservice服务发布后,我们要怎样调用呢?下面我们来试一下编写WebService客户端来调用WebService服务
使用jdk自带工具wsimport.exe生成客户端代码(bin目录下)
(1)生成客户端代码。打开cmd,输入wsimport命令(不清楚的可以输入wsimport -help命令查看此命令详情)
示例:wsimport -s . http://localhost:8888/UserServer/Webservice?wsdl。此命令为在当前目录生成客户端代码。

将生成的代码放入客户端程序中

离线解析:
当在没有网络的情况下开发客户端时,我们可以将wsdl保存为xml文件放在本地然后再解析。

(2)编写测试类

public class UserServiceClient {

public static void main(String[] args) {
//创建发服务视图,视图类名称是wsdl的service标签的name属性的值
UserServiceImplService factory = new UserServiceImplService();
//根据视图对象获取服务实现接口,名称是wsdl的portType标签的name属性值。UserServiceImpl是接口,不是类
UserServiceImpl userImpl = factory.getUserServiceImplPort();

//也可以使用下面这种service编程调用方式
//UserServiceImplService是自动生成的UserServiceImplService类的名称
//Service service = Service.create(new URL("http://localhost:8888/UserServer/Webservice?wsdl")
//        , new QName("http://impl.service.server2.dmf.com/","UserServiceImplService"));

//UserServiceImpl userImpl = service.getPort(UserServiceImpl.class);

//调用方法,wsdl的ortType标签下operation标签的name值
String userName = userImpl.getUserInfoById("123");
System.out.println("根据id获取到的用户姓名为:"+userName);

String result =  userImpl.saveUserInfo("李四", 19);
System.out.println("用户信息保存结果为:"+result);
}

(3)客户端其他实现方式
使用HttpURLConnection调用方式,这中方式编写客户端,不用工具生成代码,但是需要自己封装请求,解析响应数据。

这部分参考的是这篇博客里的:https://www.geek-share.com/detail/2711976878.html

/**
*
* @author dmf HttpURLConnection调用
*/
public class UserServiceClient1 {

public static void main(String[] args) throws IOException{
// 第一步:创建服务地址,不是WSDL地址
URL url = new URL("http://localhost:8888/UserServer/Webservice");
// 第二步:打开一个通向服务地址的连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 第三步:设置参数
// 3.1发送方式设置:POST必须大写
connection.setRequestMethod("POST");
// 3.2设置数据格式:content-type
connection.setRequestProperty("content-type", "text/xml;charset=UTF-8");
// 3.3设置输入输出,因为默认新创建的connection没有读写权限,
connection.setDoInput(true);
connection.setDoOutput(true);

// 第四步:组织SOAP数据,发送请求
String soapXML = getSOAPXML(123);
OutputStream os = connection.getOutputStream();
os.write(soapXML.getBytes());
// 第五步:接收服务端响应,打印
int responseCode = connection.getResponseCode();
if (200 == responseCode) {// 表示服务端响应成功
InputStream is = connection.getInputStream();
// 将字节流转换为字符流
InputStreamReader isr = new InputStreamReader(is, "utf-8");
// 使用缓存区
BufferedReader br = new BufferedReader(isr);

StringBuilder sb = new StringBuilder();
String temp = null;
while (null != (temp = br.readLine())) {
sb.append(temp);
}
System.out.println(sb.toString());

is.close();
isr.close();
br.close();
}

os.close();
}

// 将数据拼接成SOAP需要的格式,这是调用getUserInfoById方法时封装的方法,调用其他方法得另外重新封
//装
public static String getSOAPXML(int id){
String soapXML="<?xml version=\"1.0\" ?>"
+"<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\">"
+"<S:Body><ns2:getUserInfoById xmlns:ns2=\"http://impl.service.server2.dmf.com/\">"
+"<arg0>"+id+"</arg0></ns2:getUserInfoById></S:Body></S:Envelope>";
return soapXML;
}

}

返回结果:

<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:getUserInfoByIdResponse xmlns:ns2="http://impl.service.server2.dmf.com/">
<return>张三</return>
</ns2:getUserInfoByIdResponse>
</S:Body>
</S:Envelope>

返回结果是一个SOAPxml格式文件,要想获取返回值,还需要解析这个xml文件。查看数据格式方法:
使用eclipse自带的TCP/IP Monitor工具。
1、打开这个工具,Window》Show View》Other然后搜索TCP/IP Monitor。
2、设置要代理的服务器

第一个参数是代理端口,例如:1234
第二个参数是被代理服务器的地址,WebService服务ip。
第三个参数是被代理服务器的端口,WebService服务端口
第四个参数要选择为TCP/IP
3、启动代理,然后用客户端访问WebService服务

请求参数

GET /UserServer/Webservice?wsdl HTTP/1.1
User-Agent: Java/1.7.0_51
Host: localhost:1234
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive

POST /UserServer/Webservice HTTP/1.1
Accept: text/xml, multipart/related
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://impl.service.server2.dmf.com/UserServiceImpl/getUserInfoByIdRequest"
User-Agent: JAX-WS RI 2.2.4-b01
Host: localhost:1234
Connection: keep-alive
Content-Length: 224

<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:getUserInfoById xmlns:ns2="http://impl.service.server2.dmf.com/"><arg0>123</arg0></ns2:getUserInfoById></S:Body></S:Envelope>

响应参数:

HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml;charset=utf-8
Date: Sat, 29 Dec 2018 09:51:15 GMT

b69
<?xml version="1.0" encoding="UTF-8"?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.4-b01. --><definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://impl.service.server2.dmf.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://impl.service.server2.dmf.com/" name="UserServiceImplService">
<types>
<xsd:schema>
<xsd:import namespace="http://impl.service.server2.dmf.com/" schemaLocation="http://localhost:1234/UserServer/Webservice?xsd=1"></xsd:import>
</xsd:schema>
</types>
<message name="saveUserInfo">
<part name="parameters" element="tns:saveUserInfo"></part>
</message>
<message name="saveUserInfoResponse">
<part name="parameters" element="tns:saveUserInfoResponse"></part>
</message>
<message name="getUserInfoById">
<part name="parameters" element="tns:getUserInfoById"></part>
</message>
<message name="getUserInfoByIdResponse">
<part name="parameters" element="tns:getUserInfoByIdResponse"></part>
</message>
<portType name="UserServiceImpl">
<operation name="saveUserInfo">
<input wsam:Action="http://impl.service.server2.dmf.com/UserServiceImpl/saveUserInfoRequest" message="tns:saveUserInfo"></input>
<output wsam:Action="http://impl.service.server2.dmf.com/UserServiceImpl/saveUserInfoResponse" message="tns:saveUserInfoResponse"></output>
</operation>
<operation name="getUserInfoById">
<input wsam:Action="http://impl.service.server2.dmf.com/UserServiceImpl/getUserInfoByIdRequest" message="tns:getUserInfoById"></input>
<output wsam:Action="http://impl.service.server2.dmf.com/UserServiceImpl/getUserInfoByIdResponse" message="tns:getUserInfoByIdResponse"></o
1bb8b
utput>
</operation>
</portType>
<binding name="UserServiceImplPortBinding" type="tns:UserServiceImpl">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"></soap:binding>
<operation name="saveUserInfo">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal"></soap:body>
</input>
<output>
<soap:body use="literal"></soap:body>
</output>
</operation>
<operation name="getUserInfoById">
<soap:operation soapAction=""></soap:operation>
<input>
<soap:body use="literal"></soap:body>
</input>
<output>
<soap:body use="literal"></soap:body>
</output>
</operation>
</binding>
<service name="UserServiceImplService">
<port name="UserServiceImplPort" binding="tns:UserServiceImplPortBinding">
<soap:address location="http://localhost:1234/UserServer/Webservice"></soap:address>
</port>
</service>
</definitions>
0

HTTP/1.1 200 OK
Transfer-encoding: chunked
Content-type: text/xml; charset=utf-8
Date: Sat, 29 Dec 2018 09:51:15 GMT

5e
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body>
99
<ns2:getUserInfoByIdResponse xmlns:ns2="http://impl.service.server2.dmf.com/"><return>张三</return></ns2:getUserInfoByIdResponse></S:Body></S:Envelope>
0

三、其他

1、WSDL文件解析

前面我们讲过WSDL是web服务描述语言,相当于webservice服务使用说明书,WSDL是随服务发布成功,自动生成,无需编写。

service标签:整个WebService的服务视图,包括了所有的服务端口。
bind标签:定义每个端口的数据格式规范和具体协议。
portType标签:服务端点,描述 web service可被执行的操作方法,以及相关的消息,通过binding指向portType。
message标签:定义一个操作(方法)的数据参数(可有多个参数)。
types标签:定义WebService的全部数据类型。
阅读顺序从下往上阅读。不同语言实现wsdl可能会有少许不同,例如:java和.net生成的wsdl有少许差别。

2、SOAP详解

SOAP即简单对象访问协议,他是使用http发送的XML格式的数据,它可以跨平台,跨防火墙,SOAP不是webservice的专有协议,邮件SMPT传输协议也用这个。
SOAP结构:
必需的 Envelope 元素,可把此 XML 文档标识为一条 SOAP 消息
可选的 Header 元素,包含头部信息
必需的 Body 元素,包含所有的调用和响应信息
可选的 Fault 元素,提供有关在处理此消息所发生错误的信息

SOAP目前有1.1和1.2两个版本,目前大多数使用的是1.1版本。区别:
命名空间:
SOAP1.1命名空间:
xmlns:soap=“http://schemas.xmlsoap.org/soap/envelope/
SOAP1.2命名空间:
xmlns:soap="http://www.w3.org/2003/05/soap-envelope“
请求头:
SOAP1.1存在SOAPAction的请求头。
SOAP1.2没有SOAPAction的请求头
SOAP1.1只可以绑定到HTTP协议,而SOAP1.2除了HTTP协议之外还支持SMTP绑定。如果服务端使用1.1,那么客户端只能使用1.1,但服务端使用1.2,那么客户端可以使用1.1或1.2,优先用1.2。

3、WebService和Socket区别

1、Socket是基于TCP/IP的,WebService是基于HTTP的。
2、Socket通过流传输,不支持传输对象。WebService 支持面向对象,WebService将对象进行序列化后通过流传输。
3、Socket适用于高性能大数据的传输,传输的数据需要手动处理,socket通信的接口协议需要自定义。WebService适用于没有性能要求情况下且数据量较小的情况下,如果webservice开发大并发的应用,webservice依靠web容器提高并发数。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: