Flowable16信号事件----------------持续更新中

1.定义

信号事件就像一个公共广播系统。当一个信号被“抛出”(Throw)时,它不是发给某一个特定的流程实例,而是向整个 Flowable 引擎广播一个通知。所有正在等待这个信号的流程实例(们)都会同时“捕获”(Catch)到它,并继续执行。这是一种 一对多 (One-to-many) 的通信模式。

2. 关键特性

全局性 (Global):信号的作用域是整个流程引擎,而不是单个流程实例。
基于名称 (Name-based):信号的识别完全依赖于它的名称。例如,一个名为 user-cancelled 的信号会被所有监听 user-cancelled 的事件捕获。
解耦 (Decoupled):发送信号的实体(可以是另一个流程,也可以是外部的 Java 代码)与接收信号的流程实例之间是完全解耦的。发送者不需要知道谁在监听,监听者也不需要知道是谁发送的。
同步或异步:信号的发送可以是同步的,也可以是异步的,这取决于你的配置和使用场景。

3. 信号事件的类型和用法

信号事件可以在流程的多个地方使用:
信号启动事件 (Signal Start Event)
图标:一个圆圈,中间有一个三角形。
作用:用一个全局信号来启动一个新的流程实例。
场景:当一个外部系统完成了一项重要的初始化任务(如“日终结算完成”),它就可以发送一个信号,所有以此信号为起点的流程(如“生成日报表”、“数据归档”等)都会被启动。
中间信号捕获事件 (Intermediate Signal Catching Event)
图标:双层圆圈,中间有一个空心三角形。
作用:流程执行到这个节点时会暂停,进入等待状态,直到它所定义的信号被广播出来。
场景:一个订单流程在“等待付款”后,进入了“备货”环节。此时如果收到一个全局的 warehouse-maintenance (仓库维护) 信号,流程可以捕获它并进入一个“暂停备货”的路径。
中间信号抛出事件 (Intermediate Signal Throwing Event)
图标:双层圆圈,中间有一个实心三角形。
作用:流程执行到这个节点时,会主动向外广播一个信号。
场景:一个“新员工入职”流程成功完成后,它会抛出一个 new-employee-onboarded 信号,通知所有相关的其他流程(如“权限分配流程”、“资产申领流程”)可以开始了。
信号边界事件 (Signal Boundary Event)
图标:附加在活动(如用户任务)边框上的一个圆圈,中间有一个三角形。
作用:当它所附加的活动正在执行时,如果捕获到指定的信号,它会中断(或不中断,可配置)该活动,并将流程引向另一条路径。
场景:在一个“经理审批”的用户任务上,附加一个 order-cancelled-by-user 信号边界事件。如果经理还没审批,但用户通过另一个系统取消了订单,该系统发送一个取消信号,审批任务就会被立即中断,流程直接走向“关闭订单”的路径。

4. 在 Flowable 中如何触发信号

你主要通过 RuntimeService 来发送一个全局信号:

// 注入 RuntimeService
@Autowired
private RuntimeService runtimeService;

public void sendGlobalSignal() {
    // 发送一个名为 "my-signal" 的信号
    // 所有等待这个信号的流程实例都会被激活
    runtimeService.signalEventReceived("my-signal");

    // 你也可以在发送信号的同时传递一些流程变量
    Map<String, Object> variables = new HashMap<>();
    variables.put("reason", "Urgent escalation");
    runtimeService.signalEventReceived("my-signal", variables);
}

信号事件 vs. 消息事件 (Signal vs. Message)

这是理解这两种事件的关键部分。如果你把信号理解为“广播”,那么请把消息理解为**“点对点通信”,就像发送一封指定收件人的电子邮件**。

特性信号事件 (Signal Event)消息事件 (Message Event)
核心思想广播 (Broadcast)单点投递 (Point-to-Point)
目标一对多 (One-to-Many)。
发送给所有正在监听此信号的流程实例
一对一 (One-to-One)。
明确发送给某一个特定的流程实例
标识方式仅通过信号名称 (signalName)。通过消息名称 (messageName) + 实例关联信息。
引擎需要知道把消息送给哪个实例,通常通过流程实例ID或业务标识(Business Key)来关联。
典型用途1. 系统级状态同步(如系统维护)。
2. 触发多个相关流程(如入职成功后触发多个后续流程)。
3. 跨流程的全局取消或通知。
1. 两个流程实例之间的直接通信。
2. 外部系统回调(如支付成功后,支付网关回调通知那笔订单的流程)。
3. 启动一个与特定业务数据关联的新流程。
Flowable API (触发方式)runtimeService.signalEventReceived(signalName, …)runtimeService.messageEventReceived(messageName, executionId, …)
注意:这里需要一个 executionId 来定位到具体的执行实例。
类比公共广播 / AM/FM 电台
电台只管广播,所有调到这个频道的收音机都能收到。
电子邮件 / 快递
必须有明确的收件人地址,才能准确投递。

