??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲蜜芽在线精品一区,亚洲中文字幕不卡无码,亚洲中文字幕久久精品无码A http://www.tkk7.com/zhuyan/category/20907.htmlJAVA启发?/description>zh-cnSat, 24 Mar 2007 18:31:34 GMTSat, 24 Mar 2007 18:31:34 GMT60?Castor q行数据l定http://www.tkk7.com/zhuyan/articles/105944.html朱岩朱岩Fri, 23 Mar 2007 09:52:00 GMThttp://www.tkk7.com/zhuyan/articles/105944.htmlhttp://www.tkk7.com/zhuyan/comments/105944.htmlhttp://www.tkk7.com/zhuyan/articles/105944.html#Feedback0http://www.tkk7.com/zhuyan/comments/commentRss/105944.htmlhttp://www.tkk7.com/zhuyan/services/trackbacks/105944.html对于主要兛_(j)文档数据内容的应用程序,Java XML 数据l定是一U代?XML 文档模型的强大机制。本文中Q企?Java 专家 Dennis Sosnoski 介绍数据l定Qƈ讨论什么它如此o(h)人瞩目。然后,他向读者展CZ(jin)如何利用 Java 数据l定的开放源代码 Castor 框架来处理日益复杂的文档。如果?zhn)的应用程序更多的?XML 作ؓ(f)数据而不是文档,(zhn)就?x)愿意?jin)解这U处?XML ?Java 技术的单有效的Ҏ(gu)?/blockquote>

应用E序中?XML 文档的多数方法都把重Ҏ(gu)?XML 上:(x)?XML 的观点用文档,按照 XML 元素、属性和字符数据内容~程。如果应用程序主要关?j)文档?XML l构Q那么这U方法非常好。对于更兛_(j)文档中所含数据而非文档本n的许多应用程序而言Q?数据l定提供?jin)一U更单的使用 XML 的方法?

文档模型与数据绑?/span>

本系列文章的上一(请参?参考资?/font>Q所讨论的文档模型,是与数据l定最接近的替代方案。文档模型和数据l定都在内存?sh)徏立文档的表示Q都需要在内部表示和标准文?XML 之间双向转换。两者的区别在于文档模型可能保?XML l构Q而数据绑定只兛_(j)应用E序所使用的文档数据?

Z(jin)说明q一点,?1 l出?jin)一个简?XML 文档的数据模型视图。文档成分——在q个例子中只有元素和文本节点——通过反映原始 XML 文档的结构连接在一赗Ş成的节点?wi)很?gu)和原始文档联p,但要解释?wi)中表示的实际数据就不那么容易?jin)?/p>

?1. 文档的文档模型视?/b>
文档的文档模型视? src=

如果应用E序使用 XML 文档模型Ҏ(gu)Q?zhn)需要处理这U类型的?wi)。这U情况下Q?zhn)用节点之间的父子关系在?wi)的上下层之间DQ用属于同一父节点的子女之间的兄弟关pd?wi)的同一层中D。?zhn)可以非常详尽地处理?wi)l构Q当把树(wi)序列化ؓ(f)文本Ӟ生成?XML 文档反映?zhn)所做的修改Q比如插入的注释Q?/p>

现在来看看与?1 截然不同的图 2Q它表示同一文档的数据绑定视图。在q里Q{换过E几乎隐藏了(jin)原始 XML 文档的所有结构,但是因ؓ(f)只有通过两个对象Q更Ҏ(gu)看清楚真正的数据Q也更很Ҏ(gu)讉Kq些数据?/p>

?2. 文档的数据绑定视?/b>
文档的数据绑定视? src=

使用q种数据l构像是一般的 Java ~程——甚x(chng)本不需要知?XMLQ(哦,q是不要走得 ?/i>q了(jin)——我们这些专安问还得活……)(j)(zhn)的目中至要有h明白Q这U数据结构和 XML 文档之间的映是如何建立的,但这仍然是向化迈出的一大步?

?仅仅是编E的化,数据l定q带来其他的好处。与文档模型Ҏ(gu)相比Q因为抽掉了(jin)许多文档l节Q数据绑定通常需要的内存更少。比如前面两个图中所C的数据l构Q文档模型方法用了(jin) 10 个单独的对象Q与此相比数据绑定只使用?jin)两个。要创徏的东西少Q构造文档的数据l定表示可能更快一些。最后,数据l定与文档模型相比,应用E序可以更快地访问数据,因ؓ(f)(zhn)可以控制如何表C和存储数据。我后面q要讲到q一炏V?

既然数据l定那么好,Zq要使用文档模型呢?以下两种情况需要用文档模型:(x)

  • 应用E序真正x(chng)文档l构的细节。比方说Q如果?zhn)在编写一?XML 文档~辑器,(zhn)就?x)坚持用文档模型而非数据l定?
  • (zhn)处理的文档没有固定的结构。比如实CU通用?XML 文档数据库,数据l定׃是一U好办法?

许多应用E序使用 XML 传输数据Q但q不兛_(j)文档表示的细节。这cd用程序非帔R合使用数据l定。如果?zhn)的应用程序符合这U模式,L(fng)l读下去?/p>



回页?/font>


Castor 框架

目前有几U不同的框架支持 Java XML 数据l定Q但q没有标准的接口。这U情冉|l会(x)得到改变QJava Community Process (JCP) ?JSR-031 正在努力定义q方面的标准Q请参阅 参考资?/font>Q。现在让我们选择一个框架ƈ学习(fn)使用它的接口?

本文选择?Castor 数据l定框架。Castor 目采用 BSD cd的证书,因此可在Mcd的应用程序(包括完整版权的项目)(j)中用?Castor 实际上仅仅有 XML 数据l定Q它q支?SQL ?LDAP l定Q尽本文中不讨些其他的Ҏ(gu)。该目?2000 q初开始发P目前处于?beta 状态(一般可以用这个版本,但是如果需要问题(sh)正,(zhn)可能需要升U到目前?CVS 版本Q。请参阅 参考资?/font>部分?Castor 站点链接Q以?jin)解更多的细节ƈ下蝲该Y件?





回页?/font>


默认l定

Castor XML 数据l定很容易上手,甚至不需要定?XML 文档格式。只要?zhn)的数据用c?JavaBean 的对象表C,Castor p自动生成表示q些数据的文档格式,然后从文档重构原始数据?/p>
数据l定词汇?/b>

下面q个小的词汇表列出?jin)本文中要用到的一些术语:(x)

