一家只做特卖的网站,wordpress修改模板教程,天猫网站建设论文,五大建设的内容作者#xff1a;后端小肥肠 创作不易#xff0c;未经允许严禁转载。 姊妹篇#xff1a;独辟蹊径#xff1a;我是如何用Java自创一套工作流引擎的#xff08;上#xff09;_java工作流引擎-CSDN博客 1. 前言
在上一篇博客中#xff0c;我们详细介绍了如何利用Java语言从… 作者后端小肥肠 创作不易未经允许严禁转载。 姊妹篇独辟蹊径我是如何用Java自创一套工作流引擎的上_java工作流引擎-CSDN博客 1. 前言
在上一篇博客中我们详细介绍了如何利用Java语言从零开始打造一套工作流引擎的基础架构。通过设计核心表结构和实现基础代码框架我们建立了一个坚实的理论基础。今天我们迈入《独辟蹊径我是如何用Java自创一套工作流引擎的下》将深入探讨这一引擎在实际项目中的应用和效果。
2. 项目场景模拟
本章我们将以实际项目场景来模拟自研工作流引擎的使用分别是申请数据资源的流程和请假申请流程。
2.1. 申请数据资源流程
2.1.1. 技术流程
假设申请数据的审批级数为2级。申请数据资源的流程图如下 在上述流程图中从普通用户一级审批人员二级审批人员视角呈现了申请数据资源的整体流程
1. 用户提交审批数据表单填入申请人信息姓名、电话申请理由和需要申请的数资源
2. 一级审批人员收到用户提交的申请后进行审批如果驳回则整个流程结束如果通过则进入下一审批环节
3. 一级审批通过后二级审批人员可进行审批如果驳回则整个流程结束如何通过则开放数据下载链接用户可根据链接下载申请的数据。
2.2. 请假申请流程
2.2.1. 技术流程
请假流程如下 在上述流程中从用户和一级审批人员的角度呈现了整个请假流程
1. 用户提交审批数据表单填入申请人信息姓名、电话、申请理由、请假天数
2. 一级审批人员收到用户提交的申请后进行审批如果驳回则整个流程结束同时通知用户流程未通过如果通过则结束流程。
2.3. 技术实现
要在工作流中集成以上两套流程需要基于一下几个步骤实现
1. 设计流程定义在business_approval_workflow新建数据审批流程和请假流程。 2. 设计流程细节设计数据审批流程和请假流程的节点细节。 上图中申请业务数据包含两个流程节点第一个节点审批人为admin第二个节点审批人为super请假流程包含一个流程节点审批人为admin。
3. 编写提交申请接口。
提交申请业务数据流程接口直接使用《独辟蹊径我是如何用Java自创一套工作流引擎的上》中提交申请接口就行 public Boolean addRequest(RequestDTO requestDTO) {Request request BeanCopyUtils.copyBean(requestDTO,Request.class);request.setStatus(1);//设置整个流程状态为正在审核// 1. 插入数据到 request 表baseMapper.insert(request);// 2. 根据 workflow_id 查询业务流程的节点信息找到 serial_number 为 1 的节点,即流程开始时的第一个节点BusinessApprovalWorkflowDetail firstNode workflowDetaiSlService.findFirstNodeByWorkflowId(request.getWorkflowId());//获取下一级节点 填充下级节点审批人BusinessApprovalWorkflowDetail nextNodeworkflowDetaiSlService.getNextNodeByPreNode(firstNode);if (firstNode ! null) {// 创建一个 approval_detail 记录示例需要根据具体情况设置字段值ApprovalDetail approvalDetail new ApprovalDetail();approvalDetail.setRequestId(request.getId()); // 假设设置关联的 request_idapprovalDetail.setApproverUsername(firstNode.getNodeUsername()); // 设置首次节点的审批人用户名approvalDetail.setApprovalTime(new Date());approvalDetail.setNextApproverUsername(nextNode.getNodeUsername());//设置下游节点的审批人用户名approvalDetail.setStatus(1); // 设置初始状态为待审批approvalDetail.setWorkflowId(request.getWorkflowId());approvalDetail.setNodeName(firstNode.getNodeName());approvalDetail.setNextNodeName(nextNode.getNodeName());// 插入数据到 approval_detail 表approvalDetailService.save(approvalDetail);} else {// 如果未找到对应的节点根据实际需求进行错误处理或日志记录throw new RuntimeException(Unable to find the first node for workflow id: request.getWorkflowId());}return true;}
提交请假流程接口在编写提交请假流程接口前需要先明确请假申请表的表结构
CREATE TABLE public.leave_request (id varchar(32) COLLATE pg_catalog.default NOT NULL,workflow_id varchar(32) COLLATE pg_catalog.default NOT NULL,purpose varchar(900) COLLATE pg_catalog.default NOT NULL,leave_days int2 NOT NULL,applicant_name varchar(50) COLLATE pg_catalog.default,applicat_username varchar(50) COLLATE pg_catalog.default,applicant_phone varchar(11) COLLATE pg_catalog.default,version int4 DEFAULT 1,is_deleted int4 DEFAULT 0,create_time timestamp(6) NOT NULL,update_time timestamp(6)
)
;ALTER TABLE public.leave_request OWNER TO postgres;COMMENT ON COLUMN public.leave_request.workflow_id IS 业务流程id;COMMENT ON COLUMN public.leave_request.purpose IS 请假理由;COMMENT ON COLUMN public.leave_request.leave_days IS 请假天数;COMMENT ON COLUMN public.leave_request.applicant_name IS 申请人姓名;COMMENT ON COLUMN public.leave_request.applicat_username IS 申请人用户名;COMMENT ON COLUMN public.leave_request.applicant_phone IS 申请人电话;
编写controller层 GetMapping()public Boolean addRequest(Validated RequestBody LeaveRequestDTO leaveRequestDTO){return leaveRequestService.addRequest(leaveRequestDTO);}
编写LeaveRequestDTO
Data
AllArgsConstructor
NoArgsConstructor
public class LeaveRequestDTO {private String workflowId;private String purpose;private Integer leaveDays;private String applicantName;private String applicantPhone;private String applicatUsername;
}
编写service层 public Boolean addRequest(LeaveRequestDTO leaveRequestDTO) {LeaveRequest leaveRequest BeanCopyUtils.copyBean(leaveRequestDTO,LeaveRequest.class);// 1. 插入数据到 request 表baseMapper.insert(leaveRequest);// 2. 根据 workflow_id 查询业务流程的节点信息找到 serial_number 为 1 的节点,即流程开始时的第一个节点BusinessApprovalWorkflowDetail firstNode workflowDetaiSlService.findFirstNodeByWorkflowId(leaveRequest.getWorkflowId());//获取下一级节点 填充下级节点审批人BusinessApprovalWorkflowDetail nextNodeworkflowDetaiSlService.getNextNodeByPreNode(firstNode);if (firstNode ! null) {// 创建一个 approval_detail 记录示例需要根据具体情况设置字段值ApprovalDetail approvalDetail new ApprovalDetail();approvalDetail.setRequestId(leaveRequest.getId()); // 假设设置关联的 request_idapprovalDetail.setApproverUsername(firstNode.getNodeUsername()); // 设置首次节点的审批人用户名approvalDetail.setApprovalTime(new Date());approvalDetail.setNextApproverUsername(nextNode.getNodeUsername());//设置下游节点的审批人用户名approvalDetail.setStatus(1); // 设置初始状态为待审批approvalDetail.setWorkflowId(leaveRequest.getWorkflowId());approvalDetail.setNodeName(firstNode.getNodeName());approvalDetail.setNextNodeName(nextNode.getNodeName());// 插入数据到 approval_detail 表approvalDetailService.save(approvalDetail);} else {// 如果未找到对应的节点根据实际需求进行错误处理或日志记录throw new RuntimeException(Unable to find the first node for workflow id: leaveRequest.getWorkflowId());}return true;}
上述代码实现了提交请假申请的功能首先将从DTO转换后的请假请求数据插入数据库然后根据流程ID查询流程的第一个节点信息设置首次节点的审批人并插入到审批详情表中状态设置为待审批。
4. 基于策略模式优化审批接口。
审批申请方法在上篇中如下 TransactionalOverridepublic Boolean approvalApplication(ApprovalDTO approvalDTO) {// 这里我写死了实际获取应该走权限框架获取当前在线用户 usernameString username xfc;
// 审批人姓名从用户表中获取String name小肥肠;//查询出当前任务节点ApprovalDetail approvalDetail baseMapper.selectById(approvalDTO.getId());//获取当前审批的申请信息Request request requestMapper.selectById(approvalDetail.getRequestId());if(requestnull){throw new RuntimeException(申请id有误);}// 审批通过if (approvalDTO.getStatus().equals(2)) {// 根据 workflow_id 和 node_name 联查 business_approval_workflow_detail 表获取当前流程是否为最后节点即 is_final1BusinessApprovalWorkflowDetail currentWorkflowDetail businessApprovalWorkflowDetailService.findByWorkflowIdAndNodeName(approvalDTO.getWorkflowId(), approvalDetail.getNodeName());if (currentWorkflowDetail ! null currentWorkflowDetail.getIsFinal().equals(1)) {// 如果是最后节点则删除该条数据填充 approval_history 表根据 request 表修改 request 数据的 status 为 2baseMapper.deleteById(approvalDetail.getId()); // 删除当前审批记录// 更新 request 表中的状态为 2通过request.setStatus(2);requestMapper.updateById(request);} else {// 如果不是最后节点则更新 business_approval_workflow_detail 为下一个节点审批信息BusinessApprovalWorkflowDetail nextNode businessApprovalWorkflowDetailService.getNextNodeByPreNode(currentWorkflowDetail);
// 获取下一级节点的更下一级BusinessApprovalWorkflowDetail nextNextNode businessApprovalWorkflowDetailService.getNextNodeByPreNode(nextNode);// 更新当前 approval_detail 表中的审批人和下一个审批人信息approvalDetail.setApproverUsername(nextNode.getNodeUsername());approvalDetail.setNodeName(nextNextNode.getNodeName());approvalDetail.setNextApproverUsername(nextNextNode!null?nextNextNode.getNodeUsername():);approvalDetail.setNextNodeName(nextNextNode!null?nextNextNode.getNodeName():);approvalDetail.setApprovalTime(new Date());approvalDetail.setStatus(1); // 设置为待审批状态baseMapper.updateById(approvalDetail);}// 填充 approval_history 表ApprovalHistory approvalHistory new ApprovalHistory();approvalHistory.setRequestId(request.getId());approvalHistory.setApproverName(name); // 设置审批人姓名或者从用户表中获取approvalHistory.setApprovalTime(new Date());approvalHistory.setStatus(2); // 通过approvalHistory.setRemark(approvalDTO.getRemark());approvalHistory.setWorkflowId(approvalDTO.getWorkflowId());approvalHistory.setApplicantPhone(request.getApplicantPhone());approvalHistory.setPurpose(request.getPurpose());approvalHistory.setApplicantName(request.getApplicantName());approvalHistory.setApproverUsername(username); // 设置审批人用户名或者从用户表中获取approvalHistoryMapper.insert(approvalHistory); // 插入审批历史记录} else if (approvalDTO.getStatus().equals(3)) {// 审批驳回baseMapper.deleteById(approvalDetail.getId()); // 删除当前审批记录// 填充 approval_history 表ApprovalHistory approvalHistory new ApprovalHistory();approvalHistory.setRequestId(request.getId());approvalHistory.setApproverName(name); // 设置审批人姓名或者从用户表中获取approvalHistory.setApprovalTime(new Date());approvalHistory.setStatus(3); // 驳回approvalHistory.setRemark(approvalDTO.getRemark());approvalHistory.setWorkflowId(approvalDTO.getWorkflowId());approvalHistory.setApplicantPhone(request.getApplicantPhone());approvalHistory.setPurpose(request.getPurpose());approvalHistory.setApplicantName(request.getApplicantName());approvalHistory.setApproverUsername(username); // 设置审批人用户名或者从用户表中获取approvalHistoryMapper.insert(approvalHistory); // 插入审批历史记录// 更新 request 表中的状态为 3驳回request.setStatus(3);requestMapper.updateById(request);}return true; // 或者根据实际需求返回其他业务逻辑}上述代码其实是针对申请数据资源流程的审批操作那如果要申请别的流程该怎么做呢常规操作应该是在上述代码中增加if-else判断操作根据不通业务进行士审批操作但是随着业务流程增加就会新增许多if-else操作代码会十分雍总代码可读性较差可以通过引入策略工厂来解决上述问题。步骤如下
1.新增审批策略工厂
Service
public class ApprovalFactory {AutowiredApprovalDataRequestService approvalDataRequestService;AutowiredApprovalLeaveRequestService approvalLeaveRequestService;private static MapString, FunctionApprovalDTO,Boolean approvalMap null;PostConstructpublic void init(){approvalMapnew HashMap();approvalMap.put(2,approvalDTO-approvalDataRequestService.approvalApplication(approvalDTO));approvalMap.put(1,approvalDTO -approvalLeaveRequestService.approvalApplication(approvalDTO));}public Boolean approvalApplication(ApprovalDTO approvalDTO) {return approvalMap.get(approvalDTO.getWorkflowId()).apply(approvalDTO);}
}
上述代码为针对审批操作的策略工厂在类初始化过程中使用 PostConstruct 注解的 init() 方法通过静态的 approvalMap 对象将审批动作和对应的处理函数关联起来。具体来说
当 workflowId 为 2 时映射到 approvalDataRequestService 的 approvalApplication 方法处理数据请求的审批逻辑。当 workflowId 为 1 时映射到 approvalLeaveRequestService 的 approvalApplication 方法处理请假请求的审批逻辑。
最后approvalApplication(ApprovalDTO approvalDTO) 方法根据传入的 approvalDTO 中的 workflowId 从 approvalMap 中获取相应的处理函数并执行该函数来完成审批操作返回处理结果controller层直接调用策略工厂即可 PostMapping(/approval)public Boolean approvalApplication(Validated RequestBody ApprovalDTO approvalDTO) {return approvalFactory.approvalApplication(approvalDTO);}
2. 新增数据资源审批类
Service
Slf4j
public class ApprovalDataRequestService {AutowiredIBusinessApprovalWorkflowDetailService businessApprovalWorkflowDetailService;AutowiredRequestMapper requestMapper;AutowiredApprovalHistoryMapper approvalHistoryMapper;AutowiredApprovalDetailMapper approvalDetailMapper;Transactionalpublic Boolean approvalApplication(ApprovalDTO approvalDTO) {// 这里我写死了实际获取应该走权限框架获取当前在线用户 usernameString username xfc;
// 审批人姓名从用户表中获取String name小肥肠;//查询出当前任务节点ApprovalDetail approvalDetail approvalDetailMapper.selectById(approvalDTO.getId());//获取当前审批的申请信息Request request requestMapper.selectById(approvalDetail.getRequestId());if(requestnull){throw new RuntimeException(申请id有误);}// 审批通过if (approvalDTO.getStatus().equals(2)) {// 根据 workflow_id 和 node_name 联查 business_approval_workflow_detail 表获取当前流程是否为最后节点即 is_final1BusinessApprovalWorkflowDetail currentWorkflowDetail businessApprovalWorkflowDetailService.findByWorkflowIdAndNodeName(approvalDTO.getWorkflowId(), approvalDetail.getNodeName());if (currentWorkflowDetail ! null currentWorkflowDetail.getIsFinal().equals(1)) {// 如果是最后节点则删除该条数据填充 approval_history 表根据 request 表修改 request 数据的 status 为 2approvalDetailMapper.deleteById(approvalDetail.getId()); // 删除当前审批记录// 更新 request 表中的状态为 2通过request.setStatus(2);requestMapper.updateById(request);} else {// 如果不是最后节点则更新 business_approval_workflow_detail 为下一个节点审批信息BusinessApprovalWorkflowDetail nextNode businessApprovalWorkflowDetailService.getNextNodeByPreNode(currentWorkflowDetail);
// 获取下一级节点的更下一级BusinessApprovalWorkflowDetail nextNextNode businessApprovalWorkflowDetailService.getNextNodeByPreNode(nextNode);// 更新当前 approval_detail 表中的审批人和下一个审批人信息approvalDetail.setApproverUsername(nextNode.getNodeUsername());approvalDetail.setNodeName(nextNextNode.getNodeName());approvalDetail.setNextApproverUsername(nextNextNode!null?nextNextNode.getNodeUsername():);approvalDetail.setNextNodeName(nextNextNode!null?nextNextNode.getNodeName():);approvalDetail.setApprovalTime(new Date());approvalDetail.setStatus(1); // 设置为待审批状态approvalDetailMapper.updateById(approvalDetail);}// 填充 approval_history 表ApprovalHistory approvalHistory new ApprovalHistory();approvalHistory.setRequestId(request.getId());approvalHistory.setApproverName(name); // 设置审批人姓名或者从用户表中获取approvalHistory.setApprovalTime(new Date());approvalHistory.setStatus(2); // 通过approvalHistory.setRemark(approvalDTO.getRemark());approvalHistory.setWorkflowId(approvalDTO.getWorkflowId());approvalHistory.setApplicantPhone(request.getApplicantPhone());approvalHistory.setPurpose(request.getPurpose());approvalHistory.setApplicantName(request.getApplicantName());approvalHistory.setApproverUsername(username); // 设置审批人用户名或者从用户表中获取approvalHistoryMapper.insert(approvalHistory); // 插入审批历史记录} else if (approvalDTO.getStatus().equals(3)) {// 审批驳回approvalDetailMapper.deleteById(approvalDetail.getId()); // 删除当前审批记录// 填充 approval_history 表ApprovalHistory approvalHistory new ApprovalHistory();approvalHistory.setRequestId(request.getId());approvalHistory.setApproverName(name); // 设置审批人姓名或者从用户表中获取approvalHistory.setApprovalTime(new Date());approvalHistory.setStatus(3); // 驳回approvalHistory.setRemark(approvalDTO.getRemark());approvalHistory.setWorkflowId(approvalDTO.getWorkflowId());approvalHistory.setApplicantPhone(request.getApplicantPhone());approvalHistory.setPurpose(request.getPurpose());approvalHistory.setApplicantName(request.getApplicantName());approvalHistory.setApproverUsername(username); // 设置审批人用户名或者从用户表中获取approvalHistoryMapper.insert(approvalHistory); // 插入审批历史记录// 更新 request 表中的状态为 3驳回request.setStatus(3);requestMapper.updateById(request);}return true; // 或者根据实际需求返回其他业务逻辑}}
3.新增请假审批类
Service
public class ApprovalLeaveRequestService {public Boolean approvalApplication(ApprovalDTO approvalDTO) {/*** 一样的逻辑把对request表的操作改为leave_request*/return true;}
}
3. 结语
在本文中针对《独辟蹊径我是如何用Java自创一套工作流引擎的上》中的工作流基础代码进行了结合实际项目的扩展本工作流引擎适用于任何相对简单的审批场景有新的业务流程仅需针对申请表单和审批逻辑进行接口新增和策略工厂扩展即可如本文对你有帮助请一键三连哦~