Springboot2.0.4集成SnakerFlow2.4.0版本(mybaits实现)

SnakerFlow是一款类似于Activiti和BPMN的流程引擎,2014年已停更了,但并不影响使用。建议使用2.4.0版本别问我为什么,可以分别看看他们的源码就明白了。

最近公司需要使用该流程插件,所以就去研究了一下

首先在pom文件中引入Snaker的三个主要的依赖还有一个定时任务的依赖根据需求加

<dependency>
            <groupId>com.github.snakerflow</groupId>
            <artifactId>snaker-core</artifactId>
            <version>2.4.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.github.snakerflow</groupId>
            <artifactId>snaker-spring</artifactId>
            <version>2.4.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.github.snakerflow</groupId>
            <artifactId>snaker-mybatis</artifactId>
            <version>2.4.0</version>
        </dependency>

接下来就是配置Snaker自定义一个配置文件application-snakerflow.xml

配置如下

<?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:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
        default-autowire="byName" default-lazy-init="true">

    <context:component-scan base-package="org.snaker.engine"/>

    <bean id="engine" class="org.snaker.engine.spring.SpringSnakerEngine">
        <property name="processService" ref="processService"/>
        <property name="orderService" ref="orderService"/>
        <property name="taskService" ref="taskService"/>
        <property name="queryService" ref="queryService"/>
        <property name="managerService" ref="managerService"/>
    </bean>



    <bean id="dbAccess" class="org.snaker.engine.access.mybatis.MybatisAccess">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

    <bean id="processService" class="org.snaker.engine.core.ProcessService">
        <property name="access" ref="dbAccess"/>
        <property name="cacheManager" ref="cacheManager"/>
    </bean>
    <bean id="orderService" class="org.snaker.engine.core.OrderService">
        <property name="access" ref="dbAccess"/>
    </bean>
    <bean id="taskService" class="org.snaker.engine.core.TaskService">
        <property name="access" ref="dbAccess"/>
    </bean>
    <bean id="managerService" class="org.snaker.engine.core.ManagerService">
        <property name="access" ref="dbAccess"/>
    </bean>
    <bean id="queryService" class="org.snaker.engine.core.QueryService">
        <property name="access" ref="dbAccess"/>
    </bean>

    <bean id="cacheManager" class="org.snaker.engine.cache.memory.MemoryCacheManager"/>
    <bean class="org.snaker.engine.impl.LogInterceptor"/>
    <bean class="org.snaker.engine.spring.SpelExpression"/>
</beans>

之后还需要在spring中进行配置,在spring配置文件中需要引入mybaits的配置文件,而该配置文件理扫描的是snaker-core里的snaker所要用的mapper文件所以需要对其进行扫描再由spring容器进行事务管理。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <typeAliases>
        <package name="org.snaker.engine.entity"/>
    </typeAliases>

    <mappers>
        <mapper resource="mapper/process.xml"/>
        <mapper resource="mapper/order.xml"/>
        <mapper resource="mapper/task.xml"/>
        <mapper resource="mapper/task-actor.xml"/>
        <mapper resource="mapper/hist-order.xml"/>
        <mapper resource="mapper/hist-task.xml"/>
        <mapper resource="mapper/hist-task-actor.xml"/>
        <mapper resource="mapper/query.xml"/>
        <mapper resource="mapper/hist-query.xml"/>

    </mappers>


</configuration>

