年底Sun 公司发布了 Java Standard Edition (Java SE )的最终正式版代号 Mustang(野马)跟 Tiger(Java SE )相比Mustang 在性能方面有了不错的提升与 Tiger 在 API 库方面的大幅度加强相比虽然 Mustang 在 API 库方面的新特性显得不太多但是也提供了许多实用和方便的功能在 脚本XML 和 Web 服务编译器 API数据库JMX网络 和 Instrumentation 方面都有不错的新特性和功能加强
本系列 文章主要介绍 Java SE 在 API 库方面的部分新特性通过一些例子和讲解帮助开发者在编程实践当中更好的运用 Java SE 提高开发效率本文是系列文章的最后一篇主要介绍了 Java SE 中提供的 XML 处理框架以及在此框架之上结合注释(Annotation) 技术所提供的强大的针对 Web 服务的支持
Java SE 做为一个开发平台针对不同的应用开发需求提供了各种各样的技术框架XML 处理框架是 JDK 的重要组成部分之一它为应用程序开发人员提供了一个统一的 XML 处理 API这种框架结构有两个作用一方面开发人员透过这些框架可以透明的替换不同厂商提供的 XML 处理服务另一方面服务提供商可以透过这些框架将自己的产品插入到 JDK 中这种框架一般被称为 Service Provider 机制Java SE 的 XML 处理功能分为两个部分XML 处理(JAXP)和 XML 绑定(JAXB)在 XML 处理框架之上Java SE 结合了注释(Annotation)技术提供了强大的针对 Web 服务的支持
本文首先介绍 Service Provider 机制及其在 XML 框架中的应用然后介绍 Java SE 中 XML 框架的功能包括 SAXStAXDOM 三种机制最后介绍在此基础之上构建 Web 服务的技术JAXB 和 Web 服务的开发关系紧密故 JAXB 的介绍也放在 Web 服务部分介绍本文内容基于 Java SE SDK
Service Provider 机制
对于同一个功能不同的厂家会提供不同的产品比如不同品牌的轮胎插头等在软件行业情况也是如此比如对于数据的加密解密不同的厂家使用不同的算 法提供强度各异的不同软件包应用软件根据不同的开发需求往往需要使用不同的软件包每次更换不同的软件包都会重复以下过程更改应用软件代码 > 重新编译 > 测试 > 部署这种做法一般被称为开发时绑定这其实是一种比较原始的做法缺乏灵活性和开放性于是应用运行时绑定服务提供者的做法流行开来具体做法是使用 配置文件指定然后在运行时载入具体实现Java SE 平台提供的 Service Provider 机制是折衷了开发时绑定和运行时绑定两种方式很好的满足了高效和开放两个要求
构成一个 Service Provider 框架需要大致三个部分图 给出了一个典型的 Service Provider 组件结构Java SE 平台的大部分 Service Provider 框架都提供了 个主要个组件面向开发者的 Application 接口面向服务提供商的 Service Provider 接口和真正的服务提供者
图 Service Provider 的组件结构
这样做的主要好处包括
提供了供应商的中立性应用代码与服务提供商完全独立互不依赖应用程序开发者针对 图 中 Application 接口进行开发这个接口将不同提供商的接口差异性屏蔽掉了无论使用哪个厂商的服务应用程序都是针对一个稳定统一的接口开发业务逻辑和第三方组件之间有很强的独立性如果有需要应用程序可以针对不同提供商重新部署清单 显示某应用程序中的一段代码
清单 通过统一应用程序接口获得服务
SAXParserFactory factory = SAXParserFactorynewInstance();
Systemoutprintln(factorygetClass());
// Parse the input
SAXParser saxParser = factorynewSAXParser();
Systemoutprintln(saxParsergetClass());
Output: class orgapachexercesjaxpSAXParserFactoryImpl
Output: class orgapachexercesjaxpSAXParserImpl
本例中 saxParser 的类型被声明为 SAXParser但实际类型如 清单 中显示为 orgapachexercesjaxpSAXParserImpl实际类型是由 SAXParserFactory 的静态方法 newInstance 查找配置文件并实例化得到的图 展示了 Java SE 中 XML 包的 Service Provider 的交互细节请参考 Apache Harmony 项目的具体代码(参见 参考资源)
图 XML 包的 Service Provider 结构
提供了扩展性更多的服务可以加入开发平台为了便于不同的开发商开发各自的产品Java SE 平台同时为服务提供商设计了统一的接口只要提供者满足这些接口定义(比如继承某个接口或者扩展抽象类)服务提供者就能被添加到 Java SE 平台中来以 图 给出的结构为例服务提供者需要继承 SAXParserFactorySAXParser 等抽象类同时将类 VendorSaxParserFactoryImpl 的名字注册到 jaxpproperties 文件中就可以被使用了
兼 顾了灵活性和效率通过这种方式一方面组件提供者和应用开发者开发时绑定到一个约定的接口上另一方面载入具体哪个组件则是在运行时动态决定的不同于 Web 服务等技术的完全动态绑定(通过运行时解析 WSDL 文件来决定调用的类型)也不是完全的编码时绑定这种折衷的方式提供了松耦合高扩展性同时也保证了可接受的效率
XML 框架介绍
Java SE 平台提供的 XML 处理主要包括两个功能XML 处理(JAXPJava Architecture XML Processing)和 XML 绑定(JAXBJava Architecture XML Binding)JAXP 包括 SAX 框架 —— 遍历元素做出处理DOM 框架 —— 构造 XML 文件的树形表示StAX 框架 —— 拖拽方式的解析XSLT 框架 —— 将 XML 数据转换成其他格式JAXB 则是负责将 XML 文件和 Java 对象绑定在新版 JDK 中被大量的使用在 Web 服务技术中
SAX 框架(Simple API for XML)
SAX 全称 Simple API for XML该框架使用了事件处理机制来处理 XML 文件图 展示了这个过程
图 SAX 框架处理 XML 文件的流程
SAXParser 将 XML 文件当作流读入当 parser 遇到 Element_A就会产生一个事件然后将该事件发送给处理类SAX 框架的一大特点是对于节点的处理是上下文无关的比如 图 中 SAXParser允许注册一个处理类这个处理类对于所有节点并不加以区分对他们的处理过程都是一致的一般包括 startElement 和 endElement 等动作清单 给出了处理类的 startElement 动作的伪代码
清单 处理类的 startElement 动作的伪代码
CLASS Listener < DefaultListener
PROCEDURE StartElement(…)
IF ( node>Objname == Node )
// Do some calculation
FI
END
END
SAXParser>SetListener(new Listener)
使用 SAX 框架对于 Node 节点的处理并不会根据其前驱或者后缀节点的不同而有所区别伪代码 行说明了这一点一旦发现节点名称是 Node则进行预定的处理这个框架本身并不支持对节点进行上下文相关的处理除非开发者另外维护一些数据结构来记录上下文状态正是由于 SAX 框架不需要记录的状态信息所以运行时SAX 框架占用的内存(footprint)比较小解析的速度也比较快
DOM 框架(Document Object Model)
DOM 框架的全称是 Document Object Model顾名思义这个框架会建立一个对象模型针对每个节点以及节点之间的关系在内存中生成一个树形结构这个特点与 SAX 框架截然相反需要注意的是DOM 框架提供的对象树模型与我们通常理解的 XML 文件结构树模型是有一定的区别的图 给出了一个 XML 文件的结构
图 DOM 框架的对象模型
图 中的 Element_B 具有 清单 这样的结构
清单 Element_B 的 XML 结构
<Element_B>This is start of Element_B
<Node>…</Node>
This is end of Element_B
</Element_B>
按照 图 和 清单 给出的结构一般的对象的观点理解Element_B 包含子元素 Node而两句话This is start of Element_B与This is end of Element_B是 Element_B 节点的内容而实际上当针对 Element_B 调用 ElementgetContent得到的是 Element_B 这个名字本身两句文本同 Node 一样也是作为子节点的可以这样认为DOM 的对象模型在内存中模拟的是 XML 文件的物理存储结构而不是节点间的逻辑关系DOM 中结点的类型也是通过 getContent 返回的节点名字符串区别的当客户端识别节点类型时通常会形成以下的代码片断
清单 使用 DOM 框架的客户端代码
name = ElementgetContent
SWITCH name
CASE Element_A:
// Do something
BREAK
CASE Element_B:
// Do something
BREAK
DEFAULT:
END
这种方式是很明显的早绑定 —— 编码时 / 编译时绑定而不是面向对象语言中使用的运行时绑定技术 —— 继承带来的虚拟函数特性这个问题的产生和 DOM 框架的设计目标有关DOM 的目标是一个编程语言无关的用来处理大段复杂 XML 文件的框架(参见 参考资源) 比如书籍和文章DOM 框架一个显着的特征是善于处理节点与文本混合的 XML 文件(MixedContent Model)这种设计使得 XML 形成树的过程是一个直接映射不需要进行概念上的转换也就节省掉很多的处理细节一定程度上提高了效率这一点在处理大文件时比较明显兼顾了效率和上 下文状态问题另一方面由于编程语言无关的设计目标也决定了放弃虚函数机制是必要的
StAX 框架(Streaming API for XML)
SAX 框架的缺点是不能记录正在处理元素的上下文但是优点是运行时占内存空间比较小效率高DOM 框架由于在处理 XML 时需要为其构造一棵树所以特点正好相反StAX 框架出现于 Java SE 中它的设计目标就是要结合 SAX 框架和 DOM 框架的优点既要求运行时效率也要求保持元素的上下文状态清单 是一段使用 StAX 框架处理 XML 文件的代码
清单 使用 StAX 框架处理 XML 文件
import javaio*;
import javaxxmlstream*;
import javaxxmlstreamevents*;
public class StAXTest {
public static void main(String[] args) {
XMLInputFactory inputFactory = XMLInputFactorynewInstance();
InputStream input = new ByteArrayInputStream(
(<?xml version=\\ encoding=\UTF\?> +
<workcontactinfo> +
<Location>Shanghaishuion</Location> +
<Postal></Postal> +
<Tel><fix></fix><mobile></mobile></Tel> +
<Appellation>Mr Wang</Appellation> +
</workcontactinfo>)getBytes());
try {
XMLEventReader xmlEventReader = inputFactorycreateXMLEventReader(input);
while (xmlEventReaderhasNext()) {
XMLEvent event = xmlEventReadernextEvent();
if (eventisStartElement()) {
StartElement startElement = eventasStartElement();
Systemoutprintln(startElementgetName()toString());
}
if (eventisCharacters()) {
Characters text = eventasCharacters();
if (!textisWhiteSpace()) {
Systemoutprintln(\t + textgetData());
}
}
}
} catch (XMLStreamException e) {
eprintStackTrace();
}
}
}
观察后可以发现 StAX 框架和 SAX 框架具有相似的地方StAX 有 EventisStartElement 方法SAX 有 DefaultHandlerstartElement 方法StAX 有 EventisCharacter 方法SAX 有 DefaultHandlercharacter 方法实际上这两个框架处理 XML 文件的时候使用了相似的模型——将 XML 文件作为元素组成的流而不同于 DOM 的树模型解析 XML 文件时应用程序调用 XMLEventReader 的 nextEvent 方法解析下一个元素(或者是解析同一个元素根据解析的不同阶段产生不同元素)StAX 就会通过 XMLEventReader 产生一个事件比如针对同一个元素可能会产生 StartElement 和 EndElement 事件形象的说 XMLEventReader 就像是一根绳子拽一下解析一个元素产生一个事件于是这种技术也被称为Pull Parser技术StAX 在处理 XML 文件时产生的所有事件是通过一个 Iterator(XMLEventReader 继承了 Iterator)返回的应用程序通过这个 Iterator 能知道某个解析事件的前后分别是什么这类信息就是一个元素的上下文信息
XSLT 数据转换框架(The Extensible Stylesheet Language Transformations APIs)
一 般来说 XML 文件格式被认为是一种很好的数据交换格式于是 Java SE SDK 基于以上介绍的三种 XML 处理机制提供了一个 XML 转换框架XSLT 框架负责进行转换 —— 包括将 XML 文件转换成其他形式如 HTML和将其他形式的文件转换成 XML 文件更进一步说这个框架可以接受 DOM 作为其输入和输出可以接受 SAX 解析器作为输入或者产生 SAX 事件作为输出可以接受 I/O Stream 作为输入和输出当然也支持用户自定义形式的输入和输出图 显示了这种依赖关系
图 XSLT 框架的依赖关系
转换框架的输入输出对象的类型并不要求是一一对应的比如使用 DOMSource 做为输入可以使用 StreamResult 作为输出清单 是一段伪代码用来显示 JDK 将不同 javaxxmltransformSource 转换成不同 javaxxmltransformResult 子类型的过程
清单 JDK 转换框架的转换过程
// Construct input
factory = XMLParserDocumentFactory>NEW
parser = factory>NewParser
document = parser>Parse(File)
// Wrap input/output
source = Source>NEW( document )
sink = Result>NEW
// Construct transformer
tFactory = TransformerFactory>NEW
transformer = tFactory>NewTransformer
// Transform
transformer>Transfer( source sink)
通过这个过程的转化一个 javaxxmltransformSource 可以转化成为类型 javaxxmltransformResultJDK 提供了如 图 所示的 种 Result 子类型用户也可以定义自己的 Result 类型另一方面用户自定义的数据解析器或者数据文件也可以作为 Transformer 的输入下面一个例子针对一个数据文件首先生成了一棵 DOM 树然后又根据这棵 DOM 树提取了所有的联系信息生成了一个文本文件清单 给出了这个数据文件
清单 地址信息文件
work contactinfo
LocationShanghaishuion
Postal
Tel
fix
mobile
AppellationMr Wang
清单 为这个信息文件构造一个 DOM 树并将其作为 transformer 的输入
清单 构造 DOM 树
import javaxxmlparsersDocumentBuilder;
import javaxxmlparsersDocumentBuilderFactory;
import javaxxmltransformTransformer;
import javaxxmltransformTransformerException;
import javaxxmltransformTransformerFactory;
import javaxxmltransformdomDOMSource;
import javaxxmltransformsaxSAXResult;
import orgwcdomDocument;
import orgwcdomElement;
import orgxmlsaxSAXException;
import orgxmlsaxhelpersDefaultHandler;
class ContentHandler extends DefaultHandler {
@Override
public void characters(char[] ch int start int length)
throws SAXException {
String name = new String(ch start length);
Systemoutprint(name + \t);
}
}
public class DOMTest {
/**
* @param args
* @throws TransformerException
*/
public static void main(String[] args) {
try {
DocumentBuilderFactory documentfactory = DocumentBuilderFactory
newInstance();
DocumentBuilder builder = documentfactorynewDocumentBuilder();
Document document = buildernewDocument();
Element root = documentcreateElement(workcontactinfo);
Element loca = documentcreateElement(Location);
locasetTextContent(Shanghaishuion);
rootappendChild(loca);
Element postal = documentcreateElement(Postal);
postalsetTextContent();
rootappendChild(postal);
Element tel = documentcreateElement(Tel);
rootappendChild(tel);
Element fix = documentcreateElement(fix);
fixsetTextContent();
telappendChild(fix);
Element mobile = documentcreateElement(mobile);
mobilesetTextContent();
telappendChild(mobile);
Element appellation = documentcreateElement(Appellation);
appellationsetTextContent(Mr Wang);
rootappendChild(appellation);
documentappendChild(root);
TransformerFactory tFactory = TransformerFactorynewInstance();
Transformer transformer;
transformer = tFactorynewTransformer();
SAXResult result = new SAXResult();
ContentHandler cHandler = new ContentHandler();
resultsetHandler(cHandler);
transformertransform(new DOMSource(document) result);
} catch (Exception e) {
eprintStackTrace();
}
}
}
Java SE SDK 提供了至少以上三种内置的处理 XML 文件的机制它们分别是 Simple API for XMLDocument Object Model 和 Streaming API for XML其中 SAX 和 StAX 采用了相似的模型 —— 将 XML 文件建模为元素流DOM 采用了树形模型带来的结果是 SAX 和 StAX 运行时空间相对 DOM 紧凑状态保持能力则依次 SAX > StAX > DOM 变强特别值得一提的是 StAX 技术是最新引进的 XML 处理技术它结合了 SAX 和 DOM 的优点清单 给出了一个粗略度量 SAXStAXDOM 三个框架解析同一个 XML 文件的运行效率的代码
清单 度量 XML 解析框架的运行时间
public class StAXTest {
public static void main(String[] args) {
final String xml = <?xml version=\\ encoding=\UTF\?> +
<workcontactinfo> +
<Location>Shanghaishuion</Location> +
<Postal></Postal> +
<Tel><fix></fix> +
<mobile></mobile></Tel> +
<Appellation>Mr Wang</Appellation> +
</workcontactinfo>;
for (int i = ; i < ; i++) {
StAX(xml);
}
for (int i = ; i < ; i++) {
SAX(xml);
}
for (int i = ; i < ; i++) {
DOM(xml);
}
long current = SystemcurrentTimeMillis();
for (int i = ; i < ; i++) {
StAX(xml);
}
current = SystemcurrentTimeMillis() current;
Systemoutprintln(current);
current = SystemcurrentTimeMillis();
for (int i = ; i < ; i++) {
SAX(xml);
}
current = SystemcurrentTimeMillis() current;
Systemoutprintln(current);
current = SystemcurrentTimeMillis();
for (int i = ; i < ; i++) {
DOM(xml);
}
current = SystemcurrentTimeMillis() current;
Systemoutprintln(current);
}
private static void StAX(final String xml) {
XMLInputFactory inputFactory = XMLInputFactorynewInstance();
InputStream input;
try {
input = new ByteArrayInputStream(xmlgetBytes());
XMLEventReader xmlEventReader = inputFactory
createXMLEventReader(input);
while (xmlEventReaderhasNext()) {
XMLEvent event = xmlEventReadernextEvent();
if (eventisStartElement()) {
StartElement startElement = eventasStartElement();
}
if (eventisCharacters()) {
Characters text = eventasCharacters();
if (!textisWhiteSpace()) {
}
}
}
} catch (XMLStreamException e) {
eprintStackTrace();
}
}
private static void SAX(final String xml) {
SAXParserFactory f = SAXParserFactorynewInstance();
InputStream input;
try {
SAXParser p = fnewSAXParser();
input = new ByteArrayInputStream(xmlgetBytes());
pparse(input new DefaultHandler());
} catch (Exception e) {
eprintStackTrace();
}
}
private static void DOM(final String xml) {
DocumentBuilderFactory f = DocumentBuilderFactorynewInstance();
InputStream input;
try {
DocumentBuilder p = fnewDocumentBuilder();
input = new ByteArrayInputStream(xmlgetBytes());
pparse(input);
} catch (Exception e) {
eprintStackTrace();
}
}
}
得出的数据如下
可以看出解析速度按 SAX > StAX > DOM 依次变慢这组数据从一个侧面反映了这三种技术的特性SAX 处理小的简单的 XML 文件更高效基于三种 XML 解析技术Java SE SDK 又提供了数据格式转换框架 —— XSLT同时 XSLT 技术和其他很多的 JDK 框架一样是一个开放框架它提供了一些抽象类和接口让应用程序可以根据需求开发出不同的 XML 数据处理和转换工具然后通过之前叙述的 Service Provider 机制将这些工具插入JDK 中表 罗列了 SAXStAXDOMXSLT 在 JDK 中的位置
表 SAXStAXDOMXSLT 在 JDK 中的位置
SAX | StAX | DOM | XSLT | javax
xml
parsersjavax
xml
streamjavax
xml
parsersjavax
xml
transformjavax
xml
stream
eventsjavax
xml
transform
domjavax
xml
stream
utiljavax
xml
transform
saxjavax
xml
transform
staxjavax
xml
transform
stream
Web 服务
基于XML的数据通常被作为 Web 服务之间互相调用的标准的数据传输文件格式Java SE SDK 中基于 XML 的解析技术也提供了 Web 服务的 API 支持和较早的 JDK 相比新版本的 JDK Web 服务功能更改了名称 —— 从 JAXRPC 变成 JAXWSJDK 只支持基于 remoteprocedurecall 的 Web 服务JDK 在此基础上还支持基于 SOAP message 的 Web 服务实现下面将给出一个例子基于 SOAP message实现一个简单的 Web 服务
清单 给出了开发一个 Web services EndPoint 的代码
清单 一个 Web serviceHello服务
package hello;
import javaxjwsWebService;
import javaxjwsWebMethod;
import javaxxmlwsEndpoint;
@WebService
public class Hello {
@WebMethod
public String hello(String name) {
return Hello + name + \n;
}
public static void main(String[] args) {
// create and publish an endpoint
Hello hello = new Hello();
Endpoint endpoint = Endpointpublish(//localhost:/hello hello);
}
}
使用 apt 编译 Hellojava产生辅助文件
apt d sample example/Calculatorjava
运行完这条命令之后example 目录下面多出了一个 jaxws 子目录如 图 所示Apt 工具在该目录里生成了发布 Hello Web service 所必需的两个辅助文件
图 example 目录
发布 Hello Web service
java cp sample helloHello
将浏览器指向//localhost:/hello?wsdl 会产生如 图 所示页面
图 发布的 Hello Web service
Java SE SDK 内嵌了一个轻量级的 HTTP Server方便开发者验证简单的 Web service 功能通过以上三步一个 Web service Endpoint 就部署完成下面将开发一个调用 Hello 服务的客户端
为 Web 服务的客户端产生存根文件
wsimport p sample //localhost:/hello?wsdl
这将会在 sample 目录下产生如 图 所示的文件这一步实际是根据上面 URL 指向的 WSDL 文件通过 JAXB 技术生成了相应的 Java 对象
图 wsimport 产生的文件
开发编译运行 Web 服务客户程序清单 给出了使用 Hello 服务的客户程序
清单 使用 Hello 服务的客户程序
package sample;
class HelloApp {
public static void main(String args[]) {
HelloService service = new HelloService();
Hello helloProxy = servicegetHelloPort();
String hello = helloProxyhello(developer works);
Systemoutprintln(hello);
}
}
图 是编译并运行该客户程序产生的结果
图 调用 Hello 服务
可以说在 Java SE SDK 中Web 服务的开发过程被大大简化了原来开发中需要手工重复劳动产生的文件可以使用工具自动生成比如 WSDL 文件可以自动生成和 WSDL 绑定的 Java 对象也自动生成部署(本文仅指 JDK 提供的轻量 HTTP server 部署环境)也大大简化这些全部归功于 JDK 中引入的一些新的 JSR 实现即一些 API 和工具表 给出了 JDK 中为 Web 服务 API 提供支持的包
表 JDK 中提供 Web 服务 API 支持的包
JSR | Package | JSR
Java API for XMLBased Web Services
javax
xml
wsjavax
xml
ws
handlerjavax
xml
ws
handler
soapjavax
xml
ws
httpjavax
xml
ws
soapjavax
xml
ws
spiJSR
Java Architecture for XML Binding (JAXB)
javax
xml
bindjavax
xml
bind
annotationjavax
xml
bind
annotation
adaptersjavax
xml
bind
attachmentjavax
xml
bind
helpersjavax
xml
bind
utilJSR
Web Services Metadata for the Java Platform
javax
jwsjavax
jws
soap
除此之外 JDK 还提供了一些工具包括 wsgen wsimport 以及 Java 调用的轻量级 HTTP serverAPI 和工具联合提供了一个简单的 Web services IDE 开发环境可以简化 Web 服务应用的开发
Java class 和 XML 文件的绑定
从上一段关于 Web 服务的叙述中我们能够发现开发和部署 Web 服务的过程中存在多次 Java 对象和 XML 文件转化的过程比如开发和部署服务的时候将一个 Web Service EndPoint 发布成为一个 WSDL或者使用服务的时候将一个 WSDL 文件转换成一组 Java 对象所有的转换都是通过工具自动完成的这里存在一些问题Java 对象的类型转换成 XML 元素是需要符合一定的标准还是随意转换呢?如果按照标准转换那么这个标准是什么样子的?比如 Java 中的 int 类型是应该变成 <int></int> 呢还是 <integer></integer>如 表 列出JSR Java Architecture for XML Binding (JAXB) 标准为这些问题给出了一个规范的解答
首先示范一个简单的例子将根据一个 XML 文件的 schema转换成 Java 对象还是以 清单 中的数据文件为依据构造一个 XML schema 文件如 清单 所示要运行这个例子首先需要下载一个 JAXB Reference Implementation jar(下载请参见 参考资源)并将该 jar 文件加入到 classpath 中
清单 用于绑定的 workcontactinfoxsd 文件
<xsd:schema xmlns:xsd=>
<xsd:element name=workcontactinfo type=workcontactinfo />
<xsd:complexType name=workcontactinfo>
<xsd:sequence>
<xsd:element ref=Location maxOccurs= minOccurs= />
<xsd:element ref=Postal maxOccurs= minOccurs= />
<xsd:element ref=tel maxOccurs= minOccurs= />
<xsd:element ref=Appellation maxOccurs= minOccurs= />
</xsd:sequence>
</xsd:complexType>
<xsd:element name=tel type=tel />
<xsd:complexType name=tel>
<xsd:sequence>
<xsd:element ref=fix maxOccurs= minOccurs= />
<xsd:element ref=mobile maxOccurs= minOccurs= />
</xsd:sequence>
</xsd:complexType>
<xsd:element name=Location type=xsd:string />
<xsd:element name=Postal type=xsd:string />
<xsd:element name=Appellation type=xsd:string />
<xsd:element name=fix type=xsd:string />
<xsd:element name=mobile type=xsd:string />
</xsd:schema>
运行命令 xjc workcontactinfoxsd将会在当前目录下生成一个 generated 子目录
运行命令 javac generated\*java编译所有生成的 Java 文件
操作生成的 Java 对象清单 给出了一个操作生成的 java 对象的例子要注意一定要先将 JAXB Reference Implementation jar 放到 classpath 中
清单 调用生成的 Java 对象
import generated*;
import javaioFileOutputStream;
import javaxxmlbindJAXBContext;
import javaxxmlbindMarshaller;
public class JAXBTest {
public static void main(String[] args) {
try {
JAXBContext jContext = JAXBContextnewInstance(generated);
ObjectFactory factory = new ObjectFactory();
Workcontactinfo contactinfo = (Workcontactinfo) (factory
createWorkcontactinfo());
contactinfosetAppellation(Mr Wang);
contactinfosetLocation(Shanghaishuion);
contactinfosetPostal();
Tel tel = (Tel) (factorycreateTel());
telsetFix();
telsetMobile();
contactinfosetTel(tel);
Marshaller marshaller = jContextcreateMarshaller();
marshallersetProperty(MarshallerJAXB_FORMATTED_OUTPUT
BooleanTRUE);
marshallermarshal(contactinfo new FileOutputStream(
workcontactinfoxml));
Systemoutprintln(java tree converted into xml & filed);
} catch (Exception e) {
eprintStackTrace();
}
}
}
运行这个程序就能生成一个 XML 数据文件如 清单
清单 XML 数据文件
<?xml version= encoding=UTF standalone=yes?>
<workcontactinfo>
<Location>Shanghaishuion</Location>
<Postal></Postal>
<tel>
<fix></fix>
<mobile></mobile>
</tel>
<Appellation>Mr Wang</Appellation>
</workcontactinfo>
回顾一下 Web 服务的 WSDL 文件如 图 所示是一个符合 WC XMLSchema 规范的 schema 文件以及整个过程中生成的 Java 类我们应该能更好的理解 Web 服务开发部署使用的全过程首先 JDK 提供的工具 apt 根据 Web Service EndPoint 中相关的注释生成一些与 WSDL schema 绑定的 Java 类察看这些类可以发现它们与 JAXB 例子中 generated 目录下生成的 Java 文件十分相似接着通过 HTTP 服务将这个 WSDL schema 文件发布出来然后通过 wsimport 工具生成一个 Web 服务的客户运行时代理相当于 清单 的功能最终 Web 服务的用户程序同运行时代理交互该代理生成并传递形式如 清单 的 XML 数据文件图 结合 表 给出了 Web 服务开发到使用整个周期的工作流和涉及到的 JDK 包
图 Web 服务开发部署流程中 XML 技术的应用
总结
比较前一个版本的 JDK新版本对 XML 处理技术进行了扩展包括新加入的 StAX 和 JAXB基于这些新的 XML 数据处理技术JDK 对 Web 服务的支持也得到了大大的增强这些增强体现在引入了一些注释和 API增加了更多的工具可以自动化大部分开发和部署的工作对于 XML 应用开发者来说有更多更有力地技术可以选用对于 Web 服务提供者来说开发工具更为强大开发流程更为简化工作效率得到提高而对于 Web 服务的使用者更多的底层细节被屏蔽可以说新版 JDK 在对 XML 相关应用开发上的支持较前一个版本有了很大提升