activiti工作流面试题addcomment方法是什么意思

Activiti工作流学习-----基于5.19.0版本(2)
来源:博客园
二、activiti.cfg.xml的其他bean节点配置
2.1 新特性:Job Executor和Async Executor
从5.17.0版本的activiti开始提供作业执行者(Job Executor)和异步作业执行者(Async Executor),Async Executor执行表现更好,并且执行异步作业对数据库更加友善。activiti官方推荐使用Async Executor,并且一些老的Job Executor依旧有效。在Java EE 7运行环境中,JSR-236规范支持容器管理ManagedJobExecutor和ManagedAsyncJobExecutor,例如可以配置如下:

&bean id="threadFactory" class="org.springframework.jndi.JndiObjectFactoryBean"&
&property name="jndiName" value="java:jboss/ee/concurrency/factory/default" /&
&/bean&

&bean id="customJobExecutor" class="org.activiti.engine.impl.jobexecutor.ManagedJobExecutor"&
&!-- ... --&
&property name="threadFactory" ref="threadFactory" /&
&!-- ... --&
&/bean&

2.2 激活Job executor
Job executor作为管理多线程执行定时任务的组件,在单元测试场景里,Job executor在多线程中执行是测试不方便的,所以activiti提供了api解决了这个麻烦:
查询获取Job executor可以通过ManagementService.createJobQuery方法实现,执行该作业可以调用ManagementService.executeJob,使得在单元测试中Job executor可以被控制,顺利关闭Job executor。默认的Job executor是在流程引擎启动就被激活的,如果需要关闭这个功能,可以配置:

&property name="jobExecutorActivate" value="false" /&

2.3 激活Async executor
AsyncExecutor作为管理线程池执行定时任务的组件,默认activiti是关闭AsyncExecutor的,使用它的配置如下:

&property name="asyncExecutorEnabled" value="true" /&
&property name="asyncExecutorActivate" value="true" /&

asyncExecutorEnabled属性设置设置true后将代替那些老的Job executor,第二个属性asyncExecutorActivate是指示activiti在流程引擎启动就激活AsyncExecutor。
2.4 流程定义缓存配置
所有被解析的流程定义都会被缓存起来,这是因为流程定义是不会改变的,没有必要多次请求数据库。默认的activiti是没有限制缓存数量的,如果需要设置:

&property name="processDefinitionCacheLimit" value="10" /&

缓存内部是使用HashMap数据结构和LRU算法实现的。当然,缓存的数量的设置值最好根据流程定义的总数和正在运行的流程实例使用的流程定义数量决定。你也可以使用自定义的缓存实现类替换内部提供的缓存实现,只需要实现接口org.activiti.engine.impl.persistence.deploy.DeploymentCache,然后配置即可:

&property name="processDefinitionCache"&
&bean class="org.activiti.MyCache" /&
&/property&

对于自定义缓存实现的缓存数量限制可以设置knowledgeBaseCacheLimit和knowledgeBaseCache属性。
2.5 日志
在activiti 5.12的时候,日志框架使用的是SLF4J,替换掉早前的jdk的日志工具,现在所有的日志(activiti, spring, mybatis, …)都通过SLF4J来输出日志,你可以具体的日志实现。
工作流没有提供日志的具体实现jar包在依赖里面,需要你自己手动添加,如果没有添加,SLF4J会全程使用NOP-logger,它不会全程记录所有的日志的,并且警告没有被记录,在Maven中比如添加log4j:

&dependency&
&groupId&org.slf4j&/groupId&
&artifactId&slf4j-log4j12&/artifactId&
&/dependency&

activiti-explorer和activiti-rest项目是使用的log4j,activiti项目测试也是使用的log4j记录日志。
如果你的类路径下面已经有了commons-logging的jar了的话,这时需要commons-logging干的活交给slf4j,比如要让spring输出日志使用slf4j的话,需要使用依赖:

&dependency&
&groupId&org.slf4j&/groupId&
&artifactId&jcl-over-slf4j&/artifactId&
&/dependency&

如果使用的服务器是Tomcat,需要注意tomcat自己的类路径下面也有日志的jar包,解决办法参考:http://www.slf4j.org/codes.html#release
2.6 日志配置相关工作流上下文
从版本5.13开始,Activiti支持使用slf4j记录工作流上下文,日志通过底层日志logger记录的内容有:


processDefinition Id ------
mdcProcessDefinitionID


processInstance Id
mdcProcessInstanceID


execution Id -  
----   mdcexecutionId

日志记录有格式化的信息和其他的普通信息,例如日志记录可以配置:

 log4j.appender.consoleAppender.layout.ConversionPattern =ProcessDefinitionId=%X{mdcProcessDefinitionID}
