openxava / 文档 / 第八章:视图继承(View)

课程:1. 入门教学 | 2. 基本域模型(上) | 3. 基本域模型(下) | 4. 优化用户界面 | 5. 敏捷开发 | 6. 映射式超类继承 | 7. 实体继承 | 8. 视图继承(View) | 9. Java 属性  | 10. 计算属性 | 11. 用在集合的 @DefaultValueCalculator | 12. @Calculation 和集合总计 | 13. 从外部文件的 @DefaultValueCalculator | 14. 手动更改 schema | 15. 多用户时默认值的计算 | 16. 同步持久属性和计算属性 | 17. 从数据库中的逻辑 | 18. 使用 @EntityValidator 进行验证 | 19. 验证替代方案 | 20. 删除时验证 | 21. 自定义 Bean Validation 注解 | 22. 在验证中调用 REST 服务 | 23. 注解中的属性 | 24. 改进标准行为 | 25. 行为与业务逻辑 | 26. 参照与集合 | A. Architecture & philosophy | B. Java Persistence API | C. Annotations | D. Automated testing

目录

第八章:视图继承(View)
extendsView 属性
使用继承的 Invoice 视图
使用继承的 Order 视图
使用 @ReferenceView 和 @CollectionView 来优化视图
总结
继承不仅可以用来重复使用 Java 代码和映射,还可以重用用户界面定义、@View 定义。本章会向您展示视图继承是如何运作的。


extendsView 属性

Order 和 Invoice 都使用默认生成的用户界面,它们的成员都一行一行的显示。该注意的是我们在 CommercialDocument 中声明的 @View 注解并没被继承。也就是说,如果您没有为实体定义视图,则会生成默认视图,并且不会使用父实体的 @View。像这样:
@View(members = "a, b, c;") // 这是用来显示父的视图的,不是子的视图
public class Parent { ... }
 
public class Child extends Parent { ... }   // 子视图会使用默认视图,不是父的
通常父实体的视图不是很有用,因为它不包含当前实体所具有的新属性。所以作为默认行为也是不错。
不过,在一个重要的实体中,您可能需要优化用户界面,所以从父级继承视图(不是复制和粘贴)可能会有用。您可以使用 @View 中的 extendsView 属性来做到这一点:
@View(members = "a, b, c;") // 没名称的视图会做为默认(DEFAULT)视图
public class Parent { ... }
 
@View(name="A" members = "d", // 将 d 加到继承的视图
    extendsView = "super.DEFAULT") // extends 父的默认视图
@View(name="B" members = "a, b, c; d") // B 视图跟 A 视图是同样的
public class Child extends Parent { ... }   // 子视图会使用默认视图,不是父的
使用 extendsView 时,所显示的成员将是所 extends 视图的成员加上当前视图声明的成员。
我们将使用此功能来定义 CommercialDocument、Order 和 Invoice 的视图。

使用继承的 Invoice 视图

鉴于 CommercialDocument 的 @View 没有被继承,Invoice 的当前用户界面并不美观,每行一个成员。我们将定义一个更好的用户界面。类似我们之前定义的视图,但添加一个订单分页(tab),如下:

inheritance_en060.png

