普通表单——流程启动

leave.bpmn中有定义流程启动

<startEvent id="startevent1" name="Start" activiti:initiator="applyUserId"></startEvent>

menu.jsp中

<a rel="oa/leave/apply">请假申请(普通)</a>

然后对应控制层

@Controller
@RequestMapping(value = "/oa/leave")
public class LeaveController {

    @RequestMapping(value = {"apply", ""})
    public String createForm(Model model) {
        model.addAttribute("leave", new Leave());
        return "/oa/leave/leaveApply";
    }
}

再到流程启动页面leaveApply.jsp

<form:form id="inputForm" action="${ctx}/oa/leave/start" method="post" class="form-horizontal">
		<fieldset>
			<legend><small>请假申请</small></legend>
			<table border="1">
			<tr>
				<td>请假类型:</td>
				<td>
					<select id="leaveType" name="leaveType">
						<option>公休</option>
						<option>病假</option>
						<option>调休</option>
						<option>事假</option>
						<option>婚假</option>
					</select>
				</td>
			</tr>
			<tr>
				<td>开始时间:</td>
				<td><input type="text" id="startTime" name="startTime" /></td>
			</tr>
			<tr>
				<td>结束时间:</td>
				<td><input type="text" id="endTime" name="endTime" /></td>
			</tr>
			<tr>
				<td>请假原因:</td>
				<td>
					<textarea name="reason"></textarea>
				</td>
			</tr>
			<tr>
				<td> </td>
				<td>
					<button type="submit">申请</button>
				</td>
			</tr>
		</table>
		</fieldset>
	</form:form>

输入表单值,点击申请按钮,/oa/leave/start

/**
     * 启动请假流程
     *
     * @param leave
     */
    @RequestMapping(value = "start", method = RequestMethod.POST)
    public String startWorkflow(Leave leave, RedirectAttributes redirectAttributes, HttpSession session) {
        try {
            User user = UserUtil.getUserFromSession(session);
            // 用户未登录不能操作,实际应用使用权限框架实现,例如Spring Security、Shiro等
            if (user == null || StringUtils.isBlank(user.getId())) {
                return "redirect:/login?timeout=true";
            }
            leave.setUserId(user.getId());
            Map<String, Object> variables = new HashMap<String, Object>();
            ProcessInstance processInstance = workflowService.startWorkflow(leave, variables);
            redirectAttributes.addFlashAttribute("message", "流程已启动,流程ID:" + processInstance.getId());
        } catch (ActivitiException e) {
            if (e.getMessage().indexOf("no processes deployed with key") != -1) {
                logger.warn("没有部署流程!", e);
                redirectAttributes.addFlashAttribute("error", "没有部署流程,请在[工作流]->[流程管理]页面点击<重新部署流程>");
            } else {
                logger.error("启动请假流程失败:", e);
                redirectAttributes.addFlashAttribute("error", "系统内部错误!");
            }
        } catch (Exception e) {
            logger.error("启动请假流程失败:", e);
            redirectAttributes.addFlashAttribute("error", "系统内部错误!");
        }
        return "redirect:/oa/leave/apply";
    }

这里Map<String, Object> variables可以保存流程启动变量,当然我们是希望这些变量在流程各个节点间都可以共享,后面会介绍怎么取流程实例。

在WorkflowService中,有具体的流程启动方法,这个方法保存leave对象,启动流程,返回流程实例

/**
     * 启动流程
     *
     * @param entity
     */
    public ProcessInstance startWorkflow(Leave entity, Map<String, Object> variables) {
        leaveManager.saveLeave(entity);
        logger.debug("save entity: {}", entity);
        String businessKey = entity.getId().toString();

        ProcessInstance processInstance = null;
        try {
            // 用来设置启动流程的人员ID,引擎会自动把用户ID保存到activiti:initiator中
            identityService.setAuthenticatedUserId(entity.getUserId());

            processInstance = runtimeService.startProcessInstanceByKey("leave", businessKey, variables);
            String processInstanceId = processInstance.getId();
            entity.setProcessInstanceId(processInstanceId);
            logger.debug("start process of {key={}, bkey={}, pid={}, variables={}}", new Object[]{"leave", businessKey, processInstanceId, variables});
        } finally {
            identityService.setAuthenticatedUserId(null);
        }
        return processInstance;
    }
执行启动流程后,打印日志:

save entity: me.kafeitu.demo.activiti.entity.oa.Leave@1b9b6ad

--- starting StartProcessInstanceCmd --------------------------------------------------------

--- starting GetNextIdBlockCmd --------------------------------------------------------

Running command with propagation REQUIRES_NEW

