# 提交数据

用户在表单上点了提交按钮后,会依次触发ACTION_CLICKING,ACTION_DOING,ACTION_DONE事件,具体的调用时序请参见下图

我们在ACTION_CLICKING事件中可以验证数据并通过对表单控制字段的赋值来控制流程走向,在ACTION_DOING事件中可以验证数据、修改数据、保存数据到业务库,在ACTION_DONE事件中可以保存表单数据到业务库。

# 验证数据

在ACTION_CLICKING和ACTION_DOING事件中都可以验证表单数据,其区别是CLICKING事件触发在后续步骤选执行人之前,而DOING事件在那之后,也就是作为验证来说,CLICKING事件中写验证比DOING事件中写验证对用户更友好。虽然对于普通用户填表而言,CLICKING事件中安排验证就足够了,但是出于安全考虑,建议把验证的代码在CLICKING和DOING事件中都执行一次,这能确保提交给平台的数据一定是符合验证逻辑的。同样道理虽然我们可以在表单字段上设置必填以及一些正则验证或者动态验证,但是在DOING事件中还是应该把所有数据校验逻辑都执行一次,避免安全问题。

以下代码在CLICKING和DOING事件中简单的验证了用户是否填写了请假事由,以及请假日期是否符合开始日期小于结束日期。值得一提的是方法名的命名规则是onStep{StepCode}Action{ActionCode}Clicking,onStep{StepCode}Action{ActionCode}Doing,对于我们首节点填写请假单(节点代码Apply)用户点了提交(动作代码Submit)而言,那么CLICKING事件的方法名就是onStepApplyActionSubmitClicking。

private void validateForm(Leave form) {
    if (StringUtils.isEmpty(form.getReason())) {
        throw new InfoPlusException("请填写请假事由");
    }
    if (form.getBeginDate() == null || form.getEndDate() == null) {
        throw new InfoPlusException("请填写请假时间段");
    }
    if (form.getBeginDate().getTime() > form.getEndDate().getTime()) {
        throw new InfoPlusException("请假开始日期不得晚于结束日期");
    }
}

public InfoPlusResponse onStepApplyActionSubmitClicking(InfoPlusEvent e) {
    Leave form = e.toBean(Leave.class);
    validateForm(form);
    return null;
}

public InfoPlusResponse onStepApplyActionSubmitDoing(InfoPlusEvent e) {
    Leave form = e.toBean(Leave.class);
    validateForm(form);
    return null;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 调整数据

如前文所述在DOING事件中适合验证并调整数据,那为什么CLICKING并不适合调整数据呢?从最上面的时序图可以看到步骤8.6之后会丢弃对表单数据的修改,也就是说CLICKING事件中对数据的修改是无效的,在CLICKING事件中修改表单数据只能影响到计算后续步骤(这在下面的控制流程例子里会提到),DOING事件中修改的数据会被保存下来。

以下例子没有太多实际意义,只是演示一下DOING事件对数据的修改。

public InfoPlusResponse onStepApplyActionSubmitDoing(InfoPlusEvent e) {
    Leave form = e.toBean(Leave.class);
    validateForm(form);
    // 以下数据修改无任何实际意义,只是演示如何修改数据
    form.setReason("这是我的请假事由");
    // 为了让修改的数据生效,这里需要返回一个用表单对象为参数构造的InfoPlusResponse
    return new InfoPlusResponse(e, form);
}
1
2
3
4
5
6
7
8

# 控制流程

所谓控制流程就是根据表单上的填值计算出一些控制字段的值,流程图有判断节点会根据这些控制字段值使流程产生不同的流转。

现在我们的需求是,如果请假天数大于等于3天,那么在部门领导审核之后需要中心的分管领导审核,我们先将流程图调整至下图所示

在流程的判断节点中加入以下脚本,并把部门审核节点的Clicking事件勾上。

return ${"fieldNeedNicLeaderApprove"}?"Yes":"No";
1

然后在表单中添加隐藏字段fieldNeedNicLeaderApprove,这个字段仅用户控制流程,可以画在表单最底部,高度和宽度都自动,设置其数据类型为Boolean,渲染类型为Hidden。

更新表单对象,增加这个字段

public class Leave {
    // 省略部分代码

    /** 是否需要分管领导审核 */
    private Boolean needNicLeaderApprove;
    public Boolean getNeedNicLeaderApprove() {
        return this.needNicLeaderApprove;
    }
    public void setNeedNicLeaderApprove(Boolean needNicLeaderApprove) {
        this.needNicLeaderApprove = needNicLeaderApprove;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13

现在可以在CLICKING事件中对这个控制字段赋值来影响流程走向了,由于控制节点前的步骤节点代码是DepartmentApprove,同意动作的代码是Approve,所以方法名是onStepDepartmentApproveActionApproveClicking

private static final long DAY_MILLISECOND = 24 * 60 * 60 * 1000;

public InfoPlusResponse onStepDepartmentApproveActionApproveClicking(InfoPlusEvent e) {
    Leave form = e.toBean(Leave.class);
    if (form.getEndDate().getTime() - form.getBeginDate().getTime() >= DAY_MILLISECOND * 3) {
        form.setNeedNicLeaderApprove(true);
    }
    return new InfoPlusResponse(e, form);
}
1
2
3
4
5
6
7
8
9

在CLICKING事件中对表单字段的赋值只能影响流程下一步走向的判断,但是这个数据并不会保存在表单里,如果这个判断变量在以后的节点里还需要使用,那么需要在DOING事件里再赋值一次

private static final long DAY_MILLISECOND = 24 * 60 * 60 * 1000;

public InfoPlusResponse onStepDepartmentApproveActionApproveDoing(InfoPlusEvent e) {
    Leave form = e.toBean(Leave.class);
    if (form.getEndDate().getTime() - form.getBeginDate().getTime() >= DAY_MILLISECOND * 3) {
        form.setNeedNicLeaderApprove(true);
    }
    return new InfoPlusResponse(e, form);
}
1
2
3
4
5
6
7
8
9

# 保存数据

如果想保存表单数据到业务系统数据库,推荐使用DOING事件,DONE事件也是可以用于存库的,如果使用DONE事件并要确保保存成功后才能使流程继续那么要勾选Block。DOING和DONE都可以用于保存数据,不同之处是DOING事件是可以修改表单数据的,而DONE不行,而现实中提交时修改表单数据的可能性很大,如果开发者不能很好的区分DOING和DONE的区别(后者不能修改数据),那么如果使用DONE事件保存数据往往会产生逻辑错误,因为代码中做的数据修改都会被忽略掉。所以就在DOING事件中保存数据到业务库即可。

以下代码在流程的最后一个节点申请人确认(Confirm),用户点完成(Finish)的DOING事件里完成存库

public InfoPlusResponse onStepConfirmActionFinishDoing(InfoPlusEvent e) {
    Leave form = e.toBean(Leave.class);
    // 这里完成存库逻辑,将form内容保存即可
    // 如果修改了表单数据就return new InfoPlusResponse(e, form) ,未修改直接return null
    return null;
}
1
2
3
4
5
6

# 案例地址

download 流程链接
download 主表单模版
download Messenger代码