自定义WebService和客户端调用《二》

问题?自定义WebService和客户端调用《二》,客户端调用有几种方式


一、JDK创建WebService服务和使用

Oracle前身sun公司,早就意识到WebService的强大,和它的未来前景,所以在JDK中早就封装了这样的创建WebService服务。

查看DJK-API文档:

               自定义WebService和客户端调用《二》_第1张图片


1.新建Java或web工程,建一个类(这个类作为服务端):

<span style="font-family:Microsoft YaHei;font-size:18px;"><span style="font-family:Microsoft YaHei;font-size:18px;">package com.itcast.ws;

import javax.jws.WebService;
import javax.xml.ws.Endpoint;

@WebService  //表示这个类,代表的是启动服务,ServiceName名字可以改,默认不写的话,名字为类名加Service
public class HelloService {
	
	public String sayhello(String name){//能够访问的借口方法,必须是public方法
		System.out.println("Hello:  "+name);
		return "Hello:  "+name;
	}
	
	public String sayhello1(){
		return "成功调用第二个服务器方法";
	}
	
	 public static void main(String[] args) {
		 /*
		  * 调用静态的方法Endpoint.publish创建一个服务
		  * 1.address:URI,指定要使用的地址和传输/协议,也就是服务地址
		  * 2.implementor:实现者,也就是服务端
		  */
		 <pre name="code" class="java"><span style="white-space:pre">		</span>//使用自建端口号之前,cmd中使用netstat -a 检查一下端口是否被占用</span></span>
Endpoint.publish("http://localhost:9090/hello", new HelloService());System.out.println("启动服务:new HelloService");}}

 
 

/**如果改成private方法的话就会出现以下错误,我们做这个webservcie服务就是为了,*公布数据给别人用的,给成私有的,就达不到目的了,自然就会出错。Static、finally也不行

*Exception in thread "main"com.sun.xml.internal.ws.model.RuntimeModelerException: The web *service definedby the class com.itcast.ws.HelloService does not contain any valid WebMethods.

*/

运行:

如果出现错:Exception in thread "main" com.sun.xml.internal.ws.model.RuntimeModelerException:解决办法将jdk升级到1.7版本,MyEclispe的preference下java install(一般情况下,MyEclispe用的而是自身带的JDK,而不是安装得JDK,需要配置一下)

否则就运行成功:

       

或者网页调用:http://localhost:9090/hello或http://localhost:9090/hello?wsdl  看看wsdl服务描述文档

       自定义WebService和客户端调用《二》_第2张图片

2.新建客户端,并且调用该服务,在调用过程中,该服务必须一直开启

用wsimport -s . http://localhost:9090/hello?wsdl来生成本地代码,在上一文章中已经说过怎么做了。

把生成的文件夹拷入到客户端项目src下,并且新建一个测试调用类:

<span style="font-family:Microsoft YaHei;font-size:18px;"><span style="font-family:Microsoft YaHei;font-size:18px;">package com.itcast.test;

import org.junit.Test;

import com.itcast.ws.HelloService;
import com.itcast.ws.HelloServiceService;

public class test1 {

	@Test
	public void testService(){
		HelloServiceService helloServiceService = new HelloServiceService();
		HelloService service = helloServiceService.getHelloServicePort();
		String name = service.sayhello("李*****");
		System.out.println("成功获取数据包: "+name+" "+service.sayhello1());
	}
}
</span></span>

这里的HelloServiceService是来自访问网网址?wsdl文件中的,所以不需要去看wsdl文档。

说到这里了,我们就会忍不住提出,那么通过wsimport -s .生成的代码,导入到工程中,我怎么知道,调用哪个服务,调用哪个接口呢?就需要深入看看WebService的深入理解了。



二、深入了解WebService配置

1.注解声明类为@WebService,不然就会报错。
不然报这个错误:class cn.itcast.ws.HelloService has neither @WebService nor @WebServiceProvider annotation


必须有至少一个public方法,且这个方法不能是static,final
不然就hi报这个错误:cn.itcast.ws.HelloService does not contain any valid WebMethods.


/**如果改成private方法的话就会出现以下错误,我们做这个webservcie服务就是为了,*公布数据给别人用的,给成私有的,就达不到目的了,自然就会出错。Static、finally也不行
*Exception in thread "main" com.sun.xml.internal.ws.model.RuntimeModelerException: The web *service defined by the class com.itcast.ws.HelloService does not contain any valid WebMethods.
*/


2.如何查看说明wsdl

前面提到,怎么知道调用哪个服务,怎么知道调用哪个接口,这里就会讲到了。

WSDL文档说明
服务

