这篇文章实现java自定义工作流程,对工作流不太熟悉的可以先看下工作流相关文章:
工作流

相关表结构、实体创建

流程主表:tbl_workflow_requestbase(这里以项目工地工作流为例)

CREATE TABLE `tbl_workflow_requestbase` (`requestid` bigint(20) NOT NULL AUTO_INCREMENT,`projectno` varchar(255) COLLATE utf8_bin NOT NULL,`workflowid` bigint(20) NOT NULL,`entityid` bigint(20) NOT NULL,`requestname` varchar(255) COLLATE utf8_bin DEFAULT NULL,`currentoperatorid` varchar(255) COLLATE utf8_bin DEFAULT NULL,`status` smallint(6) DEFAULT NULL,`creator` varchar(50) COLLATE utf8_bin DEFAULT NULL,`createtime` datetime DEFAULT NULL,`lastoperatorid` bigint(20) DEFAULT NULL,`lastoperatetime` datetime DEFAULT NULL,PRIMARY KEY (`requestid`)
) ENGINE=InnoDB AUTO_INCREMENT=162561 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

entity

 @ApiModelProperty("流程ID")@Id@Column(name = "requestid")private String requestId;@ApiModelProperty("工地编码")@Column(name = "projectno")private String projectNo;@ApiModelProperty("流程类型ID")@Column(name = "workflowid")private String workflowId;@ApiModelProperty("业务ID")@Column(name = "entityid")private String entityId;@ApiModelProperty("流程标题")@Column(name = "requestname")private String requestName;@ApiModelProperty("当前操作人ID")@Column(name = "currentoperatorid")private String currentOperatorId;@ApiModelProperty("状态")@Column(name = "status")private Integer status;@ApiModelProperty("创建人")@Column(name = "creator")private String creator;@ApiModelProperty("创建时间")@Column(name = "createtime")private Date createTime;@ApiModelProperty("最后操作人ID")@Column(name = "lastoperatorid")private String lastOperatorId;@ApiModelProperty("最后操作时间")@Column(name = "lastoperatetime")private Date lastOperateTime;

然后是工作流节点表:tbl_workflow_requestnode

CREATE TABLE `tbl_workflow_requestnode` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`requestid` bigint(20) NOT NULL,`operatorid` varchar(500) COLLATE utf8_bin NOT NULL,`nodetype` smallint(6) DEFAULT NULL,`status` smallint(6) DEFAULT NULL,`sort` smallint(6) DEFAULT NULL,`createtime` datetime DEFAULT NULL,`modifytime` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=54460 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

entity

 @ApiModelProperty("ID")@Idprivate Integer id;@ApiModelProperty("流程ID")@Column(name = "requestid")private String requestId;@ApiModelProperty("操作人")@Column(name = "operatorid")private String operatorId;@ApiModelProperty("节点类型")@Column(name = "nodetype")private Integer nodeType;@ApiModelProperty("状态")@Column(name = "status")private Integer status;@ApiModelProperty("顺序")@Column(name = "sort")private Integer sort;@ApiModelProperty("创建时间")@Column(name = "createtime")private String createTime;@ApiModelProperty("更新时间")@Column(name = "modifytime")private String modifyTime;

这里简单介绍下,工作流主表:用户发起的一条涉及多用户操作的流程,记录流程详细信息,通过requestId关联流程节点表信息。
流程节点信息表:记录各个节点用户的操作。

