首页
学习
活动
专区
圈层
工具
发布

告别纸质流程,拥抱代码的审批世界

在企业管理的世界里,审批流程就像是一条永不停歇的河流,承载着组织运转的重要决策。从请假条到报销单,从采购申请到合同审核,每一个环节都需要层层把关,确保万无一失。然而,传统的纸质审批流程往往如同一场漫长的马拉松,文件在各个部门之间辗转,审批人忙碌或出差时更是雪上加霜。

今天,就让我们一起走进代码的世界,看看如何用几百行Java代码,构建一个轻量级却功能强大的审批系统,让繁琐的流程变得简单高效。

一、审批系统的核心思想

想象一下,如果能用一个简单的注解,就能让普通的业务方法自动具备审批能力,是不是很酷?

@PostMapping("/submit")

@Approval(processCode = "LEAVE_APPROVAL", businessType = "LEAVE", businessKey = "#leaveId")

public String submitLeave(@RequestParam Long leaveId) {

  return "请假申请已提交,等待审批";

}

没错,就是这么简单!只需在方法上添加@Approval注解,指定流程编码、业务类型和业务主键,这个方法就具备了发起审批的能力。当它被调用时,系统会自动创建一个审批实例,并按照预设的流程节点推进。

二、系统架构:麻雀虽小,五脏俱全

我们的审批系统虽然代码量不大,但结构清晰,功能完备。它主要包含以下几个部分:

注解层:提供了一系列注解,用于标记审批相关的操作

切面层:通过AOP拦截注解标记的方法,实现审批逻辑的自动处理

服务层:实现审批流程的核心业务逻辑

数据层:存储审批流程、节点、实例和记录等信息

2.1 注解:优雅的审批入口

系统提供了五种核心注解,分别对应审批流程中的不同操作:

@Approval  // 发起审批

@Agree     // 同意审批

@Reject    // 拒绝审批

@Cancel    // 取消审批

@Back      // 退回审批

每个注解都包含相同的属性:

/**

* 审批注解

* 用于标记需要进行审批的方法

*/

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Approval {

  /**

   * 流程编码

   */

  String processCode();

  /**

   * 业务类型

   */

  String businessType();

  /**

   * 业务主键的SpEL表达式

   */

  String businessKey();

  /**

   * 审批意见

   */

  String comment() default "";

}

2.2 切面:审批的魔法所在

审批切面是整个系统的核心,它通过AOP技术拦截带有审批注解的方法,提取注解中的信息,并在方法执行前后自动处理审批逻辑:

@Around("@annotation(cn.eking.approval.annotation.Approval)")

@Transactional(rollbackFor = Exception.class)

public Object aroundApproval(ProceedingJoinPoint point) throws Throwable {

  return handleApproval(point, Approval.class);

}

切面的处理逻辑非常巧妙:先执行业务方法,如果业务方法执行成功,再处理审批逻辑;如果审批逻辑出错,则通过事务回滚整个操作,确保数据一致性。

// 先执行业务逻辑

Object result = point.proceed();

// 业务逻辑执行成功后,处理审批逻辑

if (annotation instanceof Approval) {

  approvalService.startApproval(processCode, businessType, businessKey, comment);

} else if (annotation instanceof Agree) {

  approvalService.agree(processCode, businessType, businessKey, comment);

}

// ... 其他审批操作

三、审批流程:从提交到完成的旅程

一个完整的审批流程通常包含以下几个步骤:

发起审批:创建审批实例,设置初始状态为"待审批"

审批处理:审批人进行同意、拒绝、退回等操作

流程流转:根据审批结果,流程向下一节点推进或结束

让我们看看发起审批的核心代码:

@Transactional(rollbackFor = Exception.class)

public void startApproval(String processCode, String businessType, String businessKey, String comment) {

  // 获取流程定义

  ApprovalProcess process = getProcess(processCode);

  // 获取开始节点

  ApprovalNode startNode = getStartNode(process.getId());

  // 创建审批实例

  ApprovalInstance instance = new ApprovalInstance();

  instance.setProcessId(process.getId());

  instance.setBusinessType(businessType);

  instance.setBusinessKey(businessKey);

  instance.setStatus(ApprovalStatusEnum.PENDING.name());

  instance.setCurrentNodeId(startNode.getId());

  instance.setCreatorId(userService.getCurrentUserId());

  instance.setCreatorName(userService.getCurrentUserName());

  instance.setCreateTime(LocalDateTime.now());

  instance.setUpdateTime(LocalDateTime.now());

  instanceMapper.insert(instance);

  // 创建审批记录

  createRecord(instance.getId(), startNode.getId(), ApprovalActionEnum.APPROVE, comment);

  // 处理自动审批

  handleAutoApprove(instance, startNode);

}

当审批人同意一个审批时,系统会执行以下逻辑:

@Transactional(rollbackFor = Exception.class)

