关于Activiti工作流使用

什么是Activiti?

Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。Activiti基于Apache许可的开源BPM平台,创始人Tom Baeyens是JBoss jBPM的项目架构师,它特色是提供了eclipse插件,开发人员可以通过插件直接绘画出业务流程图。本文采用activiti5.22版本。数据库是ORACLE11g

1.Activiti数据库结构

1)通过运行activiti官方提供的数据库脚本创建数据库,支持db2、h2、hsql、mssql、mysql、oracle、postgres数据库
image.png

1、act_ge_ 通用数据表,ge是general的缩写
2、act_hi_ 历史数据表,hi是history的缩写,对应HistoryService接口
3、act_id_ 身份数据表,id是identity的缩写,对应IdentityService接口
4、act_re_ 流程存储表,re是repository的缩写,对应RepositoryService接口,存储流程部署和流程定义等静态数据
5、act_ru_ 运行时数据表,ru是runtime的缩写,对应RuntimeService接口

2.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
                           http://www.springframework.org/schema/tx      http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">


    <!-- 定义流程引擎配置 -->
    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"/>
        <property name="transactionManager" ref="transactionManager"/>
        <property name="databaseSchemaUpdate" value="true"/>
        <property name="jobExecutorActivate" value="false"/>
    </bean>

    <!-- 定义流程引擎 -->
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
    </bean>

    <!-- 定义Service服务 -->
    <bean id="repositoryService" factory-bean="processEngine"
          factory-method="getRepositoryService"/>
    <bean id="runtimeService" factory-bean="processEngine"
          factory-method="getRuntimeService"/>
    <bean id="taskService" factory-bean="processEngine"
          factory-method="getTaskService"/>
    <bean id="historyService" factory-bean="processEngine"
          factory-method="getHistoryService"/>
    <bean id="managementService" factory-bean="processEngine"
          factory-method="getManagementService"/>
    <bean id="identityService" factory-bean="processEngine"
          factory-method="getIdentityService"/>
    <bean id="formService" factory-bean="processEngine"
          factory-method="getFormService"></bean>

</beans>

七大接口:

1.RepositoryService:提供一系列管理流程部署和流程定义的API。
2.RuntimeService:在流程运行时对流程实例进行管理与控制。
3.TaskService:对流程任务进行管理,例如任务提醒、任务完成和创建任务等。
4.IdentityService:提供对流程角色数据进行管理的API,这些角色数据包括用户组、用户及它们之间的关系。
5.ManagementService:提供对流程引擎进行管理和维护的服务。
6.HistoryService:对流程的历史数据进行操作,包括查询、删除这些历史数据。
7.FormService:表单服务。

3.activiti-webapp-explorer2整合

1)将模板导入项目中

explorer整合实现在线编辑工作流
将src目录下diagram-viewer,editor-app,modeler.html 复制到自己项目中,如下图,本文是复制到webapp下


image.png

image.png
2)配置全局路径

配置前段访问路径,否则activiti编辑器会无法访问

image.png
/*
 * Activiti Modeler component part of the Activiti project
 * Copyright 2005-2014 Alfresco Software, Ltd. All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
'use strict';

var ACTIVITI = ACTIVITI || {};

ACTIVITI.CONFIG = {
    'contextRoot' : '/',#配置全文访问路径
};
3)后台配置

1.配置后台,页面访问接口配置,activti提供了基本的页面获取、流程保存、流程编辑等接口,用于工作流的在线演示与编辑。


image.png

2.将stencilset.json赋值到配置文件目录下,保证StencilsetRestResource能访问到,这是流程设计器的菜单和功能文件,保存为json格式。


image.png

4.后台实例代码

1)创建流程
/**
     * 创建流程
     */
    @RequestMapping("/createActiviti")
    public void createActiviti(HttpServletRequest request,HttpServletResponse response) throws IOException{
        Model model = repositoryService.newModel();

        String name = "新建流程";
        String description = "";
        int revision = 1;
        String key = "processKey";

        ObjectNode modelNode = objectMapper.createObjectNode();
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);

        model.setName(name);
        model.setKey(key);
        model.setMetaInfo(modelNode.toString());

        repositoryService.saveModel(model);
        String id = model.getId();

        //完善ModelEditorSource
        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);
        repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));
//        return "redirect:/modeler.html?modelId=" + id;
        response.sendRedirect(request.getContextPath() + "/modeler.html?modelId="+id);
    }
2)更新流程
    /**
     * 更新流程
     */
    @RequestMapping("/updateActiviti")
    public void updateActiviti(String id,HttpServletRequest request,HttpServletResponse response) throws IOException{
        response.sendRedirect(request.getContextPath() + "/modeler.html?modelId="+id);
    }
3)发布流程
      /**
     * 发布
     */
    @PostMapping("/publish")
    @ResponseBody
    public Object publish(@RequestParam(value="id")String id){
        Result result=new Result();
        try {
            Model modelData=repositoryService.getModel(id);
            byte[] bytes=repositoryService.getModelEditorSource(modelData.getId());
            if(bytes==null){
                result.setMsg("模型不得为空");
                result.setSuccess(false);
                return result;
            }
            JsonNode modelNode=null;
            modelNode=new ObjectMapper().readTree(bytes);
            BpmnModel model=new BpmnJsonConverter().convertToBpmnModel(modelNode);
            if(model.getProcesses().size()==0){
                result.setMsg("数据不符合要求");
                result.setSuccess(false);
                return result;
            }
            byte[] bpmnByates = new BpmnXMLConverter().convertToXML(model);
            //发布流程
            String processName=modelData.getName()+".bpmn20.xml";
            String convertToXML=new String(bpmnByates);
            System.out.println(convertToXML);
            Deployment deployment=repositoryService.createDeployment()
                    .name(modelData.getName())
                    .addString(processName, new String(bpmnByates, "UTF-8"))
                    .deploy();
            modelData.setDeploymentId(deployment.getId());
            repositoryService.saveModel(modelData);
            result.setMsg("发布成功");
            result.setSuccess(true);
        } catch (Exception e) {
            result.setMsg("发布失败");
            result.setSuccess(false);
        }
        return result;
    }