端口

方法

参数


访问看看:http://localhost:9080/hello?xsd=1



返回值


3.MyEclipes提供WebService工具

自定义WebService和客户端调用《二》_第3张图片

它有两个作用:

1.第一个作用可以用来测试服务端的数据
2.第二个作用可以获取发出SAOP请求的代码,(它会返回WSDL代码,在AJAX市级开发中使用特别多)和返回SAOP结果的代码,在AJAX之中用得比较多。比如以下:


    

注意:这个工具有一个最不好的缺点,就是它不支持SAOP1.2,它只支持1.1版本。


三、Ajax调用WebService服务


响应的一样,首先WebService服务的搭建,有服务接口,与接口中的方法,开启服务。

然后用MyEclipes提供WebService工具获取到接口的SAOP请求的代码,如以上那张图片。


首先你得有AJAX的基础才能做这一块哈。

<span style="font-family:Microsoft YaHei;font-size:18px;"><!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
	<script type="text/javascript">
		/*
			思路:
			1.创建一个XMLHTTP对象
			2.打开链接open("POST",url)
			3.设置请求头Content-Type
			4.设置回调函数,处理返回值
			5.从返回的XML中解析我们要的内容
		*/
		
		var xmlHttpReqquest = new ActiveXObject("Microsoft.XMLHTTP");
		//alert(xmlHttpReqquest);

		//发送SOAP请求
		function sendMsg(){
			//获取用户输入的内容
			var name = document.getElementById("name").value;

			var url = "http://localhost:9080/hello";
			var requestBody = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:q0=\"http://ws.itcast.cn/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
							+ "<soapenv:Body><q0:sayHello><arg0>"+name+"</arg0></q0:sayHello></soapenv:Body></soapenv:Envelope>";

			xmlHttpReqquest.open("POST", url);
			xmlHttpReqquest.setRequestHeader("Content-Type","text/xml;charset=utf-8");
			xmlHttpReqquest.onreadystatechange = _back;
			xmlHttpReqquest.send(requestBody);
		}

		//接收SOAP返回,从返回XML中解析
		function _back(){
			//处理完毕,处理成功
			if(xmlHttpReqquest.readystate==4){		//处理完
				if(xmlHttpReqquest.status==200){	//成功
					var xml = xmlHttpReqquest.responseXML;
					//alert(xml);

					//获取return标签的第一个
					var ele = xml.getElementsByTagName("return")[0];
					alert(ele.text);
				}
			}
		}
	
	</script>
</head>
<body>
	<input type="text" id="name" name="name" value=""/>
	<input type="button" name="send" value="send" onclick="sendMsg();"/>
</body>
</html>
</span>

启动tomcate或者其他服务器,测试一下是否调用得了。


四、HttpURLConnection方式调用WebService服务

同样的这种方式,也需要SAOP请求的消息。同样用MyEclispe工具获取


如:

<span style="font-family:Microsoft YaHei;font-size:18px;">package com.itcast.test;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.junit.Test;

public class RequestUrlConnectionTest {
	
	@Test
	public void uriTest() throws IOException{
		/*
		 *1.创建一个url
		 *2.打开一个连接
		 *3.设置相关参数
		 *4.创建输出流,用来发送SAOP请求
		 *5.发送完,接收数据
		 *6.用输入流获取webservice中的内容
		 */
		
		URL url = new URL("http://localhost:9090/hello");
		HttpURLConnection connection = (HttpURLConnection)url.openConnection();
		connection.setRequestMethod("POST");//必须设置为POST方式,而且必须是大写的
		connection.setDoInput(true);//因为有输入参数也有输出参数所以都为真
		connection.setDoOutput(true);
		connection.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
		
		OutputStream out = connection.getOutputStream();
		String argo="<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:q0=\"http://ws.itcast.cn/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"+"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body><q0:sayhello><arg0>jack</arg0></q0:sayhello></soapenv:Body></soapenv:Envelope>";
		
		out.write(argo.getBytes());//发送SAOP请求
		InputStream stream = connection.getInputStream();
		byte[] b = new byte[1024];
		int len=0;
		StringBuffer buffer = new StringBuffer();
		while((len=stream.read(b))!=-1){
			String s = new String(b, 0, len, "utf-8");
			buffer.append(s);
		}
		
		System.out.println(buffer.toString());
		
	}
}
</span>

五、QName调用WebService方式

这个QName的链接地址要WSDL说明书


           自定义WebService和客户端调用《二》_第4张图片

用cmd打包好的本地调用代码,复制到客户端项目中,只留下服务接口(那个是服务的接口,参照说明书),其他都删掉,里面的错的可以删掉

                    自定义WebService和客户端调用《二》_第5张图片