public void agree(String processCode, String businessType, String businessKey, String comment) {

  // 获取审批实例

  ApprovalInstance instance = getInstance(processCode, businessType, businessKey);

  // 获取当前节点

  ApprovalNode currentNode = getNode(instance.getCurrentNodeId());

  // 检查当前用户是否有权限审批

  checkApprovalPermission(currentNode);

  // 创建审批记录

  createRecord(instance.getId(), currentNode.getId(), ApprovalActionEnum.AGREE, comment);

  // 判断节点类型(普通节点或会签节点)并处理

  // ...

  // 获取下一个节点

  ApprovalNode nextNode = getNextNode(instance.getProcessId(), currentNode.getOrderNum());

  if (nextNode == null) {

      // 没有下一个节点,流程结束

      instance.setStatus(ApprovalStatusEnum.APPROVED.name());

      instance.setCurrentNodeId(null);

  } else {

      // 设置下一个节点

      instance.setCurrentNodeId(nextNode.getId());

      // 处理自动审批

      handleAutoApprove(instance, nextNode);

  }

  // 更新实例

  instance.setUpdateTime(LocalDateTime.now());

  instanceMapper.updateById(instance);

}

四、灵活多变的审批节点

审批系统支持多种类型的节点,满足不同场景的需求:

普通节点:由指定人员审批

会签节点:需要多人共同审批,支持"全部同意"、"任一同意"或"百分比同意"等规则

自动节点:系统自动审批,无需人工干预

节点的审批人也支持多种配置方式:

/**

* 审批人类型:USER-指定用户,ROLE-指定角色,DEPARTMENT-指定部门

*/

private String approverType;

/**

* 审批人ID,多个用逗号分隔

*/

private String approverValue;

这种设计使得系统能够灵活应对各种复杂的组织结构和审批场景。

五、实战案例:请假审批流程

让我们通过一个请假审批的例子,看看整个系统是如何工作的:

定义流程:在数据库中创建"请假审批流程"及其节点

-- 插入审批流程定义

INSERT INTO approval_process (process_code, process_name, process_type, status) VALUES

('LEAVE_APPROVAL', '请假审批流程', 'LEAVE', 1);

-- 插入请假审批流程的节点

INSERT INTO approval_node (process_id, node_code, node_name, node_type, approver_type, approver_value, auto_approve, order_num) VALUES

-- 开始节点

(1, 'START', '开始节点', 'START', 'USER', '1', 0, 1),

-- 直接主管审批

(1, 'DIRECT_MANAGER', '直接主管审批', 'APPROVAL', 'ROLE', 'MANAGER', 0, 2),

-- 部门经理审批

(1, 'DEPARTMENT_MANAGER', '部门经理审批', 'APPROVAL', 'ROLE', 'DEPT_MANAGER', 0, 3),

-- 人事审批

(1, 'HR_APPROVAL', '人事审批', 'APPROVAL', 'DEPARTMENT', 'HR', 0, 4),

-- 结束节点

(1, 'END', '结束节点', 'END', 'USER', '1', 0, 5);

创建控制器:提供请假审批的API接口

@RestController

@RequestMapping("/api/approval")

@RequiredArgsConstructor

public class ApprovalController {

  private final ApprovalService approvalService;

  /**

   * 提交请假申请

   */

  @PostMapping("/submit")

  @Approval(processCode = "LEAVE_APPROVAL", businessType = "LEAVE", businessKey = "#leaveId")

  public String submitLeave(@RequestParam Long leaveId) {

      return "请假申请已提交,等待审批";

  }

  /**

   * 同意请假申请

   */

  @PostMapping("/agree")

  @Agree(processCode = "LEAVE_APPROVAL", businessType = "LEAVE", businessKey = "#leaveId")

  public String agreeLeave(@RequestParam Long leaveId) {

      return "请假申请已同意";

  }

  /**

   * 拒绝请假申请

   */

  @PostMapping("/reject")

  @Reject(processCode = "LEAVE_APPROVAL", businessType = "LEAVE", businessKey = "#leaveId")

  public String rejectLeave(@RequestParam Long leaveId) {

      return "请假申请已拒绝";

  }

}

流程执行

员工提交请假申请,系统创建审批实例,状态为"待审批"

直接主管收到审批任务,进行审批

如果同意,流程流转到部门经理;如果拒绝,流程结束

部门经理审批同意后,流转到人事审批

人事审批同意后,流程结束,状态变为"已通过"

六、系统的亮点与思考

这个轻量级审批系统虽然代码不多,但设计精巧,有几个值得称赞的亮点:

注解驱动:通过注解实现审批功能,对业务代码几乎零侵入

AOP切面:利用Spring AOP实现审批逻辑与业务逻辑的分离

事务管理:确保业务操作与审批操作的原子性

灵活配置:支持多种节点类型和审批人配置方式

当然,系统也有一些可以改进的地方:

流程定义:可以支持可视化的流程设计

审批规则:可以增加更复杂的条件判断和分支流转

消息通知:集成消息推送,及时通知审批人

移动端支持:提供移动端API,实现随时随地审批

结语

从纸质流程到电子审批,从繁琐操作到一键处理,技术的力量正在改变企业的运作方式。这个小巧而精致的审批系统,展示了如何用简洁的代码解决复杂的业务问题。

在代码的世界里,我们不仅仅是在编写程序,更是在创造改变工作方式的工具。希望这个审批系统能给你带来启发,让你在自己的项目中也能设计出优雅而实用的解决方案。

记住,好的系统不在于代码的多少,而在于思想的精妙。正如这个审批系统所展示的,有时候,几百行代码就能实现一个企业级的功能模块,关键在于如何巧妙地利用已有的技术和框架,设计出简洁而强大的解决方案。

下次当你面对一个看似复杂的业务需求时,不妨试着从简单入手,寻找那个优雅的设计点,或许你会发现,复杂问题往往有着出人意料的简单解法。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OoX7OvAR-QcOBcjC2qYdohfg0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券