java 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:http://activiti.org/designer/update/

点击OK选中插件安装即可

添加 Activiti 到项目中

在 pom.xml 中添加 Activiti 依赖

5.21.0

org.activiti

activiti-engine

${activiti.version}

org.activiti

activiti-spring

${activiti.version}

org.activiti

activiti-rest

${activiti.version}

2.新建 applicationContext-activiti.xml,别忘了在主配置文件中将其import

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">

factory-method="getRepositoryService" />

factory-method="getRuntimeService" />

factory-method="getTaskService" />

factory-method="getHistoryService" />

factory-method="getManagementService" />

factory-method="getIdentityService" />

3.启动项目,如果未出现错误,Activiti会在连接的数据库中自动新建25张表,如下:

bdc9c9fa719d

25张表.png

至此Activiti流程引擎添加完毕,下面开始使用Activiti,实现一次请假流程

设计流程

流程设计插件安装成功后会在eclipse新建向导中出现Activiti向导,如图

bdc9c9fa719d

Paste_Image.png

1.我们新建一个 Activiti Diagram 命名为 leave.bpmn,完成时如下图:

bdc9c9fa719d

Paste_Image.png

主要就是拖拖拉拉,从左至右控件分别为

StartEvent,UserTask,ExlusiveGateway,UserTask,EndEvent;连线都是SequenceFlow

属性可在Properties视图中设置,如果没有这个视图,可在 eclipse 中依次点击

Window->Show View->Other 搜索Properties点击OK即可

流程属性:一般设置一个Id,Name,NameSpace就可以了,此处为分别为leaveProcess、Leave Process、http://www.mario.com; 这个Id在之后启动流程时会用到,不同流程Id不可相同

开始事件(StartEvent):流程开始

结束事件(EndEvent):流程结束

用户任务(UserTask):主要用到Id,Name,Assignee

Assignee为此任务的办理人,在查找任务时需要用到,三个任务分别指派给 apply,pm,boss

bdc9c9fa719d

Paste_Image.png

bdc9c9fa719d

Paste_Image.png

排他网关(ExlusiveGateway):只会寻找唯一一条能走完的顺序流

顺序流(SequenceFlow):主要用到Id,Name,Condition

Condition用于指定该顺序流表达式 ,day的值会在调用执行任务方法时传入

bdc9c9fa719d

Paste_Image.png

除了使用可视化组件,我们也可以通过xml来设计流程,以上流程的xml定义如下:

3}]]>

流程部署

有了流程图,我们就可以部署该流程了,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按钮来部署流程

bdc9c9fa719d

Paste_Image.png

部署成功后,会分别在 act_ge_bytearray,act_re_deployment,act_re_procdef三张表插入相应数据,多次部署同一流程的话会增加版本号,以此获取最新的流程

启动流程

我们通过一个表单来用于请假申请

bdc9c9fa719d

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);

result.info(true, 0, "保存成功");

return result;

}

Workflow.java代码片段

public static ProcessInstance startInstanceByKey(String instanceByKey) {

RuntimeService runtimeService = processEngine.getRuntimeService();

ProcessInstance instance = runtimeService.startProcessInstanceByKey(instanceByKey);

return instance;

}

流程启动成功后会在 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 data(@PathVariable String assignee){

List tasks = Workflow.findTaskByAssignee(assignee);

List 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);

}

return list;

}

Workflow.java代码片段

public static List findTaskByAssignee(String assignee) {

TaskService taskService = processEngine.getTaskService();

List taskList = taskService.createTaskQuery().taskAssignee(assignee).list();

return taskList;

}

bdc9c9fa719d

Paste_Image.png

查看流程图

我们可以通过流程定义ID(processDefinitionId)来获取流程图

@RequestMapping(value = "/shwoImg/{procDefId}")

public void shwoImg(@PathVariable String procDefId,HttpServletResponse response){

try {

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 imageStream;

}

然后通过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();

try {

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();

}

return rect;

}

Workflow.java代码片段

public static ActivityImpl getProcessMap(String procDefId, String executionId) throws Exception {

ActivityImpl actImpl = null;

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 activitiList = def.getActivities();

for (ActivityImpl activityImpl : activitiList) {

String id = activityImpl.getId();

if (id.equals(activitiId)) {

actImpl = activityImpl;

break;

}

}

return actImpl;

}

最终生成图片时分别调用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.width;

pic.rect.height = data.height;

});

picture.html

%7B%7Bpic.procDefId%7D%7D

bdc9c9fa719d

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 map = new HashMap<>();

map.put("day", 3);

Workflow.completeTask(taskId,map);

result.info(true, 0, "审批成功");

return result;

}

Workflow.java代码片段

public static void completeTask(String taskid,Map map map) {

TaskService taskService = processEngine.getTaskService();

taskService.complete(taskid, map);

}

审批成功后,就需要通过办理人(pm)来查询任务了,并且请假办理(apply)中的任务被移除了

bdc9c9fa719d

Paste_Image.png

bdc9c9fa719d

Paste_Image.png

同时流程图也流向了下一节点

bdc9c9fa719d

Paste_Image.png

项目经理再执行一次审批方法,这个流程就算走完了

最后

以上就是一次相对简单的流程:部署,启动,查询任务,显示流程图,审批。Activiti流程引擎还有很多核心操作,包括驳回、会签、转办、中止、挂起等,等有空的时候再深入研究吧

最后的最后,初来乍到,不喜勿喷或轻喷 - -!Thanks...

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值