SpringBoot深度探究(四)观察者设计模式的演进

基于Spring Boot的秒杀项目--后台代码 此项目是使用Spring Boot 2.0后台技术 + SubLine 3处理 前台页面,页面模板使用BootStrap开发 立即下载

前言

SpringBoot和SpringMVC有一个很大的改进,就是SpringBoot基于SpringMVC做了很多的事件监听模型。要弄清楚什么是Spring中的事件监听模型,首先要说明白什么是观察者设计模式。所以本篇将会从一个例子详细讲解观察者设计模式的演进。更多Spring内容进入【Spring解读系列目录】。

场景模型

为了说清楚什么是观察者设计模式,先讲一个小的场景。场景很简单:假设一个花盆里有一朵花(Flower),花朵的旁边有两个测试人员小红(XiaoHong)和李华(LiHua)。当这朵花开放(bloom)的时候小红会开心的笑(laugh),但是李华会因为花粉过敏而流泪(tear)。

基础的观察者模型

既然说到演进,就先拿LiHua做这个例子。首先要实现花开了LiHua要流泪。于是就要有一个原也就是Flower类作为被观察者,然后LiHua也要有一个类,里面有一个流泪的动作。Flower作为被观察者,一定会有动作触发LiHua流泪的动作。传统来说应该在Flower里面有一个标志,一旦有触发开花的动作改变标志位,LiHua就应该流泪。于是LiHua这里应该有一个线程不断的监视开花的动作,不然开花了LiHua不流泪就不好了。而Flower这边也应该有另一个线程去执行修改标志位的动作。因此两个类都应该做个线程去执行这些事情,所以基于上面的设计,写出了下面的Sample。

LiHua类,监听Flower的开花状态:

public class LiHua implements Runnable{

    private Flower flower;

    public LiHua(Flower flower) {
        this.flower = flower;
    }

    public void tear(){
        System.out.println("花开,李华流泪");
    }

