对WebService的一下理解
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 的。Soap1.1,soap1.2
SOAP 的组成如下:
Envelope – 必须的部分。以XML 的根元素出现。
Headers – 可选的。
Body – 必须的。在body 部分,包含要执行的服务器的方法。和发送到服务器的数据。
在JDK1.6中JAX-WS 规范定义了如何发布一个webService 服务。
JAX-WS 是指Java Api for XML – WebService.
用Jdk1.6.0_21以后的版本发布一个WebService 服务.
与Web 服务相关的类,都位于javax.jws.*包中。
主要类有:
@WebService - 它是一个注解,用在类上指定将此类发布成一个ws.
Endpoint – 此类为端点服务类,它的方法publish 用于将一个已经添加了@WebService注解对象绑定到一个地址的端口上。
JAX(Java Api for Xml)-WS规范是一组XML web services的JAVA API。JAX-WS 允许开发者可以选择RPC-oriented 或者message-oriented 来实现自己的web services。 在 JAX-WS中,一个远程调用可以转换为一个基于XML 的协议例如SOAP 。在使用JAX-WS 过程中,开发者不需要编写任何生成和处理SOAP 消息的代码。JAX-WS 的运行时实现会将这些API 的调用转换成为对应的SOAP 消息。
在服务器端,用户只需要通过Java 语言定义远程调用所需要实现的接口SEI (service endpoint interface),并提供相关的实现,通过调用JAX-WS 的服务发布接口就可以将其发布为WebService 接口。
在客户端,用户可以通过JAX-WS 的API 创建一个代理(用本地对象来替代远程的服务)来实现对于远程服务器端的调用。
当然 JAX-WS 也提供了一组针对底层消息进行操作的API 调用,你可以通过Dispatch 直接使用SOAP 消息或XML 消息发送请求或者使用Provider 处理SOAP 或XML 消息。 通过web service所提供的互操作环境,我们可以用JAX-WS 轻松实现JAVA 平台与其他编程环境(.net 等)的互操作。
JAX-WS 与JAX-RPC 之间的关系
Sun 最开始的web services的实现是JAX-RPC 1.1 (JSR 101)。这个实现是基于Java 的RPC, 并不完全支持schema 规范,同时没有对Binding 和Parsing 定义标准的实现。 JAX-WS2.0 (JSR 224)是Sun 新的web services协议栈,是一个完全基于标准的实现。在binding 层,使用的是the Java Architecture for XML Binding (JAXB, JSR 222),在parsing 层,使用的是the Streaming API for XML (StAX, JSR 173),同时它还完全支持schema 规范。
1:jdk1.6._07以后jdk 版本发布WebService 时必须要完整的对代码进行注解, 如果使用的是jdk1.6.0_21以后版本, 因为它已经内含了ws2.1所以, 可以只对类添加
@WebService的注解.
以下是两段不同的代码:
在jdk1.6.0_13的版本上发布的ws:
package com.itcast;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
import javax.xml.ws.Endpoint;
@WebService(targetNamespace="http://loalhost:9999/helloworld")
@SOAPBinding(style=Style.RPC)//只支持RPC 的消息风格
public class HelloWorld {
//以下通过@WebMethod注解, 对外公开方法
@WebMethod
public String sayHello(){
return "HelloWorld";
}
public static void main(String[] args) {
Endpoint.publish("http://localhost:9999/helloworld",new HelloWorld());
}
}
2:以下是在jdk1.6.0_24上发布的WebService 代码:
package com.itcast;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
@WebService//注意只有此一个注解, 此注解也是必须的, 默认的SOAP 消息风格为:DOCUMENT
public class HelloWorld {
public String sayHello(){
return "HelloWorld";
}
public static void main(String[] args) {
Endpoint.publish("http://localhost:9999/helloworld",new HelloWorld());
}
1、在类上添加@WebService注解。
这是jdk1.6提供的一个注解。它位于:javax.jws.*包中。
2、通过EndPoint(端点服务) 发布一个webService 。
Endpoint 也是jdk 提供的一个专门用于发布服务的类,它的publish 方法接收两个参数,一个是本地的服务地址,二是提供服务的类。它位于javax.xml.ws.*包中。 static?Endpoint.publish(String?address, Object?implementor)
在给定地址处针对指定的实现者对象创建并发布端点。
stop 方法用于停止服务。
EndPoint 发布完成服务以后,将会独立的线程运行。所以,publish 之后的代码,可以正常执行。
其他注意事项:
给类添加上@WebService注解后,类中所有的非静态方法都将会对外公布。 不支持静态方法,final 方法。-
如果希望某个方法(非static, 非final) 不对外公开,可以在方法上添加
@WebMethod(exclude=true),阻止对外公开。
如果一个类上,被添加了@WebService注解,则必须此类至少有一个可以公开的方法,否则将会启动失败。
package cn.leaf.two;
import java.util.Date;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
/**
* 发布第一个web 服务
* @author 张兆发
*/
@WebService
//以下方法由于是final 的,所以不会对外公开
public final String sayHi(String name){
return name+",你好,现在时间是:"+new Date();
}
//通过exclude=true,设置在发布时不包含此方法
@WebMethod(exclude=true)
public String sayHi1(String name){
return name+",你好,现在时间是:"+new Date();
}
public String sayHi2(String name){
return name+",你好,现在时间是:"+new Date();
}
public static void main(String[] args) throws Exception{
//发布服务
Endpoint end = Endpoint.publish("http://127.0.0.1:9999/one",new OneService()); System.out.println(“服务发布成功”);
Thread.sleep(2000);
end.stop();
}
}
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
/**
* 第一个WebService 服务应用
*/
//通过注解, 标明此类发布为一个WebService
@WebService
public String sayHello(){
return "Hello World";
}
//在main 方法中, 使用javax.xml.ws.Endpoint 端点发布一个应用
public static void main(String[] args) {
Endpoint.publish("http://127.0.0.1:9999/helloworld",
new HelloWorld());
}
}
代码说明:HelloWorld类的所有非静态公开方法将对外部暴露.
1:在MyEclipse 中新建立一个项目. 在此项目中, 将调用另一个项目中发布的WebService 2:步骤如下:
1:首先要根据http://127.0.0.1:9999/helloworld?wsdl获取WebService 的使用说明书. 2:在Jdk 的当前版本下,Jdk1.6.0_24,通过wsimport 这个工具来生成远程调用的源代码.(建议生成扩展名为.java 的文件)
3:在本项目中, 通过调用生成代码的形式调用远程服务. 成功返回”helloWorld ”.
wsimport 是jdk 自带的, 可以根据wsdl 文档生成客户端调用代码的工具. 当然, 无论服务器端的WebService 是用什么语言写的, 都将在客户端生成Java 代码. 服务器端用什么写的并不重要.
wsimport.exe 位于JAVA_HOME\bin目录下.
常用参数为:
-d - 将生成.class 文件。默认参数。
-s - 将生成.java 文件。
-p -将生成的类,放于指定的包下。
(wsdlurl) - http://server:port/service?wsdl,必须的参数。
示例:
C:/> wsimport –s . http://192.168.0.100/one?wsdl
注意:-s 不能分开,-s 后面有个小点,用于指定源代码生成的目录。点即当前目录。
如果使用了-s 参数则会在目录下生成两份代码,一份为.class 代码。一份为.java 代码。
.class 代码,可以经过打包以后使用。.java 代码可以直接Copy 到我们的项目中运行。 可以通过java –version 检查你当前的版本号. 如果版本太低可以安装高版本的jdk. 或直接将别人已安装好的jdk 目录拷贝到你的机器如D:\jdk1.6.0_24目录下.
因为以前的环境变量已经设置成以前老版本的jdk 目录, 即JAVA_HOME和PATH 两个环境变量.
可以再重新设置一下环境变量
为:JAVA_HOME=D:\jdk1.6.0_24,path=%JAVA_HOME%\bin,
重新设置了环境变量后, 要重新打开一个doc(命令行) 窗口. 才生效.
如果不想修改原来已经配置好的环境变量, 可以命令行窗口输入以下命令, 使
jdk1.6.0_24生效:
set path = D:\jdk1.6.0_24\bin;%PATH%(回车即可)
再通过java –version 查看jdk 的版本号是否已经发生变化.
2:转到一个相对干净的目录下, 我在d 盘上新建立一个目录名为:ws,并转到此目录下. 3:开启你的webService.
4:输入以下命令:
wsimport –s . http://127.0.0.1:9999/helloworld?wsdl
参数说明:-s是指编译出源代码文件, 后面的.(点) 指將代碼放到當前目錄下.
最后面的http …. 是指获取wsdl 说明书的地址.
5:此时, 将生成.java 文件和.class 文件.(都包含原始包名). 将代码Copy 到你的项目中.(只拷贝java 文件)
6:在新的项目中, 新一个类,(可位于任意包下), 对上面生成的代码进行调用, 见下一页ppt.
7:wsimport其他参数说明, 我们经常使用的参数为-d,-s,-p
-d将会生成.class 文件.
示例:wsimport –d . http://127.0.0.1:9999/helloworld?wsdl
-s将会生成.java 文件.
示例:wsimport –s . http://127.0.0.1:9999/helloworld?wsdl
-p将生成的文件(.java或是.class 修改成指定的包名)
示例:wsimport -s . -p com.beijing.itcast http://127.0.0.1:9999/helloworld?wsdl 对于-p 参数, 注意包名的修改, 它将所生成类, 全部置于通过-p 指定的包下.(演示)
需要说明的是, 当仅使用-p 参数时, 它也将同时使用-d 即编译成.class 文件. –d 参数写或不写, 它都在那里, 不离不弃.
RunMain.java 的源代码如下:
package com.leaf;
import com.itcast.HelloWorld;
import com.itcast.HelloWorldService;
/**
* 通过调用生成的类, 来调用远程代码
*/
public class RunMain {
public static void main(String[] args) {
//从HelloWorldSerice 的getHelloWorldPort 方法中返回调用接口
HelloWorld helloWorld =
new HelloWorldService().getHelloWorldPort();
String str = helloWorld.sayHello(); //执行调用
System.err.println(str);//返回HelloWorld 字符串
}
}
WebService 只采用HTTP POST方式传输数据,不使用GET 方式; -- 握手,WSDL-get, 普通http post的contentType 为
application/x-www-form-urlencoded
WebService 的contentType 为-即在Http 的基础上发SOAP 协议
text/xml 这是基于soap1.1协议。
application/soap+xml 这是基于soap1.2协议。
WebService 从数据传输格式上作了限定。WebService 所使用的数据均是基于XML 格式的。目前标准的WebService 在数据格式上主要采用SOAP 协议。SOAP 协议实际上就是一种基于XML 编码规范的文本协议。
SOAP – Simple Object Access protocol 简单对像访问协议。是运行在HTTP 协议基础之上的协议。其实就是在HTTP 协议是传输XML 文件,就变成了SOAP 协议。
SOAP1.1和SOAP1.2的 namespace不一样。可以通过查看类
javax.xml.ws.soap.SOAPBinding 来查看里面的常量
默认情况下,Jdk1.6只支持soap1.1
即:@BindingType(value=javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING
WSDL 文件的内容,一般由服务默认生成,但为了更好的向开发人员提供使用说明书,一般应做一些简单的修改。至少不应该暴露我们的包结构。而targetNamespace 默认情况下为倒置的包名,这已经暴露了我们的包结构。
通过在类文件上添加以下注解,可以修改wsdl 生成的各元素,而不是直接去修改wsdl 文件,直接去修改wsdl 文件是无效的。
WebService 的注解包括:
@WebService-定义服务 --类上
@WebMethod-定义方法 - 方法
@WebResult-定义返回值 – 返回值
@WebParam-定义参数 – 参数
import java.util.Date;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
/**
* 发布第一个web 服务
*/
@WebService
(serviceName="WjService"//修改Service 的名称,即:new WjService();
,name="One"//定义Port 名称,即端口-new WjService().getOnePort();返回接口即One
,targetNamespace="http://wj.cn"//定义命名空间,默认为倒置的包名
,portName="one"//定义获取的方法,此值可以覆盖name 的定义,即port name="getOne"
)
public class OneService{
@WebMethod(operationName="sayHello"//修改方法名
)
public
@WebResult(name="ReturnMsg")
String sayHi(
@WebParam(name="yourName")
String name){
return name+",你好,现在时间是:"+new Date();
}
public static void main(String[] args) throws Exception {
//发布服务
Endpoint ed= Endpoint.publish("http://127.0.0.1:9999/one",
new OneService());
System.err.println("服务发布成功");
}
}
}
• 最终个人感觉用第一种用cxf 比较好, 它很好地整合了spring 的beans 管理功能
以及解决JS 的跨域问题如下:
• 配置CXF 的核心servlet
•
• 目前的jQuery 不支持跨域访问。如果要进行访问必须使用jQuery 的jsonp 数
据形式。
• 但原始的ajax 可以通过get/post方式跨域访问http 上的资源。
– 以下是通过jaxb 发布的webservice 。并通过js 实现访问webService. – 第一步:书写一个webService ,通过Endpoint 端点服务发布。
–
– 第二步:书写XMLHttpRequest 的ajax 对像。
–
– 第三步:设法获取请求webService 的XML 数据和WebService 返回的
数据,以便于数据解析。
–
通过Ajax 访问WebService
使用jQuery -本域
$.ajax({
url:..
type:’post’,
dataType:’xml’,
contentType:’application/soap+xml;charset=“UTF-8”’
data:someXml,
Success:fun()…
})
另外难的是发布, 其实调用很简单, 就有myeclipse 的Web Service Client就可以
就会生成这几个类包
另外可以介绍一webservice 图形界面的工具SoapUI 4.6.4直观的了解wsdl 点击file 菜单---->New SOAP Project
在Initial WSDL中添加你发布的服务端发布的地址点击OK 就可以直观的看到一个XML 格式的
把左则的问号改成你想要获取的值右则就可以直接看到服务端给你返回的数据;