2019-02-22 · Develop

Activiti 快速入门

Activiti 流程简介

Activiti 流程引擎重点关注在系统开发的易用性和轻量性上。每一项 BPM 业务功能 Activiti 流程引擎都以服务的形式提供给开发人员。通过这些服务,开发人员能够构建出功能丰富、轻便且高效的 BPM 应用程序。

Activiti 系统服务结构图如下所示

activiti-service

下面我们来快速开发的 Activiti 的栗子。 一个完整的流程应该包含如下的几个步骤:

编辑流程文件

在开始编码前,先编辑好需要使用到的流程文件

eclipse-activiti-designer

上图中的流程文件是使用 eclipse 的 activiti 插件进行编辑。这里是编辑好的流程文件点击下载

创建流程引擎

这里使用默认的配置创建一个基于 H2 数据库的流程引擎

private static ProcessEngine createProcessEngine() {
    // 通过代码形式创建 ProcessEngineConfiguration 对象,也可以使用配置文件
    ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();
    // 设置数据库相关属性,不配置默认使用 H2 内存数据库
    // cfg.setJdbcDriver("com.mysql.jdbc.Driver");
    // cfg.setJdbcUrl("jdbc:mysql://192.168.113.131:3306/lo?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull");
    // cfg.setJdbcUsername("lo");
    // cfg.setJdbcPassword("lo");
    // 设置没有表则自动创建表
    // cfg.setDatabaseSchemaUpdate("true");
    ProcessEngine engine = cfg.buildProcessEngine();
    log.info("流程引擎名称[{}]版本[{}]", engine.getName(), engine.VERSION);
    return engine;
}

部署流程定义文件

获取到 RepositoryService 来部署流程定义文件

private static ProcessDefinition buildProcessDefinition(ProcessEngine engine) {
    RepositoryService repositoryService = engine.getRepositoryService();
    DeploymentBuilder builder = repositoryService.createDeployment();
    builder.addClasspathResource("second_approve.bpmn20.xml");
    Deployment deploy = builder.deploy();
    String id = deploy.getId();
    ProcessDefinition result = repositoryService.createProcessDefinitionQuery().deploymentId(id).singleResult();
    log.info("流程定义文件[{}],流程ID[{}]", result.getName(), result.getId());
    return result;
}

启动运行流程

使用 RuntimeService 来运行流程

private static ProcessInstance runProcessInstance(ProcessEngine engine, ProcessDefinition result) {
    RuntimeService runtimeService = engine.getRuntimeService();
    ProcessInstance processInstance = runtimeService.startProcessInstanceById(result.getId());
    log.info("启动流程[{}]", processInstance.getProcessDefinitionKey());
    return processInstance;
}

处理流程任务

最后在流程启动后去模拟处理流程,使用控制台输入 scanner 来输入表单信息,循环处理所有的任务

private static void processTasks(ProcessEngine engine, ProcessInstance processInstance) throws ParseException {
    try (Scanner scanner = new Scanner(System.in)) {
        while (processInstance != null && !processInstance.isEnded()) {
            TaskService taskService = engine.getTaskService();
            List<Task> taskList = taskService.createTaskQuery().list();
            log.info("待处理任务数量[{}]", taskList.size());
            for (Task task : taskList) {
                log.info("待处理任务[{}]", task.getName());
                // 构建参数
                Map<String, Object> variables = getVariableMap(engine, scanner, task);
                taskService.complete(task.getId(), variables);
                processInstance = engine.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstance.getId()).singleResult();
            }
        }
    }
}

其中需要构建处理任务需要的表单参数,栗子中的流程只有 String 和 Date 类型的参数需要输入。

private static Map<String, Object> getVariableMap(ProcessEngine engine, Scanner scanner, Task task) throws ParseException {
    FormService formService = engine.getFormService();
    TaskFormData taskFormData = formService.getTaskFormData(task.getId());
    List<FormProperty> formProperties = taskFormData.getFormProperties();
    Map<String, Object> variables = new HashMap<>();
    for (FormProperty formProperty : formProperties) {
        String line = null;
        if (StringFormType.class.isInstance(formProperty.getType())) {
            log.info("请输入[{}]", formProperty.getName());
            line = scanner.nextLine();
            variables.put(formProperty.getId(), line);
        } else if (DateFormType.class.isInstance((formProperty.getType()))) {
            log.info("请输入[{}],格式为[yyyy-MM-dd]", formProperty.getName());
            line = scanner.nextLine();
            variables.put(formProperty.getId(), new SimpleDateFormat("yyyy-MM-dd").parse(line));
        } else {
            log.info("暂不支持类型[{}]", formProperty.getType());
        }
        log.info("您输入的内容是[{}]", line);
    }
    return variables;
}

最后将所有的步骤组装起来运行代码

public static void main(String[] args) throws ParseException {
    log.info("启动程序");
    // 创建流程引擎
    ProcessEngine engine = createProcessEngine();
    // 部署流程定义文件
    ProcessDefinition result = buildProcessDefinition(engine);
    // 启动运行流程
    ProcessInstance processInstance = runProcessInstance(engine, result);
    // 处理流程任务
    processTasks(engine, processInstance);
    log.info("结束程序");
}

如上代码体现了 actitviti 的轻量级,可潜入的 BPM 引擎。