3.6.1.3.4. AbstractEditor
AbstractEditor
是编辑界面控制器的基类,AbstractWindow 的子类。
创建控制器类时,推荐使用需要编辑的实体作为 AbstractEditor
的泛型参数。这样会使 getItem()
和 initNewItem()
方法能操作指定的实体类型,应用程序代码也不需要做额外的类型转换。示例:
public class CustomerEdit extends AbstractEditor<Customer> {
@Override
protected void initNewItem(Customer item) {
...
AbstractEditor
定义了下列方法:
getItem()
– 返回编辑的实体实例,通过界面主数据源设置(比如在 XML 描述的根节点元素中通过datasource
属性设置)。
如果编辑的实体实例不是新建的,界面打开过程会按照主数据源设置的 view 来重新加载实体的实例。
对 getItem()
返回实例的更改,会在数据源的状态中反映出来,之后会被送到 Middleware 然后提交给数据库。
需要注意的是,只有在界面通过 setItem()
初始化之后,getItem()
方法才能返回一个值。在此之前,这个方法只会返回 null
,比如在 init()
或者 initNewItem()
方法里调用的时候。
但是,在 init()
方法中,可以通过以下方法取到传递给 openEditor()
方法参数的实体实例:
@Override
public void init(Map<String, Object> params) {
Customer item = WindowParams.ITEM.getEntity(params);
// do something
}
initNewItem()
方法可以接收正确类型的实体作为参数。
这两种情况下,获取到的实体实例之后都会被重新加载,除非是新建的。因此,不能对实体做修改,或者将此时的实体保存在某个字段留着将来用。
setItem()
– 当窗口通过openEditor()
方式打开的时候,平台会调用这个方法将需要编辑的实体设置到主数据源。调用此方法时,所有的界面组件和数据源都已经创建了,并且控制器的init()
方法也已经执行。
如果是要初始化界面的话,推荐使用模板方法 initNewItem()
和 postInit()
,而不要重写 setItem()
。
initNewItem()
– 在设置编辑实体实例到主数据源之前平台会自动调用的模板方法。
initNewItem()
方法只能给新创建的实体实例调用。这个方法不会给游离实体调用。如果新实体实例必须在设置到主数据源之前做初始化,可以在控制器实现此方法。示例:
@Inject
private UserSession userSession;
@Override
protected void initNewItem(Complaint item) {
item.setOpenedBy(userSession.getUser());
item.setStatus(ComplaintStatus.OPENED);
}
关于使用 initNewItem()
方法的更复杂的例子可以参阅 cookbook。
postInit()
– 在编辑实体实例被设置到主数据源之后马上被平台调用的模板方法。在这个方法中,可以使用getItem()
来获取新建的实体实例或者在界面初始化过程中重新加载的实体。
这个方法可以在控制器作为界面初始化的最后一步实现:
@Inject
private EntityStates entityStates;
@Inject
protected EntityDiffViewer diffFrame;
@Override
protected void postInit() {
if (!entityStates.isNew(getItem())) {
diffFrame.loadVersions(getItem());
}
}
commit()
– 验证界面,并且通过 DataSupplier 提交数据改动至 Middleware。
如果调用带有 validate = false
参数的方法,提交时不会做验证。
建议不要重写此方法,改为使用特定的模板方法 - postValidate()
,preCommit()
和 postCommit()
。
commitAndClose()
– 验证界面,提交改动到 Middleware 并且关闭界面。Window.COMMIT_ACTION_ID
的值会传递给preClose()
方法以及注册过的CloseListener
监听器。
建议不要重写此方法,改为使用特定的模板方法 - postValidate()
,preCommit()
和 postCommit()
。
preCommit()
– 在提交改动的过程中被平台调用的模板方法,在成功验证之后,但是在数据提交到 Middleware 之前。
这个方法可以在控制器实现。如果返回值是 false
,提交的过程会被中断,如果是关闭窗口过程(如果调用的 commitAndClose()
)中的话,也会被中断。示例:
@Override
protected boolean preCommit() {
if (somethingWentWrong) {
notifications.create()
.withCaption("Something went wrong")
.withType(Notifications.NotificationType.WARNING)
.show();
return false;
}
return true;
}
postCommit()
– 在提交改动的最后阶段被平台调用的模板方法。方法参数:
committed
– 如果界面有改动,并且已经提交给 Middleware,设置为true
。close
– 如果界面需要在提交改动之后关闭的话,设置为true
。
如果界面没有关闭,此方法的默认实现会展示关于成功提交的信息并且调用 postInit()
。
可以在控制器重写此方法,以便在成功提交改动之后做额外操作,比如:
@Inject
private Datasource<Driver> driverDs;
@Inject
private EntitySnapshotService entitySnapshotService;
@Override
protected boolean postCommit(boolean committed, boolean close) {
if (committed) {
entitySnapshotService.createSnapshot(driverDs.getItem(), driverDs.getView());
}
return super.postCommit(committed, close);
}
下列图表展示初始化序列过程,以及编辑界面的不同提交改动方法。
Figure 31. 编辑界面初始化过程
Figure 32. 使用 editWindowActions 子框架提交并关闭窗口
Figure 33. 使用 extendedEditWindowActions 子框架提交界面改动
Figure 34. 使用 extendedEditWindowActions 子框架提交界面改动并关闭窗口
- API
commit() - commitAndClose() - getItem() - initNewItem() - postCommit() - postInit() - preCommit() - setItem()