以下代码是在没有继承的情况下定义此视图:请注意!我们将 Invoice 中 CommercialDocument 的所有成员放在开头和第一个分页(DATA),并将订单的集合放在另一个分页。
@View( members=
    "year, number, date;" +
    "data {" +
        "customer;" +
        "details;" +
    "remarks" +
    "}" +
    "orders { orders } "
)
public class Invoice extends CommercialDocument {
您应该注意到,除了 Order(订单的集合)之外的所有成员跟 CommercialDocument 都是共通的。因此,我们将把这部分移到 CommercialDocument 中,并使用视图继承重新定义这个视图。
删除 CommercialDocument 中旧的 @View,并编写下这个:
@View(members=
    "year, number, date," + // 将开头的成员放在同一行
    "data {" + // 将文件主要的信息(DATA)放在一个分页
        "customer;" +
        "details;" +
        "remarks" +
    "}"
)
abstract public class CommercialDocument extends Identifiable {
此视图指定如何布局所有 CommercialDocument 的公共数据。现在我们可以从这里重新定义 Invoice 的视图:
@View(extendsView="super.DEFAULT", // 从 CommercialDocument 继承视图
    members="orders { orders }" // 将 Orders 放进一个分页
)
public class Invoice extends CommercialDocument {
这样子,声明 Invoice 视图时会比较短。此外,Order、Invoice 和以后其它 CommercialDocument 的通用布局都在同一个地方。因此,如果您在 CommercialDocument 添加新属性,您只需要更改 CommercialDocument 的视图。

使用继承的 Order 视图

既然在 CommercialDocument 中有一个合适的视图,那么声明 Order 视图就很简单了。我们想要的视图如下:

inheritance_en070.png

要获得这个,您可以通过 extends CommercialDocument 的默认视图后定义 Order 视图,在新分页中添加 Invoice 引用的:
@View(extendsView="super.DEFAULT", // 从 CommercialDocument 继承视图
    members="invoice { invoice } " // 将 Invoice 放进一个分页
)
public class Order extends CommercialDocument {
这样,我们就可以获取 CommercialDocument 中所有数据和发票(Invoice)的分页。

使用 @ReferenceView 和 @CollectionView 来优化视图

当从 Invoice 的界面查看订单时,我们希望该视图应该要很简洁,不需要客户跟发票信息,因为在这种情况下那些数据是多余的:

inheritance_en080.png

要获得这效果,请在 Order 中定义一个更简单的视图:
@View( extendsView="super.DEFAULT", // 默认视图
    members="invoice { invoice } "
)
@View( name="NoCustomerNoInvoice", // 一个名为 NoCustomerNoInvoice 的视图,里面不包括客户和发票,适合 Invoice 使用
    members=                       
        "year, number, date;" +    
        "details;" +
        "remarks"
)
public class Order extends CommercialDocument {
这个在 Order 中定义的新视图名为 NoCustomerNoInvoice,可以从 Invoice 引用,来显示订单集合里各个元素(使用 @CollectionView ):
public class Invoice extends CommercialDocument {

    ...

    @OneToMany(mappedBy="invoice")
    @CollectionView("NoCustomerNoInvoice") // 这视图用来显示订单
    private Collection<Order> orders;
使用此代码,订单集合将在 Invoice 使用更合适的视图来显示各个元素。
此外,我们在 Order 用户界面显示发票时,不需要客户和订单信息,因为它们在这里是多余的。为此,我们将在 Invoice 中定义一个更简洁的视图:
@View( extendsView="super.DEFAULT", // 默认视图
    members="orders { orders }"
)
@View( name="NoCustomerNoOrders", // 一个名为 NoCustomerNoOrders的视图,里面不包括客户和订单,适合 Order 使用
    members=                      
        "year, number, date;" +   
        "details;" +
        "remarks"
)
public class Invoice extends CommercialDocument {
这个在 Invoice 中定义的新视图名为 NoCustomerNoOrders,可以从 Order 引用,来显示对 Invoice 的引用(使用 @ReferenceView):
public class Order extends CommercialDocument {
 
    @ManyToOne
    @ReferenceView("NoCustomerNoOrders") // 这视图用来显示发票
    private Invoice invoice;
 
    ...
现在 Order 里的 Invoice 引用会    以没有客户和订单信息的方式显示,您将获得更简洁的用户界面:

inheritance_en090.png

总结

本章向您展示了如何使用继承将用户界面的定义简化,由使用 @View 的 extendsView 属性。当中,您还看到如何使用 @ReferenceView 和 @CollectionView 来简化引用和集合的显示方式。

下载本课源代码

对这节课有什么问题吗? 前往论譠 一切都顺利吗? 前往第九章