问题?自定义WebService和客户端调用《二》,客户端调用有几种方式
一、JDK创建WebService服务和使用
Oracle前身sun公司,早就意识到WebService的强大,和它的未来前景,所以在JDK中早就封装了这样的创建WebService服务。
查看DJK-API文档:
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服务描述文档
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>说到这里了,我们就会忍不住提出,那么通过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?
前面提到,怎么知道调用哪个服务,怎么知道调用哪个接口,这里就会讲到了。
| 服务 |
|
| 端口 |
|
| 方法 |
|
| 参数 |
访问看看:http://localhost:9080/hello?xsd=1
|
| 返回值 |
3.MyEclipes提供WebService工具
它有两个作用:
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>
四、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的链接地址要WSDL说明书
用cmd打包好的本地调用代码,复制到客户端项目中,只留下服务接口(那个是服务的接口,参照说明书),其他都删掉,里面的错的可以删掉。
<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的一个监听工具(只有高版本才有这个工具)
采用的是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。实现业务逻辑。
总结:还没完呢,请看下一篇文章点击打开文章链接
原文:http://blog.csdn.net/mr_li13/article/details/51261496