~组是在内存?sh)生成对象?XML 表示的过E。与 Java 序列化一Pq种表示需要包括所有依赖的对象Q主对象引用的对象、这些对象引用的其他对象、等{?

解组是上q过E的逆过E,在内存(sh)?XML 表示创徏对象Q以?qing)依赖的对象Q?

映射是用于编l和解组的一些规则。Castor 有一些内建的规则定义?jin)默认映,本文q一部分要描述。它也允许?zhn)使用单独的映文Ӟ参见后述?

那么“类 JavaBean”是什么意思呢Q真正的 JavaBean 是可视化lgQ可以在开发环境中配置以用?GUI 布局。一些源于真?JavaBean 的惯例已l被 Java 团体普遍接受Q特别是对于数据cR如果一个类W合以下惯例Q我q之ؓ(f)是“类 JavaBean”的Q?

  • q个cL公共?
  • 定义?jin)公q默认Q没有参敎ͼ(j)构造函?
  • 定义?jin)公q getX ?setX Ҏ(gu)讉K属性(数据Q?

关于技术定义已l扯得太q了(jin)Q当提到q些c?JavaBean cLQ我不再重复说明,只是UC为“bean”类?/p>

在整文章中Q我用航U班机时刻表作ؓ(f)CZ代码。我们从一个简单的 bean cd始说明它的工作原理,q个c表CZ个特定的航班Q包括四个信息项Q?/p>

  • 飞机~号Q航I公司)(j)
  • 航班~号
  • 起飞旉
  • 抵达旉

下面的清?1 l出?jin)处理航班信息的代码?/p>

清单 1. 航班信息 bean
public class FlightBean
{
private String m_carrier;
private int m_number;
private String m_departure;
private String m_arrival;
public FlightBean() {}
public void setCarrier(String carrier) {
m_carrier = carrier;
}
public String getCarrier() {
return m_carrier;
}
public void setNumber(int number) {
m_number = number;
}
public int getNumber() {
return m_number;
}
public void setDepartureTime(String time) {
m_departure = time;
}
public String getDepartureTime() {
return m_departure;
}
public void setArrivalTime(String time) {
m_arrival = time;
}
public String getArrivalTime() {
return m_arrival;
}
}

(zhn)可以看刎ͼq个 bean 本n没有什么意思,因此我想增加一个类q在默认?XML l定中用它Q如清单 2 所C?/p>

清单 2. 试默认的数据绑?/b>
import java.io.*;
import org.exolab.castor.xml.*;
public class Test
{
public static void main(String[] argv) {
// build a test bean
FlightBean bean = new FlightBean();
bean.setCarrier("AR");
bean.setNumber(426);
bean.setDepartureTime("6:23a");
bean.setArrivalTime("8:42a");
try {
// write it out as XML
File file = new File("test.xml");
Writer writer = new FileWriter(file);
Marshaller.marshal(bean, writer);
// now restore the value and list what we get
Reader reader = new FileReader(file);
FlightBean read = (FlightBean)
Unmarshaller.unmarshal(FlightBean.class, reader);
System.out.println("Flight " + read.getCarrier() +
read.getNumber() + " departing at " +
read.getDepartureTime() +
" and arriving at " + read.getArrivalTime());
} catch (IOException ex) {
ex.printStackTrace(System.err);
} catch (MarshalException ex) {
ex.printStackTrace(System.err);
} catch (ValidationException ex) {
ex.printStackTrace(System.err);
}
}
}

Castor 不仅能用?bean

实际上,Castor 不仅仅能用于本文所q的c?JavaBean cR它也可以访问带有公共成员变量的单数据对象类的数据。比如,E微改动前述?Test c,(zhn)就可以对航班数据用如下的定义Qƈ最l得到同L(fng) XML 格式Q?

public class FlightData
{
public String carrier;
public int number;
public String departure;
public String arrival;
}

Z(jin)?Castor 正常工作Q一个类必须全部采用q种方式或那U方式。如果类定义?MgetX ?setX Ҏ(gu)QCastor 将其视?beanQƈ在编l和解组时只使用q些Ҏ(gu)?

q段代码首先构造了(jin)一?FlightBean beanQƈ使用一些固定的数据初始化它。然后用?bean 默认?Castor XML 映射其写入一个输出文件。最后又d生成?XMLQ?同样使用默认映射重构 beanQ然后打印重构的 bean 中的信息。结果如下:(x)

Flight AR426 departing at 6:23a and arriving at 8:42a

q个输出l果表明(zhn)已l成功地来回转换?jin)航班信息(不算太糟Q只有两ơ方法调用)(j)。现在我q(sh)满于简单控制台输出Q准备再往深处挖一挖?/p>

q后

Z(jin)更清楚地?jin)解q个例子中发生了(jin)什么,看一?Marshaller.marshal() 调用生成?XML。文档如下:(x)

<?xml version="1.0"?>
<flight-bean number="426">
<arrival-time>8:42a</arrival-time>
<departure-time>6:23a</departure-time>
<carrier>AR</carrier>
</flight-bean>

Castor 使用 Java 内部(g)查机制检?Marshaller.marshal() 调用传递的对象。在本例中,它发C(jin)定义的四个属性倹{Castor 在输出的 XML 中创Z个元素(文档的根元素Q表C整个对象。元素名从对象的cd中衍生出来,在这里是 flight-bean 。然后Castor 用以下两U方法中的一个,把该对象的属性值包括进来:(x)

  • 对于h基本cd值的属性创建元素的一个属性(本例中只?number 属性通过 getNumber() Ҏ(gu)公开?int |(j)?
  • 对于每个h对象cd值的属性创建根元素的一个子元素Q本例中的所有其他属性,因ؓ(f)它们是字W串Q?

l果是上面所C的 XML 文档?/p>



回页?/font>


改变 XML 格式

如果不喜?Castor 的默认映格式,(zhn)可以方便地改变映射。在我们的航班信息例子中Q比方说Q假定我们需要更紧凑的数据表C。用属性代替子元素有助于实现这个目标,我们也许q希望用比默认的名字更短一些的名字。如下所C的文档可以很好地满我们的需要:(x)

<?xml version="1.0"?>
<flight carrier="AR" depart="6:23a" arrive="8:42a" number="426"/>

定义映射

Z(jin)?Castor 使用q种格式而非默认的格式,首先需要定义描q这U格式的映射。映描q本w(非常意外的)(j)是一?XML 文档。清?3 l出?jin)?bean ~组成上q格式的映射?/p>

清单 3. 紧凑格式的映?/b>
<!DOCTYPE databases PUBLIC
"-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.exolab.org/mapping.dtd">
<mapping>
<description>Basic mapping example</description>
<class name="FlightBean" auto-complete="true">
<map-to xml="flight"/>
<field name="carrier">
<bind-xml name="carrier" node="attribute"/>
</field>
<field name="departureTime">
<bind-xml name="depart" node="attribute"/>
</field>
<field name="arrivalTime">
<bind-xml name="arrive" node="attribute"/>
</field>
</class>
</mapping>

class 元素定义?jin)一个命名类 FlightBean 的映。通过在该元素中加?auto-complete 属性ƈ把D?true Q?zhn)可以告?Castor 对于该类的Q何属性,只要没有在这个元素中专门列出Q就使用默认映射。这样非常简便,因ؓ(f) number 属性已l按照希望的方式处理?jin)?