executionId=%X{mdcExecutionId} mdcProcessInstanceID=%X{mdcProcessInstanceID} mdcBusinessKey=%X{mdcBusinessKey} %m%n"

在系统关键的地方进行记录或检测是非常有必要的,通过日志分析也是其中一种手段。
2.7 事件处理
在Activiti 5.15中引入了事件机制,它让你在工作流引擎中的各种事件发生时得到消息,activiti能够支持注册一个侦听器对于某些类型的事件而不是任何类型的事件发生时收到通知,一方面可以在配置文件中添加engine-wide事件监听器配置,然后engine-wide事件监听器类会调用相应的API,另一方面也可以在在BPMN配置文件中配置。
所有的事件类都是org.activiti.engine.delegate.event.ActivitiEvent的子类,事件会提供type、executionId、processInstanceId和processDefinitionId,某些事件包含了事件发生的上下文,附加载荷的信息。
2.8 事件监听器的实现
事件监听器需要实现org.activiti.engine.delegate.event.ActivitiEventListener,例如:

public class MyEventListener implements ActivitiEventListener {

@Override
public void onEvent(ActivitiEvent event) {
switch (event.getType()) {

case JOB_EXECUTION_SUCCESS:
System.out.println("A job well done!");
break;

case JOB_EXECUTION_FAILURE:
System.out.println("A job has failed...");
break;

default:
System.out.println("Event received: " + event.getType());
}

@Override
public boolean isFailOnException() {
// The logic in the onEvent method of this listener is not critical, exceptions
// can be ignored if logging fails...
return false;
}
}

MyEventListener接收标准事件类型并处理和异常处理,其中isFailOnException()决定了onEvent(..)是否抛出异常,如果返回false,异常将会被忽略。如果返回true,异常将会逐级向上提交,造成当前运行的命令的失败。如果当前执行具有事务,事务将会回滚。activiti官方建议如果事件的业务不是非常重要,还是返回false。activiti提供了通用的实现类来处理普通的事件监听,例如:org.activiti.engine.delegate.event.BaseEntityEventListener:它将会监听entity类的事件,它隐藏了类型检查和重写了四个方法,onCreate(..), onUpdate(..)和onDelete(..),对于其他的事件,onEntityEvent(..)将会被调用。2.9 事件的相关配置如果一个事件监听器在流程引擎配置,流程引擎启动将会激活,即使重启引擎也会保持该状态。eventListeners属性值为org.activiti.engine.delegate.event.ActivitiEventListener的实例的list,例如:

&bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"&
&property name="eventListeners"&
&list&
&bean class="org.activiti.engine.example.MyEventListener" /&
&/list&
&/property&
&/bean&

另外typedEventListeners属性值为Map,key为事件的名称,value表示为一个org.activiti.engine.delegate.event.ActivitiEventListener的list集合,例如:

&bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"&
&property name="typedEventListeners"&
&map&
&entry key="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" &
&list&
&bean class="org.activiti.engine.example.MyJobEventListener" /&
&/list&
&/entry&
&/map&
&/property&
&/bean&

事件发生的顺序取决于被配置的监听器的顺序。首先,所有的普通的监听器会被调用(也就是说eventListeners属性,至于eventListeners的内部的监听器顺序和配置的顺序有关)
,然后是在typedListeners属性配置的会被调用。
2.10 程序运行时动态添加监听器
调用RuntimeService的api方法可以实现这个功能:(注意:系统重启会导致监听器消失)

void addEventListener(ActivitiEventListener listenerToAdd);

void addEventListener(ActivitiEventListener listenerToAdd, ActivitiEventType... types);

void removeEventListener(ActivitiEventListener listenerToRemove);


2.11 添加监听器到流程定义中
在流程定义中添加监听器是允许的,这里定义的监听器会被流程定义相关的事件和所有的相关的流程实例启动后调用,监听器的实现类可以使用全类名、能够被解析为bean的表达式。例如下面这个配置,第一个监听器将接收所有的事件,它使用的是全类名进行配置的,第二个监听器仅仅是在作业执行成功或者失败会被执行,并且使用了在流程引擎中定义的beans属性配置的监听器的表达式。
 

&process id="testEventListeners"&
&extensionElements&
&activiti:eventListener class="org.activiti.engine.test.MyEventListener" /&
&activiti:eventListener delegateExpression="${testEventListener}" events="JOB_EXECUTION_SUCCESS,JOB_EXECUTION_FAILURE" /&
&/extensionElements&
...
&/process&