<span style="font-family:Microsoft YaHei;font-size:18px;">package com.itcast.test;

import java.net.MalformedURLException;
import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.ws.Service;

import org.junit.Test;

import com.itcast.ws.HelloService;

public class QnameTest {
	
	
	/*
	 * 1.创建service对象,service.create(wsdlDocumentLocation, serviceName)
	 * wsdlDocumentLocation:URL服务地址,而且需要wsmdl描述
	 * serviceName:Qname,这就是用这个方式的核心,因为他只用到service接口
	 * Qname:需要两个参数,一个是打包的空间,另外一个是这个服务名称(描述文件中的的服务名)
	 * 
	 * 2.通过service对象调用接口
	 * 3.通过接口对象来调用服务端方法
	 */
	@Test
	public void qnametest1() throws MalformedURLException{
		URL url = new URL("http://localhost:9090/hello?wsdl");
		QName serviceName = new QName("http://ws.itcast.com/", "HelloServiceService");
		
		Service service = Service.create(url, serviceName );
		HelloService helloService = service.getPort(HelloService.class);
		String name = helloService.sayhello("Mr_Li");
		String naem1 = helloService.sayhello1();
		System.out.println("调用service成功:"+name+"\n"+naem1);
	}
}
</span>


六、注解开发

前面我用的调用接口服务,需要知道说明书上写明那个服务,然后我们才去写,因为那些服务名称都是它自动加上的基本结构为:服务名+Service,还有命名空间是跟建得包是烦着过来的。如果采取注解的形式去开发,那么就不需要知道服务名称(针对于程序猿)。


@WebService

@WebService(serviceName="MyService")
修改产生的服务的名称
@WebService(serviceName="MyService",targetNamespace="http://cn.itcast.ws/")

修改命名空间
@WebMethod(operationName="hello")
修改方法名称
@WebParam(name="name")
修改参数名称
@WebResult(name="returnMsg")
修改返回名称
@WebMethod(exclude=true)
将指定的public方法排除,用户不能访问


如:

<span style="font-family:Microsoft YaHei;font-size:18px;">package com.itcast.ws;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;

@WebService(serviceName="MyService",targetNamespace="http://com.itcast.ws/")  //表示这个类,代表的是启动服务,ServiceName名字可以改,默认不写的话,名字为类名加Service
public class HelloService {
	
	@WebMethod(operationName="Hello1")
	@WebResult(name="returnResult")
	public String sayhello(@WebParam(name="name")String name){
		System.out.println("Hello:  "+name);
		return "Hello:  "+name;
	}
	
	@WebMethod(operationName="Hello2",exclude=true)
	public String sayhello1(){
		return "成功调用第二个服务器方法";
	}
	
	 public static void main(String[] args) {
		 /*
		  * 调用静态的方法Endpoint.publish创建一个服务
		  * 1.address:URI,指定要使用的地址和传输/协议,也就是服务地址
		  * 2.implementor:实现者,也就是服务端
		  */
		Endpoint.publish("http://localhost:9090/hello", new HelloService());
		System.out.println("启动服务:new HelloService");
	}
}
</span>


执行命令看看是不是这样的:

http://localhost:9090/hello?wsdl
http://localhost:9090/hello?xsd=1


七、监控工具TCP/IP监控


有时候我们需要监听整个webservice的调用状态,需要用到MyEclipse的一个监听工具(只有高版本才有这个工具)

         自定义WebService和客户端调用《二》_第6张图片

采用的是TCP/IP的方式来监听的。需要监听的端口号和被监听的端口号不同。


八、总结

1.UDDI/WSDL/SOAP的概念

2.wsimport –s . http::///// 生产本地调用代码


3.注意:支持soap1.0协议


4.发布服务 Endpoint.publish静态方法
参数1访问地址,参数2实现类。


5.Service类,它有静态方法create可以创建一个Web服务

6.调用方式:
A. 客户端的方式
B. MyEclipse自带工具WebService Expolor 帮助测试,直接获取到发送和接收的SOAPxml
C. Ajax ,不需生成本地调用代码,可以直接访问,在实际项目中使用比较多
D. HttpURLConnection对象,是以流方式
E. QName方式,内部使用方式,实际开发中常采用实际开发中可以选择其中一种




7.对象封装
业务比较复杂,按原有的方式写po类,按原有的方式写Service层,在Server服务端调用业务层service。实现业务逻辑。

总结:还没完呢,请看下一篇文章点击打开文章链接

你可能感兴趣的:(webservice)