原文地址 :https://blog.csdn.net/xnf1991/article/details/52262135
1. 认识webservice
WebService定义: 顾名思义就是基于Web的服务。它使用Web(HTTP)方式,接收和响应外部系统的某种请求。从而实现远程调用。
Webservice理解:我们可以调用互联网上查询天气信息Web服务,然后将它嵌入到我们的程序(C/S或B/S程序)当中来,当用户从我们的网点看到天气信息时,他会认为我们为他提供了很多的信息服务,但其实我们什么也没有做,只是简单了调用了一下服务器上的一段代码而已。WebSerice可以将你的服务(一段代码)发布到互联网上让别人去调用,也可以调用别人机器上发布的WebService,就像使用自己的代码一样.。
2. Webservice调用
2.1webservice几个名词
名词1:XML. Extensible Markup Language -扩展性标记语言
XML,用于传输格式化的数据,是Web服务的基础。
namespace-命名空间。
xmlns=“http://itcast.cn”使用默认命名空间。
xmlns:itcast=“http://itcast.cn”使用指定名称的命名空间。
名词2:WSDL – WebService Description Language – Web服务描述语言。
通过XML形式说明服务在什么地方-地址。
通过XML形式说明服务提供什么样的方法 – 如何调用。
名词3:SOAP-Simple Object Access Protocol(简单对象访问协议)
SOAP作为一个基于XML语言的协议用于有网上传输数据。
SOAP= 在HTTP的基础上+XML数据。
SOAP是基于HTTP的。
SOAP的组成如下:
Envelope– 必须的部分。以XML的根元素出现。
Headers– 可选的。
Body– 必须的。在body部分,包含要执行的服务器的方法。和发送到服务器的数据。
名词4:UDDI (Universal Description, Discovery, and Integration) 是一个主要针对Web服务供应商和使用者的新项目。
在用户能够调用Web服务之前,必须确定这个服务内包含哪些商务方法,找到被调用的接口定义,还要在服务端来编制软件,UDDI是一种根据描述文档来引导系统查找相应服务的机制。
UDDI利用SOAP消息机制(标准的XML/HTTP)来发布,编辑,浏览以及查找注册信息。
它采用XML格式来封装各种不同类型的数据,并且发送到注册中心或者由注册中心来返回需要的数据。
2.2 webservice服务网址
Webservice服务网站:http://www.webxml.com.cn
2.3 WSDL解析
Wsdl文档从下往上读
Types - 数据类型定义的容器,它使用某种类型系统(一般地使用XML Schema中的类型系统)。(入参和出参的数据类型)
Message - 通信消息的数据结构的抽象类型化定义。使用Types所定义的类型来定义整个消息的数据结构(入参和出参)。
Operation - 对服务中所支持的操作的抽象描述,一般单个Operation描述了一个访问入口的请求/响应消息对(方法)。
PortType- 对于某个访问入口点类型所支持的操作的抽象集合,这些操作可以由一个或多个服务访问点来支持(服务类)。
Binding- 特定服务访问点与具体服务类的绑定(不看内容,看关系)。
Port- 定义为webservice单个服务访问点。
Service-相关服务访问点的集合。
2.4生成客户端代码方式调用webservice
1. wsimport是jdk自带的,可以根据wsdl文档生成客户端调用代码的工具.当然,无论服务器端的WebService是用什么语言写的,都将在客户端生成Java代码,服务器端用什么写的并不重要。
3. wsimport.exe位于JAVA_HOME\bin目录下.
常用参数为:-d<目录> - 将生成.class文件。默认参数。
• -s<目录> -将生成.java文件和class文件。
• -p<生成的新包名> -将生成的类,放于指定的包下。
• (wsdlurl) - http://server:port/service?wsdl,必须的参数。
示例:
C:/> wsimport –s . http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
4.注意:-s不能分开,-s后面有个小点,用于指定源代码生成的目录。点即当前目录。
如果使用了-s参数则会在目录下生成两份代码,一份为.class代码。一份为.java代码。
.class代码,可以经过打包以后使用。.java代码可以直接Copy到我们的项目中运行。
调用webservice步骤
1) 打开WSDL文档
2) 从下往上读WSDL文档,先找到Services(服务访问点集合),根据Services里面binding属性找到binding元素,再根据binding元素的type属性找到绑定的portType(服务类)
3) 根据WSDL的地址生成客户端代码wsimport -s . -p com.rl.trans d:/wsCode/EnglishChinese.wsdl
4) 把客户端代码拷贝到项目中
5) 创建服务访问点集合对象
6) 根据服务访问点获得服务类
7) 调用服务类的方法
3. jdk发布webservice服务
注意:用Jdk1.6.0_21以后的版本发布一个WebService服务.
说明: 在JDK1.6中JAX-WS规范定义了如何发布一个webService服务。
JAX-WS是指Java Api for XML –WebService.
与Web服务相关的类,都位于javax.xml.ws.*包中。
主要类有:
a) @WebService - 它是一个注解,用在类上指定将此类发布成一个webservice服务,如下所示:
@WebService
public class HelloServer {
/**
* 1.需要方法权限是public
* 2.不能是final类型
* 3.方法不能是静态的
* 4.服务类至少有一个方法
* @paramname
*@return
*/
@WebMethod(exclude=false)
public String sayHello(String name){
return name + " hello!";
}
@WebMethod(exclude=false)
public String sayBye(String name){
return name + " bye!";
}
}
b) Endpoint – 此类为端点服务类,它的方法publish用于将一个已经添加了@WebService注解对象绑定到一个地址的端口上。Endpoint是jdk提供的一个专门用于发布服务的类,它的publish方法接收两个参数,一个是服务的地址,二是提供服务的类。它位于javax.xml.ws.*包中。
static Endpoint.publish(String address,Object implementor) 在给定地址处针对指定的实现者对象创建并发布端点。
public static void main(String[] args) {
//jdk发布webservice服务,第一个参数服务地址,第二个参数具体服务类
Endpoint.publish("http://127.0.0.1:8080/hello",new HelloServer());
}
stop方法用于停止服务。
其他注意事项:
1) 给类添加上@WebService注解后,类中所有的非静态方法都将会对外公布。不支持静态方法,final方法。
2) 如果希望某个方法(非static,非final)不对外公开,可以在方法上添加@WebMethod(exclude=true),阻止对外公开。
3) 如果一个类上,被添加了@WebService注解,则必须此类至少有一个可以公开的方法,否则将会启动失败。
4) 服务类中不能没有方法
5) @WebMethod(exclude=true)屏蔽方法
4.其他调用webservice的方式
4.1使用ajax+xml调用
var xhr;
function invoke(){
if(window.ActiveXObject){
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}else{
xhr = new XMLHttpRequest();
}
//指定请求地址
var url ="http://127.0.0.1:7777/hello?wsdl";
//定义请求类型和地址和异步
xhr.open("POST", url,true);
//设置Content-Type
xhr.setRequestHeader("Content-Type","text/xml;charset=UTF-8");
//指定回调方法
xhr.onreadystatechange = back;
var textVal =document.getElementById("mytext").value;
//组装消息体的数据
var data = '<soapenv:Envelopexmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"xmlns:q0="http://server.hm.com/"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
+'<soapenv:Body>'
+'<q0:sayHello>'
+'<arg0>'+textVal+'</arg0>'
+'</q0:sayHello>'
+'</soapenv:Body>'
+'</soapenv:Envelope>';
xhr.send(data);
}
function back(){
if(xhr.readyState == 4){
if(xhr.status == 200){
var doc =xhr.responseXML;
alert(doc);
alert(xhr.responseText);
var tag =doc.getElementsByTagName("return")[0];
alert(tag)
}
}
}
4.2通过HttpURLConnection调用
//创建url地址
URL url = new URL("http://127.0.0.1:8080/hello?wsdl");
//打开连接
URLConnection conn = url.openConnection();
//转换成HttpURL
HttpURLConnection httpConn = (HttpURLConnection) conn;
//打开输入输出的开关
httpConn.setDoInput(true);
httpConn.setDoOutput(true);
//设置请求方式
httpConn.setRequestMethod("POST");
//设置请求的头信息
httpConn.setRequestProperty("Content-type","text/xml;charset=UTF-8");
//拼接请求消息
String data = "<soapenv:Envelopexmlns:soapenv=" +
"\"http://schemas.xmlsoap.org/soap/envelope/\"" +
"xmlns:q0=\"http://server.rl.com/\"" +
"xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
+"<soapenv:Body>"
+"<q0:sayHello>"
+"<arg0>renliang</arg0>"
+"</q0:sayHello>"
+"</soapenv:Body>"
+"</soapenv:Envelope>";
//获得输出流
OutputStream out = httpConn.getOutputStream();
//发送数据
out.write(data.getBytes());
//判断请求成功
if(httpConn.getResponseCode() == 200){
//获得输入流
InputStream in = httpConn.getInputStream();
//使用输入流的缓冲区
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuffer sb = new StringBuffer();
String line = null;
//读取输入流
while((line = reader.readLine()) !=null){
sb.append(line);
}
//创建sax的读取器
SAXReader saxReader = new SAXReader();
//创建文档对象
Document doc = saxReader.read(new StringReader(sb.toString()));
//获得请求响应return元素
List<Element> eles = doc.selectNodes("//return");
for(Element ele : eles){
System.out.println(ele.getText());
}
5.复杂消息请求
对于ajax和HttpURLConnection调用webservice有一个缺点是都需要自己来组装消息体,这对于复杂的web请求就比较麻烦,所以一般都会用生成客户端代码的方式来调用webservice,下面是的例子是通过添加person这个实体对象来发送请求。
创建一个实体person:
public class Person {
private int id;
private Stringname;
private int age;
private Stringaddress;
get和set方法…
}
服务端代码:
@WebService
public class PersonServer {
List<Person> pList = new ArrayList<Person>();
/**
* 添加人
* @param person
*/
public void addPerson(Person person){
pList.add(person);
}
/**
* 获得所有的人
* @return
*/
public List<Person> getPersonAll(){
return pList;
}
public static void main(String[] args) {
Endpoint.publish("http://127.0.0.1:6060/person",new PersonServer());
}
在F:/wsCode/生成客户端代码:
wsimport–s . –p com.rl.person http://127.0.0.1:6060/person?wsdl
客户端调用web服务:
public class TestPersonClient {
public static void main(String[] args) {
//创建服务访问点集合
PersonServerService pss = new PersonServerService();
//根据服务访问点获得绑定的类
PersonServer server = pss.getPersonServerPort();
//调用具体业务逻辑
Person person = new Person();
person.setId(1);
person.setName("zhaoliu");
person.setAge(20);
person.setAddress("xiangyashan");
Person person1 = new Person();
person1.setId(2);
person1.setName("tianqi");
person1.setAge(25);
person1.setAddress("gaolaozhang");
//调用添加人的webservice服务方法
server.addPerson(person);
server.addPerson(person1);
//调用查询所有人的webservice服务方法
List<Person> pList = server.getPersonAll();
for(Person p : pList){
System.out.println("id: "+p.getId()+" name:"+p.getName()+" age:"+p.getAge() + " address:"+p.getAddress());
}
}
6.wsdl文档元素名称修改
自动生成的文档的名字有时不规范,可以手动进行修改。
@WebService(
portName="myHelloService",修改端口名字
serviceName="HelloServices",修改服务访问点集合名字
name="HelloService",修改服务类的名字
targetNamespace="hello.test.com"修改命名空间名字
)
@WebMethod(exclude=false)
public @WebResult(name="byeResult") String sayBye(@WebParam(name="personName ") String name){
return name +" bye!";
}
@WebResult(name="byeResult")修改返回值的元素的父标签名字
@WebParam(name="personName")修改传入参数的元素的父标签名字