Spring Boot 2.0 集成 Activiti 6.0 详解

序言

工作流框架是每一个比较复杂的OA或者ERP系统都会用到的一套自动化工作流程的组件,刚开始从官网下载下来的时候看到辣么大的一个包(解压下来完整整150M左右。。。。),然后再稍微建一下数据库,打开表一看,当时我就方了(整整23张表),但是没办法,自己框架要用到,早晚也要看的,只能硬着头皮撸了~

网上的资料大部分都是Activiti与Spring集成的,用的都是Activiti5的版本,但是由于我的基础框架是Spring Boot,所以只能撸一套和Spring Boot集成的框架,而且还得支持RESTful,仔细想一下,要填的坑还是不少的。

1.尝试直接使用activiti-spring-boot-starter-basic来与Spring Boot进行集成

用过Spring Boot的同学都知道Spring Boot Stater是个好东西,基于这个东东开发的组件基本上是零配置就能集成进Spring Boot里面,非常的方便,即官方所说的“开箱即用",现在有不少插件都是有这个开箱即用的版本,activiti也不例外。

当找到这个插件以后心里微微一喜,毕竟有了这个可以很简单的使用activiti,然鹅,集成之后稍微一试,控制到就无情的报错了。仔细一查控制台才发现,这个插件的最新版本是基于Activiti 6.0来做的,并不支持Spring Boot 2.0这个版本。内心一下万马奔腾。

然后找了一下Activiti 7,当然这不是Release的版本,只存在于Github里,这一个版本是基于Spring Boot 2.0来开发的,但是它并没有开箱即用的版本,所以还是放弃了,最后选择了一个折中的方法,选择了Activiti6使用与Spring集成的方式来与Spring Boot集成,虽然没有做到开箱即用,但是配置代码还是没有太多的。

2.使用activiti-spring与Spring Boot集成

Spring Boot的配置都是基于文件的,也就是说零配置文件来实现,想到这里的话我们就可以开始开工了:


        
            com.fasterxml.jackson.core
            jackson-core
            2.9.5
        

        
        
            org.activiti
            activiti-spring
            6.0.0
        

先引入activiti的依赖,并且可能会用到jackson的依赖,所以一并导入。

导入依赖之后新建activiti的配置文件ActivitiConfig.java:

package tec.gomoo.oa.config;

import org.activiti.engine.*;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.io.IOException;

/**
 * @author phw
 * @date Created in 05-09-2018
 * @description
 */
@Configuration
public class ActivitiConfig {

    @Bean
    public ProcessEngine processEngine(DataSourceTransactionManager transactionManager, DataSource dataSource) throws IOException {
        SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration();
        //自动部署已有的流程文件
        Resource[] resources = new PathMatchingResourcePatternResolver().getResources(ResourceLoader.CLASSPATH_URL_PREFIX + "processes/*.bpmn");
        configuration.setTransactionManager(transactionManager);
        configuration.setDataSource(dataSource);
        configuration.setDatabaseSchemaUpdate("true");
        configuration.setDeploymentResources(resources);
        configuration.setDbIdentityUsed(false);
        return configuration.buildProcessEngine();
    }

    @Bean
    public RepositoryService repositoryService(ProcessEngine processEngine) {
        return processEngine.getRepositoryService();
    }

    @Bean
    public RuntimeService runtimeService(ProcessEngine processEngine) {
        return processEngine.getRuntimeService();
    }

    @Bean
    public TaskService taskService(ProcessEngine processEngine) {
        return processEngine.getTaskService();
    }

    @Bean
    public HistoryService historyService(ProcessEngine processEngine) {
        return processEngine.getHistoryService();
    }

    @Bean
    public ManagementService managementService(ProcessEngine processEngine) {
        return processEngine.getManagementService();
    }

    @Bean
    public IdentityService identityService(ProcessEngine processEngine) {
        return processEngine.getIdentityService();
    }

}

在Config文件上打上@Configuration注解表示这是一个自动配置文件。

首先配置一下activiti流程引擎ProcessEngine的配置类SpringProcessEngineConfiguration,这一个类是activiti和Spring集成的关键类,这个类需要我们注入两个东西,一个是数据源DataSource,一个是数据源的事务管理器DataSourceTransactionManager,这两个东西都可以通过Spring自动注入的东西。