何时使用信号事件?
当你需要通知多个流程实例某个事件发生了。
当发送方不关心也不需要知道谁是接收方时。
用于实现全局的、跨流程的协调。
例子:一个管理员按下“系统紧急暂停”按钮,所有正在处理的订单流程都应该暂停。
何时使用消息事件?
当你需要与某个特定的流程实例进行交互时。
当一个流程需要等待来自外部系统的、针对它自己的回调时。
当一个流程需要向另一个已知的流程发送指令时。
例子:一个订单流程调用了支付接口,然后等待支付网关返回“支付成功”的消息。这个消息只应该继续这一个订单的流程,而不是其他订单的。

业务场景

我们将设计一个非常贴合实际业务的场景:电商平台的订单履行流程,与IT部门的系统维护流程之间的交互。
这个场景完美地诠释了信号事件的“广播”和“解耦”特性。
主流程:订单履行流程 (Order Fulfillment Process)
一个客户下单后,系统启动此流程。
流程中有一个关键步骤是“与WMS(仓库管理系统)同步,分配库存”。这是一个自动化的服务任务。
正常情况下,分配库存后,流程继续走向“打包发货”。
触发流程:IT系统维护流程 (IT System Maintenance Process)
当IT部门需要对WMS进行维护时,他们会启动一个维护流程。
这个流程首先会向整个系统广播一个“维护开始”的信号。
在维护工作完成后,它会再次广播一个“维护结束”的信号。
核心交互逻辑
当“订单履行流程”正好执行到“分配库存”这一步时,如果IT部门发出了“维护开始”的信号,订单流程应该能捕获到这个信号。
捕获到信号后,订单流程应该中断当前的“分配库存”任务,并进入一个“等待维护结束”的状态。
当IT部门完成维护并发出“维护结束”的信号后,订单流程应该能再次捕获到这个新信号,然后重新尝试“分配库存”任务。
这里,信号事件是最佳选择,因为IT部门不需要知道当前有多少个订单正在运行,它只需要发出一个全局通知,所有相关的流程都应该能响应。
文件一:订单履行流程 (orderFulfillmentProcess.bpmn20.xml)
作用:这是主业务流程。它处理单个订单,并且能够响应外部的系统维护信号。
核心逻辑:
在“与WMS同步分配库存”任务上,附加了一个边界信号事件,用于捕获“维护开始”信号 (wmsMaintenanceStart)。
如果捕获到信号,流程会中断同步任务,进入等待状态。
在等待状态,一个中间信号捕获事件会等待“维护结束”信号 (wmsMaintenanceEnd)。
收到结束信号后,流程会重新尝试同步库存。

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
             xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
             xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
             xmlns:flowable="http://flowable.org/bpmn"
             targetNamespace="http://www.flowable.org/processdef">

  <!-- 
    定义此流程关心(监听)的信号。
    即使信号由其他流程抛出,在这里定义可以使模型自描述。
  -->
  <signal id="wmsMaintenanceStartSignal" name="wmsMaintenanceStart"></signal>
  <signal id="wmsMaintenanceEndSignal" name="wmsMaintenanceEnd"></signal>

  <process id="orderFulfillmentProcess" name="E-commerce Order Fulfillment Process" isExecutable="true">
    
    <startEvent id="startOrder" name="订单已创建"></startEvent>
    <sequenceFlow id="flow_to_review" sourceRef="startOrder" targetRef="reviewOrder"></sequenceFlow>
    
    <userTask id="reviewOrder" name="审核订单"></userTask>
    <sequenceFlow id="flow_to_sync" sourceRef="reviewOrder" targetRef="syncWmsTask"></sequenceFlow>
    
    <serviceTask id="syncWmsTask" name="与WMS同步分配库存" flowable:class="com.example.flowable.delegate.SyncWmsDelegate"></serviceTask>
    <sequenceFlow id="flow_to_ship" sourceRef="syncWmsTask" targetRef="shipOrder"></sequenceFlow>
    
    <!-- 边界信号事件:捕获“维护开始”信号 -->
    <boundaryEvent id="catchMaintenanceStart" attachedToRef="syncWmsTask" cancelActivity="true">
      <signalEventDefinition signalRef="wmsMaintenanceStartSignal"></signalEventDefinition>
    </boundaryEvent>
    <sequenceFlow id="flow_to_wait" sourceRef="catchMaintenanceStart" targetRef="waitForMaintenanceEnd"></sequenceFlow>
    
    <!-- 中间信号捕获事件:等待“维护结束”信号 -->
    <intermediateCatchEvent id="waitForMaintenanceEnd" name="等待WMS维护结束">
      <signalEventDefinition signalRef="wmsMaintenanceEndSignal"></signalEventDefinition>
    </intermediateCatchEvent>
    <sequenceFlow id="flow_to_retry" sourceRef="waitForMaintenanceEnd" targetRef="syncWmsTask"></sequenceFlow>
    
    <userTask id="shipOrder" name="打包并安排发货"></userTask>
    <sequenceFlow id="flow_to_end" sourceRef="shipOrder" targetRef="endOrder"></sequenceFlow>
    
    <endEvent id="endOrder" name="订单完成"></endEvent>
    
  </process>

  <bpmndi:BPMNDiagram id="BPMNDiagram_orderFulfillmentProcess">
    <bpmndi:BPMNPlane bpmnElement="orderFulfillmentProcess" id="BPMNPlane_orderFulfillmentProcess">
      <bpmndi:BPMNShape bpmnElement="startOrder" id="BPMNShape_startOrder">
        <omgdc:Bounds x="100" y="200" width="36" height="36"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="reviewOrder" id="BPMNShape_reviewOrder">
        <omgdc:Bounds x="180" y="183" width="105" height="70"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="syncWmsTask" id="BPMNShape_syncWmsTask">
        <omgdc:Bounds x="330" y="183" width="105" height="70"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="shipOrder" id="BPMNShape_shipOrder">
        <omgdc:Bounds x="480" y="183" width="105" height="70"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endOrder" id="BPMNShape_endOrder">
        <omgdc:Bounds x="630" y="200" width="36" height="36"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="catchMaintenanceStart" id="BPMNShape_catchMaintenanceStart">
        <omgdc:Bounds x="399" y="238" width="36" height="36"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="waitForMaintenanceEnd" id="BPMNShape_waitForMaintenanceEnd">
        <omgdc:Bounds x="365" y="300" width="36" height="36"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow_to_review" id="BPMNEdge_flow_to_review">
        <omgdi:waypoint x="136" y="218"></omgdi:waypoint>
        <omgdi:waypoint x="180" y="218"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow_to_sync" id="BPMNEdge_flow_to_sync">
        <omgdi:waypoint x="285" y="218"></omgdi:waypoint>
        <omgdi:waypoint x="330" y="218"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow_to_ship" id="BPMNEdge_flow_to_ship">
        <omgdi:waypoint x="435" y="218"></omgdi:waypoint>
        <omgdi:waypoint x="480" y="218"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow_to_end" id="BPMNEdge_flow_to_end">
        <omgdi:waypoint x="585" y="218"></omgdi:waypoint>
        <omgdi:waypoint x="630" y="218"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow_to_wait" id="BPMNEdge_flow_to_wait">
        <omgdi:waypoint x="417" y="274"></omgdi:waypoint>
        <omgdi:waypoint x="417" y="318"></omgdi:waypoint>
        <omgdi:waypoint x="401" y="318"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow_to_retry" id="BPMNEdge_flow_to_retry">
        <omgdi:waypoint x="365" y="318"></omgdi:waypoint>
        <omgdi:waypoint x="300" y="318"></omgdi:waypoint>
        <omgdi:waypoint x="300" y="218"></omgdi:waypoint>
        <omgdi:waypoint x="330" y="218"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