子元?map-to 告诉 CastorQ要?FlightBean cȝ实例映射?XML 文档中的 flight 元素。如果?zhn)l箋(hu)使用默认的元素名 flight-bean Q参?q后节中默认映输出的例子Q,可以不用该元素?

最后,对于每个希望以非默认方式处理的属性,可以引入一?field 子元素。这些子元素都按照相同的模式Q?name 属性给出映的属性名Q?bind-xml 子元素告?Castor 如何映射那个属性。这里要求把每个属性映成l定名称的属性?

使用映射

现在已经定义?jin)一个映,(zhn)需要告?Castor 框架在编l和解组数据时用那个映。清?4 说明?jin)要实现q一点,需要对前面的代码做哪些修改?/p>

清单 4. 使用映射~组和解l?/b>
...
// write it out as XML (if not already present)
Mapping map = new Mapping();
map.loadMapping("mapping.xml");
File file = new File("test.xml");
Writer writer = new FileWriter(file);
Marshaller marshaller = new Marshaller(writer);
marshaller.setMapping(map);
marshaller.marshal(bean);
// now restore the value and list what we get
Reader reader = new FileReader(file);
Unmarshaller unmarshaller = new Unmarshaller(map);
FlightBean read = (FlightBean)unmarshaller.unmarshal(reader);
...
} catch (MappingException ex) {
ex.printStackTrace(System.err);
...

与前?清单 2默认映射所用的代码相比Q这D代码稍微复杂一炏V在执行M其他操作之前Q首先要创徏一?Mapping 对象载入(zhn)的映射定义。真正的~组和解l也有区别。ؓ(f)?jin)用这个映,?zhn)需要创?Marshaller ?Unmarshaller 对象Q用定义的映配|它们,调用q些对象的方法,而不是像W一个例子那样用静(rn)态方法。最后,(zhn)必L供对映射错误产生的另一个异常类型的处理?

完成q些修改后,(zhn)可以尝试再ơ运行程序。控制台输出与第一个例子相同(?清单 2所C)(j)Q但是现在的 XML 文档看v来符合我们的需要:(x)

<?xml version="1.0"?>
<flight carrier="AR" depart="6:23a" arrive="8:42a" number="426"/>





回页?/font>


处理集合

现在单个航班数据已经有了(jin)我们喜欢的Ş式,(zhn)可以定义一个更高的结构:(x)航线数据。这个结构包括v降机场的标识W以?qing)在该航U上飞行的一l航班。清?5 l出?jin)一个包含这些信息的 bean cȝ例子?/p>

清单 5. 航线信息 bean
import java.util.ArrayList;
public class RouteBean
{
private String m_from;
private String m_to;
private ArrayList m_flights;
public RouteBean() {
m_flights = new ArrayList();
}
public void setFrom(String from) {
m_from = from;
}
public String getFrom() {
return m_from;
}
public void setTo(String to) {
m_to = to;
}
public String getTo() {
return m_to;
}
public ArrayList getFlights() {
return m_flights;
}
public void addFlight(FlightBean flight) {
m_flights.add(flight);
}
}

在这D代码中Q我定义?jin)一?addFlight() Ҏ(gu)Q用于每ơ增加一个属于这条航U的航班。这是在试E序中徏立这U数据结构非常简便的办法Q但是可能和(zhn)预料的相反Q?Castor 在解l时q不使用U方法向航线中增加航班。相反,它?getFlights() Ҏ(gu)讉K一l航班,然后直接d到集合中?

在映中处理航班集合只需要稍微改变(sh)一个例子(?清单 3所C)(j)中的 field 元素。清?6 昄?jin)修改后的映文件?



清单 6. 映射包含一l航班的航线
<!DOCTYPE databases PUBLIC
"-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.exolab.org/mapping.dtd">
<mapping>
<description>Collection mapping example</description>
<class name="RouteBean">
<map-to xml="route"/>
<field name="from">
<bind-xml name="from" node="attribute"/>
</field>
<field name="to">
<bind-xml name="to" node="attribute"/>
</field>
<field name="flights" collection="collection" type="FlightBean">
<bind-xml name="flight"/>
</field>
</class>
<class name="FlightBean" auto-complete="true">
<field name="carrier">
<bind-xml name="carrier" node="attribute"/>
</field>
<field name="departureTime">
<bind-xml name="depart" node="attribute"/>
</field>
<field name="arrivalTime">
<bind-xml name="arrive" node="attribute"/>
</field>
</class>
</mapping>

一切都和上一个映(?清单 3所C)(j)完全相同Q只不过?field 元素定义?jin)一?RouteBean ?flights 属性。这个映用C(jin)两个原来不需要的属性?collection 属性的?collection 把该属性定义成一?java.util.Collection Q其他值分别定义数l,java.util.Vectors {等Q?type 属性定义包含在集合中的对象cdQ值是完整的限定类名。这里的值是 FlightBean Q因为对q些cL没有使用包?

另一个区别在 FlightBean cd素中Q不再需要?map-to 子元素定义绑定的元素名。定?RouteBean ?flights 属性的 field 元素Q通过它的 bind-xml 子元素定义了(jin)q一炏V因为编l或解组 FlightBean 对象只能通过该属性,它们永q用这?bind-xml 元素讑֮的名U?

我不再详l列?gu)个例子的试E序Q因为数据绑定部分和上一个例子相同。以下是用一些示例数据生成的 XML 文档Q?/p>
<?xml version="1.0"?>
<route from="SEA" to="LAX">
<flight carrier="AR" depart="6:23a" arrive="8:42a"
number="426"/>
<flight carrier="CA" depart="8:10a" arrive="10:52a"
number="833"/>
<flight carrier="AR" depart="9:00a" arrive="11:36a"
number="433"/>
</route>





回页?/font>


对象引用

现在可以为处理完整的航班时刻表做最后的准备?jin)。?zhn)q需要增加三?beanQ?

  • AirportBean 用于用于机场信息
  • CarrierBean 用于航线信息
  • TimeTableBean 把一切组合v?