然后把已有的流程文件设置到Configuration里面,在服务启第一次启动时就会自动创建那23张数据库的表,并且部署bpmn文件。生成ProcessEngine后就可以生成那常用几大服务了,像RepositoryService/RuntimeService/TaskService等等。

然后我们再来测试一下:

package tec.gomoo.oa.config;

/**
 * @author phw
 * @date Created in 05-14-2018
 * @description
 */
@Slf4j
@Service
@Transactional
public class ActivitiService {

    private final RuntimeService runtimeService;

    private final TaskService taskService;

    private final HistoryService historyService;

    private final RepositoryService repositoryService;

    @Autowired
    public ActivitiService(RuntimeService runtimeService, TaskService taskService, HistoryService historyService, RepositoryService repositoryService) {
        this.runtimeService = runtimeService;
        this.taskService = taskService;
        this.historyService = historyService;
        this.repositoryService = repositoryService;
    }

    public ProcessDefinition deployProcess(MultipartFile bpmn, String path) throws IOException {
        if (BaseUtils.isNullOrEmpty(bpmn) || BaseUtils.isNullOrEmpty(path)) {
            return null;
        }
        //上传文件到processes
        File file = new File(path + bpmn.getOriginalFilename());
        bpmn.transferTo(file);

        String resource = ResourceLoader.CLASSPATH_URL_PREFIX + bpmn.getOriginalFilename();
        Deployment deployment = repositoryService.createDeployment().addClasspathResource(resource).deploy();
        log.info("Process [" + deployment.getName() + "] deployed successful");
        return repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
    }

    public ProcessInstance startProcess(String key) {
        if (BaseUtils.isNullOrEmpty(key)) {
            return null;
        }
        return runtimeService.startProcessInstanceByKey(key);
    }

    public List getTasksByAssignee(String assignee) {
        if (BaseUtils.isNullOrEmpty(assignee)) {
            return null;
        }
        List tasks = taskService.createTaskQuery().taskAssignee(assignee).list();
        if (BaseUtils.isNullOrEmpty(tasks)) {
            return null;
        }
        List infos = new ArrayList<>();
        for (Task task: tasks) {
            infos.add(new TaskInfo(task.getId(), task.getName()));
        }
        return infos;
    }

    public List getTasksByGroup(String group) {
        if (BaseUtils.isNullOrEmpty(group)) {
            return null;
        }
        List tasks = taskService.createTaskQuery().taskCandidateGroup(group).list();
        if (BaseUtils.isNullOrEmpty(tasks)) {
            return null;
        }
        List infos = new ArrayList<>();
        for (Task task : tasks) {
            infos.add(new TaskInfo(task.getId(), task.getName()));
        }
        return infos;
    }

    public List getTasks(String assigneeOrGroup) {
        if (BaseUtils.isNullOrEmpty(assigneeOrGroup)) {
            return null;
        }
        List tasks = taskService.createTaskQuery().taskCandidateOrAssigned(assigneeOrGroup).list();
        if (BaseUtils.isNullOrEmpty(tasks)) {
            return null;
        }
        List infos = new ArrayList<>();
        for (Task task : tasks) {
            infos.add(new TaskInfo(task.getId(), task.getName()));
        }
        return infos;
    }

    public void completeTask(String taskId, Object item) {
        Map map = BaseUtils.object2ConditionMap(item);
        if (BaseUtils.isNullOrEmpty(taskId) || BaseUtils.isNullOrEmpty(map)) {
            log.error("Params cannot be empty");
            throw new RuntimeException("Params cannot be empty");
        }
        taskService.complete(taskId, map);
    }

    public void completeTask(String taskId) {
        if (BaseUtils.isNullOrEmpty(taskId)) {
            log.error("Param taskId cannot be empty");
            return;
        }
        taskService.complete(taskId);
    }

    public static class TaskInfo {

        private String id;
        private String name;

        public TaskInfo(String id, String name) {
            this.id = id;
            this.name = name;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getId() {
            return id;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }
    }

}

在Junit中进行测试,若没有报错就说明我们集成完成了。

下一步就是在Activiti中统一用户管理,不使用它自带的比较简陋的用户管理。

(未完待续...)

你可能感兴趣的:(Spring,Boot,Activiti)