一:什么是Activiti
Activiti是一个开源的工作流引擎,它实现了BPMN 2.0规范,可以发布设计好的流程定义,并通过api进行流程调度。
业务流程模型注解(Business Process Modeling Notation - BPMN)是 业务流程模型的一种标准图形注解。包括用户任务,定时任务都有统一的模型规范。
Activiti 作为一个遵从 Apache 许可的工作流和业务流程管理开源平台,其核心是基于Java的超快速、超稳定的 BPMN2.0 流程引擎,强调流程服务的可嵌入性和可扩展性,同时更加强调面向业务人员。
在项目中,Activiti实际上相当于一个第三方插件帮助原本系统业务更好的执行,Activiti本身并没有任何业务逻辑。
二:为什么需要引入Activiti工作流
举个例子:
如果我们要开发一套请假流程,具体流程如下:
在没有Activiti工作流引擎帮助下,我们会怎么设计表结构?默认模式下,应该会设计两张表,一张来存请假内容,一张来存请假审批过程。只有总经理和HR人力能够批改。假设当我们设计好表后,需求改变了,经理审批这个节点改成组长审批,那这个时候,我们是不是又要修改代码或者表结构?
这个时候Activiti引擎起作用。我们不会把具体节点人写死,而是可以在流程过程中指定。
三:如何使用Activiti
Activiti使用时注意的概念
1.保存流程图—>相当于将流程图存到activiti数据库中,此时是静态资源。
2.发布流程---->相当java中的类,如果开始节点部署的普通的开始事件,则不会自动启动流程,如果里面开始节点使用定时事件,则到时间便会自动启动流程实例(可以内置定时事件应用到TCL电子的点检任务)。
3.启动流程实例—>相当java中的对象
1.每个节点的任务都指定具体人
/**
-
保存流程
-
@param modelId 模型ID
-
@param name 流程模型名称
-
@param description
-
@param json_xml 流程文件
-
@param svg_xml 图片
*/
@RequestMapping(value="/model/{modelId}/save", method = RequestMethod.PUT)
@ResponseStatus(value = HttpStatus.OK)
public void saveModel(@PathVariable String modelId
, String name, String description
, String json_xml, String svg_xml) {
try {Model model = repositoryService.getModel(modelId);
ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
modelJson.put(MODEL_NAME, name);
modelJson.put(MODEL_DESCRIPTION, description);
model.setMetaInfo(modelJson.toString());
model.setName(name);
repositoryService.saveModel(model);repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes(“utf-8”));
InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes(“utf-8”));
TranscoderInput input = new TranscoderInput(svgStream);PNGTranscoder transcoder = new PNGTranscoder();
// Setup output
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(outStream);// Do the transformation
transcoder.transcode(input, output);
final byte[] result = outStream.toByteArray();
repositoryService.addModelEditorSourceExtra(model.getId(), result);
outStream.close();
} catch (Exception e) {
LOGGER.error(“Error saving model”, e);
throw new ActivitiException(“Error saving model”, e);
}
}
/**
* 发布流程
* @param modelId 模型ID
* @return
*/
@ResponseBody
@RequestMapping("/publish")
public Object publish(String modelId){
logger.info(“流程部署入参modelId:{}”,modelId);
Map<String, String> map = new HashMap<String, String>();
try {
Model modelData = repositoryService.getModel(modelId);
byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
if (bytes == null) {
logger.info(“部署ID:{}的模型数据为空,请先设计流程并成功保存,再进行发布”,modelId);
map.put(“code”, “FAILURE”);
return map;
}
JsonNode modelNode = new ObjectMapper().readTree(bytes);
BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
Deployment deployment = repositoryService.createDeployment()
.name(modelData.getName())
.addBpmnModel(modelData.getKey()+".bpmn20.xml", model)
.deploy();
modelData.setDeploymentId(deployment.getId());
repositoryService.saveModel(modelData);
map.put(“code”, “SUCCESS”);
} catch (Exception e) {
logger.info(“部署modelId:{}模型服务异常:{}”,modelId,e);
map.put(“code”, “FAILURE”);
}
logger.info(“流程部署出参map:{}”,map);
return map;
}
/**
-
启动流程实例
/
@Test
public void startProcessInstance() {
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(“process”);
}
/* -
完成Task任务需在最后执行
*/
@Test
public void completeTask() {List list = taskService.createTaskQuery().taskAssignee(“张三”).list();
for (Task task : list) {
taskService.complete(task.getId());
}
}
2.节点代理人是动态的
流程变量概念:相当于局部变量,使用范围在当前实例内有效
/**
- 启动流程实例
*/
@Test
public void startProcessInstance() {
Map<String, Object> map = new HashMap<>();
map.put(“name”, “张三”);
runtimeService.startProcessInstanceByKey(“process”,map);
}
3.流程分支控制
/**
-
完成任务设置流程变量 方式一
*/
@Test
public void completeTask() {List list = taskService.createTaskQuery().taskAssignee(“张三”).list();
for (Task task : list) {
taskService.setVariable(task.getId(),“num”,2);
taskService.complete(task.getId());
}
}
/**
-
完成任务设置流程变量 方式二
*/
@Test
public void completeTask() {List list = taskService.createTaskQuery().taskAssignee(“张三”).list();
for (Task task : list) {
Map<String, Object> map = new HashMap<>();
map.put(“num”, 2);
taskService.complete(task.getId(),map);
}
}
4.候选人和候选组
在实现上,候选人和候选组是一样的
假设总经理有多个人可以审批请假流程,那我们不能把审批人固定为某个人。我们可以直接写死候选人,也可以将候选人设置为流程变量,然后在流程执行过程中设置变量值。
@Test
public void claimTask() {
List list = taskService.createTaskQuery().taskCandidateUser(“刘备”).list();
for (Task task : list) {
taskService.claim(task.getId(), "刘备");
}
}
5.定时任务和脚本任务
假设总经理比较忙,太长时间忘记审批,这个时候可以设置定时任务,调用脚本进行通知
定时任务设置
时间格式使用ISO-8601使用方式可以参考百度百科;其中循环时间可以使用corn表达式
脚本任务设置
脚本支持JavaScript, groovy,研究当中,使用JavaScript
脚本内容中我们可以调用java后台代码中方法
如下callService是我们在java后台中写的一个托管给spring的类,execution是activiti内置的对象,javascript和java代码中都能对其进行调用,可以通过execution获取该流程当前实例id,流程变量等。
@Component
public class CallService {
public String get(DelegateExecution execution){
System.out.println("----get----"+new Date()+"processInstanceId="+execution.getProcessInstanceId()+"--businessKey="+execution.getProcessBusinessKey());
return null;
}
}
6.内置定时启动事件
应用场景:需要定时启动某些流程的时候,我们可以使用定时启动事件做为开始事件。
此时只需要将此流程部署即可,注意点:如果需要使用该定时启动事件的流程来定时启动任务,则部署该定时启动事件流程时需要设置不同流程名(processDefinitonKey)。
和前端探讨:1.修改节点内容
四.Activiti架构
activiti.cfg.xml
activiti 的引擎配置文件,包括:ProcessEngineConfiguration 的定义、数据源定义、事务管理器等,此文件其实就是一个 spring 配置文件。
ProcessEngineConfiguration
流程引擎的配置类,通过 ProcessEngineConfiguration 可以创建工作流引擎 ProceccEngine。
ProcessEngine
工作流引擎,相当于一个门面接口,通过 ProcessEngineConfiguration 创建 processEngine,通过ProcessEngine 创建各个 service 接口。
7个service,在研究当中只看
IdentityService, FormService,ManagementService暂无研究
RepositoryService
是 activiti 的资源管理类,提供了管理和控制流程发布包和流程定义的操作。使用工作流建模工具设计的业务流程图需要使用此 service 将流程定义文件的内容部署到计算机。
除了部署流程定义以外还可以:
查询引擎中的发布包和流程定义。
暂停或激活发布包,对应全部和特定流程定义。 暂停意味着它们不能再执行任何操作了,激活
是对应的反向操作。
获得多种资源,像是包含在发布包里的文件, 或引擎自动生成的流程图。
获得流程定义的 pojo 版本, 可以用来通过 java 解析流程,而不必通过 xml。
RuntimeService
它是 activiti 的流程运行管理类。可以从这个服务类中获取很多关于流程执行相关的信息
TaskService
是 activiti 的任务管理类。可以从这个类中获取任务的信息。
HistoryService
是 activiti 的历史管理类,可以查询历史信息,执行流程时,引擎会保存很多数据(根据配置),比
如流程实例启动时间,任务的参与者, 完成任务的时间,每个流程实例的执行路径,等等。 这个
服务主要通过查询功能来获得这些数据。