Z(jin)保持味性,除了(jin)上一个例子(参阅 处理集合Q中用到?RouteBean ?FlightBean 之间的从属关p,(zhn)还要在 bean 之间增加一些联pR?

q接 bean

要增加的W一个联pL修改 FlightBean Q让它直接引用班Z息,而不再仅仅用代码标识班机。以下是?FlightBean 的修改:(x)

public class FlightBean
{
private CarrierBean m_carrier;
...
public void setCarrier(CarrierBean carrier) {
m_carrier = carrier;
}
public CarrierBean getCarrier() {
return m_carrier;
}
...
}

然后?RouteBean 做同L(fng)修改Q让它引用机Z息:(x)

public class RouteBean
{
private AirportBean m_from;
private AirportBean m_to;
...
public void setFrom(AirportBean from) {
m_from = from;
}
public AirportBean getFrom() {
return m_from;
}
public void setTo(AirportBean to) {
m_to = to;
}
public AirportBean getTo() {
return m_to;
}
...
}

我没有给出新?bean 自n的代码,因ؓ(f)和前面的代码相比没有什么新鲜的东西。?zhn)可以从下载文?code.jar 中找到完整的CZ代码Q请参阅 参考资?/font>Q?

映射引用

(zhn)可能需要映文档的其他一些特性,以支持编l和解组的对象之间的引用。清?7 l出?jin)一个完整的映射Q?/p>

清单 7. 完整的时刻表映射
<!DOCTYPE databases PUBLIC
"-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.exolab.org/mapping.dtd">
<mapping>
<description>Reference mapping example</description>
<class name="TimeTableBean">
<map-to xml="timetable"/>
<field name="carriers" type="CarrierBean" collection="collection">
<bind-xml name="carrier"/>
</field>
<field name="airports" type="AirportBean" collection="collection">
<bind-xml name="airport"/>
</field>
<field name="routes" type="RouteBean" collection="collection">
<bind-xml name="route"/>
</field>
</class>
<class name="CarrierBean" identity="ident" auto-complete="true">
<field name="ident">
<bind-xml name="ident" node="attribute"/>
</field>
</class>
<class name="AirportBean" identity="ident" auto-complete="true">
<field name="ident">
<bind-xml name="ident" node="attribute"/>
</field>
</class>
<class name="RouteBean">
<field name="from" type="AirportBean">
<bind-xml name="from" node="attribute" reference="true"/>
</field>
<field name="to" type="AirportBean">
<bind-xml name="to" node="attribute" reference="true"/>
</field>
<field name="flights" type="FlightBean" collection="collection">
<bind-xml name="flight"/>
</field>
</class>
<class name="FlightBean" auto-complete="true">
<field name="carrier">
<bind-xml name="carrier" node="attribute" reference="true"/>
</field>
<field name="departureTime">
<bind-xml name="depart" node="attribute"/>
</field>
<field name="arrivalTime">
<bind-xml name="arrive" node="attribute"/>
</field>
</class>
</mapping>

除了(jin)新增?bean 之外Q这里有一个重要的变化Q就是增加了(jin) identity ?reference 属性?class 元素?identity 属性,通知 Castor q个命名属性是该类实例的唯一标识W。在q里Q我?CarrierBean ?AirportBean ?ident 属性定义成它们的标识符?

bind-xml 元素?reference 属性,提供?jin)对于该映?Castor 所需要的另一部分链接信息?reference 设ؓ(f) true 的映告?Castor ~组和解l引用对象的标识W,而不是对象本w的副本。从 RouteBean 链接 AirportBean Q表CU的h点)(j)的引用,?FlightBean 链接 CarrierBean 的引用,都用了(jin)q种Ҏ(gu)?

?Castor 使用q种cd的映解l数据时Q它自动把对象标识符转化为对实际对象的引用。?zhn)需要保证标识符的值确实是唯一的,甚至不同cd的对象之间也要保证这U唯一性。对于本例中的数据,q一点不成问题:(x)飞机的标识符是两个字W,而机场的标识W是三个字符Q永q不?x)冲H。如?有潜在冲H的可能性,只要在所代表的对象类型的每个标识W加上唯一的前~Q就可以很容易地避免q种问题?

~组后的时刻?/font>

q个例子的测试代码没有新东西Q只是增加了(jin)一些示例数据。清?8 l出?jin)编lŞ成的 XML 文档Q?/p>

清单 8. ~组的时刻表
<?xml version="1.0"?>
<timetable>
<carrier ident="AR" rating="9">
<URL>http://www.arcticairlines.com</URL>
<name>Arctic Airlines</name>
</carrier>
<carrier ident="CA" rating="7">
<URL>http://www.combinedlines.com</URL>
<name>Combined Airlines</name>
</carrier>
<airport ident="SEA">
<location>Seattle, WA</location>
<name>Seattle-Tacoma International Airport</name>
</airport>
<airport ident="LAX">
<location>Los Angeles, CA</location>
<name>Los Angeles International Airport</name>
</airport>
<route from="SEA" to="LAX">
<flight carrier="AR" depart="6:23a" arrive="8:42a" number="426"/>
<flight carrier="CA" depart="8:10a" arrive="10:52a" number="833"/>
<flight carrier="AR" depart="9:00a" arrive="11:36a" number="433"/>
</route>
<route from="LAX" to="SEA">
<flight carrier="CA" depart="7:45a" arrive="10:20a" number="311"/>
<flight carrier="AR" depart="9:27a" arrive="12:04p" number="593"/>
<flight carrier="AR" depart="12:30p" arrive="3:07p" number="102"/>
</route>
</timetable>





回页?/font>


使用数据

现在Q时刻表中的所有数据都最l完成了(jin)Q简单地看一看如何在E序中处理它们。用数据绑定,(zhn)已l徏立了(jin)时刻表的数据l构Q它由几U类型的 bean l成。处理数据的应用E序代码可以直接使用q些 bean?/p>

