Skip to end of metadata
Go to start of metadata

(一)区分字段翻译还是业务关联

1.简述

在页面开发和设计时,我们经常会遇到一些大对象,这些对象动则几十个到几百个字段,其中很多字段都是保存了相关业务对象的code,在编辑的时候我们要显示相关业务对象的label.

如下图中的“性别”和“titleOfCourtest”字段:

数据库中保存的是code,但是我们希望展现给用户的时候显示对应label,这样更容易看懂:

dorado开发这种code转label的工作有两种实现方式:

  • 方式一:通过mapping实现,实现时开发人员将mapping的值穷举,并输出到客户端,同时和对应的字段做绑定设置,这样在页面初始化过程中,就可以自动将code和mapping中的值比对,找到对应的label后并显示;
  • 方式二:通过调整数据的模型实现,类似的设计有POJO转VO,新建一个VO对象,在VO对象中添加POJO中code对应的label字段,并在查询初始化的时候同时初始化label的值,并最终将整个VO对象输出到客户端,客户端就隐藏code字段,而是直接通过label字段来显示值;当然在dorado的模型设计中支持虚拟属性,VO的创建不是必须的,可以基于虚拟属性添加对应的label属性,虚拟属性的具体说明参考:01. 虚拟属性

上面两种方式使用的详细说明如下:

(1)mapping实现:

01. mapping

(2)通过调整数据模型实现

VO的设计和使用属于纯Java开发,SSH开发框架的常规讨论,这儿不再详细说明。

如果采用droado的虚拟属性实现label特性,则可以参考如下的文章:

01. 虚拟属性

2.用mapping还是修改数据模型?

在业务开发的过程中,这两种方式如何区分呢?

区分规则:

  • 面向对象的关系来区分:如果相互关联的是两个业务对象,则一定用方式二。例如:淘宝订单中的用户和商家,用户和商品,商家和商品等
  • 数据量来区分:code和label在数据库中有专门的表,可以单独维护,并且对应表的数据量是几十个数量级的就可以用mapping实现,如果数据量是几千个数量级的就应该通过调整数据模型实现,如果是几百个数量级的要根据页面实际情况综合判断
  • 静态动态区分:一般来说数据量很少,且在整个系统的运行期很少会发生变化的数据,则可以用mapping实现。如:性别,员工上班状态,流程审批状态等

之所以要慎重选择转换方式的原因

由于两种转换方式所采用的开发手段有很大区别,并且相对来说mapping的开发更为简洁,很多开发人员在未区分的情况下将上面应该通过数据模型转换实现的需求通过mapping方式实现,并且在测试阶段可能没有任何问题(理论上可以实现相同的功能),但是一到正式运行环境就发现速度很忙。究其原因就是正式环境下由于数据库更完整,mapping穷举的数量很大,而mapping运行机制中要求将mapping中穷举出来的所有数据都输出到客户端,有时候这个数据量可能是几千条,有时候可能是几十万条,这对于网络和浏览器来说都是不可承受的。因此在设计的时候就需要注意到这个规则,我们在很多管理不善的项目中都发现项目上线之后再匆忙的将mapping实现修改为修改数据模型实现的应急开发。

(二)子对象

DataType下可以添加两种类型的属性对象:

  • PropertyDef:可定义简单类型或对象类型的数据,也可以是Collection类型的数据;
  • Reference:对象类型的数据,也可以是Collection类型的数据,简单类型的数据不推荐用Reference定义;

PropertyDef一般用来定义POJO中的简单类型的子属性或子对象,而Reference一般用来定义对象类型的数据或对象集合类型的数据。

其中Reference对象有自己独立的数据装载器,可以实现延迟数据装载,而PropertyDef中的数据是随着当前的Entity对象直接下载的。

1.PropertyDef

一般用于定义简单类型的数据,如:String, int, Integer, long, Long,char,Date,Float,float等;

如果是对象类型的数据,则我们还需要进一步通过其dataType属性定义内部对象的对象结构。如下图(Product中含category属性):

如果是集合类的数据,则也需要定义dataType属性,且外面还要包含中括号,表示是一个集合:

上面的对象类型的PropertyDef或集合类型的PropertyDef并不是一定要设置dataType属性的,事实上当你从DataProvider放回对应的数据对象的时候,如果DataProvider判断到其中包含的子属性是一个对象或对象集合的时候,就会从model.xml的配置中根据其中DataType的matchType属性找到对应的POJO的对应的DataType,并用这种DataType作为当前PropertyDef的默认dataType属性。关于matchType的说明已经在上文的03. modal.xml中提到过,这儿就是一个具体应用场景。