定义流程的方法,创建、执行、退回

 /*** 创建工作流*/public ResponseResult create(CreateWorkflowVo createWorkflowVo) {// 同一个业务ID不能重复多线程创建流程synchronized (createWorkflowVo.getEntityId()) {return handleAction("/workflow/create", createWorkflowVo);}}/*** 执行工作流,往下一节点走*/public ResponseResult execute(ExecuteWorkflowVo executeWorkflowVo) {// 同一条流程不能重复操作synchronized (executeWorkflowVo.getRequestId()) {return handleAction("/workflow/execute", executeWorkflowVo);}}/*** 退回工作流*/public ResponseResult reject(RejectWorkflowVo rejectWorkflowVo) {// 同一条流程不能重复操作synchronized (rejectWorkflowVo.getRequestId()) {return handleAction("/workflow/reject", rejectWorkflowVo);}}private ResponseResult handleAction(String action, Object vo) {Asserts.notEmpty(uri, "请求地址");try {String res = restTemplate.postForObject(uri + action, vo, String.class);if (!StringUtils.isEmpty(res)) {ResponseResult responseResult = JSONObject.parseObject(res, ResponseResult.class);return responseResult;}} catch (Exception ex) {log.error("调用工作流服务失败:action=" + action, ex);}throw new GlobalException("12000", "调用工作流服务失败,action=" + action + ":无法获取请求数据");}

执行对应流程创建、执行、退回的方法,会调用执行定义好的一个工作流工程的回调函数,把函数的指针(地址)作为参数传递给另一个函数,返回结果。uri=工程的ip+端口
如下:

 /*** 创建工作流** @param createWorkflowVo* @return*/@PostMapping("create")public ResponseResult<String> create(@RequestBody CreateWorkflowVo createWorkflowVo) {return processService.createFlow(createWorkflowVo);}/*** 流程往下走** @param executeWorkflowVo* @return*/@PostMapping("execute")public ResponseResult<String> execute(@RequestBody ExecuteWorkflowVo executeWorkflowVo) {return processService.executeFlow(executeWorkflowVo);}/*** 退回** @param rejectWorkflowVo* @return*/@RequestMapping("reject")public ResponseResult<String> reject(@RequestBody RejectWorkflowVo rejectWorkflowVo) {return processService.rejectFlow(rejectWorkflowVo);}

service代码实现:

 //创建工作流@Override@Transactional(propagation = Propagation.REQUIRED)public ResponseResult<String> createFlow(CreateWorkflowVo createWorkflowVo) {log.info("请求参数: {}", createWorkflowVo);assertNotNull(createWorkflowVo);WorkflowBase base = workflowBaseMapper.selectByPrimaryKey(createWorkflowVo.getWorkflowBaseId());if (base == null) {throw new GlobalException("120004", "找不到Workflow base配置表信息");}// 回调地址不能为空Asserts.notNull(base.getActionUrl(), "actionUrl");WorkflowRequestBase srchBase = new WorkflowRequestBase();srchBase.setEntityId(createWorkflowVo.getEntityId());srchBase.setStatus(0);Integer count = workflowRequestBaseMapper.selectCount(srchBase);if (count != null && count > 0) {throw new GlobalException("120011", "同一条业务不能重复创建流程");}WorkflowRequestBase requestBase = setRequestBase(createWorkflowVo);// 插入流程审批表workflowRequestBaseMapper.insertReturnKeys(requestBase);log.info("id = {}", requestBase.getRequestId());if (requestBase.getRequestId() != null && requestBase.getRequestId().length() > 0) {List<String> requestNodes = createWorkflowVo.getRequestNodes();// 插入流程节点表int sort = 0;requestNodes.add("0");// 归档节点List<WorkflowRequestNode> nodesList = new ArrayList<WorkflowRequestNode>();for (String userid : requestNodes) {WorkflowRequestNode node = new WorkflowRequestNode();node.setRequestId(requestBase.getRequestId());node.setOperatorId(userid);node.setNodeType("0".equalsIgnoreCase(userid) ? 1 : 0);node.setStatus(0);node.setSort(sort++);nodesList.add(node);}workflowRequestNodeMapper.batchInsert(nodesList);} else {throw new GlobalException("120005", "无法获取Request ID");}return ResponseResult.success(String.valueOf(requestBase.getRequestId()));}//执行流程/*** 流程往下走** @param executeWorkflowVo* @return*/@Override@Transactional(propagation = Propagation.REQUIRED)public ResponseResult executeFlow(ExecuteWorkflowVo executeWorkflowVo) {WorkflowRequestBase requestBase = getRequestBase(executeWorkflowVo.getRequestId());// 如果工作流的状态不对,不能继续操作if (requestBase.getStatus() != 0) {throw new GlobalException("120010", "该工作流可能已归档,无法继续操作");}// 只有当前操作人才能操作,防重复提交if (!requestBase.getCurrentOperatorId().equalsIgnoreCase(String.valueOf(executeWorkflowVo.getCurrentOperatorId()))) {throw new GlobalException("120007", "当前操作人不合法");}WorkflowRequestNode nextNode = null;// 如果需要插入节点if (executeWorkflowVo.isInsertNode()) {if (CollectionUtils.isEmpty(executeWorkflowVo.getNodes())) {throw new GlobalException("120011", "插入的节点操作人不能为空");}// 获取当前操作人节点及以后的节点List<WorkflowRequestNode> afterNodes = workflowRequestNodeMapper.selectNextOperator(executeWorkflowVo.getRequestId(),executeWorkflowVo.getCurrentOperatorId());Integer initSort = afterNodes.get(0).getSort();List<String> nodes = executeWorkflowVo.getNodes();List<WorkflowRequestNode> insertNodes = Lists.newArrayList();for (int i = 0; i < nodes.size(); i ++) {initSort ++;WorkflowRequestNode eachNode = new WorkflowRequestNode();eachNode.setRequestId(executeWorkflowVo.getRequestId());eachNode.setNodeType(0);// 不是归档节点eachNode.setOperatorId(executeWorkflowVo.getNodes().get(0));eachNode.setStatus(0);eachNode.setSort(initSort);eachNode.setCreateTime(DateUtil.getCurrentDateTime());eachNode.setModifyTime(DateUtil.getCurrentDateTime());if (i == 0) {nextNode = eachNode;}insertNodes.add(eachNode);}// 将当前操作人节点后面的节点sort都往后推移for (WorkflowRequestNode node : afterNodes) {initSort ++;node.setSort(initSort);// 更新workflowRequestNodeMapper.updateByPrimaryKeySelective(node);}// 插入节点workflowRequestNodeMapper.batchInsert(insertNodes);} else {// 查询下一节点操作人List<WorkflowRequestNode> nextNodes = workflowRequestNodeMapper.selectNextOperator(executeWorkflowVo.getRequestId(),executeWorkflowVo.getCurrentOperatorId());if (CollectionUtils.isEmpty(nextNodes)) {throw new GlobalException("120008", "流程下一节点为空!");}nextNode = nextNodes.get(0);}Integer nextNodeType = nextNode.getNodeType();String nextOperatorId = nextNode.getOperatorId();// 修改当前操作人的状态为审核通过WorkflowRequestNode requestNode = new WorkflowRequestNode();requestNode.setStatus(1);requestNode.setModifyTime(DateUtil.getCurrentDateTime());updateRequestNode(requestNode, executeWorkflowVo.getRequestId(),executeWorkflowVo.getCurrentOperatorId());// 修改流程审批表的当前操作人为查询出来的下一节点操作人WorkflowRequestBase updateBase = new WorkflowRequestBase();updateBase.setCurrentOperatorId(nextOperatorId);updateBase.setLastOperatorId(executeWorkflowVo.getCurrentOperatorId());updateBase.setLastOperateTime(DateUtil.currentDate());updateRequestBase(updateBase, executeWorkflowVo.getRequestId(),executeWorkflowVo.getCurrentOperatorId());// 记录一条操作日志recordRequestLog(executeWorkflowVo.getRequestId(), executeWorkflowVo.getCurrentOperatorId(),nextOperatorId, 1, "已审批");// 如果下一节点是归档节点,则直接归档if (nextNodeType == 1) {boolean flag = finish(requestBase.getWorkflowId(), requestBase.getEntityId(),executeWorkflowVo.getRequestId());log.info("归档结果,{}", flag);}return ResponseResult.success();}/*** 流程退回** @param rejectWorkflowVo* @return*/@Override@Transactional(propagation = Propagation.REQUIRED)public ResponseResult rejectFlow(RejectWorkflowVo rejectWorkflowVo) {WorkflowRequestBase requestBase = getRequestBase(rejectWorkflowVo.getRequestId());// 如果工作流的状态不对,不能继续操作if (requestBase.getStatus() != 0) {throw new GlobalException("120010", "该工作流可能已归档,无法继续操作");}// 只有当前操作人才能操作,防重复提交if (!requestBase.getCurrentOperatorId().equalsIgnoreCase(String.valueOf(rejectWorkflowVo.getCurrentOperatorId()))) {throw new GlobalException("120007", "当前操作人不合法");}// 修改当前操作人的状态为审核通过WorkflowRequestNode requestNode = new WorkflowRequestNode();requestNode.setStatus(-1);requestNode.setModifyTime(DateUtil.getCurrentDateTime());updateRequestNode(requestNode, rejectWorkflowVo.getRequestId(),rejectWorkflowVo.getCurrentOperatorId());// 修改流程审批表的当前操作人为查询出来的下一节点操作人WorkflowRequestBase updateBase = new WorkflowRequestBase();updateBase.setStatus(-1);updateBase.setLastOperatorId(rejectWorkflowVo.getCurrentOperatorId());updateBase.setLastOperateTime(DateUtil.currentDate());updateRequestBase(updateBase, rejectWorkflowVo.getRequestId(),rejectWorkflowVo.getCurrentOperatorId());// 记录一条操作日志recordRequestLog(rejectWorkflowVo.getRequestId(), rejectWorkflowVo.getCurrentOperatorId(),null, 1, "已退回:" + rejectWorkflowVo.getRejectNote());boolean flag =callbackAction(requestBase.getWorkflowId(), requestBase.getEntityId(), -1, rejectWorkflowVo.getRejectNote());log.info("退回结果,{}", flag);return ResponseResult.success();}

相关Vo

创建工作流

public class CreateWorkflowVo implements Serializable {@ApiModelProperty("流程标题")private String requestName;@ApiModelProperty("哪种类型的流程")private String workflowBaseId;@ApiModelProperty("实际业务ID")private String entityId;@ApiModelProperty("工地编码")private String projectNo;@ApiModelProperty("提交人ID")private String creator;@ApiModelProperty("流程节点处理人")private List<String> requestNodes;}

执行工作流,走向下一节点

public class ExecuteWorkflowVo implements Serializable {/*** 工作流ID*/private String requestId;/*** 当前操作人ID*/private String currentOperatorId;/*** 是否插入节点*/private boolean insertNode;/*** 节点*/private List<String> nodes;}

退回工作流

public class RejectWorkflowVo implements Serializable {/*** 工作流ID**/private String requestId;/*** 当前操作人ID*/private String currentOperatorId;/*** 退回原因*/private String rejectNote;}

工作流流程用户在创建、往下执行、退回调用对应的自定义工作流方法,举例:一条由工地项目经理发起的流程,设置涉及的流程节点:项目经理、项目主管、片区工程经理、业主。执行创建流程:

             CreateWorkflowVo workflow = new CreateWorkflowVo();workflow.setProjectNo(contractMeasure.getClientNo());workflow.setEntityId(contractMeasure.getId());workflow.setCreator(Integer.toString(xmjl));workflow.setWorkflowBaseId("12");workflow.setRequestName("关于××审批");//创建审批节点List<String> requestNodes = new ArrayList<String>();//项目主管节点requestNodes.add(Integer.toString(xmzg));//添加业主节点requestNodes.add(contractMeasure.getClientNo());workflow.setRequestNodes(requestNodes);ResponseResult result = workflowUtil.create(workflow);

查看流程主表,会有一条新的记录

查看requestid关联的流程节点表

后面节点审批就省略了,无非也是封装对应的参数Vo,调用流程方法。

Java实现自定义工作流相关推荐

  1. 自定义工作流任务控件

    读moss sdk中的自定义工作流任务控件. 自定义工作流任务控件:任务的创建,修改,删除,完成于一体,同时定义了这四个动作的历史纪录. 自定义时封装属性:  1. 封装任务属性 IsTaskComp ...

  2. java 怎么自定义排序_Java如何实现List自定义排序

    Java如何实现List自定义排序,自定义,即为,详细内容,相关文章,更多关于 Java如何实现List自定义排序 易采站长站,站长之家为您整理了Java如何实现List自定义排序的相关内容. 实体类 ...

  3. Jira 自定义工作流

    一.添加修改工作流 打开 设置--问题--工作流 复制一个工作流,然后进去编辑页面 添加状态 增加转换动作 切换到文本,设置跳转过程中的事件 针对Stop Progress事件,修改跳转界面(界面需先 ...

  4. java简单自定义Annotation

    为什么80%的码农都做不了架构师?>>>    原文内容比较多,这里就简单地说一下.java 5以后增加了3个annotation, @Override @Deprecated @S ...

  5. Robot Framework自动化测试框架核心指南-如何使用Java编写自定义的RobotFramework Lib

    如何使用Java编写自定义的RobotFramework Lib 本文包括2个章节 1. Robot Frdamwork中如何调用java Lib库 2.使用 java编写自定义的Lib 本文作者为: ...

  6. Java Map 自定义排序

    HashMap是不保证顺序的,要有顺序,要用LinkedHashMap,这是按照插入顺序排列的. Map接口的哈希表和链接列表实现,具有可预知的迭代顺序.此实现与HashMap的不同之处在于,后者维护 ...

  7. java计算机毕业设计工作流流程编辑OA系统MyBatis+系统+LW文档+源码+调试部署

    java计算机毕业设计工作流流程编辑OA系统MyBatis+系统+LW文档+源码+调试部署 java计算机毕业设计工作流流程编辑OA系统MyBatis+系统+LW文档+源码+调试部署 本源码技术栈: ...

  8. java使用自定义HTML模板发送邮件——记录开发篇1

    java使用自定义HTML模板发送email VO接收参数 @Data public class EmailVo {@ApiModelProperty("收件人列表")@NotNu ...

  9. Java AOP自定义注解

    一.背景 在之前文章:Java注解详解中,主要介绍了注解的含义.作用.以及常用的各类注解.今天主要介绍在Springboot中如何实现一个自定义注解,通过自定义注解去实现一些定制化的需求. 二.了解元 ...

  10. Java开源 开源工作流

     Willow   点击次数:18942 由Huihoo Power开发详细可到其中文主页查看.  OpenWFE   点击次数:17672 OpenWFE是一个开放源码的Java工作流引擎.它是一个 ...

最新文章

  1. windows服务程序设置为自动 重启后又变为手动启动_系统小技巧:解决Windows无法正常关机的问题...
  2. linux 内核驱动模块的编译及加载
  3. 2020-10-27(dex文件解析)
  4. real类型_如何使用REAL方法对您的Web内容进行现实检查
  5. mysqld_safe启动mysql
  6. nyoj 586 疯牛(二分+贪心)
  7. sqlmap-学习1 配置环境
  8. Echarts数据可视化grid直角坐标系(xAxis、yAxis),开发全解+完美注释
  9. 程序员生存定律——打造属于自己的稀缺性(转载)
  10. netlify支持php吗,用 hugo 和 netlify 搭建blog【转】
  11. wlnmp+nginx+mysql+php集合包_Centos7下编译安装Nginx、Mysql、PHP
  12. 如何下载谷歌浏览器官方最新离线安装包
  13. kali linux 无线攻击——aircrack-ng
  14. Windows 10 的快捷关机方式
  15. P值计算(Excel)
  16. 电力系统服务器是什么,什么是电网调度?
  17. c语言变量表达式计算器,C语言表达式计算器~
  18. 申请美国大学计算机专业,美国TOP20大学计算机专业申请建议
  19. 【Oracle】并行等待之PX Deq: Signal ACK
  20. HDU 新生赛 油菜花王国(并查集)

热门文章

  1. 链路聚合_链路聚合的配置命令
  2. opencv遍历像素输出像素值
  3. 【工具类】java数字金额转换成大写
  4. 统计学中p值计算公式_统计学中的P值应该怎么计算
  5. 基于ASP的高校宿舍管理系统设计与实现
  6. php环境安装Java_常用PHP运行环境一键安装包推荐
  7. 老师常用选择题,选择框,单选框,以及各行业产品配置表单选配置明细等
  8. qt web混合编程_Qt+VS混合编程教程
  9. 三菱PLC与上位机进行通讯
  10. ESP8266通过VS1838B 解码红外遥控器