Preparing: select * from ACT_GE_PROPERTY where NAME_ = ? 
Parameters: next.dbid(String)

--- GetNextIdBlockCmd finished --------------------------------------------------------

insert ProcessInstance[12]

Preparing: insert into ACT_RU_EXECUTION (ID_, REV_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, ACT_ID_, IS_ACTIVE_, IS_CONCURRENT_, IS_SCOPE_,IS_EVENT_SCOPE_, PARENT_ID_, SUPER_EXEC_, SUSPENSION_STATE_, CACHED_ENT_STATE_, TENANT_ID_, NAME_) values ( ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
Parameters: 12(String), 12(String), 2(String), leave:1:20(String), deptLeaderAudit(String), true(Boolean), false(Boolean), true(Boolean), false(Boolean), null, null, 1(Integer), 2(Integer), (String), null

insert VariableInstanceEntity[id=13, name=applyUserId, type=string, textValue=kafeitu]

Preparing: insert into ACT_RU_VARIABLE (ID_, REV_, TYPE_, NAME_, PROC_INST_ID_, EXECUTION_ID_, TASK_ID_, BYTEARRAY_ID_, DOUBLE_, LONG_ , TEXT_, TEXT2_) values ( ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
Parameters: 13(String), string(String), applyUserId(String), 12(String), 12(String), null, null, null, null, kafeitu(String), null

insert HistoricVariableInstanceEntity[id=13, name=applyUserId, revision=0, type=string, textValue=kafeitu]

Preparing: insert into ACT_HI_VARINST (ID_, PROC_INST_ID_, EXECUTION_ID_, TASK_ID_, NAME_, REV_, VAR_TYPE_, BYTEARRAY_ID_, DOUBLE_, LONG_ , TEXT_, TEXT2_, CREATE_TIME_, LAST_UPDATED_TIME_) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
Parameters: 13(String), 12(String), 12(String), null, applyUserId(String), 0(Integer), string(String), null, null, null, kafeitu(String), null, 2015-05-05 15:27:45.127(Timestamp), 2015-05-05 15:27:45.127(Timestamp)

insert IdentityLinkEntity[id=14, type=starter, userId=kafeitu, processInstanceId= 12]

Preparing: insert into ACT_RU_IDENTITYLINK (ID_, REV_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_, PROC_DEF_ID_) values (?, 1, ?, ?, ?, ?, ?, ?) 
Parameters: 14(String), starter(String), kafeitu(String), null, null, 12(String), null

insert org.activiti.engine.impl.persistence.entity.HistoricIdentityLinkEntity@f2818d

Preparing: insert into ACT_HI_IDENTITYLINK (ID_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_) values (?, ?, ?, ?, ?, ?) 
Parameters: 14(String), starter(String), kafeitu(String), null, null, 12(String)

insert HistoricProcessInstanceEntity[superProcessInstanceId=null]

Preparing: insert into ACT_HI_PROCINST ( ID_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, START_TIME_, END_TIME_, DURATION_, START_USER_ID_, START_ACT_ID_, END_ACT_ID_, SUPER_PROCESS_INSTANCE_ID_, DELETE_REASON_, TENANT_ID_, NAME_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
Parameters: 12(String), 12(String), 2(String), leave:1:20(String), 2015-05-05 15:27:45.206(Timestamp), null, null, kafeitu(String), startevent1(String), null, null, null, (String), null

insert HistoricActivityInstanceEntity[activityId=startevent1, activityName=Start]

Preparing: insert into ACT_HI_ACTINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_, ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
Parameters: 15(String), leave:1:20(String), 12(String), 12(String), startevent1(String), null, null, Start(String), startEvent(String), null, 2015-05-05 15:27:45.206(Timestamp), 2015-05-05 15:27:45.268(Timestamp), 62(Long), (String)

insert HistoricActivityInstanceEntity[activityId=deptLeaderAudit, activityName=部门领导审批]

Preparing: insert into ACT_HI_ACTINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, ACT_ID_, TASK_ID_, CALL_PROC_INST_ID_, ACT_NAME_, ACT_TYPE_, ASSIGNEE_, START_TIME_, END_TIME_, DURATION_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
Parameters: 16(String), leave:1:20(String), 12(String), 12(String), deptLeaderAudit(String), 17(String), null, 部门领导审批(String), userTask(String), null, 2015-05-05 15:27:45.268(Timestamp), null, null, (String)

insert Task[id=17, name=部门领导审批]

Preparing: insert into ACT_RU_TASK (ID_, REV_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, PRIORITY_, CREATE_TIME_, OWNER_, ASSIGNEE_, DELEGATION_, EXECUTION_ID_, PROC_INST_ID_, PROC_DEF_ID_, TASK_DEF_KEY_, DUE_DATE_, CATEGORY_, SUSPENSION_STATE_, TENANT_ID_, FORM_KEY_) values (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
Parameters: 17(String), 部门领导审批(String), null, null, 50(Integer), 2015-05-05 15:27:45.268(Timestamp), null, null, null, 12(String), 12(String), leave:1:20(String), deptLeaderAudit(String), null, null, 1(Integer), (String), null

insert org.activiti.engine.impl.persistence.entity.HistoricTaskInstanceEntity@1177565

Preparing: insert into ACT_HI_TASKINST ( ID_, PROC_DEF_ID_, PROC_INST_ID_, EXECUTION_ID_, NAME_, PARENT_TASK_ID_, DESCRIPTION_, OWNER_, ASSIGNEE_, START_TIME_, CLAIM_TIME_, END_TIME_, DURATION_, DELETE_REASON_, TASK_DEF_KEY_, FORM_KEY_, PRIORITY_, DUE_DATE_, CATEGORY_, TENANT_ID_ ) values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) 
Parameters: 17(String), leave:1:20(String), 12(String), 12(String), 部门领导审批(String), null, null, null, null, 2015-05-05 15:27:45.268(Timestamp), null, null, null, null, deptLeaderAudit(String), null, 50(Integer), null, null, (String)

insert IdentityLinkEntity[id=18, type=candidate, groupId=deptLeader, taskId=17]

Preparing: insert into ACT_RU_IDENTITYLINK (ID_, REV_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_, PROC_DEF_ID_) values (?, 1, ?, ?, ?, ?, ?, ?) 
Parameters: 18(String), candidate(String), null, deptLeader(String), 17(String), null, null

insert org.activiti.engine.impl.persistence.entity.HistoricIdentityLinkEntity@11c4ef6

Preparing: insert into ACT_HI_IDENTITYLINK (ID_, TYPE_, USER_ID_, GROUP_ID_, TASK_ID_, PROC_INST_ID_) values (?, ?, ?, ?, ?, ?) 
Parameters: 18(String), candidate(String), null, deptLeader(String), 17(String), null

--- StartProcessInstanceCmd finished --------------------------------------------------------

start process of {key=leave, bkey=2, pid=12, variables={}}

可以看到,

每次启动流程实例,首先会去ACT_GE_PROPERTY表取next.dbid,即流程实例ID;

启动流程的核心的部分就是往ACT_RU_*表中添加当前运行流程实例信息,往ACT_HI_*表中记录流程实例历史数据,当前流程实例和流程任务同步添加到运行表和历史表中。

ACT_RU_EXECUTION表记录运行中流程实例,ACT_RU_TASK表记录运行中的流程实例当前任务,

当流程跳转时,ACT_RU_EXECUTION表中记录是更新的(update),ACT_RU_TASK表中记录是先新增(insert)新任务后删除(delete)旧任务。


ps: 

关于流程变量,流程启动时会在act_ru_variable和act_hi_varinst表中都记录变量,记录流程发起人(对应bpmn中的activiti:initiator)的NAME_为applyUserId,TEXT_为流程启动用户,比如:kafeitu;

刚才也提到我们代码中可以设置其它流程变量,修改代码

Map<String, Object> variables = new HashMap<String, Object>();
variables.put("testKey", "testValue");
然后测试启动一个新的流程,发现act_ru_variable和act_hi_varinst表中确实各多了一条记录

然后编写测试用例

	/**
	 * 测试获取流程变量
	 * @throws Exception
	 */
	@Test
	public void testGetVariable(){
		String pid = "2524";
		Map<String, Object> variables = taskService.getVariables(pid);
		Set<String> keySet = variables.keySet();
		for(String key : keySet){
			System.out.println(key);
		}
	}
打印日志如:

--- starting GetTaskVariablesCmd --------------------------------------------------------
Running command with propagation REQUIRED
Preparing: select * from ACT_RU_TASK where ID_ = ? 
Parameters: 2524(String)
Total: 1

Preparing: select * from ACT_RU_VARIABLE where TASK_ID_ = ? 
Parameters: 2524(String)
Total: 0

Preparing: select * from ACT_RU_EXECUTION where ID_ = ? 
Parameters: 2512(String)
Total: 1
[

Preparing: select * from ACT_RU_VARIABLE where EXECUTION_ID_ = ? and TASK_ID_ is null 
Parameters: 2512(String)
Total: 3

--- GetTaskVariablesCmd finished --------------------------------------------------------

输出:                                                                                             
applyUserId
testKey
deptLeaderPass

可见这些变量都不是作为某个任务的变量存储在数据库中的,而是和整个流程实例关联。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值