文件二:IT系统维护流程 (itMaintenanceProcess.bpmn20.xml)
作用:这是一个辅助流程,由IT部门在需要维护时启动。它的唯一目的就是向整个系统广播开始和结束维护的信号。
核心逻辑:
流程开始后,立即通过一个中间信号抛出事件广播“维护开始”信号 (wmsMaintenanceStart)。
然后进入一个人工任务,代表IT人员正在进行实际的维护工作。
人工任务完成后,通过另一个中间信号抛出事件广播“维护结束”信号 (wmsMaintenanceEnd)。

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
             xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
             xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
             targetNamespace="http://www.flowable.org/processdef">
  
  <!-- 
    定义此流程会抛出的信号。
  -->
  <signal id="wmsMaintenanceStartSignal" name="wmsMaintenanceStart"></signal>
  <signal id="wmsMaintenanceEndSignal" name="wmsMaintenanceEnd"></signal>

  <process id="itMaintenanceProcess" name="IT System Maintenance Process" isExecutable="true">

    <startEvent id="startMaintenance" name="启动维护流程"></startEvent>
    <sequenceFlow id="flow_m1" sourceRef="startMaintenance" targetRef="throwMaintenanceStart"></sequenceFlow>
    
    <!-- 中间信号抛出事件:广播“维护开始” -->
    <intermediateThrowEvent id="throwMaintenanceStart" name="广播维护开始信号">
      <signalEventDefinition signalRef="wmsMaintenanceStartSignal"></signalEventDefinition>
    </intermediateThrowEvent>
    <sequenceFlow id="flow_m2" sourceRef="throwMaintenanceStart" targetRef="performMaintenanceTask"></sequenceFlow>

    <userTask id="performMaintenanceTask" name="执行WMS维护工作" flowable:assignee="it_admin"></userTask>
    <sequenceFlow id="flow_m3" sourceRef="performMaintenanceTask" targetRef="throwMaintenanceEnd"></sequenceFlow>

    <!-- 中间信号抛出事件:广播“维护结束” -->
    <intermediateThrowEvent id="throwMaintenanceEnd" name="广播维护结束信号">
      <signalEventDefinition signalRef="wmsMaintenanceEndSignal"></signalEventDefinition>
    </intermediateThrowEvent>
    <sequenceFlow id="flow_m4" sourceRef="throwMaintenanceEnd" targetRef="endMaintenance"></sequenceFlow>
    
    <endEvent id="endMaintenance" name="维护完成"></endEvent>

  </process>

  <bpmndi:BPMNDiagram id="BPMNDiagram_itMaintenanceProcess">
    <bpmndi:BPMNPlane bpmnElement="itMaintenanceProcess" id="BPMNPlane_itMaintenanceProcess">
      <bpmndi:BPMNShape bpmnElement="startMaintenance" id="BPMNShape_startMaintenance">
        <omgdc:Bounds x="100" y="100" width="36" height="36"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="throwMaintenanceStart" id="BPMNShape_throwMaintenanceStart">
        <omgdc:Bounds x="180" y="100" width="36" height="36"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="performMaintenanceTask" id="BPMNShape_performMaintenanceTask">
        <omgdc:Bounds x="260" y="83" width="105" height="70"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="throwMaintenanceEnd" id="BPMNShape_throwMaintenanceEnd">
        <omgdc:Bounds x="410" y="100" width="36" height="36"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endMaintenance" id="BPMNShape_endMaintenance">
        <omgdc:Bounds x="490" y="100" width="36" height="36"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow_m1" id="BPMNEdge_flow_m1">
        <omgdi:waypoint x="136" y="118"></omgdi:waypoint>
        <omgdi:waypoint x="180" y="118"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow_m2" id="BPMNEdge_flow_m2">
        <omgdi:waypoint x="216" y="118"></omgdi:waypoint>
        <omgdi:waypoint x="260" y="118"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow_m3" id="BPMNEdge_flow_m3">
        <omgdi:waypoint x="365" y="118"></omgdi:waypoint>
        <omgdi:waypoint x="410" y="118"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow_m4" id="BPMNEdge_flow_m4">
        <omgdi:waypoint x="446" y="118"></omgdi:waypoint>
        <omgdi:waypoint x="490" y="118"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