而spring中在配置sqlSessionfactory bean时需要引入mybaits配置文件,之后就是对snaker中的方法进行事务管理

 <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="start*" propagation="REQUIRED"/>
            <tx:method name="execute*" propagation="REQUIRED"/>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="remove*" propagation="REQUIRED" />
            <tx:method name="assign*" propagation="REQUIRED" />
            <tx:method name="create*" propagation="REQUIRED" />
            <tx:method name="complete*" propagation="REQUIRED" />
            <tx:method name="finish*" propagation="REQUIRED" />
            <tx:method name="terminate*" propagation="REQUIRED" />
            <tx:method name="take*" propagation="REQUIRED" />
            <tx:method name="deploy*" propagation="REQUIRED" />
            <tx:method name="undeploy*" propagation="REQUIRED" />
            <tx:method name="redeploy*" propagation="REQUIRED" />

            <tx:method name="get*" propagation="REQUIRED" read-only="true" />
            <tx:method name="find*" propagation="REQUIRED" read-only="true" />
            <tx:method name="query*" propagation="REQUIRED" read-only="true" />
            <tx:method name="search*" propagation="REQUIRED" read-only="true" />
            <tx:method name="is*" propagation="REQUIRED" read-only="true" />
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* org.snaker.engine.core..*.*(..))"/>
    </aop:config>
    <aop:aspectj-autoproxy proxy-target-class="true" />

这样你就可以正常运行了,至于使用springboot怎么使spring文件和snaker配置文件生效,这就是另外的方面了 个人使用注解引入外部配置文件,用着也很方便,

使用的话我提供一个引擎大家可以复制下来对其进行调整,其实就是在作者的基础上进行了改进而已

/* Copyright 2013-2015 www.snakerflow.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alijk.bq.workflow.engine.impl;

import com.alijk.bq.workflow.engine.SnakerEngineFacade;
import org.apache.commons.lang.StringUtils;
import org.snaker.engine.DBAccess;
import org.snaker.engine.IProcessService;
import org.snaker.engine.SnakerEngine;
import org.snaker.engine.access.Page;
import org.snaker.engine.access.QueryFilter;
import org.snaker.engine.core.AccessService;
import org.snaker.engine.core.SnakerEngineImpl;
import org.snaker.engine.entity.*;
import org.snaker.engine.entity.Process;
import org.snaker.engine.model.TaskModel.TaskType;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Component(把普通pojo实例化到spring容器中,相当于配置文件中的 <bean id="" class=""/>)
 *
 */
@Component("snakerEngineFacade")
public class SnakerEngineFacadeImpl implements SnakerEngineFacade, InitializingBean {

    @Autowired
    private SnakerEngine engine;


    private IProcessService process;

    public SnakerEngine getEngine() {
        return engine;
    }




    @Override
    public void afterPropertiesSet() throws Exception {
        process = engine.process();
    }

    public IProcessService getProcess() {
        return process;
    }

    /**
     * 得到所有流程定义的名称
     *
     * @return
     */
    public List<String> getAllProcessNames() {
        List<Process> list = engine.process().getProcesss(new QueryFilter());
        List<String> names = new ArrayList<String>();
        for (Process entity : list) {
            if (names.contains(entity.getName())) {
                continue;
            } else {
                names.add(entity.getName());
            }
        }
        return names;
    }

    public Order startInstanceById(String processId, String operator, Map<String, Object> args) {
        return engine.startInstanceById(processId, operator, args);
    }

    public Order startInstanceByName(String name, Integer version, String operator, Map<String, Object> args) {
        return engine.startInstanceByName(name, version, operator, args);
    }

    public Order startAndExecute(String name, Integer version, String operator, Map<String, Object> args) {
        Order order = engine.startInstanceByName(name, version, operator, args);
        List<Task> tasks = engine.query().getActiveTasks(new QueryFilter().setOrderId(order.getId()));
        List<Task> newTasks = new ArrayList<Task>();
        if (tasks != null && tasks.size() > 0) {
            Task task = tasks.get(0);
            newTasks.addAll(engine.executeTask(task.getId(), operator, args));
        }
        return order;
    }

    public Order startAndExecute(String processId, String operator, Map<String, Object> args) {
        Order order = engine.startInstanceById(processId, operator, args);
        List<Task> tasks = engine.query().getActiveTasks(new QueryFilter().setOrderId(order.getId()));
        List<Task> newTasks = new ArrayList<Task>();
        if (tasks != null && tasks.size() > 0) {
            Task task = tasks.get(0);
            newTasks.addAll(engine.executeTask(task.getId(), operator, args));
        }
        return order;
    }