比方_(d)假设(zhn)要查看在西雅图和洛杉矶之间有哪些航班可供选择Qƈ且要求班具备指定的最低品质评L(fng)别。清?9 l出?jin)用数据绑?bean l构获取q些信息的基本代码(完整的细节请参阅?参考资?/font>下蝲的源文gQ?



清单 9. 航班查找E序代码
private static void listFlights(TimeTableBean top, String from,
String to, int rating) {
// find the routes for outbound and inbound flights
Iterator r_iter = top.getRoutes().iterator();
RouteBean in = null;
RouteBean out = null;
while (r_iter.hasNext()) {
RouteBean route = (RouteBean)r_iter.next();
if (route.getFrom().getIdent().equals(from) &&
route.getTo().getIdent().equals(to)) {
out = route;
} else if (route.getFrom().getIdent().equals(to) &&
route.getTo().getIdent().equals(from)) {
in = route;
}
}
// make sure we found the routes
if (in != null && out != null) {
// find outbound flights meeting carrier rating requirement
Iterator o_iter = out.getFlights().iterator();
while (o_iter.hasNext()) {
FlightBean o_flight = (FlightBean)o_iter.next();
if (o_flight.getCarrier().getRating() >= rating) {
// find inbound flights meeting carrier rating
//  requirement, and leaving after outbound arrives
int time = timeToMinute(o_flight.getArrivalTime());
Iterator i_iter = in.getFlights().iterator();
while (i_iter.hasNext()) {
FlightBean i_flight = (FlightBean)i_iter.next();
if (i_flight.getCarrier().getRating() >= rating
&&
timeToMinute(i_flight.getDepartureTime())
> time) {
// list the flight combination
printFlights(o_flight, i_flight, from, to);
}
}
}
}
}
}

(zhn)可以尝试用前?清单 8中的数据。如果?zhn)询问从西雅图QSEAQ到z杉ӞLAXQ、别大于或{于 8 的班机,׃(x)得到如下的结果:(x)

Leave SEA on Arctic Airlines 426 at 6:23a
return from LAX on Arctic Airlines 593 at 9:27a
Leave SEA on Arctic Airlines 426 at 6:23a
return from LAX on Arctic Airlines 102 at 12:30p
Leave SEA on Arctic Airlines 433 at 9:00a
return from LAX on Arctic Airlines 102 at 12:30p

与文档模型的比较

q里我不准备全面讨论使用 XML 文档模型的等价代码,那太复杂?jin),以单独成章。解册个问题最单的方式Q可能是首先解析 carrier 元素Q创建每个标识符代码到相应对象之间的映射链接。然后用和 清单 9中示例代码类似的逻辑。和使用 bean 的例子相比,每一步都更加复杂Q因Z码用的?XML 成分而不是真正的数据倹{性能可能更糟——只Ҏ(gu)据进行少量的操作q(sh)是问题Q但是如果数据处理是应用E序的核?j),q就?x)成Z个主要的焦点?

如果?bean ?XML 的映中使用更多的数据类型{换,差别?x)更大(无论从代码的复杂性还是从性能的角度看Q。比方说Q假设?zhn)使用很多的航班时_(d)可能希望把文本时间{化成一U更好的国际化表C(如一天内的分钟数Q参?清单 9Q。?zhn)可以选择为文本和国际化格式定义可以替换的 get ?set Ҏ(gu)Q让映射仅仅使用文本形式Q,也可以定义一个定制的 org.exolab.castor.mapping.FieldHandler 实现?Castor 使用q些倹{保留时间值的内部形式Q可以避免匹配清?9 中的航班时进行{换,也许q能加快处理速度?

除了(jin)本文中所q的之外—?FieldHandler 只是一个例子,Castor q有许多qh的特性。但愿这些例子和讨论使?zhn)能够初步领略q个框架的强大功能和灉|性?我相信,(zhn)将和我一样发?Castor 非常有用也非常有?





回页?/font>


l束?/span>

对于使用 XML 交换数据的应用程序,数据l定是文档模型很好的替代品。它化了(jin)~程Q因为?zhn)不必再按?XML 的方式思考。相反,(zhn)可以直接用代表应用程序所用数据含义的对象。与文档模型相比Q它q潜在地提供?jin)更好的内存和处理器使用效率?/p>

本文中,我?Castor 框架展示?jin)一些越来越复杂的数据绑定的例子。所有这些例子都使用所谓的 直接数据l定Q开发h员根据数据定义类Q然后把数据映射?XML 文档l构。下一文章中Q我探讨另一U方法:(x) 模式数据l定Q利用模式(?DTD、XML 模式或者其他的cdQ生成和那个模式对应的代码?

Castor 同时支持模式Ҏ(gu)和本文中介绍的直接绑定,(zhn)将在以后看到更多的 Castor 应用。我q关注着 JSR-031 Java 数据l定标准的进展,q对q些Ҏ(gu)的性能q行比较。更多了(jin)?Java 中的 XML 数据l定q个领域Q请速来讉KL最q的 IBM developerWorks?



参考资?



关于作?/span>

Dennis Sosnoski 是西雅图地区 Java 咨询公司 Sosnoski Software Solutions, Inc.的创始h和首席顾问,他是 J2EE、XML ?Web 服务支持斚w的专家。他已经?30 多年专业软g开发经验,最q几q他集中研究服务器端?Java 技术。Dennis l常在全国性的?x)议上?XML ?Java 技术发表演Ԍ(zhn)可以通过 dms@sosnoski.com?Dennis 联系?/p>



