在这次学习工作流的过程中,工作流如何与业务结合有多种方式,虽然很简单,但是每次都要再次梳理几分钟,这次拿出来整理一下,将它真正成为自己的知识。
从启动流程开始说:
申请页面:选择所用流程(即画的流程图的id)
<table cellpadding="0" cellspacing="0" class="mainForm">
<tr>
<td width="120px">
<div>
所用流程:<s:select name="processDefinitionKey" cssClass="SelectStyle"
list="processDefinitionList" listKey="key" listValue="key"/>
</div>
</td>
</tr>
<tr>
<td>申请名称:</td>
<td><input type="text" name="title" cssClass="InputStyle" /></td>
</tr>
<tr>
<td>申请理由:</td>
<td><input type="text" name="reason" cssClass="InputStyle" /></td>
</tr>
</table>
提交申请:获取前台传来的值
/** 提交申请 */
public String submit() throws Exception {
// 封装申请信息
Application application = new Application();
title=new String(title.getBytes("iso-8859-1"),"utf-8");
reason=new String(reason.getBytes("iso-8859-1"),"utf-8");
application.setApplicant(getCurrentUser()); // 申请人,当前用户
application.setTitle(title);
application.setReason(reason);
String processDefinitionKeyStr=new String(processDefinitionKey.getBytes("iso-8859-1"),"utf-8");
application.setProcessDefinitionKey(processDefinitionKeyStr);
// 调用业务方法(保存申请信息,并启动流程开始流转)
applicationService.submit(application);
return "toMyApplicationList"; // 成功后转到"我的申请查询"
}
public void submit(Application application) {
// 1,设置属性并保存application
application.setApplyTime(sdf.format(new Date())); // 申请时间,当前时间
application.setStatus(Application.STATUS_RUNNING);
// 2,启动程程实例开始流转
// >> 准备流程变量
Map<String, Object> variablesMap = new HashMap<String, Object>();
variablesMap.put("application", application);
// >> 启动流程实例,并带上流程变量(当前的申请信息)
//获取流程定义的key
String pdKey = application.getProcessDefinitionKey();
//根据流程定义的key值和相应的流程变量启动流程
ProcessInstance pi = processEngine.getExecutionService()//
.startProcessInstanceByKey(pdKey, variablesMap);
application.setExecuteId(pi.getId());
getSession().save(application); // 保存
// >> 办理完第1个任务“提交申请”
Task task = processEngine.getTaskService()//
.createTaskQuery()// 查询出本流程实例中当前仅有的一个任务“提交申请”
.processInstanceId(pi.getId())//
.uniqueResult();
processEngine.getTaskService().completeTask(task.getId());
}
当点击提交申请时application,我们来看看工作流的各个表的变化:
jbpm4_execution:
jbpm4_task:
jbpm4_variable:
那么通过查看上面表的变化,我们不难发现执行的流程是通过什么和业务绑定的,即jbpm4_execution和jbpm4_variable的关系。
从流程的启动开始,就与业务绑定关系,那么接下来如何应用呢?
下面只是简单介绍,对于一些结合业务的查询问题会单独再说明:
查看待办任务:一般是根据用户名来查看(当前登陆用户)
/** 待我审批(我的任务列表) */
public String myTaskList() throws Exception {
List<TaskView> taskViewList = applicationService.getMyTaskViewList(getCurrentUser());
//List<TaskView> taskViewList = applicationService.getMyTaskViewList(user);
ActionContext.getContext().put("taskViewList", taskViewList);
return "myTaskList";
}
审批处理:
本环节因为单独出来有一个审批意见表,故会将所有的审批意见添加的审批意见表中,故这个环节的内容是保存数据然后办理任务并判断流程是否结束。当然我们也可以不单独设计审批意见表,而是将所有的审批意见存储到流程变量中。
办理任务需要获取任务id,也就是在查看任务列表中获取taskViewList。
审批处理页面,审批处理:
/** 审批处理页面 */
public String approveUI() throws Exception {
Set<String> outcomes = applicationService.getOutcomesByTaskId(taskId);
ActionContext.getContext().put("outcomes", outcomes);
return "approveUI";
}
/** 审批处理 */
public String approve() throws Exception {
// 封装
ApproveInfo approveInfo = new ApproveInfo();
comment=new String(comment.getBytes("iso-8859-1"),"utf-8");
approveInfo.setComment(comment);
approveInfo.setApproval(approval);
approveInfo.setApplication(applicationService.getById(applicationId));
approveInfo.setApprover(getCurrentUser()); // 审批人,当前登录用户
approveInfo.setApproveTime(sdf.format(new Date())); // 当前时间
if(outcome!=null){
// 调用用业务方法(保存本次审批信息,并办理完任务,并维护申请的状态)
outcome=new String(outcome.getBytes("iso-8859-1"),"utf-8");
}
applicationService.approve(approveInfo, taskId, outcome);
return "toMyTaskList"; // 成功后转到待我审批页面
}
//办理任务
public void approve(ApproveInfo approveInfo, String taskId, String outcome) {
// 1,保存本次审批信息
getSession().save(approveInfo);
// 2,办理完任务
Task task = processEngine.getTaskService().getTask(taskId); // 一定要先取出Task对象,再完成任务,否则拿不到,因为执行完就变成历史信息了。
if (outcome == null) {
processEngine.getTaskService().completeTask(taskId);
} else {
processEngine.getTaskService().completeTask(taskId, outcome);
}
// >> 取出所属的流程实例,如果取出的为null,说明流程实例执行完成了,已经变成了历史记录
ProcessInstance pi = processEngine.getExecutionService().findProcessInstanceById(task.getExecutionId());
// 3,维护申请的状态
Application application = approveInfo.getApplication();
if (!approveInfo.isApproval()) {
// 如果本环节不同意,则流程实例直接结束,申请的状态为:未通过
if (pi != null) { // 如果流程还未结束
processEngine.getExecutionService().endProcessInstance(task.getExecutionId(), ProcessInstance.STATE_ENDED);
}
application.setStatus(Application.STATUS_REJECTED);
} else {
// 如果本环节同意,而且本环节是最后一个环节,则流程实例正常结束,申请的状态为:已通过
if (pi == null) { // 本环节是最后一个环节,即流程已经结束了
application.setStatus(Application.STATUS_APPROVED);
}
}
getSession().update(application);
}
查看流转记录:即类似淘宝查看物流信息类似,完全使用业务信息
/** 查看流转记录 applicationId*/
public String approveHistory() throws Exception {
Application application = applicationService.getById(applicationId);
System.out.println(application.getTitle());
ActionContext.getContext().put("approveInfos", application.getApproveInfos());
return "approveHistory";
}
查看我的申请:完全查看自己的业务信息表即可
/** 我的申请查询 */
public String myApplicationList() throws Exception {
String strHQL="from Application where applicant="+getCurrentUser().getUserId() ;
// 准备数据
List<Application> applicationList = applicationService.findByHql(strHQL);
ActionContext.getContext().put("applicationList", applicationList);
return "myApplicationList";
}
/**
* 查看流程图,高亮当前正在执行的节点
*/
public String showProcessImageUI() throws Exception {
/*boolean isEnded = "true".equals(request.getParameter("isEnded")); // 是否已执行完
String processInstanceId = getParameter(request, "processInstanceId");*/
//未考虑是否完成情况
//boolean isEnded=false;
//启动的实例id
//String processInstanceId="ApplyDepartment.8";
// 1,获取当前正在执行的活动名称
String deploymentId = null;
String processDefinitionId = null;
Set<String> activityNames = null;
status=new String(status.getBytes("iso-8859-1"),"utf-8");
if (!status.equals("审批中")) {
// 已执行完的,就查询历史
HistoryProcessInstance hpi = processEngine.getHistoryService()//
.createHistoryProcessInstanceQuery()//
.processInstanceId(processInstanceId)//
.uniqueResult();
processDefinitionId = hpi.getProcessDefinitionId();
activityNames = new HashSet<String>();
activityNames.add(hpi.getEndActivityName()); // 结束的活动名称
} else {
// 正在执行的,就使用ExecutionService查询
ProcessInstance pi = processEngine.getExecutionService()//
.createProcessInstanceQuery()//
.processInstanceId(processInstanceId)//
.uniqueResult();
processDefinitionId = pi.getProcessDefinitionId();
activityNames = new HashSet<String>(pi.findActiveActivityNames()); // 当前正在执行的活动的名称
}
ActionContext.getContext().put("processDefinitionId", processDefinitionId);
// 2,找出他们的坐标
Set<ActivityCoordinates> coordList = new HashSet<ActivityCoordinates>();
for (String activityName : activityNames) {
ActivityCoordinates coord = processEngine.getRepositoryService().getActivityCoordinates(
processDefinitionId, activityName);
coordList.add(coord);
}
ActionContext.getContext().put("coordList", coordList);
// 3,获取 deploymentId
deploymentId = processEngine.getRepositoryService().createProcessDefinitionQuery()//
.processDefinitionId(processDefinitionId)//
.uniqueResult()//
.getDeploymentId();
ActionContext.getContext().put("deploymentId", deploymentId);
return "showProcessImageUI";
}
总结:
其实写这篇博客的目的是结合工作流的数据库来分析业务与流程是如何绑定的,那么对于流程中需要的一些常用方法的使用在这里也简单的介绍了一番,这样做的目的也是为后面的Activiti中的应用实例的常用方法介绍做个对比,其实无论是JBPM4.4还是它的升级版Activiti本质上都是一样的。