 如果我们需要在流程定义中配置监听entity的监听器的话,可以这样配置:

&process id="testEventListeners"&
&extensionElements&
&activiti:eventListener class="org.activiti.engine.test.MyEventListener" entityType="task" /&
&activiti:eventListener delegateExpression="${testEventListener}" events="ENTITY_CREATED" entityType="task" /&
&/extensionElements&
...
&/process&

其中entityType的值有:attachment, comment, execution, identity-link, job, process-instance, process-definition, task。
 
 
 

免责声明:本站部分内容、图片、文字、视频等来自于互联网,仅供大家学习与交流。相关内容如涉嫌侵犯您的知识产权或其他合法权益,请向本站发送有效通知,我们会及时处理。反馈邮箱&&&&。
学生服务号
在线咨询,奖学金返现,名师点评,等你来互动activiti 用户任务
- serv - ITeye博客
博客分类:
user task 是一个需要由实际用户操作的节点. 当流程执行到这么一个用户任务节点时,会通过user(用户) 或者组(group) 在task中定义的 assigned 角色来创建一个新的用户任务.
用户任务就是左上角有人员图标的图形
id="theTask"name="Important task"
documentation 是描述信息,可选
id="theTask"name="Schedule meeting"
Schedule an engineering meeting for next week with the new hire.
通过task获取方式如下:
task.getDescription()
Due 到期日
到期日 必须是java.util.Date 类型, 或者 格式化后的String类型,或者null ,
生成方式可以是表单输入,或者之前的service 任务生成.
&userTask id="theTask" name="Important task" activiti:dueDate="${dateVariable}"/&
也可以通过 TaskService 或者TaskListeners , DelegateTask.改变值
User assignment 审批人
可以分配给一个用户 ,通过 humanPerformer 节点 的 sourceAssignmentExpression 节点 指定人员 . 现在 仅支持 formalExpressions 属性.
&process ... &
&userTask id='theTask' name='important task' &
&humanPerformer&
&resourceAssignmentExpression&
&formalExpression&kermit&/formalExpression&
&/resourceAssignmentExpression&
&/humanPerformer&
&/userTask&
解释为受让人, 或者审批人,
只有一个审批人的任务. 由其在 代办任务中查看, 其他人是看不到的.
直接分配assignee 的用户任务,可以通过 taskService 检索到其 需要代办的任务列表:
List&Task& tasks = taskService.createTaskQuery().taskAssignee("kermit").list();
任务也可以开放给 候选人 列表.那么, potentialOwner 节点就用上了, 用法跟 humanPerformer 节点类似. 要注意的是:候选人必须制定候选人是用户,还是组, 否则无法解析定义的到底是什么东西
&process ... &
&userTask id='theTask' name='important task' &
&potentialOwner&
&resourceAssignmentExpression&
&formalExpression&user(kermit), group(management)&/formalExpression&
&/resourceAssignmentExpression&
&/potentialOwner&
&/userTask&
列出候选人 所属的task 列表 ,代码如下:
List&Task& tasks = taskService.createTaskQuery().taskCandidateUser("kermit");
如果没有制定 user 或者group 默认以组方式查询 类似: group(accountancy)
&formalExpression&accountancy&/formalExpression&
Activiti extensions for task assignment 审批人简单扩展
下面是通过activiti 提供的简单的描述方式,来定义审批人.比上面那种xml格式简单多了.
assignee attribute: 指定实际用户.
&userTask id="theTask" name="my task" activiti:assignee="kermit" /&
跟 humanPerformer 定义效果一样
candidateUsers attribute: 指定候选人
&userTask id="theTask" name="my task" activiti:candidateUsers="kermit, gonzo" /&
跟 potentialOwner定义效果一样. 不用再像 user(kermit) 这样输入, 因为他本身就是user节点. 直接输入用户代码就行了
candidateGroups attribute:指定候选人的组名
&userTask id="theTask" name="my task" activiti:candidateGroups="management, accountancy" /&
同上, 直接写group name就行了
candidateUsers 和 candidateGroups can 在同一个task节点中可以同时存在
验证用户权限,在集成到业务系统中时需要用上监听:
&userTask id="task1" name="My task" &
&extensionElements&
&activiti:taskListener event="create" class="org.activiti.MyAssignmentHandler" /&
&/extensionElements&
&/userTask&
DelegateTask 也是通过 TaskListener 实现,来指定受让人,或者受让组(候选人/候选组)
public class MyAssignmentHandler implements TaskListener {
public void notify(DelegateTask delegateTask) {
// Execute custom identity lookups here
// and then for example call following methods:
delegateTask.setAssignee("kermit");
delegateTask.addCandidateUser("fozzie");
delegateTask.addCandidateGroup("management");
如果你使用了spring,可以使用service 表达式实现, 如下,就定义了 通过 ldapServie 的 findManagerForEmployee 方法或者审批人.
&userTask id="task" name="My Task" activiti:assignee="${ldapService.findManagerForEmployee(emp)}"/&
获取受让人(候选人) 如出一辙:
&userTask id="task" name="My Task" activiti:candidateUsers="${ldapService.findAllSales()}"/&
注意: 方法返回值 必须是 String 或者 List&String& 类型:
public class FakeLdapService {
public String findManagerForEmployee(String employee) {
return "Kermit The Frog";
public List&String& findAllSales() {
return Arrays.asList("kermit", "gonzo", "fozzie");
浏览 18751
浏览: 363852 次
来自: 北京
lz,您的diagram-viewer可以访问吗?
我也遇到了被事务代理的spring service 不能使用注 ...
处理的方法,就是在ListWorker中增加对TYPE指令设置 ...
抱歉,光这么改貌似还有问题,会导致一个文件上传完毕之后不能自动 ...
虽然好几年前的帖子了,不过我最近要用到,发现源码里有个很大的坑 ...11:57 提问
activiti工作流,退回问题。。
执行退回到上一节点操作时,完成操作执行报错空指针,task的值都取到了啊,执行到plete
Map&String, Object&
// 取得当前任务.当前任务节点
HistoricTaskInstance currTask = historyService
.createHistoricTaskInstanceQuery().taskId(taskId)
.singleResult();
// 取得流程实例,流程实例
ProcessInstance instance = runtimeService
.createProcessInstanceQuery()
.processInstanceId(currTask.getProcessInstanceId())
.singleResult();
if (instance == null) {
("流程结束");
log.error("出错啦!流程已经结束");
return "ERROR";
variables = instance.getProcessVariables();
// 取得流程定义
ProcessDefinitionEntity definition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(currTask
.getProcessDefinitionId());
if (definition == null) {
("流程定义未找到");
log.error("出错啦!流程定义未找到");
return "ERROR";
// 取得上一步活动
ActivityImpl currActivity = ((ProcessDefinitionImpl) definition)
.findActivity(currTask.getTaskDefinitionKey());
//也就是节点间的连线
List&PvmTransition& nextTransitionList = currActivity
.getIncomingTransitions();
// 清除当前活动的出口
List&PvmTransition& oriPvmTransitionList = new ArrayList&PvmTransition&();
//新建一个节点连线关系集合
List&PvmTransition& pvmTransitionList = currActivity
.getOutgoingTransitions();
for (PvmTransition pvmTransition : pvmTransitionList) {
oriPvmTransitionList.add(pvmTransition);
pvmTransitionList.clear();
// 建立新出口
List&TransitionImpl& newTransitions = new ArrayList&TransitionImpl&();
for (PvmTransition nextTransition : nextTransitionList) {
PvmActivity nextActivity = nextTransition.getSource();
ActivityImpl nextActivityImpl = ((ProcessDefinitionImpl) definition)
.findActivity(nextActivity.getId());
TransitionImpl newTransition = currActivity
.createOutgoingTransition();
newTransition.setDestination(nextActivityImpl);
newTransitions.add(newTransition);
// 完成任务
List&Task& tasks = taskService.createTaskQuery()
.processInstanceId(instance.getId())
.taskDefinitionKey(currTask.getTaskDefinitionKey()).list();
for (Task task : tasks) {
plete(task.getId(), variables);
UserInfo user = SessionUtil.getUser();
Authentication.setAuthenticatedUserId(user.getUserId()+"");//批注人的名称
一定要写,不然查看的时候不知道人物信息
taskService.addComment(taskId, null, comment);//comment为批注内容
historyService.deleteHistoricTaskInstance(task.getId());
// 恢复方向
for (TransitionImpl transitionImpl : newTransitions) {
currActivity.getOutgoingTransitions().remove(transitionImpl);
for (PvmTransition pvmTransition : oriPvmTransitionList) {
pvmTransitionList.add(pvmTransition);
("流程结束");
return "SUCCESS";
} catch (Exception e) {
log.error("失败");
log.error(e.getMessage());
return "ERROR";
下面是控制台代码
11:51:06|http-bio-8080-exec-10|DEBUG|org.activiti.engine.mandContext.close(CommandContext.java:171)|Error while closing command context
java.lang.NullPointerException
at org.activiti.engine.impl.bpmn.behavior.BpmnActivityBehavior.performOutgoingBehavior(BpmnActivityBehavior.java:126)
at org.activiti.engine.impl.bpmn.behavior.BpmnActivityBehavior.performDefaultOutgoingBehavior(BpmnActivityBehavior.java:66)
at org.activiti.engine.impl.bpmn.behavior.FlowNodeActivityBehavior.leave(FlowNodeActivityBehavior.java:44)
at org.activiti.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior.leave(AbstractBpmnActivityBehavior.java:47)
at org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior.signal(UserTaskActivityBehavior.java:225)
at org.activiti.engine.impl.persistence.entity.ExecutionEntity.signal(ExecutionEntity.java:409)
at org.activiti.engine.impl.persistence.plete(TaskEntity.java:203)
at org.activiti.engine.pleteTaskCmd.execute(CompleteTaskCmd.java:52)
at org.activiti.engine.pleteTaskCmd.execute(CompleteTaskCmd.java:24)
at org.activiti.engine.impl.cmd.NeedsActiveTaskCmd.execute(NeedsActiveTaskCmd.java:59)
at org.activiti.engine.mandInvoker.execute(CommandInvoker.java:24)
at org.activiti.engine.mandContextInterceptor.execute(CommandContextInterceptor.java:57)
at org.activiti.spring.SpringTransactionInterceptor$1.doInTransaction(SpringTransactionInterceptor.java:47)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
at org.activiti.spring.SpringTransactionInterceptor.execute(SpringTransactionInterceptor.java:45)
at org.activiti.engine.impl.interceptor.LogInterceptor.execute(LogInterceptor.java:37)
at org.activiti.engine.mandExecutorImpl.execute(CommandExecutorImpl.java:40)
at org.activiti.engine.mandExecutorImpl.execute(CommandExecutorImpl.java:35)
at org.activiti.engine.plete(TaskServiceImpl.java:179)
at com.skysoft.irevisit.visit.service.dengji.DengJiService.boHui(DengJiService.java:649)
at com.skysoft.irevisit.visit.web.dengji.DengJiController.execute(DengJiController.java:355)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:214)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:748)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:945)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:931)
按赞数排序
问题解决了,是bpmn文件损坏了,重新画了个流程图,部署上去就好了!Activiti 工作流引擎的初步使用 - 简书
Activiti 工作流引擎的初步使用
 最近领导让我研究下工作流,于是查啊查就查到了Activiti,特么刚开始一直查的是Activity,查出来一堆Android的东西,我也是醉了。话不多说,下面就记录下这2天的研究成果吧。
 Maven工程 JDK:jdk1.8.0_73 IDE:eclipse Mars.2 Release (4.5.2) 数据库:mysql 5.1.39-ndb-7.0.9-cluster-gpl SSM框架:(spring + spring-mvc)4.3.2.RELEASE + mybatis3.4.1 Activiti:5.21.0
 spring+mvc+mybatis整合就不贴了,网上一大堆了
eclipse安装流程设计插件
 eclipse依次点击 Help -& Install New Software -& Add: Name:Activiti Designer Location: 点击OK选中插件安装即可
添加 Activiti 到项目中
在 pom.xml 中添加 Activiti 依赖
&activiti.version&5.21.0&/activiti.version&
&dependency&
&groupId&org.activiti&/groupId&
&artifactId&activiti-engine&/artifactId&
&version&${activiti.version}&/version&
&/dependency&
&dependency&
&groupId&org.activiti&/groupId&
&artifactId&activiti-spring&/artifactId&
&version&${activiti.version}&/version&
&/dependency&
&dependency&
&groupId&org.activiti&/groupId&
&artifactId&activiti-rest&/artifactId&
&version&${activiti.version}&/version&
&/dependency&
2.新建 applicationContext-activiti.xml,别忘了在主配置文件中将其import
&?xml version="1.0" encoding="UTF-8"?&
&beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"&
&!-- 流程配置 --&
&bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"&
&property name="dataSource" ref="dataSource" /&
&property name="transactionManager" ref="transactionManager" /&
&property name="databaseSchemaUpdate" value="true" /&
&property name="jobExecutorActivate" value="true" /&
&!-- 以下2个是为了防止生成流程图片时出现乱码 --&
&property name="activityFontName" value="宋体"/&
&property name="labelFontName" value="宋体"/&
&!-- 流程引擎 --&
&bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean"&
&property name="processEngineConfiguration" ref="processEngineConfiguration" /&
&!-- 流程服务 --&
&bean id="repositoryService" factory-bean="processEngine"
factory-method="getRepositoryService" /&
&bean id="runtimeService" factory-bean="processEngine"
factory-method="getRuntimeService" /&
&bean id="taskService" factory-bean="processEngine"
factory-method="getTaskService" /&
&bean id="historyService" factory-bean="processEngine"
factory-method="getHistoryService" /&
&bean id="managementService" factory-bean="processEngine"
factory-method="getManagementService" /&
&bean id="IdentityService" factory-bean="processEngine"
factory-method="getIdentityService" /&
 3.启动项目,如果未出现错误,Activiti会在连接的数据库中自动新建25张表,如下:
25张表.png
 至此Activiti流程引擎添加完毕,下面开始使用Activiti,实现一次请假流程
 流程设计插件安装成功后会在eclipse新建向导中出现Activiti向导,如图
Paste_Image.png
1.我们新建一个 Activiti Diagram 命名为 leave.bpmn,完成时如下图:
Paste_Image.png
 主要就是拖拖拉拉,从左至右控件分别为StartEvent,UserTask,ExlusiveGateway,UserTask,EndEvent;连线都是SequenceFlow
 属性可在Properties视图中设置,如果没有这个视图,可在 eclipse 中依次点击Window-&Show View-&Other 搜索Properties点击OK即可
流程属性:一般设置一个Id,Name,NameSpace就可以了,此处为分别为leaveProcess、Leave Process、 这个Id在之后启动流程时会用到,不同流程Id不可相同
开始事件(StartEvent):流程开始
结束事件(EndEvent):流程结束
用户任务(UserTask):主要用到Id,Name,AssigneeAssignee为此任务的办理人,在查找任务时需要用到,三个任务分别指派给 apply,pm,boss
Paste_Image.png
Paste_Image.png
排他网关(ExlusiveGateway):只会寻找唯一一条能走完的顺序流
顺序流(SequenceFlow):主要用到Id,Name,ConditionCondition用于指定该顺序流表达式 ,day的值会在调用执行任务方法时传入
Paste_Image.png
 除了使用可视化组件,我们也可以通过xml来设计流程,以上流程的xml定义如下:
&?xml version="1.0" encoding="UTF-8"?&
&definitions xmlns="http://www.omg.org/spec/BPMN//MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN//DI" xmlns:omgdc="http://www.omg.org/spec/DD//DC" xmlns:omgdi="http://www.omg.org/spec/DD//DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace=""&
&process id="leaveProcess" name="Leave Process" isExecutable="true"&
&startEvent id="startevent1" name="开始"&&/startEvent&
&userTask id="usertask1" name="请假申请" activiti:assignee="apply"&&/userTask&
&exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"&&/exclusiveGateway&
&sequenceFlow id="flow2" name="天数判断" sourceRef="usertask1" targetRef="exclusivegateway1"&&/sequenceFlow&
&userTask id="usertask2" name="审批(项目经理)" activiti:assignee="pm"&&/userTask&
&sequenceFlow id="flow3" name="小于等于三天" sourceRef="exclusivegateway1" targetRef="usertask2"&
&conditionExpression xsi:type="tFormalExpression"&&![CDATA[${day&=3}]]&&/conditionExpression&
&/sequenceFlow&
&userTask id="usertask3" name="审批(老板)" activiti:assignee="boss"&&/userTask&
&sequenceFlow id="flow4" name="大于三天" sourceRef="exclusivegateway1" targetRef="usertask3"&
&conditionExpression xsi:type="tFormalExpression"&&![CDATA[${day&3}]]&&/conditionExpression&
&/sequenceFlow&
&endEvent id="endevent1" name="End"&&/endEvent&
&sequenceFlow id="flow5" sourceRef="usertask2" targetRef="endevent1"&&/sequenceFlow&
&sequenceFlow id="flow6" sourceRef="usertask3" targetRef="endevent1"&&/sequenceFlow&
&sequenceFlow id="flow7" sourceRef="startevent1" targetRef="usertask1"&&/sequenceFlow&
&/process&
&bpmndi:BPMNDiagram id="BPMNDiagram_leaveProcess"&
&bpmndi:BPMNPlane bpmnElement="leaveProcess" id="BPMNPlane_leaveProcess"&
&bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1"&
&omgdc:Bounds height="35.0" width="35.0" x="30.0" y="211.0"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1"&
&omgdc:Bounds height="55.0" width="105.0" x="110.0" y="201.0"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1"&
&omgdc:Bounds height="40.0" width="40.0" x="285.0" y="208.0"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2"&
&omgdc:Bounds height="55.0" width="105.0" x="400.0" y="120.0"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3"&
&omgdc:Bounds height="55.0" width="105.0" x="400.0" y="290.0"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1"&
&omgdc:Bounds height="35.0" width="35.0" x="560.0" y="211.0"&&/omgdc:Bounds&
&/bpmndi:BPMNShape&
&bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2"&
&omgdi:waypoint x="215.0" y="228.0"&&/omgdi:waypoint&
&omgdi:waypoint x="285.0" y="228.0"&&/omgdi:waypoint&
&bpmndi:BPMNLabel&
&omgdc:Bounds height="14.0" width="48.0" x="230.0" y="228.0"&&/omgdc:Bounds&
&/bpmndi:BPMNLabel&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3"&
&omgdi:waypoint x="305.0" y="208.0"&&/omgdi:waypoint&
&omgdi:waypoint x="452.0" y="175.0"&&/omgdi:waypoint&
&bpmndi:BPMNLabel&
&omgdc:Bounds height="14.0" width="100.0" x="295.0" y="180.0"&&/omgdc:Bounds&
&/bpmndi:BPMNLabel&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4"&
&omgdi:waypoint x="305.0" y="248.0"&&/omgdi:waypoint&
&omgdi:waypoint x="452.0" y="290.0"&&/omgdi:waypoint&
&bpmndi:BPMNLabel&
&omgdc:Bounds height="14.0" width="48.0" x="285.0" y="257.0"&&/omgdc:Bounds&
&/bpmndi:BPMNLabel&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5"&
&omgdi:waypoint x="452.0" y="175.0"&&/omgdi:waypoint&
&omgdi:waypoint x="577.0" y="211.0"&&/omgdi:waypoint&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6"&
&omgdi:waypoint x="452.0" y="290.0"&&/omgdi:waypoint&
&omgdi:waypoint x="577.0" y="246.0"&&/omgdi:waypoint&
&/bpmndi:BPMNEdge&
&bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7"&
&omgdi:waypoint x="65.0" y="228.0"&&/omgdi:waypoint&
&omgdi:waypoint x="110.0" y="228.0"&&/omgdi:waypoint&
&/bpmndi:BPMNEdge&
&/bpmndi:BPMNPlane&
&/bpmndi:BPMNDiagram&
&/definitions&
 有了流程图,我们就可以部署该流程了,Activiti提供多种部署方法(有自动部署,手动部署等),这里演示两种手动部署方法
Workflow.java代码片段
private static ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
* 通过定义好的流程图文件部署,一次只能部署一个流程
public static void deploy() {
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("death/note/lawliet/web/workflow/leave.bpmn").deploy();
* 将多个流程文件打包部署,一次可以部署多个流程
public void deployByZip() {
InputStream is = this.getClass().getClassLoader().getResourceAsStream("diagrams/bpm.zip");
ZipInputStream zip = new ZipInputStream(is);
Deployment deployment = processEngine
.getRepositoryService()
.createDeployment()
.addZipInputStream(zip)
.deploy();
 方便起见,通过一个Deploy按钮来部署流程
Paste_Image.png
 部署成功后,会分别在 act_ge_bytearray,act_re_deployment,act_re_procdef三张表插入相应数据,多次部署同一流程的话会增加版本号,以此获取最新的流程
 我们通过一个表单来用于请假申请
Paste_Image.png
 我们定义一个 Leave 对象用于保存请假信息,相应的数据表为 leave 。Result 对象用于封装一些返回信息。这里的 "leaveProcess" 就是在流程属性中定义的Id。启动成功后会返回一个 ProcessInstance
对象,这个对象主要是一些流程的基本信息,具体可以查看文档或源码。这里将返回的流程实例 id 存入到我们的 leave 表,以便以后可以通过这个 id 查询相关的流程。
@ResponseBody
@RequestMapping(value = "/save", method = RequestMethod.POST)
public Result save(@RequestBody Leave user) {
Result result = new Result();
ProcessInstance pi = Workflow.startInstanceByKey("leaveProcess");
user.setInstaceId(pi.getId());
leaveService.insert(user);
(true, 0, "保存成功");
Workflow.java代码片段
public static ProcessInstance startInstanceByKey(String instanceByKey) {
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance instance = runtimeService.startProcessInstanceByKey(instanceByKey);
 流程启动成功后会在 act_hi_actinst,act_hi_identitylink,act_hi_procinst,act_hi_taskinst,act_ru_execution,act_ru_identitylink,act_ru_task 表中插入相应数据。我们比较关心的就是 act_ru_task 表了,它存储了任务的相关信息。
 流程启动完毕后,应该就是进入了请假申请任务,我们可以通过请假申请的办理人 apply 来查询该任务(当然还有其他方法),这里可以指定不同查询条件和过滤条件。返回 taskList 就是当前的任务列表了,Task是Activiti为我们定义好的接口对象,主要封装了任务的信息。 这里由于 Activiti
的Task是接口对象无法转换为json,所以自定义了一个Task对象,来转换成json
@ResponseBody
@RequestMapping(value = "/data/{assignee}")
public List&death.note.lawliet.web.model.Task& data(@PathVariable String assignee){
List&Task& tasks = Workflow.findTaskByAssignee(assignee);
List&death.note.lawliet.web.model.Task& list = new ArrayList&&();
for(Task task : tasks){
death.note.lawliet.web.model.Task t = new death.note.lawliet.web.model.Task();
t.setTaskId(task.getId());
t.setName(task.getName());
t.setAssignee(task.getAssignee());
t.setExecutionId(task.getExecutionId());
t.setProcessInstanceId(task.getProcessInstanceId());
t.setProcessDefinitionId(task.getProcessDefinitionId());
list.add(t);
Workflow.java代码片段
public static List&Task& findTaskByAssignee(String assignee) {
TaskService taskService = processEngine.getTaskService();
List&Task& taskList = taskService.createTaskQuery().taskAssignee(assignee).list();
return taskL
Paste_Image.png
查看流程图
 我们可以通过流程定义ID(processDefinitionId)来获取流程图
@RequestMapping(value = "/shwoImg/{procDefId}")
public void shwoImg(@PathVariable String procDefId,HttpServletResponse response){
InputStream pic = Workflow.findProcessPic(procDefId);
byte[] b = new byte[1024];
int len = -1;
while((len = pic.read(b, 0, 1024)) != -1) {
response.getOutputStream().write(b, 0, len);
} catch (Exception e) {
e.printStackTrace();
Workflow.java代码片段
public static InputStream findProcessPic(String procDefId) throws Exception {
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId)
.singleResult();
String diagramResourceName = procDef.getDiagramResourceName();
InputStream imageStream = repositoryService.getResourceAsStream(procDef.getDeploymentId(), diagramResourceName);
return imageS
 然后通过processDefinitionId,executionId 来获取当前正在执行任务的位置坐标,以便用于标识流程图上的位置。ActivityImpl 对象封装了任务的位置信息,包括xy坐标,长和宽。自定义 Rect 对象用于转换json
@ResponseBody
@RequestMapping(value = "/showImg/{procDefId}/{executionId}")
public Rect showImg(@PathVariable String procDefId,@PathVariable String executionId ) {
Rect rect = new Rect();
ActivityImpl img = Workflow.getProcessMap(procDefId,executionId );
rect.setX(img.getX());
rect.setY(img.getY());
rect.setWidth(img.getWidth());
rect.setHeight(img.getHeight());
} catch (Exception e) {
e.printStackTrace();
Workflow.java代码片段
public static ActivityImpl getProcessMap(String procDefId, String executionId) throws Exception {
ActivityImpl actImpl =
RepositoryService repositoryService = processEngine.getRepositoryService();
//获取流程定义实体
ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(procDefId);
RuntimeService runtimeService = processEngine.getRuntimeService();
//获取执行实体
ExecutionEntity execution = (ExecutionEntity) runtimeService.createExecutionQuery().executionId(executionId)
.singleResult();
// 获取当前任务执行到哪个节点
String activitiId = execution.getActivityId();
// 获得当前任务的所有节点
List&ActivityImpl& activitiList = def.getActivities();
for (ActivityImpl activityImpl : activitiList) {
String id = activityImpl.getId();
if (id.equals(activitiId)) {
actImpl = activityI
return actI
 最终生成图片时分别调用2个 showImg 方法即可,红框可以根据返回的 Rect 来绘制,起始坐标根据自己的布局自行调整
LeavePicController.js片段
var pic.rect = {};
var pic.procDefId = $stateParams.procDefId;
$http.get('workflow/showImg/'+$stateParams.procDefId +'/'+$stateParams.executionId)
.success(function(data) {
pic.rect.x = data.x;
pic.rect.y = data.y;
pic.rect.width = data.
pic.rect.height = data.
picture.html
&div class="container-fluid" ng-controller="LeavePicController as pic"&
&img src="workflow/showImg/{{pic.procDefId}}"&
&div style="position: border:2
left:{{pic.rect.x + 20 }}
top:{{pic.rect.y + 88 }}
width:{{pic.rect.width }}
height:{{pic.rect.height }}"&
Paste_Image.png
 通过 taskId 就可以对当前执行的任务进行审批,这里的 day 应该从 leave 表中查询出来,方便起见就写死了,这个day也就是在顺序流的Condition中指定的变量,小于等于3就会流向项目经理(pm)审批任务了
@ResponseBody
@RequestMapping(value = "/check/{taskId}")
public Result check(@PathVariable String taskId) {
Result result = new Result();
Map&String, Object& map = new HashMap&&();
map.put("day", 3);
pleteTask(taskId,map);
(true, 0, "审批成功");
Workflow.java代码片段
public static void completeTask(String taskid,Map&String, Object& map map) {
TaskService taskService = processEngine.getTaskService();
plete(taskid, map);
 审批成功后,就需要通过办理人(pm)来查询任务了,并且请假办理(apply)中的任务被移除了
Paste_Image.png
Paste_Image.png
 同时流程图也流向了下一节点
Paste_Image.png
 项目经理再执行一次审批方法,这个流程就算走完了
 以上就是一次相对简单的流程:部署,启动,查询任务,显示流程图,审批。Activiti流程引擎还有很多核心操作,包括驳回、会签、转办、中止、挂起等,等有空的时候再深入研究吧 最后的最后,初来乍到,不喜勿喷或轻喷 - -!Thanks...}

我要回帖

更多关于 activiti工作流面试题 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信