3)流程查询
    /**
     * 流程查询
     */
    @PostMapping("/deployDatagrid")
    @ResponseBody
    public Object deployDatagrid(String s_name, HttpServletResponse response,Integer page, Integer rows, String sort, String order){
        PageInfo pageInfo = new PageInfo(page, rows, sort, order);
        if(StringUtils.isBlank(s_name)){
            s_name="";
        }
        int p1=page-1;
        int r1=9-p1;
        List<Deployment> deploymentList=repositoryService.createDeploymentQuery()
                .deploymentNameLike("%" + s_name + "%").orderByDeploymenTime().desc()
                .listPage(p1, r1);
        long total=repositoryService.createDeploymentQuery().deploymentNameLike("%"+s_name+"%").count();
        List<com.pasic.model.po.DeploymentEntity> deploymentList2=new ArrayList<com.pasic.model.po.DeploymentEntity>();
        for (Deployment deployment : deploymentList) {
            com.pasic.model.po.DeploymentEntity depm=new com.pasic.model.po.DeploymentEntity(deployment.getId(),deployment.getName(),deployment.getCategory(),deployment.getTenantId(),deployment.getDeploymentTime());
            deploymentList2.add(depm);
        }

        System.out.println(deploymentList2);
        pageInfo.setRows(deploymentList2);
        pageInfo.setTotal((int)total);
        if(total/rows==0){
            pageInfo.setPagesize(0);
        }else{
            pageInfo.setPagesize(page++);
        }
        
        pageInfo.setNowpage(page);
        pageInfo.setSize(rows);
        pageInfo.setSuccess(true);
        pageInfo.setMessage("列表获取成功");
        return pageInfo;
    }
4)删除流程
    /**
     * 删除流程
     */
    @PostMapping("/deleteDeploy")
    @ResponseBody
    public Object deleteDeploy(@RequestParam(value="id")String id){
        Result result=new Result();
        try {
            //加true强制删除
            repositoryService.deleteDeployment(id,true);
            result.setSuccess(true);
            result.setMsg("删除成功");
        } catch (Exception e) {
            result.setSuccess(false);
            result.setMsg("删除失败");
        }
        return result;
    }
5)查看流程图片

1.后台

    /**
     * 查看流程图 图片
     */
    @GetMapping("/showProcessPng")
    public String showProcessPng(@RequestParam(value="deployId")String deployId,org.springframework.ui.Model model){
        
//      model.addAttribute("diagramResourceName", processDefinition.getDiagramResourceName());
        model.addAttribute("deployId", deployId);
        return "activiti/deploy/showProcessPng";
    }
    
    @RequestMapping("/showView")
    public String showView(String deploymentId, HttpServletResponse response)
            throws Exception {
        ProcessDefinition processDefinition=repositoryService.createProcessDefinitionQuery()
                   .deploymentId(deploymentId)
                   .singleResult();
        InputStream inputStream = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
        OutputStream outputStream = response.getOutputStream();
        for (int b = -1; (b = inputStream.read()) != -1; ) {
            outputStream.write(b);
        }
        outputStream.close();
        inputStream.close();
        return null;
    }

2.前台

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="/commons/global.jsp" %>
<script>
</script>
<div class="bootui-layout" data-options="fit:true,border:false">
    <div data-options="region:'center',fit:true,border:false">
        <img style="position:absolute;top:0px;left:0px" src="${path }/act/showView?deploymentId=${deployId}">
    </div>
</div>
6)将用户同步到activiti认证表中
    /**
     * 同步用户到activiti中
     */
    @PostMapping("/syncdata")
    @ResponseBody
    public Object syncdata(){
        Result result=new Result();
        try {
            Wrapper<SysUser> wrapper=new EntityWrapper<SysUser>();
            List<SysUser> userList=userService.selectList(wrapper);
            User au = null;
            for (SysUser user : userList) {
                au=new UserEntity();
                au.setId(user.getId());
                au.setFirstName(user.getName());
                au.setEmail("");
                identityService.deleteUser(au.getId());
                identityService.saveUser(au);
            }
            Wrapper<SysRole> wrapper2=new EntityWrapper<SysRole>();
            List<SysRole> sysRoleList=roleService.selectList(wrapper2);
            Group group=null;
            for (SysRole role : sysRoleList) {
                group=new GroupEntity();
                group.setId(role.getId());
                group.setName(role.getName());
                identityService.deleteGroup(group.getId());
                identityService.saveGroup(group);
            }
            Wrapper<SysUserRole> wrapper3=new EntityWrapper<SysUserRole>();
            List<SysUserRole> roleUserList=userRoleService.selectList(wrapper3);
            for (SysUserRole userRole : roleUserList) {
                identityService.deleteMembership(userRole.getUserId(), userRole.getRoleId());
                identityService.createMembership(userRole.getUserId(), userRole.getRoleId());
            }
            result.setMsg("同步成功");
            result.setSuccess(true);
        } catch (Exception e) {
            result.setMsg("同步失败");
            result.setSuccess(false);
        }
        return result;
    }

*****整合完成后效果

image.png

image.png

image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容