- 浏览: 63912 次
- 性别:
- 来自: 武汉
最新评论
-
武大鹏程加内特:
武大鹏程加内特 写道任雅菲 写道
3Q 呵呵
你QQ多少? ...
第十一章 MyEclipse自动生成映射文件(上) -
武大鹏程加内特:
zzy90718 写道
第九章 Spring配置数据连接池 -
武大鹏程加内特:
任雅菲 写道
3Q 呵呵
第十一章 MyEclipse自动生成映射文件(上) -
武大鹏程加内特:
任雅菲 写道
第十一章 MyEclipse自动生成映射文件(上) -
任雅菲:
第十一章 MyEclipse自动生成映射文件(上)
继承模型
在企业中经常会有员工的分类
我们在Java对象模型中可以使用继承的关系来实现,如下图:
一张表映射
数据库中表的结构如下:
ID 姓名 地址 生日 开发人员技能 销售人员技能 员工类型
我们可以约定一种员工类型的规则,比如0普通员工,1开发人员,2销售人员
接下来,我们看一下Model层的实现和映射文件的编写:
Employee:
public class Employee {
protected String id;
protected String name;
protected String address;
protected Date birthday;
public Employee() {
super();
}
public Employee(String name, String address, Date birthday) {
super();
this.name = name;
this.address = address;
this.birthday = birthday;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
Programmer:
public class Programmer extends Employee {
private String skill;
public Programmer(String name, String address, Date birthday, String skill) {
super(name, address, birthday);
this.skill = skill;
}
public Programmer() {
super();
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
Seller:
public class Seller extends Employee {
private String sell;
public Seller() {
super();
}
public Seller(String name, String address, Date birthday, String sell) {
super(name, address, birthday);
this.sell = sell;
}
public String getSell() {
return sell;
}
public void setSell(String sell) {
this.sell = sell;
}
}
映射文件:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees"
discriminator-value="0">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid.hex" />
</id>
<discriminator column="type" type="int" />
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday"
length="10" />
<subclass name="chapter5.model.Programmer" discriminator-value="1">
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</subclass>
<subclass name="chapter5.model.Seller" discriminator-value="2">
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</subclass>
</class>
</hibernate-mapping>
<discriminator column="type" type="int" />
鉴别器是给Hibernate来区分类型用的.就像listIndex是给list标签来记住元素顺序的作用是一样的,我们使用时不需要去理会这个字段,我们还是按我们平常的使用方式即可.
Dao层:
public class EmployeeDao {
public void create(Employee employee) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.save(employee);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
public void delete(Employee employee) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.delete(employee);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
public void update(Employee employee) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.update(employee);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
public Employee findById(Serializable id) throws Exception {
Session session = null;
Employee employee = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
employee = (Employee) session.get(Employee.class, id);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
return employee;
}
}
Test:
public class Test {
public static void main(String[] args) throws Exception {
EmployeeDao employeeDao = new EmployeeDao();
Employee employee = new Employee("张三", "武汉", new Date());
Programmer programmer = new Programmer("李四", "咸宁", new Date(),
"Java,sql,JS");
Seller seller = new Seller("李四", "襄樊", new Date(), "一流的销售技能");
employeeDao.create(employee);
employeeDao.create(programmer);
employeeDao.create(seller);
}
}
查找员工时应该注意要转型:
public class Test {
public static void main(String[] args) throws Exception {
EmployeeDao employeeDao = new EmployeeDao();
Employee employee = employeeDao
.findById("40285c8127d5f31b0127d5f31d4e0001");
System.out.println(employee.getName());
Programmer programmer = (Programmer) employeeDao
.findById("40285c8127d5f31b0127d5f31dbb0002");
System.out.println(programmer.getName() + ":" + programmer.getSkill());
Seller seller = (Seller) employeeDao
.findById("40285c8127d5f31b0127d5f31dcb0003");
System.out.println(seller.getName() + ":" + seller.getSell());
}
}
这种方法有个僻端:
可以看到数据库中,有很多空白的字段出现.
解决方案:每个类映射到一张表
员工表:
ID 姓名 地址 生日
开发人员表
ID(主键,外键) 掌握的开发技能
销售人员表
ID(主键,外键) 掌握的销售技能
表之间的关系
类模型不动,主要改动配置文件即可.
Dao层也不动,Test也不动
配置文件改动如下:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid.hex" />
</id>
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday" />
<joined-subclass name="chapter5.model.Programmer"
table="programmer">
<key column="id" />
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</joined-subclass>
<joined-subclass name="chapter5.model.Seller" table="seller">
<key column="id" />
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</joined-subclass>
</class>
</hibernate-mapping>
<key column="id" /> id在这里即是主键又是外键, 和一对一关系差不多, 指定的是子表的ID
再运行一下Test文件的增加代码,可以看到生成了三张表.
运行一下查询代码,可以看到,查询是多表联合查询,在查询效率上比一张表要复杂一些,但是在表结构上却合理的多.
第三种解决方案
鉴别器与子表接合方案
比如开发人员表中只有一个字段,销售人员表中有多个字段,那么为开发人员单独加一张表有点浪费,可以将开发人员表与普通员工表二合一,只需要单独为销售人员增加一张表即可.
只需要改动配置文件即可:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees"
discriminator-value="0">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid.hex" />
</id>
<discriminator column="type" type="int" />
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday" />
<subclass name="chapter5.model.Programmer"
discriminator-value="1">
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</subclass>
<subclass name="chapter5.model.Seller" discriminator-value="2">
<join table="seller">
<key column="id" />
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</join>
</subclass>
</class>
</hibernate-mapping>
第四种解决方案:
每个类映射一张表
适用于公共字段较少的情况.
映射文件如下:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid.hex" />
</id>
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday" />
<union-subclass name="chapter5.model.Programmer" table="programmer">
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</union-subclass>
<union-subclass name="chapter5.model.Seller" table="seller">
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</union-subclass>
</class>
</hibernate-mapping>
以上就是解决继承的四种方案
在企业中经常会有员工的分类
我们在Java对象模型中可以使用继承的关系来实现,如下图:
一张表映射
数据库中表的结构如下:
ID 姓名 地址 生日 开发人员技能 销售人员技能 员工类型
我们可以约定一种员工类型的规则,比如0普通员工,1开发人员,2销售人员
接下来,我们看一下Model层的实现和映射文件的编写:
Employee:
public class Employee {
protected String id;
protected String name;
protected String address;
protected Date birthday;
public Employee() {
super();
}
public Employee(String name, String address, Date birthday) {
super();
this.name = name;
this.address = address;
this.birthday = birthday;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
Programmer:
public class Programmer extends Employee {
private String skill;
public Programmer(String name, String address, Date birthday, String skill) {
super(name, address, birthday);
this.skill = skill;
}
public Programmer() {
super();
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
Seller:
public class Seller extends Employee {
private String sell;
public Seller() {
super();
}
public Seller(String name, String address, Date birthday, String sell) {
super(name, address, birthday);
this.sell = sell;
}
public String getSell() {
return sell;
}
public void setSell(String sell) {
this.sell = sell;
}
}
映射文件:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees"
discriminator-value="0">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid.hex" />
</id>
<discriminator column="type" type="int" />
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday"
length="10" />
<subclass name="chapter5.model.Programmer" discriminator-value="1">
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</subclass>
<subclass name="chapter5.model.Seller" discriminator-value="2">
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</subclass>
</class>
</hibernate-mapping>
<discriminator column="type" type="int" />
鉴别器是给Hibernate来区分类型用的.就像listIndex是给list标签来记住元素顺序的作用是一样的,我们使用时不需要去理会这个字段,我们还是按我们平常的使用方式即可.
Dao层:
public class EmployeeDao {
public void create(Employee employee) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.save(employee);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
public void delete(Employee employee) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.delete(employee);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
public void update(Employee employee) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.update(employee);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
public Employee findById(Serializable id) throws Exception {
Session session = null;
Employee employee = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
employee = (Employee) session.get(Employee.class, id);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
return employee;
}
}
Test:
public class Test {
public static void main(String[] args) throws Exception {
EmployeeDao employeeDao = new EmployeeDao();
Employee employee = new Employee("张三", "武汉", new Date());
Programmer programmer = new Programmer("李四", "咸宁", new Date(),
"Java,sql,JS");
Seller seller = new Seller("李四", "襄樊", new Date(), "一流的销售技能");
employeeDao.create(employee);
employeeDao.create(programmer);
employeeDao.create(seller);
}
}
查找员工时应该注意要转型:
public class Test {
public static void main(String[] args) throws Exception {
EmployeeDao employeeDao = new EmployeeDao();
Employee employee = employeeDao
.findById("40285c8127d5f31b0127d5f31d4e0001");
System.out.println(employee.getName());
Programmer programmer = (Programmer) employeeDao
.findById("40285c8127d5f31b0127d5f31dbb0002");
System.out.println(programmer.getName() + ":" + programmer.getSkill());
Seller seller = (Seller) employeeDao
.findById("40285c8127d5f31b0127d5f31dcb0003");
System.out.println(seller.getName() + ":" + seller.getSell());
}
}
这种方法有个僻端:
可以看到数据库中,有很多空白的字段出现.
解决方案:每个类映射到一张表
员工表:
ID 姓名 地址 生日
开发人员表
ID(主键,外键) 掌握的开发技能
销售人员表
ID(主键,外键) 掌握的销售技能
表之间的关系
类模型不动,主要改动配置文件即可.
Dao层也不动,Test也不动
配置文件改动如下:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid.hex" />
</id>
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday" />
<joined-subclass name="chapter5.model.Programmer"
table="programmer">
<key column="id" />
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</joined-subclass>
<joined-subclass name="chapter5.model.Seller" table="seller">
<key column="id" />
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</joined-subclass>
</class>
</hibernate-mapping>
<key column="id" /> id在这里即是主键又是外键, 和一对一关系差不多, 指定的是子表的ID
再运行一下Test文件的增加代码,可以看到生成了三张表.
运行一下查询代码,可以看到,查询是多表联合查询,在查询效率上比一张表要复杂一些,但是在表结构上却合理的多.
第三种解决方案
鉴别器与子表接合方案
比如开发人员表中只有一个字段,销售人员表中有多个字段,那么为开发人员单独加一张表有点浪费,可以将开发人员表与普通员工表二合一,只需要单独为销售人员增加一张表即可.
只需要改动配置文件即可:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees"
discriminator-value="0">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid.hex" />
</id>
<discriminator column="type" type="int" />
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday" />
<subclass name="chapter5.model.Programmer"
discriminator-value="1">
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</subclass>
<subclass name="chapter5.model.Seller" discriminator-value="2">
<join table="seller">
<key column="id" />
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</join>
</subclass>
</class>
</hibernate-mapping>
第四种解决方案:
每个类映射一张表
适用于公共字段较少的情况.
映射文件如下:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid.hex" />
</id>
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday" />
<union-subclass name="chapter5.model.Programmer" table="programmer">
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</union-subclass>
<union-subclass name="chapter5.model.Seller" table="seller">
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</union-subclass>
</class>
</hibernate-mapping>
以上就是解决继承的四种方案
发表评论
-
第十七章 离线,命名查询
2010-05-03 20:29 825 离线查询 在Hibernate中,查询有两种方式,一种是 ... -
第十六章 批量插入,多类分页查询
2010-05-03 20:26 956批量插入 有时候我们需要做导入的功能,那么这个时候就需要批量插 ... -
第十五章 事务边界问题
2010-05-03 20:24 2590 事务边界问题 我们先回顾一下我们现在写的代码: 可 ... -
第十四章 缓存的使用
2010-05-03 20:18 826缓存的使用 我们先来模拟一个缓存的机制 以查询学生为示例: p ... -
第十三章 lazy懒加载
2010-05-03 20:12 945lazy属性:懒加载 作用:当调用方法的时候才去执行要执行的S ... -
第十一章 MyEclipse自动生成映射文件(下)
2010-04-28 19:57 1251选中必要的选项 选择主键生成的策略: 设置类名与数据库 ... -
第十一章 MyEclipse自动生成映射文件(上)
2010-04-28 19:44 3191 设置数据库连接 转换视图 创建新的数据库连接 设置 ... -
第十章 Inverse的作用
2010-04-28 19:04 741Inverse的作用 我们还是拿上一章的班级与学生的示例来说 ... -
第九章 级联,集合映射
2010-04-28 19:03 763级联开关 1.级联是指两个对象之间的操作联动关系,对一个对象执 ... -
第八章 Hibernate分页
2010-04-28 18:55 655Hibernate分页 -
第七章 多对多
2010-04-28 18:50 637 多对多 什么情况下会出现多对多呢?比如学生选课就会出现多 ... -
第六章 一对一关系
2010-04-28 18:49 744什么时候采用一对一关系映射呢? 比如我们有时在网上注册的时候, ... -
第五章 一对多关系
2010-04-28 18:44 797 一对多的关系 在学生与班级对象模型中,通常多个学生实体对应 ... -
第四章 多对一关系
2010-04-28 18:43 838今天我们讲多表操作, 多对一的关系 何为多对一呢? 示例: 学 ... -
第三章 对象的状态
2010-04-28 18:42 852 current_session_context_class ... -
第二章 Hibernate增删改查参考
2010-04-28 18:39 1659Hibernate中对增删改查的小结 mysql中库表N ... -
第二章 策略及对象增删改查操作
2010-04-28 18:37 1067Generator 主键生成器 incre ... -
第二章 对象关系数据库映射基础
2010-04-28 18:35 899Generator 主键生成器 incre ... -
第一章 Hibernate环境搭建
2010-04-28 18:34 1415如果是WEB工程,我们只需 ...
相关推荐
第十二章迭代器 第十三章迭代器的实现 第十四章堆栈 第十五章队列与优先队列 第十六章二叉树 第十七章二叉树的应用 第十八章二叉搜索树 第十九章集与映射 第二十章有序集与映射的实现 第二十一章实现映射的散列法 第...
第 10 章 继承映射(Inheritance Mapping) 第 11 章 与对象共事 第 12 章 Read-only entities 第 13 章 事务和并发 第 14 章 拦截器与事件(Interceptors and events) 第 15 章 批量处理(Batch...
第12章 高级I/O 273 12.1 引言 273 12.2 非阻塞I/O 273 12.3 记录锁 275 12.3.1 历史 276 12.3.2 fcntl记录锁 276 12.3.3 锁的隐含继承和释放 280 12.3.4 4.3+BSD的实现 281 12.3.5 建议性锁和强制性锁 284 12.4 流 ...
第12章 基于annotation注解技术的ssh 2整合开发 12.1 初识annotation522 12.2 亲身体验annotation的威力524 12.3 struts 2.x的annotation插件convention-plugin528 12.4 hibernate 3.x的annotation解决之道532 ...
第12部分 查询之使用SQL语句 第13部分 查询之使用Entity SQL 第14部分 查询之查询中设置默认值和存储过程返回多结果集 第15部分 查询之与列表值比较和过滤关联实体 第16部分 查询之左连接和在TPH中通过派生类排序 第...
第12章 映射继承关系 12.1 继承关系树的每个具体类对应一个表 12.1.1 创建映射文件 12.1.2 操纵持久化对象 12.2 继承关系树的根类对应一个表 12.2.1 创建映射文件 12.2.2 操纵持久化对象 12.3 继承...
第12章 映射继承关系 12.1 继承关系树的每个具体类对应一个表 12.1.1 创建映射文件 12.1.2 操纵持久化对象 12.2 继承关系树的根类对应一个表 12.2.1 创建映射文件 12.2.2 操纵持久化对象 12.3 继承...
第12章 映射继承关系 12.1 继承关系树的每个具体类对应一个表 12.1.1 创建映射文件 12.1.2 操纵持久化对象 12.2 继承关系树的根类对应一个表 12.2.1 创建映射文件 12.2.2 操纵持久化对象 12.3 继承...
第12章 映射继承关系 12.1 继承关系树的每个具体类对应一个表 12.1.1 创建映射文件 12.1.2 操纵持久化对象 12.2 继承关系树的根类对应一个表 12.2.1 创建映射文件 12.2.2 操纵持久化对象 12.3 继承...
本书是为全英文版本。...第12章 uml和模式 第13章 借口和内部类 第14章 泛型和arraylist类 第15章 链式数据结构 第16章 稽核,映射和迭代器 第17章 初探swing 第18章 深入swing 第19章 java的发展永无止境
第12章 与Spring整合 155 12.1 依赖注入与Spring容器基础 155 12.1.1 依赖注入 155 12.1.2 Spring容器基础 157 12.2 在Grails中使用Spring 158 12.3 本章小结 160 第13章 深入Controller 161 13.1 Controller中常用...
第12章 动态对象创建 12.1对象创建 12.1.1C从堆中获取存储单元的方法 12.1.2运算符new 12.1.3运算符delete 12.1.4一个简单的例子 12.1.5内存管理的开销 12.2重新设计前面的例子 12.2.1仅从堆中创建string类 12.2.2...
第十二章:高级I/O流 192 学习目标 192 I/O基础知识 193 字节流 193 字符流 194 节点流 194 过程流 194 基本字符流类 198 对象串行化 201 实例分析 203 内容总结 211 独立实践 212 第十三章:网络 213 学习目标 213 ...
第12章 有效修改对象 12.1 传播性持久化 12.1.1 按可到达性持久化 12.1.2 把级联应用到关联 12.1.3 使用传播性状态 12.1.4 利用JPA的传播性关联 12.2 大批量和批量操作 12.2.1 使用...
第5章 集合类(Collections)映射 13 持久化集合类(Persistent Collections) 13 映射集合(Mapping a Collection) 13 值集合和多对多关联(Collections of Values and Many-To-Many Associations) 14 一对多关联(One-To-...
Hibernate的继承关系 21 每棵继承树映射成一张表(hibernate_extends_1) 22 每个子类映射成一张表(hibernate_extends_2) 24 每个具体类映射成一张表(hibernate_extends_3) 25 组件component映射(hibernate_...
第12章 高级纹理技术 12.1 多层纹理映射 12.2 纹理阶段混合操作 12.2.1 黑暗映射 12.2.2 黑暗贴图动画 12.2.3 混合纹理与材质漫反射颜色 12.2.4 混合黑暗贴图与材质漫反射颜色 12.2.5 发光映射 12.2.6 细节映射 ...
《深入浅出MFC》2/e 简体版 目录 ...第12章 打印与预览 第13章 多重文件与多重显示 第14章 MFC多线程程序设计 第15章 定制一个AppWizard 第16章 站上众人的肩膀——使用Components&activeX; Controls