美文网首页Spring
Activiti工作流开发指南(springboot 2.x i

Activiti工作流开发指南(springboot 2.x i

作者: Exrick | 来源:发表于2019-04-25 13:13 被阅读464次

    集成Activiti 5.22,考虑到文档资料较多未选用新版本(模型设计器改动较大)或Flowable

    集成的工作流编辑器在后台静态资源中,记得在系统配置中设置访问域名,开发时直接填后台请求地址前缀 http://localhost:8888 即可

    几大常用接口

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

    25张表

    image

    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接口和TaskService接口,存储流程实例和用户任务等动态数

    XBoot扩展基本开发指南

    • 通用流程状态表t_act_bussiness,其中table_id字段存储关联的表单ID

    • 后台仅需开发相应表单增删改接口,存储至单张表中,如t_leave,唯一需注意的地方为新增接口(添加新数据时)需关联业务act_buniess表,向其添加流程和表ID等信息,参考LeaveController

    • 前台仅需开发相应单个表单页面(可以通过路由传参实现相应按钮显示),参考leave.vue(以菜单中配置的该路由名name跳转),记得在src/router/router.js中添加路由

    • 最后记得在系统中配置相应流程信息

      • 数据字典"业务表"中添加相应业务表名,如"t_leave";"业务表单路由"中添加相应前端表单组件路由名,如"leave"
      • 流程管理中编辑填写关联刚开发的表单信息,业务表的作用主要为用户删除申请时关联删除相应表单数据,表单路由名作用为跳转显示刚前端开发的表单页面
      QQ截图20190113212518.png
    • 流程节点审批人可根据角色、部门负责人、人员设置多个,设置后默认勾选,为或签(任意一人审批,流程进入下一步,即先到先审)

    • 如何实现会签?

      • 请增加审批节点!
      image
    • 分支网关设定

      • 注意:暂仅支持互斥(排他)网关设置。为保证工作流简单性,建议仅使用开始、结束、任务节点和单向连线,设置分支后流程将变得不灵活,用户容易编辑出错。

    若部署后流程图中文字符无法显示,是因为服务器环境jdk中无相应中文字体,百度安装即可(配置文件已配置微软雅黑,若未配置默认宋体)

    互斥(排他)网关设定

    顾名思义,当出现多个分支时仅选择一个满足条件的分支流转

    WX20190523-221422@2x.png
    • 点击互斥网关后的连线设置流转条件的条件UEL表达式 https://www.activiti.org/userguide/#apiExpressions

      WX20190523-221523@2x.png
    • 注意勾选默认网关后不得设置流转条件,否则无法部署成功


      WX20190523-221700@2x.png
    • 启动流程时或完成一个任务节点时务必加入该变量(否则配置了流转条件变量的流程会报错),示例:

    // 启动流程时添加变量,详见ActBusinessController的apply或start方法,在ActBusiness中设置params
    actBusiness.getParams().put("duration", 36);
    
    // 或者完成任务节点时加入变量
    Map<String, Object> params = new HashMap<>(16);
    taskService.complete(id, params);
    

    绑定监听器示例

    常见的业务需求需要完成一个审批流程后改变原数据状态、通知审批结果消息或执行其他操作,在结束节点上绑定监听器即可,一旦结束说明流程全部通过,触发自定义业务。

    • 绘制流程图填写定义的监听器类
    image image image
    • 监听器示例代码
    @Slf4j
    public class MyListener implements ExecutionListener {
    
        @Override
        public void notify(DelegateExecution delegateExecution) throws Exception {
    
            // 获取关联业务表ID变量(启动流程代码里已存入tableId,此处直接获取即可)
            String tableId = (String) delegateExecution.getVariable("tableId");
            log.info(tableId);
            LeaveService leaveService = SpringContextUtil.getBean(LeaveService.class);
            Leave leave = leaveService.get(tableId);
            ... ...
        }
    }
    

    使用发起流程组件示例

    • 前端vue示例,注意各状态下仅能显示的各操作按钮
    <template>
        <process-start
            ref="processStart"
            @on-submit="submitedProcess"
            @on-loading="processLoading=true"
            @on-loaded="processLoading=false"
        />
        <process-cancel ref="processCancel" @on-submit="submitedProcess"/>
    </template>
    
    <script>
    ...
    import processStart from '../../../views/my-components/xboot/process-start'
    import processCancel from '../../../views/my-components/xboot/process-cancel'
    
    export default {
      name: 'demo',
      components: {
        processStart,
        processCancel
      },
      data () {
        return {
          ...
          columns: [
            // 表头
            {
              title: '申请状态',
              key: 'status',
              sortable: true,
              minWidth: 110,
              fixed: 'right',
              render: (h, params) => {
                let text = '未知',
                  color = ''
                if (params.row.status === 0) {
                  text = '草稿'
                  color = 'default'
                } else if (params.row.status === 1) {
                  text = '处理中'
                  color = 'orange'
                } else if (params.row.status === 2) {
                  text = '已结束'
                  color = 'blue'
                }
                return h('div', [
                  h(
                    'Tag',
                    {
                      props: {
                        color: color,
                      },
                    },
                    text,
                  ),
                ])
              },
            },
            {
              title: '申请结果',
              key: 'result',
              sortable: true,
              minWidth: 110,
              fixed: 'right',
              render: (h, params) => {
                let text = '未知',
                  color = ''
                if (params.row.result == 0) {
                  text = '未提交'
                  color = 'default'
                } else if (params.row.result == 1) {
                  text = '处理中'
                  color = 'orange'
                } else if (params.row.result == 2) {
                  text = '已通过'
                  color = 'green'
                } else if (params.row.result == 3) {
                  text = '已驳回'
                  color = 'red'
                }
                return h('div', [
                  h(
                    'Tag',
                    {
                      props: {
                        color: color,
                      },
                    },
                    text,
                  ),
                ])
              },
            },
            {
              title: '操作',
              key: 'action',
              align: 'center',
              fixed: 'right',
              width: 260,
              render: (h, params) => {
                let result = params.row.result
                if (result == 0) {
                  return h('div', [
                    h(
                      'Button',
                      {
                        props: {
                          type: 'primary',
                          size: 'small',
                        },
                        style: {
                          marginRight: '5px',
                        },
                        on: {
                          click: () => {
                            this.showProcess(params.row)
                          },
                        },
                      },
                      '发起申请',
                    ),
                    h(
                      'Button',
                      {
                        props: {
                          size: 'small',
                          icon: 'ios-create-outline',
                        },
                        style: {
                          marginRight: '5px',
                        },
                        on: {
                          click: () => {
                            this.edit(params.row)
                          },
                        },
                      },
                      '编辑',
                    ),
                    h(
                      'Button',
                      {
                        props: {
                          type: 'error',
                          size: 'small',
                          icon: 'md-trash',
                        },
                        on: {
                          click: () => {
                            this.remove(params.row)
                          },
                        },
                      },
                      '删除',
                    ),
                  ])
                }
                if (result == 1) {
                  return h('div', [
                    h(
                      'Button',
                      {
                        props: {
                          size: 'small',
                          type: 'warning',
                        },
                        style: {
                          marginRight: '5px',
                        },
                        on: {
                          click: () => {
                            this.cancelProcess(params.row)
                          },
                        },
                      },
                      '撤回申请',
                    ),
                    h(
                      'Button',
                      {
                        props: {
                          size: 'small',
                        },
                        style: {
                          marginRight: '5px',
                        },
                        on: {
                          click: () => {
                            this.history(params.row)
                          },
                        },
                      },
                      '审批历史',
                    ),
                  ])
                }
                if (result == 2) {
                    h(
                      'Button',
                      {
                        props: {
                          size: 'small',
                        },
                        style: {
                          marginRight: '5px',
                        },
                        on: {
                          click: () => {
                            this.history(params.row)
                          },
                        },
                      },
                      '审批历史',
                    ),
                  ])
                }
                if (result === 3) {
                  return h('div', [
                    h(
                      'Button',
                      {
                        props: {
                          type: 'primary',
                          size: 'small',
                        },
                        style: {
                          marginRight: '5px',
                        },
                        on: {
                          click: () => {
                            this.showProcess(params.row)
                          },
                        },
                      },
                      '重新申请',
                    ),
                    h(
                      'Button',
                      {
                        props: {
                          size: 'small',
                          icon: 'ios-create-outline',
                        },
                        style: {
                          marginRight: '5px',
                        },
                        on: {
                          click: () => {
                            this.edit(params.row)
                          },
                        },
                      },
                      '编辑',
                    ),
                  ])
                }
              },
            },
          ]
        }
      },
      methods: {
        ...
        showProcess (v) {
          // 显示通过key发起流程组件
          this.$refs.processStart.show('demand', v.actBusinessId)
        },
        cancelProcess (v) {
          // 取消流程
          this.$refs.processCancel.show(v.actBusinessId, v.procInstId)
        },
        submitedProcess () {
          // 进行流程操作后刷新表单数据显示流程状态
          this.getDataList()
        },
        history (v) {
          // 审批历史
          if (!v.procInstId) {
            this.$Message.error('流程实例ID不存在')
            return
          }
          let query = { id: v.procInstId, backRoute: this.$route.name }
          this.$router.push({
            name: 'historic_detail',
            query: query,
          })
        }}
      }
    }
    
    • 后端业务接口,注意与“工作流程-我的申请”中已有请假示例LeaveController示例中的区别,这里无需传入流程定义ID,ActBussines表与业务表两两关联记录对方ID方便查询
        @RequestMapping(value = "/add",method = RequestMethod.POST)
        @ApiOperation(value = "添加审批需求")
        public Result<Object> add(@ModelAttribute Demand demand){
    
            Demand d = demandService.save(demand);
            // 保存至我的申请业务
            String userId = securityUtil.getCurrUser().getId();
            ActBusiness actBusiness = new ActBusiness();
            actBusiness.setUserId(userId);
            // 记录关联业务表ID
            actBusiness.setTableId(d.getId());
            ActBusiness a = actBusinessService.save(actBusiness);
            // 记录关联流程状态表ID
            d.setActBusinessId(a.getId());
            demandService.update(d);
            return new ResultUtil<Object>().setSuccessMsg("操作成功");
        }
    
    • 效果预览
    image

    相关文章

      网友评论

        本文标题:Activiti工作流开发指南(springboot 2.x i

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