activiti 附件为什么不是一开始加附件

博客分类:
Activiti 5对表单的支持目前还是比较弱的,表现在对表单的开发还需要写Freemark模板,并且它的模板还需要跟class文件一起打包发布。这使得流程的表单设计必须由开发人员来开发处理。因而,开发一套易用性强的流程表单功能就显得很有必要。
用户一般都希望能有如Microsoft的Office套件中的InfoPath那样,可以自己进行设计,并且能与工作流程绑在一起进行流转处理。如下所示:
表单中每个字段有固定的数据类型,并由不同的数据控件展示,如日期、数字、单选或多选、下拉、多行文本甚至富文本编辑器。在实现更强的功能上,我们还允许控件能实现脚本交互。
三、设计实现思路
在表单与流程的整合中,我们一般不建议把表单的所有数据都存储在流程中,仅需要把参与流程跳转的数据才存到流程变量中去。如请假出差的流程,如下所示:
如申请出差金额则需要参与流程的处理中去,因而在进入这个判断节点之前,流程变量中需要存在这个变量,并且通过判断这个变量值来让流程自动跳转。
1.流程实例与业务表单关联
基于以上设计的原则,流程中则不存储业务表单的数据,那么流程与业务表单又如何关联?在Activiti 5 则比Jbpm4考虑了这块,他在流程实例表及任务实例表相关运行表中增加了一个字段(BusinessKey),用来关联业务表单的数据,我们一般把这个字段称为业务主键。其关联关系如下所示:
那么流程表单的数据如何存储及如何展示,从上图可以看到,我们对自定义的表单提供了生成物理表的方式,那么表单的存储则通过在线生成的页面获取物理表必需要的数据,然后保存至物理表中。这需要我们在设计表单时,生成一套表单数据规范,在审批时,能够进行页面表单的数据验证及存储。另外,还需要对在执行过程中的表单进行权限控制,如同一节点上审批相同的表单,不同角色的人员对表单的字段的读写权限是不一样的。
2.在线表单设计功能要求
我们把以上的需求进行了用例描述,则得到如下示例
1.设计表单模板
允许用户预先设置好一些带有漂亮格式的表单,如包括表头、表脚及样式。方便用户调整表单。
2.设计表单布局
允许用户在线进行在线布局,目前一般来说都是基于表格的布局方式。
3.设计表单字段控件、数据类型、数据验证
设计表单字段的输入控件类型及数据类型,用于保证用户输入的数据的正确性
4.设置表单字段权限
用于控制表单的字段的读写权限,结合工作流的审批,可以更有效显示数据。
5.支持表单动态脚本
允许对表单控件加上交互脚本,以实现如一些级联更新等的数据交互等。
6.表单预览
可以在线实时显示表单的显示效果
7.预设流程变量
把参与流程运算的表单字段标识为流程变量。
3.在线流程表单设计逻辑结构分析
生成流程表单的流程如下所示:
表单设计可以先设计物理表再根据模板生成在线表单
也可以先设计表单的样式再生成物理表
以上两种方式最终的目标均需要生成物理表,物理表的结构及数据展示控件等我们则需要用表来记录。因此,以下为他们大体上的数据结构模型:
表单生成物理表后,表单页面需要跟物理表单的数据对应起来,在提交页面表单时,我们采用了Json的数据结构来提交,在后台获取可以有效转存为物理表的数据。如下格式:
表单数据分为3部分:
1.主表数据。
2.子表数据
3.意见数据
数据格式如:
{"main":{"tableId":"tableId","fields":{"itemSubject":"出差深圳两天","total":"230","creatorID":"9","creator":"张小军","descp":"出差深圳两天"}},"sub":[],"opinion":[]}
在线表单的控件展示,需要按字段及结构来解析最终显示及数据验证。
流程启动后,需要把业务主键传至流程实例中去,幸好,activiti已经提供了比较完整的API接口,如下:
ProcessInstance processInstance=runtimeService.startProcessInstanceById(porcessDefId, businessKey, variables);
以上方法会把业务表单中需要参与流程运行的字段放到variables作为流程变量。
4.流程定义与业务表单绑定
流程定义允许绑定多种业务表单,目前我们可以简单分为三种模式,在线表单、同系统的定制业务表单、第三方业务表单。
在线表单可以用全局表单,则整个流程用同一个表单,如果每个流程节点的表单不一样,则可以通过设计表单。 表单数据结构如下所示:
所以在启动流程时及在任务进行跳转时,均可以获取流程节点的表单设置,从而在启动流程或执行任务处理时能进行正确的表单展示。
流程在完成整个审批后,还可以通过流程运行历史,能通过该以下该表可以查询当时每个节点审批时的表单情况。
更多资讯请加QQ了解
论坛回复 /
(9 / 18077)
浏览: 330195 次
来自: 广州
哎。假的。
这是主流程调用子流程报的错大神指导原因吗?
pageoffice也是office在线编辑的吧,J.Offi ...
你好,想问下,串行的多实例任务能做到回退么
参考这个实现思路,可以弄个自定义的表单设计器http://wi ...博客分类:
应用场景:在企业或事业单位,经常需要把一个任务分派给多条线去处理,每条线可以由一个或多个步骤构成,多条线的任务完成后需要再汇总一起于某个任务上。如下例子为一个公文下发流程,这个流程就涉及到任务的两级分发。
图一 原流程定义图
图二 执行过程中流程图
以上黄色的代表任务分发,紫黄代表任务汇总。 解决方法一: 我们可以把多个任务线用子流程去实现也可以,这样在分发那里会产生多个子流程,子流程完成后,需要汇总。但若有多级分发与汇总,则需要子流程再嵌套子流程。 解决方法二:
把分发的任务线当作普通的任务来实现,该产生多少个任务可由分发任务决定,这些任务的名称是一样的,但任务实例id不一样,执行人不一样。 在jbpm4或Activiti5上,动态创建子流程及对子流程的处理上,相对要完成的工作多一些,主要是activity或jbpm4上没有提供这块api。而动态创建任务在jbpm4或activiti5上也是没有提供的,只有activiti5上提供了一个taskService.newTask,而该方法产生的新任务则跟流程定义无关,则表示该任务完成后,不能产生后续的任务。在此,我们先提供activiti5的解决办法。Jbpm4的解决方法可以参照该方式实现,以下为解决方案的步骤: 1.
第二种解决方案的关键点在于如何动态创建任务,在这里,我们绕过activiti的API直接对activiti5表进行生成处理,让他生成我们需要流程数据。 如下所示:
* 按任务Id,复制另一会签任务出来
* @param orgTaskId
* @param assignee
public ProcessTask newTask(String orgTaskId,String assignee)
String newExecutionId=UniqueIdUtil.getNextId();
String newTaskId=UniqueIdUtil.getNextId();
TaskEntity taskEntity=getTask(orgTaskId);
ExecutionEntity executionEntity=
if(taskEntity.getExecution()!=null){
executionEntity=taskEntity.getExecution();
executionEntity=getExecution(taskEntity.getExecutionId());
ProcessExecution newExecution=new ProcessExecution(executionEntity);
newExecution.setId(newExecutionId);
ProcessTask newTask=new ProcessTask(taskEntity);
newTask.setId(newTaskId);
newTask.setExecutionId(newExecutionId);
newTask.setCreateTime(new Date());
newTask.setAssignee(assignee);
newTask.setOwner(assignee);
ProcessTaskHistory newTaskHistory=new ProcessTaskHistory(taskEntity);
newTaskHistory.setAssignee(assignee);
newTaskHistory.setStartTime(new Date());
newTaskHistory.setId(newTaskId);
newTaskHistory.setOwner(assignee);
executionDao.add(newExecution);
taskDao.insertTask(newTask);
taskHistoryDao.add(newTaskHistory);
return newT
说明:以上代码写在BpmService类里,关键是从原来的任务中复制一份新的数据出来,同时需要复制其Execution的记录以及执行历史的记录。
需要记录分发与汇总的节点
所以在流程节点的设置上,我们提供了以下的配置实体。
public class BpmNodeSet extends BaseModel
* 在线表单
public static Short FORM_TYPE_ONLINE=0;
public static Short FORM_TYPE_URL=1;
* 普通任务节点
public static Short NODE_TYPE_NORMAL=0;
* 分发任务节点
public static Short NODE_TYPE_FORK=1;
protected Long setId;
// 流程定义ID
protected Long defId;
protected String nodeN
// Activiti流程定义ID
protected String actDefId;
protected String nodeId;
// 表单类型(0:在线表单,1:URL表单)
protected Short formType=-1;
// 表单URL
protected String formU
// 表单定义ID
protected Long formDefId;
// 表单名称
protected String formDefN
* 任务类型:
* 0=普通任务
* 1=分发任务
protected Short nodeT
* 当任务类型=1时,可以指定汇总任务Key
protected String joinTaskK
* 当任务类型=1时,指定的汇总任务名称
protected String joinTaskN
然后在任务的创建及完成的事件里加上监听若当前的任务为分发任务,则动态产生分发的任务。若为汇总任务,则只产生最后一个汇总,以免得由Activiti产生多个汇总任务。 在监听事件创建分发任务(TaskCreateListener.java类)
BpmNodeSet bpmNodeSet=bpmNodeSetService.getByActDefIdNodeId(actDefId, nodeId);
if(bpmNodeSet!=null && BpmNodeSet.NODE_TYPE_FORK.equals(bpmNodeSet.getNodeType())){//当前任务为分发任务
Map&String,List&String&& nodeUserMap=taskUserAssignService.getNodeUserMap();
//若当前的线程里包含了该任务对应的执行人员列表,则任务的分发用户来自于此
if(nodeUserMap!=null && nodeUserMap.get(nodeId)!=null){
List&String& userIds=nodeUserMap.get(nodeId);
bpmService.newForkTasks((TaskEntity)delegateTask, userIds);
//产生分发记录,以方便后续的任务汇总处理
taskForkService.newTaskForks(delegateTask,bpmNodeSet.getJoinTaskName(), bpmNodeSet.getJoinTaskKey(), userIds.size());
ForkUser forkUser=taskUserAssignService.getForkUser();
if(forkUser!=null){
bpmService.newForkTasks((TaskEntity)delegateTask, forkUser.getForkUserIdsAsList());
以上代码中,分发任务的创建对应的人员来自表单中指定的人员。 任务汇总时,我们需要记录完成的情况,若为汇总节点,我们会根据汇总完成的情况,进行处理,若汇总的任务尚没有全部完成,后续产生的汇总任务我们则采用删除策略,该方法定义在BpmService类中。
* 检查及删除重复的汇总任务
* @param processInstanceId
public void deleteRepeatJoinTask(String processInstanceId){
List&TaskEntity& taskList=getTasks(processInstanceId);
for(TaskEntity task:taskList){
//判断后续的节点是否为汇总节点,若是,则需要检查是否需要产生后续的任务
BpmNodeSet joinNodeSet=bpmNodeSetService.getByActDefIdJoinTaskKey(task.getProcessDefinitionId(), task.getTaskDefinitionKey());
if(joinNodeSet!=null){
TaskFork taskFork=taskForkService.getByInstIdJoinTaskKey(task.getProcessInstanceId(), task.getTaskDefinitionKey());
if(taskFork!=null){
if(taskFork.getFininshCount()&taskFork.getForkCount()-1){
taskService.deleteTask(task.getId());
//更新完成任务的个数
taskFork.setFininshCount(taskFork.getFininshCount()+1);
taskForkService.update(taskFork);
taskForkService.delById(taskFork.getTaskForkId());
最终实现的效果可以如下所示:
更多资讯请加QQ了解
可以用泳道和foreach-join实现这个的确可以实现
扩展他们本身的api实现的能说具体点吗?哪个API?具体怎么实现的,请不吝赐教,小弟感激了。
浏览: 330197 次
来自: 广州
哎。假的。
这是主流程调用子流程报的错大神指导原因吗?
pageoffice也是office在线编辑的吧,J.Offi ...
你好,想问下,串行的多实例任务能做到回退么
参考这个实现思路,可以弄个自定义的表单设计器http://wi ...一、流程引擎的API和服务(services)
& &&&引擎的API是影响Activiti最常见的一种方法。我们一开始最关注的中心是ProcessEngine,像之前描述的那样,流程引擎可以被多种方式创建。从这个流程引擎里面,你能获得各个包含workflow/BPM方法的服务。流程引擎和这些获得的服务是线程安全的。所以你能为整个服务器保留这些中的一个引用。
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
TaskService taskService = processEngine.getTaskService();
ManagementService managementService = processEngine.getManagementService();
IdentityService identityService = processEngine.getIdentityService();
HistoryService historyService = processEngine.getHistoryService();
FormService formService = processEngine.getFormService();
& & &ProcessEngines.getDefaultProcessEngine();这个方法被调用之后,会首先初始化并且创建一个流程引擎,并且以后会一直返回同一个流程引擎。ProcessEngine.init()和ProcessEngine.destroy方法会被用来创建和关闭所有流程引擎的属性。
& & &ProcessEngine这个类会被所有的activiti.cfg.xml和activiti-context.xml文件扫描到。对于所有的activiti.cfg.xml来说,流程引擎都会用一种典型的方式被创建。这种方式就是:
& & &&&&&&&&&&&&&&&&&&&&&&&&&&ProcessEngineConfiguration.
& & &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&createProcessEngineConfigurationFromInputStream(inputStream).
& & &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&buildProcessEngine()。
& & &对于所有的activiti-context.xml来说,流程引擎会被用Spring的方式来创建。这种方式是:
& & & & & & &&&首先Spring的应用上下文被创建,然后流程定义会在应用的上下文中获得。 & &&
& & &所有的Services服务是没有国界的。这就意味着你可以很轻松的在一个集群的多个节点中运行Activiti,每一个都用到相同的数据库,并且在以前的调用中,哪一个机器实际上被执行不会出现错误。任何服务的调用都是同等的,不管它在哪里被执行。
& & &当用流程引擎工作的时候,第一个被需要的服务大概就是&RepositoryService。这个服务为管理、多个部署和流程定义都提供了操作。这里不作详细介绍,一个流程定义是BPMN 2.0的一个java相关。它是一个流程每一步的结构和行为的表现。一个部署包是Activiti引擎下的包的单元。一个部署包能包含多个BPMN 2.0 xml文件和其他的一些资源。一个部署包里面包含什么由开发者决定。这些包括从单一的流程BPMN
2.0文件到一个整个的流程包和相关的资源。RepositoryService允许去部署这样的包。部署一个部署包意味着这是上传到引擎中,引擎中的所有的流程在被存到数据库之前都会被检查和解析。从这点来看,这个部署包被系统能识别,并且任何流程都被包含进这个部署包中,这样的部署包现在才能被启动。
& & &进一步说,这样的服务允许去:
& & &RepositoryService相当于静态的信息,&RuntimeService正好是相反的。它处理一个流程定义中新的流程实例。像上面说的,一个流程定义决定着一个流程中的不同步骤的结构和行为。一个流程实例是这样一个流程定义的的一个执行。对于每一个流程定义,同时会有很多实例在运行。RuntimeService同样是被用在取回和存储流程变量的服务。这些数据是特别是流程实例的,并且这些数据能被用在流程中的各种各样的结构。RuntimeService同样允许在流程实例和executions中去查询。Executions是BPMN
2.0 概念‘token’的一种表现。基本上,一个execution就是一个指向流程实例当前在哪里的指针。最后,任何一个流程实例在等待一个额外的出触发器和流程需要继续的时候,RuntimeService都会被用到。一个流程实例有各种各样的等待状态,并且这个服务对单个实例包含了各种各样的操作。这个实例额外的触发器会被接收到并且这个流程实例会比继续执行。
& & &Tasks是BPM的核心,比如Activiti。它需要被系统中的真实用户所执行。在&TaskService中,围绕着任务的每一件事情都是分组的。比如:
& & &&IdentityService是相当简单的。它允许对于用户和组的管理。在运行的时候,Activiti实际上不对用户作任何检查。这对于理解Activiti是很重要的。举个例子,一个任务能分配给任何人,但是如果系统知道这个用户,引擎不会去区分它。这是因为Activiti引擎也能和服务一起结合使用。
& & &&FormService是一个可选的服务。意味着Activiti没有FormService,也能正确的被使用,不会牺牲消失任何其他的功能。这个服务介绍了start form和task form的概念。一个start form是一个表单,这个表单在流程实例启动之前展现给用户。然而一个task form是一个用户想要去完成一个表单的时候,展示的表单。Activiti允许在BPMN
&2.0的流程定义中去定义这些表单。
& &&&&HistoryService暴露了所有被Activiti 引擎生成的历史数据。当流程执行的时候,一些数据能被引擎保留。比如流程实例开始的时间,谁做的哪个任务,这个任务完成花了多长时间,在这个流程实例中,哪个路径是被跟踪的等等。这个服务暴露了主要的访问数据的查询方法。
& & &用activiti的时候,当编码自定义应用的时候,&ManagementService是不需要的。它允许去取回数据库表信息和表的元数据。进一步说,它暴露了对计划的查询和管理操作。在Activiti里,计划被用于各种各样的事情,比如计时器,异步连续,延迟暂停/激活等。这些话题会在更多的细节中进行讨论。
& & &要获得更多的关于服务和引擎API的详细信息,请参考doc文档。
二、异常策略
& &在activiti中,最基本的异常是org.activiti.engine.ActivitiException,一个未经检查的异常。这个异常在任何时间都能被API抛出,但是除非这个异常是发生在那些在doc文档中记录的那些特殊的方法。举个例子,从TaskService中抛出的一个异常:
* 当任务被成功执行的时候调用.
* @param taskId 是要去完成的任务的ID,不能为空.
* @throws ActivitiObjectNotFoundException 当给出的id没有任务存在的时候,会抛出异常.
void complete(String taskId);
& & &在上面的例子中,当传的id任务不存在时,会抛出一个异常。同样,因此在javadoc中明确的规定任务id不能为空,当传过来的是个null,就会抛出ActivitiIllegalArgumentException。
& & &即使我们想避开一个大级别的异常,当在特殊情况下一些异常被抛出的时候,下面的子类会被添加。在经过process-execution或者API-invokation报的错如果不在下面列出的异常之内,他们通常都会抛出一个ActivitiException。
三、工作中用Activiti服务
& & &像上述一样,和Activiti 引擎互动的方式就是通过org.activiti.engine.ProcessEngine这个类的实例暴露的服务。下面的代码片段假设了你有一个工作中的Activiti环境,你也能获取到一个有效的org.activiti.engine.ProcessEngine。如果你仅仅想要提炼出下面的代码,你能下载或者克隆Activiti unit test
template(&),把它导入到你的IDE,并且添加一个testUserguideCode()方法到org.activiti.MyUnitTest
单元测试。
& &&&3.1 部署流程
& & &通过ResponsitoryService访问的任何数据都与静态数据有关(比如流程定义)。概念地,每一个这样的静态的一部分数据,都是Activiti引擎'respository'的内容。
& & &在src/test/resources/org/activiti/test文件夹中,创建一个新的xml文件,名字为VacationRequest.bpmn20.xml,下面是具体内容。这一节不会解释被用于上面例子中的xml的结构。
&?xml version=&1.0& encoding=&UTF-8& ?&
&definitions id=&definitions&
targetNamespace=&http://activiti.org/bpmn20&
xmlns=&http://www.omg.org/spec/BPMN//MODEL&
xmlns:xsi=&http://www.w3.org/2001/XMLSchema-instance&
xmlns:activiti=&http://activiti.org/bpmn&&
&process id=&vacationRequest& name=&Vacation request&&
&startEvent id=&request& activiti:initiator=&employeeName&&
&extensionElements&
&activiti:formProperty id=&numberOfDays& name=&Number of days& type=&long& value=&1& required=&true&/&
&activiti:formProperty id=&startDate& name=&First day of holiday (dd-MM-yyy)& datePattern=&dd-MM-yyyy hh:mm& type=&date& required=&true& /&
&activiti:formProperty id=&vacationMotivation& name=&Motivation& type=&string& /&
&/extensionElements&
&/startEvent&
&sequenceFlow id=&flow1& sourceRef=&request& targetRef=&handleRequest& /&
&userTask id=&handleRequest& name=&Handle vacation request& &
&documentation&
${employeeName} would like to take ${numberOfDays} day(s) of vacation (Motivation: ${vacationMotivation}).
&/documentation&
&extensionElements&
&activiti:formProperty id=&vacationApproved& name=&Do you approve this vacation& type=&enum& required=&true&&
&activiti:value id=&true& name=&Approve& /&
&activiti:value id=&false& name=&Reject& /&
&/activiti:formProperty&
&activiti:formProperty id=&managerMotivation& name=&Motivation& type=&string& /&
&/extensionElements&
&potentialOwner&
&resourceAssignmentExpression&
&formalExpression&management&/formalExpression&
&/resourceAssignmentExpression&
&/potentialOwner&
&/userTask&
&sequenceFlow id=&flow2& sourceRef=&handleRequest& targetRef=&requestApprovedDecision& /&
&exclusiveGateway id=&requestApprovedDecision& name=&Request approved?& /&
&sequenceFlow id=&flow3& sourceRef=&requestApprovedDecision& targetRef=&sendApprovalMail&&
&conditionExpression xsi:type=&tFormalExpression&&${vacationApproved == 'true'}&/conditionExpression&
&/sequenceFlow&
&task id=&sendApprovalMail& name=&Send confirmation e-mail& /&
&sequenceFlow id=&flow4& sourceRef=&sendApprovalMail& targetRef=&theEnd1& /&
&endEvent id=&theEnd1& /&
&sequenceFlow id=&flow5& sourceRef=&requestApprovedDecision& targetRef=&adjustVacationRequestTask&&
&conditionExpression xsi:type=&tFormalExpression&&${vacationApproved == 'false'}&/conditionExpression&
&/sequenceFlow&
&userTask id=&adjustVacationRequestTask& name=&Adjust vacation request&&
&documentation&
Your manager has disapproved your vacation request for ${numberOfDays} days.
Reason: ${managerMotivation}
&/documentation&
&extensionElements&
&activiti:formProperty id=&numberOfDays& name=&Number of days& value=&${numberOfDays}& type=&long& required=&true&/&
&activiti:formProperty id=&startDate& name=&First day of holiday (dd-MM-yyy)& value=&${startDate}& datePattern=&dd-MM-yyyy hh:mm& type=&date& required=&true& /&
&activiti:formProperty id=&vacationMotivation& name=&Motivation& value=&${vacationMotivation}& type=&string& /&
&activiti:formProperty id=&resendRequest& name=&Resend vacation request to manager?& type=&enum& required=&true&&
&activiti:value id=&true& name=&Yes& /&
&activiti:value id=&false& name=&No& /&
&/activiti:formProperty&
&/extensionElements&
&humanPerformer&
&resourceAssignmentExpression&
&formalExpression&${employeeName}&/formalExpression&
&/resourceAssignmentExpression&
&/humanPerformer&
&/userTask&
&sequenceFlow id=&flow6& sourceRef=&adjustVacationRequestTask& targetRef=&resendRequestDecision& /&
&exclusiveGateway id=&resendRequestDecision& name=&Resend request?& /&
&sequenceFlow id=&flow7& sourceRef=&resendRequestDecision& targetRef=&handleRequest&&
&conditionExpression xsi:type=&tFormalExpression&&${resendRequest == 'true'}&/conditionExpression&
&/sequenceFlow&
&sequenceFlow id=&flow8& sourceRef=&resendRequestDecision& targetRef=&theEnd2&&
&conditionExpression xsi:type=&tFormalExpression&&${resendRequest == 'false'}&/conditionExpression&
&/sequenceFlow&
&endEvent id=&theEnd2& /&
&/process&
&/definitions&
& & &要让流程引擎认识我们的这个流程,我们必须先发布它。发布意味着引擎会解析BPMN 2.0xml文件给一些事情执行并且为包含在发布包中的每一个流程定义都会添加一个新的数据库记录。这样的好处是:当流程引擎重启的时候,它会一直所有已经发布的流程:
& &&&3.2 开始一个流程实例
& & &在把流程定义部署到流程引擎之后,我们就能启动一个新的流程实例。对于每一个流程定义来说,会有很多典型的流程实例。当流程定义的一个流程实例正在运行期,这个流程定义是'buleprint'。
& & &每一件和流程运行状态的事情,都会被RuntimeService监控。有各种各样的方法去启动一个新的流程实例。在下面的代码片段中,我们用我们在流程定义xml中定义的key去启动一个流程实例。我们也会在流程实例启动的时候,提供一些处理过的变量。因为第一个用户任务的描述会用到他们在它的表达式中。因为他们为一个确定的流程定义中的流程实例赋予意义的时候,这些变量通常会被用到。典型的来说,这些变量是让流程实例区别于其他实例的因素。
Map&String, Object& variables = new HashMap&String, Object&();
variables.put(&employeeName&, &Kermit&);
variables.put(&numberOfDays&, new Integer(4));
variables.put(&vacationMotivation&, &I'm really tired!&);
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(&vacationRequest&, variables);
// Verify that we started a new process (&Number of process instances: & + runtimeService.createProcessInstanceQuery().count());
& & &3.3 正在完成的任务
& & &当一个流程开始的时候,第一步会成为一个用户的任务。这是一个必须被系统用户执行的步骤。典型的来说,这样的用户将会有一个'inbox of tasks','inbox of tasks'列出了所有需要被这个用户完成的任务。下面的代码就展现了这样一个查询怎么被执行:
// Fetch all tasks for the management group
TaskService taskService = processEngine.getTaskService();
List&Task& tasks = taskService.createTaskQuery().taskCandidateGroup(&management&).list();
for (Task task : tasks) {
(&Task available: & + task.getName());}
& & &继续流程实例,我们需要完成这个任务。对于Activiti引擎来说,这意味着你需要这个任务。下面的代码断展示了怎么做的:
Task task = tasks.get(0);
Map&String, Object& taskVariables = new HashMap&String, Object&();
taskVariables.put(&vacationApproved&, &false&);
taskVariables.put(&managerMotivation&, &We have a tight deadline!&);
plete(task.getId(), taskVariables);
& & &流程实例会继续到下一步,在这个例子中,这又会成为第一个布骤,因为这个任务没有被审核过。
& & &3.4 暂停和激活一个流程
& & &暂停一个流程定义是可能的。当一个流程定义被暂停,一个新的流程实例不会被创建(一个异常将会被抛出)。通过RepositoryService去暂停一个流程定义。
repositoryService.suspendProcessDefinitionByKey(&vacationRequest&);
runtimeService.startProcessInstanceByKey(&vacationRequest&);
} catch (ActivitiException e) {
e.printStackTrace();
& & &重新激活一个流程定义,通常的调用repositoryService.activateProcessDefinitionXXX方法中的一个方法。
& & &暂停一个流程实例也有可能。当暂停的时候,这个流程不会继续下去并且没有计划会被执行。暂停流程实例可以通过调用runtimeService.suspendProcessInstance()方法.再次激活流程实例可以调用runtimeService.activateProcessInstanceXXX方法。
& & &3.5 进一步阅读
四、查询API
& & &从引擎中查询数据有两种方法:查询API和本地查询。查询API允许完全安全的用流畅的API编程。你能添加各种各样的条件到你的查询中并且精确地排序。下面的代码是个例子:
List&Task& tasks = taskService.createTaskQuery()
.taskAssignee(&kermit&)
.processVariableValueEquals(&orderId&, &0815&)
.orderByDueDate().asc()
& & &有时,你需要更强大的查询,用一个OR操作或者约束的查询,用API,你不能明确的实现。对于这种情况,我们介绍本地查询,本地查询允许你写自己的SQL查询.返回类型被你用的查询对象定义,并且数据会被映射到正确的对象.如认为,流程实例...因此,你不得不用在数据库中定义的表和字段的名字作为被映射到数据库的查询。这需要一些关于数据结构的知识,并且它推荐给我们要小心的进行本地查询。表的名字能通过API被重新寻回,以致于尽可能的远离对它的依赖。
List&Task& tasks = taskService.createNativeTaskQuery()
.sql(&SELECT count(*) FROM & + managementService.getTableName(Task.class) + & T WHERE T.NAME_ = #{taskName}&)
.parameter(&taskName&, &gonzoTask&)
long count = taskService.createNativeTaskQuery()
.sql(&SELECT count(*) FROM & + managementService.getTableName(Task.class) + & T1, &
+ managementService.getTableName(VariableInstanceEntity.class) + & V1 WHERE V1.TASK_ID_ = T1.ID_&)
五、表达式
& & &Activiti用UEL去解析表达式。UEL代表统一表达式语言(Unifies Expression Language),并且是EE6的一部分。为了支持在所有环境中最新的UEL的所有特点,我们用JUEL的一个编辑版本。
& & &&表达式能被用在java service tasks/execution Listeners/Task Listener和Condition sequence flows。尽管有两种表达式类型,值表达式和方法表达式,Activiti概括了他们,以致于他们都能用在表达式需要的地方。
& & & & & 这些表达式支持解析实体类、集合、数组和map。
& & & & & 在所有进程变量中最上面,有一小部分默认的对象变量是被用到表达式中的:
六、在一个web应用中的流程引擎
& &&&流程引擎是线程安全的类并且能被很容易的在多个线程中分享。在一个web应用中,这意味着当一个容器启动或者当一个容器关闭的时候,马上去创建一个流程引擎是可能的。
& & &下面的代码片段,就展示了你能怎么写一个简单的ServletContextListener,在一个纯粹的Servlet环境中去初始化和销毁流程引擎:
public class ProcessEnginesServletContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
ProcessEngines.init();
public void contextDestroyed(ServletContextEvent servletContextEvent) {
ProcessEngines.destroy();
& & & & contextInitialized方法会委托ProcessEngines.init()方法。它会去扫描activiti.cfg.xml文件,并且根据配置信息去创建一个流程引擎。如果你有多个这样的资源文件,你要确保他们都有不同的名字。 当流程引擎是需要的时候,它能用下面的方法取到。&
ProcessEngines.getDefaultProcessEngine()
ProcessEngines.getProcessEngine(&myName&);
& & &当然,用任何一个创建流程引擎的变体方法中也是可能的。想配置信息中描述的那样。contextDestryed方法会委托ProcessEngines.destroy()。这样,所有初始化的流程引擎都会关闭。 &&& & & &&
本文转自http://itindex.net/detail/44058-activiti-activiti-api,所有权利归原作者所有。
本文已收录于以下专栏:
相关文章推荐
1. 初识Activiti
1.1. 工作流与工作流引擎
工作流(workflow)就是工作流程的计算模型,即将工作流程中的工作如何前后组织在一起的逻辑和规则在计算机中以恰当的模型进行表示并对其实...
Activiti 组件介绍
activiti 项目由三种类型的组件组成, 分别是: 专用工具 (Dedicated Tools) 、 存储内容(St 具 ored Content) 、协作工(C...
/view/6fc5a85ee53a580217fcfebd.html
-》Pracess(该流程的基本数据,流程名字等)
1 部署流程定义
Ø 部署流程定义(方式一):将设计的流程图发布到数据库中
public void run3() {
// 创建流程部署建造对象
DeploymentBuilder deplo...
/articles/yUnURjy
他的最新文章
讲师:王哲涵
讲师:王渊命
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 activiti 流程附件 的文章

 

随机推荐