2.Reference

一般用于定义POJO中对象类型的属性或集合类型的属性。同样我们也需要为Reference定义dataType属性,以便于DataSet可以知道这个Reference属性的内部数据结构。另外同样根据model.xml的基本设计规范,这个dataType在满足基本设计规范的情况下是可以省略的。

看起来Reference与PropertyDef都可以定义子属性为对象或对象集合。不同的地方是,它可以定义自身的数据提供者(DataProvider),如:

Reference中的数据是异步加载的,如上图中的Category对象有一个名称为products的Reference,这就意味着当你在客户端获取到一个Category数据对象的时候,其products中的值可能还没有加载到客户端,只有当你尝试着访问它的时候,它才会触发异步的数据加载动作,如:category.get(“products”);

3.PropertyDef还是Reference?

根据上面的描述,做为开发人员应该可以清楚的做如下判断:

当某一个POJO中的某一个属性为简单数据类型的时候,我们就一定用PropertyDef定义。

但是如果这个子属性是一个POJO或一个对象集合的时候,我们该怎么选择呢?

我们在DataType的设计时,对自己提出以下几个问题:

  • 得到子属性的值是不是一个非常耗时的工作,例如:

对应的SQL查询非常耗时;

需要调用第三方系统的接口才能获得的数据,如:WebService,工作流接口,规则引擎等;

  • 子属性的数据量是不是非常大,例如:子属性是一个数据集合,有几千条数据;
  • 这个子属性如果是一个集合,是不是还要支持翻页操作;
  • 在页面操作过程中,应为目的的不同,是不是某些操作场景下可以忽略这个子属性的,如:多标签页场景,用户一般情况下可能只操作其中的某几个标签页,而另外几个标签页中的数据很少操作,而这个子属性的数据恰好是在这几个不常用的标签页对象中。同样适合这种分析的场景有:一开始隐藏起来的Dialog或某些Fieldset或GroupBox中显示的子属性。

如果以上问题的任意一个你根据业务场景的分析所得到的答案是确定的,那么这个子属性就应该用Reference来设计。

Reference中的数据是异步加载的,采用这样的设计后,即使这个数据没有加载到客户端,也不会对用户的操作带来任何影响,同时这种设计也有利于页面快速的展现给系统的操作人员,从而提高更好的用户体验。

(三)不支持循环引用的数据实体

DataType可以用于定义复杂数据对象,以及定义对象关系。但是对象关系定义时,要避免嵌套逻辑关系的定义,因为最终当一个数据实体被输出到客户端时,Java对象会根据DataType的定义决定输出那些属性到客户端,而如果你的DataType的定义中形成了嵌套的闭环关系,会导致这个对象无法被正常的转换为一个合适的JSON对象输出到客户端。为避免这种情况Dorado会在服务器端输出时提起做这种检查,一旦发现这种问题就会直接抛出如下的异常:

举例:

Category和Propduct两个Java对象是一对多的关系,Category中含products属性,Product又包含Category对象。

这个时候上面的Category和Product是相互引用的关系,而这个时候直接转Json是会出错的。

当然在日常的开发中我们可能并不需要输出这种相互引用的嵌套关系。我们而采取一些技巧避免这种问题,如输出Product信息的时候我们就不输出Product中的category属性了。

在Dorado中由于我们是通过DataType来定义Java对象的结构的,通常我们用PropertyDef来定义一个对象的属性,如果你通过PropertyDef定义对象的属性,一旦你将一个Java对象通过Dorado的Ajax技术返回到前台的时候,Dorado就会将Java对象对应的这个属性的值转换为Json输出到前台。由于这个规则,如果你返回的是一个具有相互应用关系的两个不同对象,而恰好DataType设计时,又正好通过PropertyDef定义导致了DataType的相互引用,这个时候就会出现上面的“不支持循环引用的数据实体”的错误。以上面的Category和Product对象为例,看下面的DataType配置,就会导致错误。

Category下有一个名称为products的PropertyDef,他DataType是Product集合类型的:

而对应名称为Product的DataType的内部又含有category对象的定义,并且dataType属性为Category:

 

(四)Boolean和boolean的差别

虽然这个差别与Java中Boolean和boolean的差别一样,但是在展现层开发的时候很多人还是会忽略这两种类型的差别,所以再强调一下。

如下图中的“性别”数据:

复选框选中代表true,不选中不一定是false,还有可能是null,只是在Java或JS运算中null的运算结果也是false。

因此当一个属性允许存在null的情况下就要用对象类型定义DataType,类似的DataType还有:

  • int和Integer
  • float和Float
  • double和Double

 




Labels
  • No labels