美文网首页
springboot 2.x整合 activiti 6.0.0(

springboot 2.x整合 activiti 6.0.0(

作者: 指下光年 | 来源:发表于2022-01-27 16:11 被阅读0次

    activiti 在 5.22.0 后面的版本就不支持在线设计流程图插件,那就从 5.22.0 里面把能拿的东西拿出来,整合到自己项目里面

    源码地址:https://gitee.com/wwspace/online-process-design.git

    1. 下载源码包

    官网下载5.22.0的源码包:https://www.activiti.org/get-started
    github 不太好下载,我网盘分享一下
    链接:https://pan.baidu.com/s/1oMF7wsFCf1w1TWUyI1y5Qw
    提取码:a58p

    1. 添加pom依赖

            <!--activiti依赖-->
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-spring-boot-starter-basic</artifactId>
                <version>6.0.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-json-converter</artifactId>
                <version>6.0.0</version>
    
                <exclusions>
                    <exclusion>
                        <groupId>org.activiti</groupId>
                        <artifactId>activiti-bpmn-model</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!--  activiti依赖-->
    
    <!--xml解析依赖-->
            <dependency>
    
                <groupId>org.apache.xmlgraphics</groupId>
                <artifactId>batik-codec</artifactId>
                <version>1.7</version>
            </dependency>
            <dependency>
                <groupId>org.apache.xmlgraphics</groupId>
                <artifactId>batik-css</artifactId>
                <version> 1.7</version>
            </dependency>
            <dependency>
                <groupId>org.apache.xmlgraphics</groupId>
                <artifactId>batik-svg-dom</artifactId>
                <version>1.7</version>
            </dependency>
            <dependency>
                <groupId>org.apache.xmlgraphics</groupId>
                <artifactId>batik-svggen</artifactId>
                <version>1.7</version>
            </dependency>
            <!--xml解析依赖-->
            <!-- SpringBoot集成thymeleaf模板 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-thymeleaf</artifactId>
            </dependency>
    
    
    1. 配置文件
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/oa?useSSL=false&nullCatalogMeansCurrent=true
        username: root
        password: ****
      activiti:
        # 不自动检查resources/bpmn目录
        check-process-definitions: false 
      thymeleaf:
        cache: false
    
    1. 5.22.0 版本的静态资源
      1. 解压activiti-5.22.0的包,解压wars/activiti-explorer.war
      2. diagram-viewer、editor-app复制到springboot项目下的static目录下;modeler.html(主界面)复制到templates目录下
      3. activiti-5.22.0\wars\activiti-explorer\WEB-INF\classes\stencilset.json复制到resources目录下
      4. libs下的activiti-modeler-5.22.0-sources.jar解压。把org\activiti\rest\editor路径下的main、model文件夹里面的三个类复制到你的controller文件夹,主要用于读取stencilset.json。
      5. 新建 ModelerController
    package com.system.web.controller;
    
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import lombok.extern.slf4j.Slf4j;
    import org.activiti.bpmn.model.BpmnModel;
    import org.activiti.editor.constants.ModelDataJsonConstants;
    import org.activiti.editor.language.json.converter.BpmnJsonConverter;
    import org.activiti.engine.HistoryService;
    import org.activiti.engine.RepositoryService;
    import org.activiti.engine.RuntimeService;
    import org.activiti.engine.history.HistoricActivityInstance;
    import org.activiti.engine.history.HistoricProcessInstance;
    import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
    import org.activiti.engine.repository.Deployment;
    import org.activiti.engine.repository.Model;
    import org.activiti.engine.runtime.ProcessInstance;
    import org.activiti.image.ProcessDiagramGenerator;
    import org.activiti.image.impl.DefaultProcessDiagramGenerator;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.MediaType;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 流程控制器
     */
    @Controller
    @Slf4j
    public class ModelerController {
    
        private static final Logger logger = LoggerFactory.getLogger(ModelerController.class);
    
        @Resource
        private RepositoryService repositoryService;
        @Resource
        private ObjectMapper objectMapper;
        @Resource
        private HistoryService historyService;
        @Resource
        private RuntimeService runtimeService;
    
    
    
        @GetMapping("/")
        public void index(HttpServletResponse response){
    
            try {
                response.sendRedirect("/create");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    
        /**
         * 跳转编辑器页面
         * @return
         */
        @GetMapping("editor")
        public String editor(){
            return "modeler";
        }
    
    
        /**
         * 创建模型
         * @param response
    
         * @throws IOException
         */
        @RequestMapping("/create")
        public void create(HttpServletResponse response,String name,String key) throws IOException {
            logger.info("创建模型入参name:{},key:{}",name,key);
            Model model = repositoryService.newModel();
            ObjectNode modelNode = objectMapper.createObjectNode();
            modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
            modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, "");
            modelNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
            model.setName(name);
            model.setKey(key);
            model.setMetaInfo(modelNode.toString());
            repositoryService.saveModel(model);
            createObjectNode(model.getId());
            response.sendRedirect("/editor?modelId="+ model.getId());
            logger.info("创建模型结束,返回模型ID:{}",model.getId());
        }
    
        /**
         * 创建模型时完善ModelEditorSource
         * @param modelId
         */
        @SuppressWarnings("deprecation")
        private void createObjectNode(String modelId){
            logger.info("创建模型完善ModelEditorSource入参模型ID:{}",modelId);
            ObjectNode editorNode = objectMapper.createObjectNode();
            editorNode.put("id", "canvas");
            editorNode.put("resourceId", "canvas");
            ObjectNode stencilSetNode = objectMapper.createObjectNode();
            stencilSetNode.put("namespace","http://b3mn.org/stencilset/bpmn2.0#");
            editorNode.put("stencilset", stencilSetNode);
            try {
                repositoryService.addModelEditorSource(modelId,editorNode.toString().getBytes("utf-8"));
            } catch (Exception e) {
                logger.info("创建模型时完善ModelEditorSource服务异常:{}",e);
            }
            logger.info("创建模型完善ModelEditorSource结束");
        }
    
        /**
         * 发布流程
         * @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;
        }
    
        /**
         * 撤销流程定义
         * @param modelId 模型ID
    
         * @return
         */
        @ResponseBody
        @RequestMapping("/revokePublish")
        public Object revokePublish(String modelId){
            logger.info("撤销发布流程入参modelId:{}",modelId);
            Map<String, String> map = new HashMap<String, String>();
            Model modelData = repositoryService.getModel(modelId);
            if(null != modelData){
                try {
                    /**
                     * 参数不加true:为普通删除,如果当前规则下有正在执行的流程,则抛异常
                     * 参数加true:为级联删除,会删除和当前规则相关的所有信息,包括历史
                     */
                    repositoryService.deleteDeployment(modelData.getDeploymentId(),true);
                    map.put("code", "SUCCESS");
                } catch (Exception e) {
                    logger.error("撤销已部署流程服务异常:{}",e);
                    map.put("code", "FAILURE");
                }
            }
            logger.info("撤销发布流程出参map:{}",map);
            return map;
        }
    
        /**
         * 删除流程实例
         * @param modelId 模型ID
         *
         * @return
         */
        @ResponseBody
        @RequestMapping("/delete")
        public Object deleteProcessInstance(String modelId){
            logger.info("删除流程实例入参modelId:{}",modelId);
            Map<String, String> map = new HashMap<>();
            Model modelData = repositoryService.getModel(modelId);
    
            if(null != modelData){
                try {
                    ProcessInstance pi = runtimeService.createProcessInstanceQuery().processDefinitionKey(modelData.getKey()).singleResult();
                    if(null != pi) {
                        runtimeService.deleteProcessInstance(pi.getId(), "");
                        historyService.deleteHistoricProcessInstance(pi.getId());
    
                    }
    
                    map.put("code", "SUCCESS");
                } catch (Exception e) {
                    logger.error("删除流程实例服务异常:{}",e);
                    map.put("code", "FAILURE");
                }
            }
    
            logger.info("删除流程实例出参map:{}",map);
            return map;
        }
    
        @RequestMapping(value = "/image/{pid}",produces = MediaType.IMAGE_PNG_VALUE)
        @ResponseBody
        public byte[] definitionImage(@PathVariable("pid") String processDefinitionId) throws IOException {
    
            BpmnModel model = repositoryService.getBpmnModel(processDefinitionId);
            if (model != null && model.getLocationMap().size() > 0) {
                ProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
                InputStream imageStream = generator.generateDiagram(model, "png", new ArrayList<>());
                byte[] buffer = new byte[imageStream.available()];
                imageStream.read(buffer);
                imageStream.close();
                return buffer;
            }
    
    
            return new byte[0];
        }
    
        @GetMapping("/showImage")
        public String image(){
    
            return "image";
        }
    
    
        @RequestMapping(value = "/image2/{pid}",produces = MediaType.IMAGE_PNG_VALUE)
        @ResponseBody
        public byte[] getProcessImage(@PathVariable("pid") String processInstanceId) throws Exception {
    
            //  获取历史流程实例
    
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            if (historicProcessInstance == null) {
                throw new Exception();
            } else {
                // 获取流程定义
                ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService
                        .getProcessDefinition(historicProcessInstance.getProcessDefinitionId());
    
                // 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
                List<HistoricActivityInstance> historicActivityInstanceList = historyService
                        .createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
                        .orderByHistoricActivityInstanceId().asc().list();
    
                // 已执行的节点ID集合
                List<String> executedActivityIdList = new ArrayList<>();
                @SuppressWarnings("unused") int index = 1;
                log.info("获取已经执行的节点ID");
                for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
                    executedActivityIdList.add(activityInstance.getActivityId());
                    log.info("第[" + index + "]个已执行节点=" + activityInstance.getActivityId() + " : " + activityInstance
                            .getActivityName());
    
                    index++;
                }
                // 获取流程图图像字符流
                BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
                DefaultProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
                InputStream imageStream = generator.generateDiagram(bpmnModel, "png", executedActivityIdList);
                byte[] buffer = new byte[imageStream.available()];
                imageStream.read(buffer);
                imageStream.close();
    
                return buffer;
            }
    
        }
    
    
    }
    
    
    1. 修改editor-app下的app-cfg.js,把contextRoot后面改成 ''(这个和ModelerController里面加的requestMapping要一致
    • 解决启动报错
    @SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
    public class ActivitiWebDemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ActivitiWebDemoApplication.class, args);
        }
    
    }
    
    image.png

    相关文章

      网友评论

          本文标题:springboot 2.x整合 activiti 6.0.0(

          本文链接:https://www.haomeiwen.com/subject/vyjahrtx.html