    public List<Task> execute(String taskId, String operator, Map<String, Object> args) {
        return engine.executeTask(taskId, operator, args);
    }

    public List<Task> executeAndJump(String taskId, String operator, Map<String, Object> args, String nodeName) {
        return engine.executeAndJumpTask(taskId, operator, args, nodeName);
    }

    public List<Task> transferMajor(String taskId, String operator, String... actors) {
        List<Task> tasks = engine.task().createNewTask(taskId, TaskType.Major.ordinal(), actors);
        engine.task().complete(taskId, operator);
        return tasks;
    }

    public List<Task> transferAidant(String taskId, String operator, String... actors) {
        List<Task> tasks = engine.task().createNewTask(taskId, TaskType.Aidant.ordinal(), actors);
        engine.task().complete(taskId, operator);
        return tasks;
    }

    public Map<String, Object> flowData(String orderId, String taskName) {
        Map<String, Object> data = new HashMap<String, Object>();
        if (StringUtils.isNotEmpty(orderId) && StringUtils.isNotEmpty(taskName)) {
            List<HistoryTask> histTasks = engine.query()
                    .getHistoryTasks(
                            new QueryFilter().setOrderId(orderId).setName(
                                    taskName));
            List<Map<String, Object>> vars = new ArrayList<Map<String, Object>>();
            for (HistoryTask hist : histTasks) {
                vars.add(hist.getVariableMap());
            }
            data.put("vars", vars);
            data.put("histTasks", histTasks);
        }
        return data;
    }

    public void addSurrogate(Surrogate entity) {
        if (entity.getState() == null) {
            entity.setState(1);
        }
        engine.manager().saveOrUpdate(entity);
    }

    public void deleteSurrogate(String id) {
        engine.manager().deleteSurrogate(id);
    }

    public Surrogate getSurrogate(String id) {
        return engine.manager().getSurrogate(id);
    }

    public List<Surrogate> searchSurrogate(Page<Surrogate> page, QueryFilter filter) {
        return engine.manager().getSurrogate(page, filter);
    }


}

继承的接口

public interface SnakerEngineFacade {


    /**
     * 得到所有流程定义的名称
     *
     * @return
     */
    public List<String> getAllProcessNames();

    public Order startInstanceById(String processId, String operator, Map<String, Object> args);

    public Order startInstanceByName(String name, Integer version, String operator, Map<String, Object> args);

    public Order startAndExecute(String name, Integer version, String operator, Map<String, Object> args);

    public Order startAndExecute(String processId, String operator, Map<String, Object> args);

    public List<Task> execute(String taskId, String operator, Map<String, Object> args);

    public List<Task> executeAndJump(String taskId, String operator, Map<String, Object> args, String nodeName);

    public List<Task> transferMajor(String taskId, String operator, String... actors);

    public List<Task> transferAidant(String taskId, String operator, String... actors);

    public Map<String, Object> flowData(String orderId, String taskName);

    public void addSurrogate(Surrogate entity) ;

    public void deleteSurrogate(String id);

    public Surrogate getSurrogate(String id);

    public List<Surrogate> searchSurrogate(Page<Surrogate> page, QueryFilter filter);

}

service层进行使用或者controller层使用

@Autowired

private SnakerEngineFacadeImpl snakerEngineFacade;

这样你就可以调用其中的接口了 其实可以根据个人需求进行修改。

扫描二维码关注公众号,回复: 3549321 查看本文章

总结

在最初使用snaker时在网上找的博客文档都是存在一些问题的,几乎没有和springboot整合的,好像只有一个但很简单,其实不管是springmvc、Struts还是springboot都只是一个框架,都不印象它的使用,个人在对snaker还是存在一些看法,打算在公司忙完项目之后对其进行修整,比如剔除hibernate作为持久层,以及对个别需求进行改进。到时候会跟大家分享。同时也会尊重原创作者snaker。一位了不起的大佬。

猜你喜欢

转载自blog.csdn.net/Fly_Eason/article/details/81632128