第一个流程:订单履行流程 (orderFulfillmentProcess)
这个流程是你的核心业务流程,是公司里真正在“干活”的流程。

  1. 它的目的是什么?
    它的目标很明确:完整地处理一个从客户那里来的订单,从创建、审核、分配库存直到最后发货。
  2. 它的正常执行路径(“快乐路径”)
    一个订单的生命周期通常是这样的:
    订单已创建 (Start):流程被触发。
    审核订单 (User Task):可能需要人工审核一下订单信息是否合规。
    与WMS同步分配库存 (Service Task):这是一个关键的自动化步骤,流程会自动调用仓库管理系统(WMS)的接口来锁定商品库存。
    打包并安排发货 (User Task):库存分配成功后,通知仓库员工打包发货。
    订单完成 (End):流程结束。
  3. 它的“智能”之处:如何处理意外情况?
    这正是信号事件发挥作用的地方。我们预设了一种可能发生的意外:当我们正要和WMS系统同步时,IT部门突然要对WMS进行维护。
    这个流程通过以下两个关键元素来优雅地处理这种情况:
    边界信号事件 (catchMaintenanceStart)
    它像什么? 就像一个附加在“分配库存”任务上的“警报接收器”。
    它何时工作? 只有当流程执行到“分配库存”这一步时,这个警报接收器才被激活。
    它做什么? 它一直“竖着耳朵听”一个名为 wmsMaintenanceStart 的全局广播。一旦听到,它会立刻做两件事:
    中断当前正在进行的“分配库存”任务(cancelActivity=“true”)。
    将流程的执行路径引向一条预设的“等待”路径。
    中间信号捕获事件 (waitForMaintenanceEnd)
    它像什么? 就像一个“等待室”。
    它做什么? 流程进入这里后就会暂停,什么也不做,只是安静地等待。它在等什么呢?它在等另一个名为 wmsMaintenanceEnd 的全局广播。
    唤醒后做什么? 一旦等到“维护结束”的信号,流程就会被唤醒,然后沿着预设的路线返回到“分配库存”任务,重新尝试一次。
    第二个流程:IT系统维护流程 (itMaintenanceProcess)
    这个流程是一个辅助流程或管理流程。它本身不产生业务价值,但它为核心业务流程的稳定运行提供了保障。
  4. 它的目的是什么?
    它的唯一目的就是充当一个“广播站”,在IT部门进行系统维护时,向整个系统发出通知。
  5. 它的执行路径
    这个流程非常简单直接:
    启动维护流程 (Start):IT管理员决定开始维护,启动此流程。
    广播维护开始信号 (Intermediate Throw Event):流程立即通过一个信号抛出事件,向外广播 wmsMaintenanceStart 信号。它不关心谁会收到,它只管喊话。
    执行WMS维护工作 (User Task):这是一个分配给IT管理员的任务,代表他们正在进行的实际维护工作。流程会在这里等待他们完成。
    广播维护结束信号 (Intermediate Throw Event):当IT管理员完成维护任务后,流程继续,并立即通过另一个信号抛出事件,向外广播 wmsMaintenanceEnd 信号,告诉所有人“维护结束了,系统恢复正常”。
    维护完成 (End):流程结束。
    两者如何协作:一个生动的剧本
    想象一下这个场景:
    10:00 AM: 客户A下单,一个“订单履行流程”实例(我们叫它订单A)启动,并顺利走到了“分配库存”这一步,开始与WMS系统通信。
    10:01 AM: 客户B也下单了,另一个实例(订单B)也走到了“分配库存”这一步。
    10:02 AM: IT部门的小王启动了“IT系统维护流程”。流程立刻广播了 wmsMaintenanceStart 信号。
    信号的影响:
    订单A的“警报接收器”听到了这个信号,立刻中断了与WMS的通信,流程被转向“等待室”。
    订单B的“警报接收器”也听到了这个信号,同样中断任务,进入“等待室”。
    此时,如果有新的订单进来,也会在走到“分配库存”时被中断并进入等待。
    10:02 AM - 10:30 AM: 小王在埋头做系统维护。所有相关的订单流程都在“等待室”里安静地排队。
    10:30 AM: 小王完成了维护工作,并在流程系统中点击“完成”了他的任务。
    广播恢复信号: 小王的流程继续执行,立刻广播了 wmsMaintenanceEnd 信号。
    集体唤醒:
    订单A和订单B都在“等待室”里听到了这个“维护结束”的信号。
    它们被同时唤醒,并自动返回到“分配库存”任务,重新开始执行。
    总结
    这个设计完美地体现了信号事件的精髓:
    解耦 (Decoupling):订单流程不需要知道IT部门的存在,IT部门也不需要知道有多少订单在运行。它们通过一个约定好的“频道”(信号名称)进行通信。
    广播 (Broadcast):一个信号可以同时影响多个正在运行的流程实例,实现了高效的全局协调。
    健壮性 (Robustness):核心业务流程因此变得更加健壮,能够优雅地处理外部系统的临时不可用,而不是直接报错失败。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值