    @Override
    public void run() {
        System.out.println("李华开始观察是否花开");
        //无线循环监听是否开花了
        while(!flower.isBloom()){
            try { //每隔1s监听一次
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果开花了,跳出循环,执行流泪
        tear();
    }
}

Flower类,操作自己的开花状态:

public class Flower implements Runnable{
    //开花的变量
    private boolean bloom=false;

    public boolean isBloom() {
        return bloom;
    }

    public void bloomNow(){
        //修改开花变量
        bloom=true;
    }

    @Override
    public void run() {
        try {//模拟开花的时间
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bloomNow();
    }
}

测试类:

public class TestObserver {
    public static void main(String[] args) {
        Flower flower=new Flower();
        Thread threadf=new Thread(flower);
        threadf.start();

        LiHua LiHua=new LiHua(flower);
        Thread threadl=new Thread(LiHua);
        threadl.start();
    }
}

程序开始运行,当flower调用bloomNow()方法改变开花状态的时候,LiHua就会因为监听到开花了而执行tear()方法。虽然这种方法可以实现功能目标,但是其缺点也是非常明显的。我们看while(!flower.isBloom())非常类似于Socket,在这里一直等待数据写入。也就意味着LiHua线程非常的消耗资源,无论花开不开,一直需要盯着flower。如果有别的动作,比如吃饭那就无法切换。基于此我们可以针对这个问题做一个修改,那就是当flower开始的时候,通知LiHua来看就可以了。也就是说这种极度消耗资源的设计可以修改为:当某个事件发生的时候,主动通知它的监听者,就可以优化程序耗能。

观察者模型的第一次改进:角色互换

根据上面的分析,我们需要做的就是让Flower通知LiHua开花这个事件。上面的例子实际上是让LiHua持有Flower类,并一直监听Flower中的变量。如果要让Flower主动通知LiHua,那就意味着Flower类要持有LiHua类才可以。也就是说这样的改进将会使被观察者(Flower)拥有观察者(LiHua),这点要特别注意,因为这也是观察者设计模式中非常重要的一个概念。这点和我们正常理解的观察者与被观察者的情形是相反的:在观察者设计模式被观察者是主动的,而观察者才是被动的。

由于LiHua不需要一直看着Flower,首先LiHua可以不需要单独作为线程存在,Runable接口就可以被优化掉。其次Flower作为主动方,需要添加LiHua类作为传递的参数。由于LiHua类对象能够直接被Flower持有,所以也不需要在使用标识作为判断依据,只要开花立刻调用tear()流泪方法就可以了,因此第一次的改进如下。

LiHua类:

public class LiHua{
    //只保留动作
    public void tear(){
        System.out.println("花开,李华流泪");
    }
}

Flower类:

public class Flower implements Runnable{
    //持有LiHua类,并在开花动作以后,直接调用流泪方法
    private LiHua LiHua;

    public Flower(LiHua LiHua) {
        this.LiHua = LiHua;
    }

    public void bloomNow(){
       //由于直接通知,因此标识变量也可以优化掉
        LiHua.tear();
    }

    @Override
    public void run() {
        System.out.println("开花倒计时开始");
        try {//模拟开花的时间
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bloomNow();
    }
}

测试类:

public class TestObserver {
    public static void main(String[] args) {
        Flower flower=new Flower(new LiHua());
        Thread threadf=new Thread(flower);
        threadf.start();
    }
}

从上面的改进中,可以看到LiHua已经不需要在持续的占用资源去监听花开的状态,只要花开LiHua就触发流泪的动作。LiHua是否进行流泪的动作,取决于Flower而不是LiHua,这样修改性能就是一个很大的提升。

但是这样的修改,还是有问题的。因为如果按照这样设计,那么LiHua除了流泪什么都做不了,而且只有LiHua能够对花开进行反应。但是设想的场景里还有XiaoHong的角色和动作都无法加入进来。因此此时又引入了观察者模式的另一个概念:事件。

观察者模型的第二次改进:抽象事件

上面的改进导致了bloomNow()中开花动作的消失,只有LiHua动作被体现出来。那么可以预期,LiHua由于开花导致的动作可以被抽象提取出来,作为一个公用的行为action。不同的行为对应不同的动作或者不同人的不同动作。因此抽象出来的东西,就被称为事件。为了同时对开花这个事件进行不同的反应,因此就有了EventListener事件监听器的概念。到了这一步,整个程序并不在多少人观察了花的状态,也不在乎观察者看了花的状态以后执行的action是什么,只需要把应该通知的内容告诉观察者即可。那么此时观察者就变成被动的监听者。因此继续修改程序如下。

FlowerListener监听者接口:

public interface FlowerListener {
    public void action(FlowerEvent event);
}

LiHua类实现监听者接口:

public class LiHua implements FlowerListener{
    public void action(FlowerEvent event){
        if (1==event.getAction()){
            System.out.println("花开,李华流泪");
        }
    }
}

XiaoHong类实现监听者接口:

public class XiaoHong implements FlowerListener{
    public void action(FlowerEvent event){
        if (1==event.getAction()){
            System.out.println("花开,小红开始笑");
        }
    }
}

FlowerEvent开花的事件类:

public class FlowerEvent {
    private int action;

    public int getAction() {
        return action;
    }

    public void setAction(int action) {
        this.action = action;
    }
}

Flower类作为被观察者,持有观察者(LiHua,XiaoHong)的引用:

public class Flower implements Runnable{
    //为了实现一个事件多个监听,使用一个集合把所有监听的事件放进来
    private List<FlowerListener> flowerListeners=new ArrayList<>();

    //从外部添加事件
    public void addListeners(FlowerListener listener){
        flowerListeners.add(listener);
    }

    public void bloomNow(){
        FlowerEvent event=new FlowerEvent();
        event.setAction(1); //这里设置为1,当设置为2的时候可以有更多的反应
        //对于某一个事件,不同人的action表达不同的反应
        for (FlowerListener flowerListener : flowerListeners) {
            flowerListener.action(event);
        }
    }

    @Override
    public void run() {
        System.out.println("开花倒计时开始");
        try {//模拟开花的时间
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bloomNow();
    }
}

测试类:

public class TestObserver {
    public static void main(String[] args) {
        Flower flower=new Flower();
        flower.addListeners(new LiHua()); //LiHua被动监听花的状态
        flower.addListeners(new XiaoHong()); //XiaoHong被动监听花的状态
        Thread threadf=new Thread(flower);
        threadf.start();
    }
}
当程序运行,同时对不同人进行不同的action:
开花倒计时开始
花开,李华流泪
花开,小红开始笑

可以看到经过这样的改进以后,被观察者(Flower)不仅可以在改变状态以后通知观察者(LiHua),而且可以支持增加和删除观察者。那么一个观察者模式的实现就正式结束了。

总结

那么我们总结一下观察者设计模式的特点:

  • 被观察者持有监听的观察者的引用。
  • 被观察者支持增加和删除观察者。
  • 被观察者主题状态改变,会通知观察者做相应的动作。

本篇讲观察者模式的概念和实现做了一个完整的介绍,下一篇【JDK观察者模式探究】将会讲解JDK如何实现的观察者模式的。

Springboot-前后端分离-秒杀流程.zip 入门SpringBoot项目,前后端分离,简单页面效果。用户注册、登录、查看商品列表、商品详情、商品秒杀倒计时、下单购买 立即下载

相关推荐

UIPath 获取网页元素做遍历点击的实现

UIPath 获取网页元素做遍历点击的实现

geekqian的博客 1万+

利用Spring Boot提供的ScheduledExecutorService实现定期执行任务或倒计时执行任务

ScheduledExecutorService

MonGoo的博客 1488

海鸥派OpenEuler开发板实战:从烧写到SSH连接的完整指南

本文提供海鸥派OpenEuler开发板从开箱到SSH远程连接的完整实战指南。详细介绍了基于海思SD3403/SS928芯片的算力开发板系统烧写、存储扩容、网络配置等关键步骤,帮助开发者快速上手这款AI边缘计算设备,并实现高效的远程开发与管理。

ruby5的博客 1121

springboot整合websocket

网上有一些例子,但是关于类并不是很全,所以写了这篇; 目录结构: 2.引用 &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xs...

qingfulang9322的博客 1394

GB 44497-2024《智能网联汽车 自动驾驶数据记录系统》标准解读

GB 44497-2024《智能网联汽车 自动驾驶数据记录系统》针对智能网联汽车的自动驾驶数据记录系统进行了全面规范。标准要求我们记录车辆在自动驾驶模式下的所有关键操作数据,如:1. 车辆状态数据,如速度、加速度、转向角度、制动状态等;2. 环境感知数据,如周围物体的位置、速度、类型等;3. 驾驶决策数据,如路径规划、避障决策、紧急制动指令等;4. 系统状态数据,如软件版本、硬件状态、系统警告信息等。在数据存储方面,标准强调了数据的安全性和可靠性。

daopuyun的博客 2670

Kali Linux下John the Ripper实战:从识别yescrypt哈希到破解zip压缩包(保姆级避坑指南)

本文详细介绍了在Kali Linux中使用John the Ripper工具从识别yescrypt哈希到破解zip压缩包的全过程。针对常见的'No password hashes loaded'报错,提供了两种解决方案,并扩展讲解了哈希识别、zip文件破解及性能优化技巧,是安全测试人员的实用指南。

weixin_29323365的博客 236

SpringBoot秒杀系统实战13-秒杀商品详情页+秒杀倒计时功能实现

程序鹏 于 2020-05-08 00:00:00 发布 1326 收藏 4 分类专栏: Spring Boot 秒杀系统 文章标签: java spring boot web 版权 Spring Boot 同时被 2 个专栏收录 29 篇文章1 订阅 订阅专栏 秒杀系统 26 篇文章8 订阅 订阅专栏 文章目录 秒杀倒计时: 1、在GoodsController里面创建toDetail方法,接收详情页面的请求 2、 前端页面处理逻辑 3、goods_detail.html完整代码: 怎么注入M..

竹林幽深 1398

RK3588 MIPI屏幕调试避坑指南:双通道8Lane下DSC压缩屏的花屏、分层问题排查实录

本文详细解析了RK3588平台在双通道8Lane MIPI接口下调试DSC压缩屏时遇到的花屏、分层问题。通过硬件信号完整性检查、软件配置验证及帧数据分析,提供了一套系统化的排查方法,并深入探讨了初始化序列优化和双通道同步机制,帮助工程师高效解决高分辨率屏幕显示异常问题。

weixin_27015733的博客 280

一些在线系统的计时操作的实现(spring-boot计时器使用,时间戳比较先后)

最近在搞一个含有在线考试模块的系统。既然是考试,必不可少的一部分就是计时了。总的来说,需要计时的系统大体上分两种:1.规定时间内的倒计时。2.规定时间段内的计时判断。对于第一种倒计时,我觉得下面这篇文章写的很好,这是链接:https://blog.youkuaiyun.com/a13432421434/article/details/71346153对于第二种倒计时,我并没有找到合适的,首先介绍一下这个项目的...

TateBrwonJava的博客 5785

操作系统知识点汇总(王道)

操作系统不论是就业还是升学都是核心的一门课程,对于大部分工科更是必修课程。本文章是对《王道操作系统》所有知识点的总结笔记,以供大家学习以及在备考期间复习使用。让我们一起把知识往脑子里旋好吗!!!......

S mile0804的博客 5万+

GD32F4xx MCU ADC+DMA 多通道采样

1、GD32F4xx ADC GD32F4xx 的12位ADC是一种采用逐次逼近方式的模拟数字转换器。 1.1 主要特征 可配置12位、10位、8位、6位分辨率; ADC采样率:12位分辨率为2.6MSPs,10位分辨率为3.0 MSPs。分辨率越低,转换越快; PS: MSPs (模拟混合信号转换速率),是指完成1次从模拟转换到数字的AD转换所需的时间的倒数。常用单位是ksps和Msps,表示每秒采样(千)/(百万)次(kilo / Million Samples per Second)。 1msps

madao1234的博客 8117

springboot项目学习(一)

项目内容以及学习目录详情----来自黑马: 能够说出电商的行业特点 能够说出电商行业的技术特点 理解畅购技术架构 能够完成畅购工程搭建 能够实现商品微服务搭建 能闪现品牌的增删改查通用mapper+pagehelper 掌握fastdfs的工作原理以及fastdfs的作用 能够实现rocker容器安装fastdfs 能够搭建文件上传微服务 实现相册管理 实现规格参数管理 实现商品分类管理 能够说出spu sku的概念 能够实现新增商品,修改商品 能够实现商品审核,商家下架 能够实现品牌和分类

Masha 564

YOLOv26与其他目标检测算法的对比分析

本文对YOLOv26与其他主流目标检测算法进行了全面对比分析。YOLOv26在COCO数据集上达到96.0% mAP@0.5和79.0% mAP@0.5:0.95,显著优于其他YOLO系列算法,同时保持85FPS的推理速度和35MB的轻量级模型。相比两阶段算法(如Faster R-CNN),YOLOv26在速度、模型大小和内存占用方面优势明显;相比Anchor-free算法(如CenterNet),YOLOv26在速度和模型压缩方面更优。其核心创新包括动态锚框分配、自注意力机制和轻量级设计,使其成为适用于复

一键难忘的博客 994

SpringBoot深度探究(五)JDK观察者模式探究

前言 上一篇博客【观察者设计模式的演进】详细的讲解了观察者模式的概念以及如何从零开始实现一个观察者模式,那么这一篇的主要内容就是JDK中观察者设计模式的实现。通过对比观察者模式,JDK观察者模式,以及Spring对观察者模式的应用去研究SpringBoot中的事件编程模型是怎样的一个过程。 场景回顾 上一篇做了一个小场景去实施观察者模式,再回顾一下:假设一个花盆里有一朵花(Flower),花朵的旁边有两个测试人员小红(XiaoHong)和李华(Lihua)。当这朵花开放(bloom)的时候小红会开心的笑(l

Smallc0de的博客 424

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

Java 设计模式——观察者模式:从 4 种写法到 SpringBoot 进阶

本文介绍了观察者模式在Java中的4种实现方式,重点推荐SpringBoot环境下的两种主流写法:1)通过接口注入自动装配观察者,实现业务解耦,支持执行顺序控制;2)利用Spring事件机制实现更灵活的事件发布/监听,支持异步和事务边界控制。文章还分析了传统JDK实现和Guava事件总线的优缺点,并针对复杂场景给出设计建议,帮助开发者根据不同需求选择最佳实现方案,实现业务模块间的松耦合通信。

qq_46601365的博客 1198

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

SpringBoot深度探究(七)源码探究启动流程之一

前面已经罗嗦了三篇博客用来介绍观察者模式的理论以及实现,都是为了本节讲解SpringBoot启动流程的源码做准备的,因为在阅读SpringBoot源码启动流程的时候发现spring公司的大神们在设计SpringBoot的时候,把观察者模式用到了极限。如果不把观察者模式讲清楚,那么读起来SpringBoot的源码会非常的痛苦。那么既然观察者模式已经搞清楚了,下面就开始正式进入SpringBoot的源码探究的过程。

Smallc0de的博客 531

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

SpringBoot深度探究(九)源码探究启动流程之三

前言 上一篇【SpringBoot深度探究(八)源码探究启动流程之二】主要说了SpringBoot中如何应用的观察者模式,如何使用广播引起相关监听器兴趣的以及监听器的反应。本篇将会探究SpringBoot是在何时启动的Tomcat以及相关Web环境初始化的。更多Spring内容进入【Spring解读系列目录】。 SpringApplication.run 接着上篇的run()方法里面的内容,从try-catch块讲起。 public ConfigurableApplicationContext run(St

Smallc0de的博客 364

springboot中的观察者模式

在现代分布式系统中,模块解耦和高效通信是系统设计的核心挑战。Spring Boot通过其强大的事件驱动模型,为开发者提供了优雅的观察者模式实现方案。本文将深入剖析其实现原理,并通过实战案例展示如何构建松耦合、高扩展的分布式系统。

不知道说什么的博客 1606

SpringBoot深度探究(六)事件编程模型(Listener-Event)详解

前言 前两篇博客【观察者设计模式的演进】和【JDK观察者模式探究】深度讲了观察者模式的实现和作用,相信很多同学都知道SpringBoot是基于Spring Framework的一套东西做出来的。之所以SpringBoot能够做到非常简便的启动,很大一部分功劳应该属于Spring Framework中提供的Listener-Event功能。所以这篇博客就是要看下Spring的Listener-Event到底是有什么功能,以及它在SpringBoot的启动中扮演了什么角色。 Spring Events Spri

Smallc0de的博客 1088

吃透 Java 常用设计模式:从原理到企业级实战(含 SpringBoot 应用 + 代码案例)

本文系统介绍了Java开发中最常用的8种设计模式,包括创建型(单例、工厂、建造者)、结构型(代理、装饰器、适配器)和行为型(策略、观察者)模式。通过JDK源码、SpringBoot框架实现和企业级实战案例,详细解析了每种模式的原理、应用场景和代码实现。文章强调设计模式的核心价值在于解耦、复用和扩展,并提供了企业级开发中的模式选型指南。最后指出学习设计模式的关键是理解其设计思想,而非生搬硬套,在实际项目中灵活运用才能写出更优雅、易维护的代码。

m0_75223236的博客 670

Java 设计模式——实战指南:从理论到 SpringBoot 落地,面试项目双丰收

《Java设计模式实战指南:从理论到SpringBoot落地》是一篇聚焦实战的设计模式教程,结合5年项目经验总结出8个高频设计模式的应用场景。不同于传统理论讲解,本文通过SpringBoot框架下的真实项目案例(如单例模式与Spring Bean结合、策略模式实现支付系统),提供可直接运行的代码示例。内容涵盖设计模式核心原则、常见误区,并特别针对面试高频考点(如单例线程安全、Spring AOP代理模式)进行深度解析。帮助开发者避免"纸上谈兵",真正掌握设计模式在项目中的落地应用,提升代

qq_46601365的博客 809

《JAVA面经实录》- SpringBoot 电商项目23种设计模式(三)

最终版·生产级 SpringBoot 电商项目: 已补全所有漏洞 + 23 种设计模式真实串联 + Spring 生态融合 + 可简历可面试可上线

专注 Java 后端开发,分享基础语法、JVM、并发、Spring 全家桶、微服务、分布式、性能优化等实战干货。坚持输出高质量技术笔记,用简单语言讲清复杂原理,助力每一位 Java 开发者稳步进阶。 556

Java面试通关⑰:设计模式全集

摘要:设计模式是代码架构思维、框架源码设计、高质量代码必备能力,大厂面试高频问模式原理、落地场景、源码应用。多数开发者只会CRUD,代码冗余、耦合严重、扩展性差,不懂设计模式思想,无法写出高复用、高扩展、低耦合代码,面试架构思维题失分严重。本篇全覆盖23种设计模式核心、常用模式原理、场景、源码案例、手写实现,掌握架构设计思维,写出高质量工程代码。

折哥|智能物流与Java实战,副高数据库工程师。深耕出版社物流WMS/OMS(线体/立库/VGA),也分享Java进阶与OMS电商对接。Oracle→PG实战派。相信沉淀可迁移能力,分享通用技术,不藏不虚。 485

SpringBoot面试宝典:44道核心题深度解析与实战指南

SpringBoot作为Java后端开发的主流框架,其核心设计理念是“约定大于配置”,通过自动配置机制简化了传统Spring应用的繁琐配置。理解其自动配置原理,关键在于掌握@SpringBootApplication注解及其背后的条件注解机制,如@ConditionalOnClass和@ConditionalOnMissingBean,这些机制使得框架能够根据类路径和容器状态智能装配Bean。这一特性极大地提升了开发效率,降低了项目启动和维护成本,是现代微服务架构和云原生应用的基础。在实际工程实践中,Spr

weixin_30411819的博客 362

《JAVA面经实录》- 设计模式面试题(一)

【摘要】《JAVA面经实录》设计模式面试专题提供标准答案背诵版,涵盖三大类23种设计模式核心考点。内容分为九大模块:基础必问题(分类/原则/应用场景)、单例模式(线程安全实现与防护)、创建型模式(工厂/建造者/原型对比)、结构型模式(代理/适配器/享元等实现差异)、行为型模式(策略/观察者/状态等应用场景)、手写题模板、架构场景题(支付/订单/日志等解决方案)、框架源码解析(Spring/MyBatis设计模式应用)及陷阱题避坑指南。重点突出开闭原则、组合优于继承等设计理念,提供DCL单例、策略模式消除if

专注 Java 后端开发,分享基础语法、JVM、并发、Spring 全家桶、微服务、分布式、性能优化等实战干货。坚持输出高质量技术笔记,用简单语言讲清复杂原理,助力每一位 Java 开发者稳步进阶。 323

深入解析@NacosValue注解:SpringBoot动态配置刷新的利器

本文深入解析了@NacosValue注解在SpringBoot项目中的核心应用。作为@Value注解的增强版,@NacosValue通过与Nacos配置中心集成,实现了配置值的动态刷新,无需重启服务即可使新配置实时生效。文章详细介绍了其从环境搭建、基础使用到高级监听功能的完整实践,并提供了关键的避坑指南,是构建高灵活性微服务应用的利器。

js777的博客 349
上一篇: 源码解析异常expected single matching bean but found 2是如何发生的
下一篇: SpringBoot深度探究(五)JDK观察者模式探究
Smallc0de
博客等级 码龄15年 148粉丝 147原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值