朱岩 2007-03-23 17:52 发表评论
]]>
Castor是ExoLab Group下面的一个开放源代码的项?/title><link>http://www.tkk7.com/zhuyan/articles/105757.html</link><dc:creator>朱岩</dc:creator><author>朱岩</author><pubDate>Fri, 23 Mar 2007 02:43:00 GMT</pubDate><guid>http://www.tkk7.com/zhuyan/articles/105757.html</guid><wfw:comment>http://www.tkk7.com/zhuyan/comments/105757.html</wfw:comment><comments>http://www.tkk7.com/zhuyan/articles/105757.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/zhuyan/comments/commentRss/105757.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/zhuyan/services/trackbacks/105757.html</trackback:ping><description><![CDATA[ <br /> <center> <h4>castor概述</h4> </center> <br />(<font color="#008000"><em>by </em>huihoo.com</font> reimon) <br /><br />Castor是ExoLab Group下面的一个开放源代码的项目,它主要实现的是O/R映射功能。它主要API和数据接口ؓ(f)QJDO-like, SQL, OQL, JDBC, LDAP, XML, DSML。它支持分布式目录事务处理和旉Q提供处理XML、Directory、XADirectory的类库,提供从XML到JAVAcȝ转换机制?<br /><br />上面q段是网上的一D评论,大概介绍?jin)Castor的一些特性,我们需要注意的是,Castor所提供的是Castor JDOQ而不是SUN所提供的JDO规范QJSR000012Q,所以在上面的评Z使用?jin)JDO-likeq样的评语,在后面我们会(x)q一步讨个问题的?<br /><br />呵呵Q不q在我看来,CastorҎ(gu)们的意义Q最重要的就是其XML映射机制和其独创的Castor JDO的机制了(jin)。下面我?x)分别就q两个问题加以介l:(x) <br /><br /><b>一、Castor XML</b><br /><br />我们可以认ؓ(f)q是一个独立的FrameworkQ专门负责与XML打交道。在?jin)解众多的类和API之前Q我们有必要?jin)解其整体的构徏思想。在OOP中,我们都知道,对象是类的实体化Q我们也知道Q在OP中所要完成的工作是将对象持久保存?sh)来Q那么相对的Q我们同样可以用cM的方法将cȝ定义和信息也保存?sh)来Q这是否可以UCؓ(f)CP呢?呵呵Q不叫什么名字,在Castor中的XML处理中,是Ҏ(gu)q样的思想完成?jin)两个独立的功能块,一块负责类到XML的保存和加蝲Q另一块负责对象到XML的保存和加蝲。具体的构造我们可以参看下图:(x) <br /><img src="mhtml:file://D:\My Documents\Huihoo Power_ - castor概述.mht!http://docs.huihoo.com/development/oo/i/castor1.gif" /><br /><br />如上图所描述的,marshaller和unmarshaller负责对象和XML文g间的转换。这U{换过E主要在服务器端完成。在q行中,客户端的h发送到服务器端后,对内存(sh)的对象进行相应操作,然后处理完毕的对象marshall成ؓ(f)XML文gQ或者进一步将XML文g格式化ؓ(f)HTML文g发送到客户端。如果以XML文g格式发送到客户端,那么在客L(fng)实行unmarshall操作XML文gq原为内存(sh)的对象,q样完成了(jin)交互q程?<br /><img src="mhtml:file://D:\My Documents\Huihoo Power_ - castor概述.mht!http://docs.huihoo.com/development/oo/i/castor2.gif" /><br /><br />至于source generator则和TOPLINK中实现的相类|不过它没有提供可视化的XML Schema的工兯(g)已。我们编写好描述cȝ构的XML文gQ然后运行Castor提供的source generator可以自动生成JAVA代码?jin)。有的是,它自动生成的代码和BEAN的风格很cMQ很Ҏ(gu)看懂?<br /><br />对于XML而言Q只要把握了(jin)q样的整体,其他的诸如代码生成中的两U模式、映规范、数据结构问题等l节问题很单了(jin)Q在文档中附有很实用的例子和解释Q这里就不再多说?jin)?<br /><br /><b>二、Castor JDO</b><br /><br />要了(jin)解JDO首先要认识两个基本的问题Q?<br /><br />1、和SUN JDO的关p?<br /><br />Castor JDO和SUN JDOq不相同QCastor JDO是独立于SUN JDO发展h的,但是它们所完成的工作非常相伹{虽然也可以Castor JDO重新定制成SUN JDO那个样子Q但是由于两者在锁定{略上存在的Ҏ(gu)差异Q这样做q不划算。在内部QCastor JDO为所有事务中的每个活动的持久性对象只l护一份锁定(和缓存)(j)的备份。而在SUN中则Ҏ(gu)个事务中的每个持久性对象各l护一个备份,q且SUN JDOq需要字节码~辑器,而CastorJDOq不需要。Castorq提供了(jin)其他的一些特性,比如说key generatorsQlong transaction support 以及(qing) OQL queryQ这些都在SUN的JSR中是看不到的。所以我们在前面对Castor的评hJDO-LIKE的?<br /><br />2、和EJB的关p?<br /><br />Castor和EJB很难说谁更好一些?<br /><br />一个实体Bean可以理它自w的持久化。它要么调用BMPQBean Managed PersistenceQ来自己理持久化,要么׃靠它的容器的CMP(Container Managed Persistence)来做到持久化?<br /><br />对于BMP来说Q一个实体BEAN可以使用Castor JDO作ؓ(f)它的持久化机Ӟ也可以用其他的机制Q比如说直接调用JDBC?<br /><br />对于CMP来说Q一个EJB Container可以它们的CMPZCastor JDO来实玎ͼ那么Castor JDO被用来实体BEAN持久化。如果开发者需要EJB的life-cycle理, , "write once deploy anywhere" 和其他分布式应用E序的优点,那么你直接用EJB。否则,使用Castor会(x)更简单,而且q开放源代码Q开销更小Qƈ提供更多的设计自由性,以及(qing)所提供的集成的XML支持。我们应当根据实际情冉|选择所使用的机制?<br /><br />具体的用我׃知道怎么说了(jin)Q呵呵,下面把它的一个概括性介l的文档l翻译了(jin)下来QCastor JDO的一些基本的使用Ҏ(gu)里面基本上都介l或者提?qing)?jin)Q比如说JDO的两U用环境的区别、OQL query、生存期问题、基本语义、与XML联用{,如果需要更具体的情况请自行查询Castor的文档?<br /><br /><译来自castor的联机文档-QCastor JDO概况> <br /><br />打开一个JDO数据?<br /><br />CatorJDO支持两种cd的环境,客户端应用程序和J2EE服务器。客L(fng)应用E序负责讄数据库连接和理事务处理。J2EE应用E序使用JNDI来获取预先配|好的数据库q接Qƈ且用UserTransaction或者CMT(container managed transaction)来管理事务。如果你在这两种环境中用qJDBCQ那么你对它们之间的异同?x)很了(jin)解?<br /><br />客户端应用程?<br /><br />客户端应用程序负责设|数据库q接和管理事务处理。数据库的设|是通过一个与映射文g相连接的独立的XML文g来实现的。在例子中就是database.xml,但是其实我们可以使用M的名字?<br /><br />org.exolab.castor.jdo.JDO定义?jin)数据库的名字和属性,q被用来打开一个数据库q接。通过使用setConfiguration命o(h)来指定配|文件URLQ我们可以装载数据库的配|。用同一个配|来创徏多个JDO对象只会(x)装蝲配置文g一ơ?org.exolab.castor.jdo.Database对象实现?jin)到数据库的开放连接。在定义里,database对象不是thread safe因而不应该用于q发q程中。当开启多个Database对象是会(x)有一点开销Qƈ且JDBCq接is acquired only per open transaction。下面的代码片显CZ(jin)在典型的客户端应用程序中的打开一个数据库Q运行一个事务,然后关闭数据库的q程?<br /><br />JDO jdo; <br />Database db; <br /><br />// 定义JDO对象 <br />jdo = new JDO(); <br />jdo.setDatabaseName( "mydb" ); <br />jdo.setConfiguration( "database.xml" ); <br />jdo.setClassLoader( getClass().getClassLoader() ); <br /><br />// 获取一个新的数据库 <br /><br />db = jdo.getDatabase(); <br /><br />// 开始事务处?<br />db.begin(); <br /><br />// 事务q程 <br />. . . <br /><br />// 提交事务Q关闭数据库 <br />db.commit(); <br />db.close(); <br /><br />J2EE E序( 不太懂,所以没译,大概说的是在J2EE中由于用持久化方式的不通而生的~码不同的问题,可以参考一下我们前面对EJB持久化问题的探讨) <br /><br />Note: We are now working on supporting Castor inside a J2EE container. Stay tuned for more information. J2EE applications depend on the J2EE container (Servlet, EJB, etc) to configure the database connection and use JNDI to look it up. This model allows the application deployer to configure the database properties from a central place, and gives the J2EE container the ability to manage distributed transactions across multiple data sources. Instead of constructing a org.exolab.castor.jdo.JDO the application uses the JNDI namespace to look it up. We recommend enlisting the JDO object under the java:comp/env/jdo namespace, compatible with the convention for listing JDBC resources. <br /><br />下面的代码片使用JNDI来查找一个数据库Qƈ且用UserTransaction来进行事务管理:(x) <br /><br />InitialContext ctx; <br />UserTransaction ut; <br />Database db; <br /><br />// 在JNDI中查找数据库 <br />ctx = new InitialContext(); <br />db = (Database) ctx.lookup( "java:comp/env/jdo/mydb" ); <br /><br />// 开始事务处?<br />ut = (UserTransaction) ctx.lookup( "java:comp/UserTransaction" ); <br />ut.begin(); <br /><br />// 事务q程 <br />. . . <br /><br />// 提交事务Q关闭数据库 <br />ut.commit(); <br />db.close(); <br /><br />When the transaction is managed by the container, a common case with EJB beans and in particular entity beans, there is no need to being/commit the transaction explicitly. Instead the application server takes care of enlisting the database in the ongoing transaction and commiting/rollingback at the proper time. <br /><br />The following code snippet relies on the container to manage the transaction: <br /><br />InitialContext ctx; <br />UserTransaction ut; <br />Database db; <br /><br />// Lookup databse in JNDI <br />ctx = new InitialContext(); <br />db = (Database) ctx.lookup( "java:comp/env/jdo/mydb" ); <br /><br />// Do something <br />. . . <br /><br />// Close the database <br />db.close(); <br /><br />ȝQ开启一个数据库在客L(fng)和在服务器端是有区别的,主要体现在事务处理的q程、配|问题等上面Q需要注意?<br /><br />使用JDO数据?<br />临时对象和持久对?<br />所有的JDO操作都发生在事务中。事务提交时QJDO数据从数据库中加蝲到内存(sh)的对象中Q让应用E序对对象进行操作,然后再将对象的新状态存储到数据库中。所有的对象可以是两U状态:(x)临时的或者持久的?<br />临时的:(x)指当事务提交时状态不?x)被保存的对象。对对象的修改不?x)表现在数据库中?<br />持久的:(x)指当事务提交时状态将被保存的对象。对对象的修改将反映在数据库中?<br />在下面情况下对象为持久的Q?1、一个查询的l果Q?<br />2、用create(java.lang.Object)或者update(java.lang.Object)它加入到数据库中?<br />所有不是持久性的对象是临时性对象,当事务提交或者回滚时Q所有的持久性对象变成(f)时对象?<br />在客L(fng)E序中,使用begin()Qcommit()和rollback()来管理事务。在J2EEE序中,JDO依靠container来含蓄或明确Q基于bean的transaction属性|(j)的用javax.transaction.UserTransaction接口来管理事务?<br />如果一个持久对象在事务中被改变?sh)(jin),在提交时修改会(x)存入数据库。如果事务回滚,数据库不?x)被改变。如果要在两个不同的事务中用同一个对象,你必重新查询?<br />对象的(f)时和持久是从事务所属的数据库的角度来看的。一般来说持久对象只是对于一个数据库而言Q如果在另外一个数据库中调用isPersistent(java.lang.Object)返回false。当然也可以让一个持久对象对应于两个数据库,比如说在一个数据库中运行查询,而在另一个数据库中创建它?<br />OQLQuery <br />OQL查询被用来从数据库中查询和寻扑֯象。OQL查询和SQL查询cMQ但是用对象名U而不是SQL名称Qƈ且不需要join子句。比如说Q如果类型ؓ(f)TestObject的对象被加蝲?jin),OQL查询用“FROM TestObject”,而不到底表名ؓ(f)什么。如果加载关联的对象需要joinQCastor自动实现连接?<br />下面的代码片使用OQL查询来加载指定组中所有的对象。注意品和l是兌的对象,JDBC查询使用?jin)连接?x) <br /><br />OQLQuery oql; <brt>QueryResults results; <br /><br />// Construct a new query and bind its parameters <br />oql = db.getOQLQuery( "SELECT p FROM Product p WHERE Group=$" ); <br />oql.bind( groupId ); <br /><br />// Retrieve results and print each one <br />results = oql.execute(); <br />while ( results.hasMore() ) { <br />System.out.println( results.next() ); <br />} <br /><br />下面的代码片使用前面的查询来获得产品Q将它们的h(hun)格减?5%Qƈ且将它们存(sh)(x)数据库(在这里用了(jin)客户端程序事务)(j)Q?<br />while ( results.hasMore() ) { <br />Product prod; <br />prod = (Product) results.next(); <br />prod.markDown( 0.25 ); <br />prod.setOnSale( true ); <br />} <br /><br />// Explicitly commit transaction <br />db.commit(); <br />db.close(); <br /><br />如上面所描述的,查询分三个步骤实玎ͼ(x)一、用OQL语法从数据库中创Z个query对象Q二、如果有参数Q就参数绑定到查询中。参数绑定的序和它们在OQL语法中出现的序保持一_(d)三、执行查询ƈ获得一pd为org.exolab.castor.jdo.QueryResults的对象。查询创Zơ后可以多次使用Q不q每ơ都得重新绑定参数。查询再ơ执行后Q上一ơ的l果集可以l用。参考下面的代码来调用存储过E:(x) <br />oql = db.getOQLQuery( "CALL sp_something($) AS myapp.Product" ); 在这里sp_something是一个返回一个或多个l果集的存储q程Q字D顺序和前面相同Q对于没有关联的对象Q顺序ؓ(f)Q标识符Q接下来是所有其他的字段Q顺序和mapping.xml中定义的序一_(d)(j)?<br />Create/remove/update <br />create(java.lang.Object)Ҏ(gu)在数据库中创Z个新的对象,或者在JDO terminology中得一个(f)时对象持久化。如果事务被提交的话Q这个用createҎ(gu)创徏的对象将保持在数据库中,否则被删除。如果用数据库中已l存在的标识来创建对象,会(x)产生一个异常?下面的代码片为先前查询出来的一个组创徏?jin)一个新的品:(x) <br /><br />Product prod; <br />// Create the Product object <br />prod = new Product(); <br />prod.setSku( 5678 ); <br />prod.setName( "Plastic Chair" ); <br />prod.setPrice( 55.0 ); <br />prod.setGroup( furnitures ); <br /><br />// Make is persistent <br />db.create( prod ); <br /><br />remove(java.lang.Object)Ҏ(gu)产生相反的效果,它将删除一个持久性对象。一旦删除,M事务都无法用该对象。如果事务提交,q个对象从数据库中删除Q否则对象将仍然存在于数据库中。如果试囑ֈ除一个非持久性对象,生异常?<br /><br />使用 JDO ?XML <br /><br />CastorJDO和CastorXMLl合hQ可以通过使用XML作ؓ(f)输入和输出来实现事务性数据库操作。下面的E序片用持久性和临时性对象的l合来描qC个胦(ch)务操作?<br /><br />q个例子获取?jin)两个account对象q且从其中一个{UM(jin)一W金额到另外一个̎戗{U被描述Z用一个(f)时对象(比如说无数据库中的记录)(j)Q这个对象接下来被用于生成一个XML文档来描q这ơ{U过E。另外还有一个附加的q程Q这里没有表现出来)(j)Q是使用XSLT来将XML文档转换Z个HTML面?<br /><br />Transfer tran; <br />Account from; <br />Account to; <br />OQLQuery oql; <br />tran = new Transfer(); <br /><br />// Construct a query and load the two accounts <br />oql = db.getOQLQuery( "SELECT a FROM Account a WHERE Id=$" ); <br />oql.bind( fromId ); <br />from = oql.execute().nextElement(); <br />oql.bind( toId ); <br />to = oql.execute().nextElement(); <br /><br />// Move money from one account to the other <br />if ( from.getBalance() >= amount ) { <br />from.decBalance( amount ); <br />to.incBalance( amount ); <br />trans.setStatus( Transfer.COMPLETE ); <br />trans.setAccount( from ); <br />trans.setAmount( amount ); <br />} else { <br /><br />// Report an overdraft <br />trans.setStatus( Transfer.OVERDRAFT ); <br />} <br /><br />// Produce an XML describing the transfer <br />Marshaller.marshal( trans, outputStream ); <br />The XML produced by the above code might look like: <br /><br /><brt><br /><report><br /><status>Completed</status><br /><account id="1234-5678-90" balance="50" /><br /><transfer amount="49.99" /><br /></report><br /><br />ȝQ在使用数据库的q程中,我们需要区分好临时对象和持久对象,q掌握灵z运用它们的Ҏ(gu)Q另外,Castor所支持的OQL的用法也值得研究Q我们可以参考Castor所提供的详l文档进一步了(jin)解?/brt></brt><img src ="http://www.tkk7.com/zhuyan/aggbug/105757.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/zhuyan/" target="_blank">朱岩</a> 2007-03-23 10:43 <a href="http://www.tkk7.com/zhuyan/articles/105757.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.tkk7.com/" title="亚洲av成人片在线观看">亚洲av成人片在线观看</a> <div class="friend-links"> </div> </div> </footer> վ֩ģ壺 <a href="http://www-554757.com" target="_blank">ۺ͵Ļ</a>| <a href="http://33sse.com" target="_blank">AVһ</a>| <a href="http://xx16xx.com" target="_blank">պӰ</a>| <a href="http://caocl1024liu.com" target="_blank">պëƬ޶Ƶۿ</a>| <a href="http://tttui.com" target="_blank">Ƶ߹ۿ </a>| <a href="http://shadaiym.com" target="_blank">AVվ߹ۿ</a>| <a href="http://ywgj50225.com" target="_blank">AVۺɫAV</a>| <a href="http://0359puju.com" target="_blank">һ</a>| <a href="http://www62hth.com" target="_blank">޹av߲</a>| <a href="http://8884493.com" target="_blank">Ʒþһ</a>| <a href="http://lebaojj.com" target="_blank">Ƶ</a>| <a href="http://44g8.com" target="_blank">޾Ʒ˳߲ӰԺ </a>| <a href="http://wwwly6080.com" target="_blank">޹˾þһþ</a>| <a href="http://cct68.com" target="_blank">ŷղһëƬ</a>| <a href="http://www-7607.com" target="_blank">þþþAV</a>| <a href="http://jjwgzx.com" target="_blank">͵v͵v޸</a>| <a href="http://fennenll.com" target="_blank">AV뾫Ʒɫҹ </a>| <a href="http://rr7733.com" target="_blank">պƷһҳһ</a>| <a href="http://jiajuco.com" target="_blank">ڵ߿</a>| <a href="http://njyadi.com" target="_blank">ֻˬʹƬҹ </a>| <a href="http://mordernshasha.com" target="_blank">˳վ߲ӰԺ</a>| <a href="http://chandou8.com" target="_blank">˾Ʒ</a>| <a href="http://yw5168.com" target="_blank">ŷ޾Ʒ˾þԻӰƬ</a>| <a href="http://7778kk.com" target="_blank">޾ƷþþӰԺӰƬ </a>| <a href="http://hongyue8.com" target="_blank">߹ۿƵ</a>| <a href="http://yjjinfeng.com" target="_blank">þùƷһ</a>| <a href="http://yutuzb.com" target="_blank">99þѹۿ</a>| <a href="http://xiaojiejieav.com" target="_blank">߹ۿվ </a>| <a href="http://fl6fe.com" target="_blank">www߹ۿ</a>| <a href="http://78555yy.com" target="_blank">ɫһ</a>| <a href="http://wkk3.com" target="_blank">eeussӰԺֱ</a>| <a href="http://011107.com" target="_blank">þþƷ˳</a>| <a href="http://leeszewan.com" target="_blank">avƬ߿</a>| <a href="http://yhanalati.com" target="_blank">ٸѾƷ</a>| <a href="http://zzhjnmzp.com" target="_blank">þԭAV鶹</a>| <a href="http://zmnhssn.com" target="_blank">˳վ</a>| <a href="http://tsxyhq.com" target="_blank">ؼëƬѹۿƵ</a>| <a href="http://adcacs.com" target="_blank">һ</a>| <a href="http://xdxsw.com" target="_blank">ëƬ߹ۿ</a>| <a href="http://zanyoo.com" target="_blank">ҹľƷ</a>| <a href="http://jdwx58.com" target="_blank">91޾ƷƵ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>