quartz - springboot2.1.5 整合

【Quartz】Quartz表的SQL语句,版本2.3.0 quartz表DDL 阅读详情

一. 整合的步骤

  • 建立springboot工程映入相关依赖
  • 导入quartz的tables_mysql_innodb.sql文件到数据库中
  • 建立中间数据控制表
  • 建立Job工厂类
  • 建立任务Trigger触发器监听类
  • 建立业务控制处理类
  • 项目重启重置任务处理
  • 配置quartz参数

二. 详细描述

  (1) 建立springboot工程映入相关依赖

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

 

  (2) 导入quartz的tables_mysql_innodb.sql文件到数据库中

  (3) 建立中间数据控制表

    中间数据控制表用于管理任务的增删改以及初始化

CREATE TABLE `sys_schedule_info` (
  `id` varchar(100) NOT NULL,
  `task_description` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '任务描述',
  `task_name` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '任务名称',
  `task_group` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '任务组名称',
  `trigger_name` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '触发器名称',
  `trigger_group` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '触发器组',
  `trigger_cron_expression` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '表达式',
  `execute_class_name` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '目标执行类类名',
  `execute_method_name` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '执行类的具体执行方法',
  `target_table` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '数据目标所在表集合","分割用于统计',
  `is_start` tinyint(1) DEFAULT NULL COMMENT '是否启动',
  `status` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT '1' COMMENT '0删,1允正常',
  `updated_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '创建人id',
  `updated_time` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

 

  (4) 建立Job工厂类

import com.tools.SpringUtil;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @CreateTime: 2019-05-20 15:07
 * @Description: 任务执行器
 * @Author: WH
 */
public class SystemJobFactory implements Job {
    Logger log = LoggerFactory.getLogger(getClass());

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        log.debug(jobDetail.getKey().getName()+"="+jobDetail.getKey().getGroup());
        JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        //具体处理类组件名(处理类上加了@Component()注解,注意默认首字母数据库存的时候是小写)
        String className = jobDataMap.getString("className");
        //具体处理类的方法名
        String methodName = jobDataMap.getString("methodName");
        //获取对应的Bean
        Object object = SpringUtil.getBean(className);
        try {
            //利用反射执行对应方法
            Method method = object.getClass().getMethod(methodName);
            method.invoke(object);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

  (5) 建立任务Trigger触发器监听类

import org.quartz.JobExecutionContext;
import org.quartz.Trigger;
import org.quartz.TriggerListener;

/**
 * @CreateTime: 2019-05-20 16:13
 * @Description: 任务监听
 * @Author: WH
 */
public class SystemJobTriggerListener implements TriggerListener {

    @Override
    public String getName() {
        return this.getClass().getSimpleName();
    }

    @Override
    public void triggerFired(Trigger trigger, JobExecutionContext jobExecutionContext) {
        
    }

    @Override
    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext jobExecutionContext) {
       return false;
    }

    @Override
    public void triggerMisfired(Trigger trigger) {
      
    }

    @Override
    public void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) {
      
    }
}

 

  (6) 建立业务控制处理类

private Boolean startTask(SysScheduleInfo sysScheduleInfo){
        boolean ret = true;
        try {
            //创建触发器
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity(sysScheduleInfo.getTriggerName(),sysScheduleInfo.getTaskGroup())
                .withSchedule(CronScheduleBuilder.cronSchedule(sysScheduleInfo.getTriggerCronExpression()).withMisfireHandlingInstructionDoNothing())
                .startNow()
                .build();

            //创建任务
            JobDetail jobDetail = JobBuilder.newJob(SystemJobFactory.class)
                .withIdentity(sysScheduleInfo.getTaskName(),sysScheduleInfo.getTaskGroup())
                .usingJobData("className",sysScheduleInfo.getExecuteClassName())
                .usingJobData("methodName",sysScheduleInfo.getExecuteMethodName())
                .build();

            //调度作业
            scheduler.scheduleJob(jobDetail, trigger);

            //添加监听
            ListenerManager listenerManager = scheduler.getListenerManager();
            TriggerListener systemJobTriggerListener = listenerManager.getTriggerListener("systemJobTriggerListener");
            if(systemJobTriggerListener==null){
                listenerManager.addTriggerListener(new SystemJobTriggerListener(), EverythingMatcher.allTriggers());
            }
        } catch (SchedulerException e) {
            ret = false;
            e.printStackTrace();
        }
        return ret;
    }

    private Boolean deleteTask(SysScheduleInfo sysScheduleInfo){
        boolean ret = true;
        try {
            //触发器标识
            TriggerKey triggerKey = TriggerKey.triggerKey(sysScheduleInfo.getTriggerName(),sysScheduleInfo.getTriggerGroup());
            //任务标识
            JobKey jobKey = JobKey.jobKey(sysScheduleInfo.getTaskName(),sysScheduleInfo.getTaskGroup());
            //停止任务
            scheduler.pauseJob(jobKey);
            //停止触发器
            scheduler.pauseTrigger(triggerKey);
            //移除触发器
            scheduler.unscheduleJob(triggerKey);
            //删除任务
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            ret = false;
            e.printStackTrace();
        }
        return ret;
    }

 

  (7) 项目重启重置任务处理

import com.base.taskmanager.bean.SysScheduleInfo;
import com.base.taskmanager.bean.SystemJobFactory;
import com.base.taskmanager.bean.SystemJobTriggerListener;
import com.base.taskmanager.dao.SysScheduleInfoMapper;
import org.quartz.*;
import org.quartz.impl.matchers.EverythingMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;

/**
 * @CreateTime: 2019-05-21 09:12
 * @Description: 项目初始化-在springboot的最后一步执行
 * @Author: WH
 */
@Component
public class DataCenerInitialization  implements CommandLineRunner {
    Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private SysScheduleInfoMapper sysScheduleInfoMapper;
    @Autowired
    private Scheduler scheduler;

    @Override
    public void run(String... args) throws Exception {
        //项目重新启动的时候从新加载任务数据
        List<SysScheduleInfo> sysScheduleInfos = sysScheduleInfoMapper.selectEffectiveData();//状态1,并且允许启动的数据

        //添加监听
        ListenerManager listenerManager = scheduler.getListenerManager();
        TriggerListener systemJobTriggerListener = listenerManager.getTriggerListener("systemJobTriggerListener");
        if(systemJobTriggerListener==null){
            listenerManager.addTriggerListener(new SystemJobTriggerListener(), EverythingMatcher.allTriggers());
        }

        //终止之前的所有任务
        int start = 0;
        for (SysScheduleInfo sysScheduleInfo : sysScheduleInfos) {
            //触发器标识
            TriggerKey triggerKey = TriggerKey.triggerKey(sysScheduleInfo.getTriggerName(),sysScheduleInfo.getTriggerGroup());
            //任务标识
            JobKey jobKey = JobKey.jobKey(sysScheduleInfo.getTaskName(),sysScheduleInfo.getTaskGroup());
            //停止任务
            scheduler.pauseJob(jobKey);
            //停止触发器
            scheduler.pauseTrigger(triggerKey);
            //移除触发器
            scheduler.unscheduleJob(triggerKey);
            //删除任务
            scheduler.deleteJob(jobKey);
            start++;
        }

        //从新加载当前任务
        int end = 0;
        for (SysScheduleInfo sysScheduleInfo : sysScheduleInfos) {
            try {            //创建触发器
                Trigger trigger = TriggerBuilder.newTrigger().withIdentity(sysScheduleInfo.getTriggerName(),sysScheduleInfo.getTaskGroup())
                    .withSchedule(CronScheduleBuilder.cronSchedule(sysScheduleInfo.getTriggerCronExpression()).withMisfireHandlingInstructionDoNothing())
                    .startAt(date)
                    .build();

                //创建任务
                JobDetail jobDetail = JobBuilder.newJob(SystemJobFactory.class)
                    .withIdentity(sysScheduleInfo.getTaskName(),sysScheduleInfo.getTaskGroup())
                    .usingJobData("className",sysScheduleInfo.getExecuteClassName())
                    .usingJobData("methodName",sysScheduleInfo.getExecuteMethodName())
                    .build();

                //调度作业
                scheduler.scheduleJob(jobDetail, trigger);
                end++;
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
    }
}

 

  (8) 配置quartz参数

spring:
 profiles: dev
 quartz:
  job-store-type: jdbc #数据库方式
  jdbc:
   initialize-schema: never #不初始化表结构
  properties:
   org:
    quartz:
     scheduler:
      instanceId: AUTO #默认主机名和时间戳生成实例ID,可以是任何字符串,但对于所有调度程序来说,必须是唯一的 对应qrtz_scheduler_state INSTANCE_NAME字段
      instanceName: clusteredScheduler #quartzScheduler
      jobStore:
       acquireTriggersWithinLock: true
       class: org.quartz.impl.jdbcjobstore.JobStoreTX #持久化配置
       driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #我们仅为数据库制作了特定于数据库的代理
       useProperties: true #以指示JDBCJobStore将JobDataMaps中的所有值都作为字符串,因此可以作为名称 - 值对存储而不是在BLOB列中以其序列化形式存储更多复杂的对象。从长远来看,这是更安全的,因为您避免了将非String类序列化为BLOB的类版本问题。
       tablePrefix: qrtz_  #数据库表前缀
       misfireThreshold: 60000 #在被认为“失火”之前,调度程序将“容忍”一个Triggers将其下一个启动时间通过的毫秒数。默认值(如果您在配置中未输入此属性)为60000(60秒)。
       clusterCheckinInterval: 5000 #设置此实例“检入”*与群集的其他实例的频率(以毫秒为单位)。影响检测失败实例的速度。
       isClustered: false #打开群集功能,集群模式需要在多台服务器上做时间同步或者使用zookeeper去解决
      threadPool: #连接池
       class: org.quartz.simpl.SimpleThreadPool
       threadCount: 10
       threadPriority: 5
       threadsInheritContextClassLoaderOfInitializingThread: true
  startup-delay: 30 
  overwrite-existing-jobs: true 

 三. 目前的认识(个人理解)

  因为是单服务器项目其实现在并不涉及集群部署,但是自己想尝试下动态配置quartz的感觉,所有就这几天复习了下基础,随便搭建了一个可以动态调度任务的简单服务出来;

  在做的时候越遇到了一些坑,比如停止服务后重启服务时会重新执行停止期间的任务,动态调用直接使用quartz的sql表进行处理很难,需要建立中间表进行处理,对于整个quartz而已无非就是开启任务和关闭任务等;

  关闭任务 = 移除任务  --> delete

  暂停任务 = 移除任务  --> delete

  开启任务 = 新建任务添加到调度中 --> add

  停止服务器后,重启的时候直接移除调度队列中的所有任务,从新在数据库中间表把任务从新添加进去(初始化);

  重启服务器后重启的问题,给服务增加延迟启动时间,在启动好在初始化数据库中间表中的任务,这样就不会启动过程中去执行停止服务期间遗漏的任务了;

  多个CommandLineRunner可以被同时执行在同一个spring上下文中并且执行顺序是以order注解的参数顺序一致,用于初始化

spring boot整合quartz实现多个定时任务 最近收到了很多封邮件,都是想知道spring boot整合quartz如何实现多个定时任务的,由于本人生产上并没有使用到多个定时任务,这里给个实现的思路。 1、新建两个定时任务,如下: public class ScheduledJob implements Job{ @Override public void execute(JobExecutionContext cont 阅读详情

相关推荐

SpringBoot整合Quartz(v2.3.2)定时任务不执行?5个排查思路与解决方案

本文针对SpringBoot整合Quartz定时任务不执行的常见问题,提供了一套系统性的排查思路与解决方案。文章从依赖配置、Spring容器集成、Quartz调度器启动流程、触发器定义到任务执行环境,层层深入剖析,并重点讲解了如何通过检查Scheduler状态、配置Misfire策略及集群环境调试来定位和解决任务“静默失效”的难题。

gold的博客 927

quartz mysql表文件_spring boot+Quartz+数据库存储

SpingBoot+Quartz+数据库存储1、Spring整合Quartz2、读取数据库中表达式启动定时任务1(每5s执行)3、更改定时任务状态(启用/禁用),定时任务1停止4、读取数据库中表达式启动定时任务2(每5s执行),在对应作业类中打印定时任务2携带的参数5、读取数据库中表达式启动定时任务3(每5s执行改成每20s执行),更改数据库定时任务表达式,定时任务3对应执行策略相应发生改变。Sp...

weixin_39604276的博客 976

SpringBoot整合Quartz

目录`Quartz` 简介 Quartz 简介 Quartz 是一款功能强大的开源任务调度框架,几乎可以集成到任何 Java 应用程序中(小到单机应用,大到分布式应用)。Quartz 可用于创建简单或复杂的任务调度,用以执行数以万计的任务。任务被定义为标准化的 Java 组件,Java 编写的任务都可以被执行 Quartz 是一个任务日程管理系统,一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统 Quartz 用一个小 Java 库发布文件(.jar文件),这个库文件包含了所

桐花思雨 4万+

【Quartz】Quartz存储与持久化-基于quartz.properties的配置

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka 一、   Quartz存储与持久化          Quartz提供两种基本作业存储类型。第一种类型叫做RAMJobStore,第二种类型叫做JDBC作业存储。在默认情况下Quartz将任务调度的运行信息保存在内存中,这种方法提供了最佳的性能,因为内存中数据访问最快。不足之处是缺乏数据的

杜海的博客 2355

Springboot 整合 Quartz(定时任务框架)

Quartz是 OpenSymphony 开源组织在 Job scheduling 领域又一个开源项目,完全由 Java 开发,可以用来执行定时任务,类似于 java.util.Timer。持久性作业 - 就是保持调度定时的状态;作业管理 - 对调度作业进行有效的管理;

原名:@程序员大禹 7655

【微服务】springboot整合quartz使用详解

springboot整合quartz详解

congge_study的博客 7302

MySQL(九):InnoDB 表空间(Tables)

本节着重分析一下表空间,通过本节我们将清楚以下几个问题: 1、什么是表空间(Tablespace)? 2、InnoDB 存储引擎有哪些表空间(Tablespace)? 3、InnoDB 存储引擎中的表空间(Tablespace)有什么用? 4、表空间(Tablespace)有哪些组成部分?及各个表空间的作用? 文章目录1、简述2、InnoDB 逻辑存储结构2.1、段(segment)2.2、区(e...

码客 1万+

tables_mysql_innodb.sql

Quartz初始化数据库建表SQL,包含每个字段及每个表的注释,可以帮助你快速创建所需要的表

springboot 1.5.7 + quartz 2.1.7 整合 分布式集群 动态cronExpression

目前公司需要在分布式springboot 上加个批量定时器,选择了quartz 来做。(公司代码拿不出来,所有代码为手敲,可能有拼错单词,遇到我敲错的自己百度改正) springboot 1 需要引入 spring-context-support 4.5.7包,里面有spring对于quartz的一些 factoryBean的封装。看了一下包里的spring官网注释,里面说可以完美适配quart...

qq_25993145的博客 1126

quartz框架mysql表结构 2.3版本 共11张表(tables_mysql_innodb.sql)

这是quartz的mysql类型的11个管理quartz的建表语句,全部来自于官网下载,全名:tables_mysql_innodb.sql

MTK-Display技术解析:从MDP到DDP的架构演进

本文深入解析了联发科(MTK)显示技术从MDP到DDP的架构演进。MDP作为多媒体数据预处理中心,负责格式转换与缩放;而DDP则整合了OVL、COLOR、AAL等模块,并引入CMDQ与场景化模式,实现了从分散处理到统一智能调度的飞跃,旨在提升画质、流畅度并降低功耗。

weixin_29218509的博客 255

springboot和quartz整合实现动态定时任务(持久化单节点)

  Quartz是一个完全由java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制,它支持定时任务持久化到数据库,从而避免了重启服务器时任务丢失,支持分布式多节点,大大的提高了单节点定时任务的容错性。springboot在2.0版本以前没有对quartz做自动配置,因此需要我们自己去手动配置,网上找了许多资料,但是大都不能完全满足自己的需要,因此自己整合了一下方便...

weixin_30653023的博客 320

带你学习Android中的ContentObserver

通过使用,开发者可以有效地监听系统设置的变化,例如屏幕亮度等。这种机制使得应用能够动态响应系统设置的更改,提升用户体验。在实现需要与系统设置交互的应用时,合理使用是非常重要的。

执剑人 1311

Spring Boot 2(一):【重磅】Spring Boot 2.0权威发布

熟悉Spring Boot/Cloud的技术者们都知道,Spring Boot依赖于Spring,而Spring Cloud又依赖于Spring Boot,因此Spring Boot2.0的发布正式整合了Spring5.0的很多特性,同样后面Spring Cloud最新版本的发布也需要整合最新的Spring Boot2.0内容。当客户端需要的时候,它已经在客户端了。

weixin_45223949的博客 672

大疆控制算法笔试复习指南:从PID到MPC核心考点解析

控制算法是无人机、机器人等智能装备实现自主运行的核心技术。从经典控制到现代控制,PID控制算法、LQR控制算法、预测控制算法(MPC)以及Stanley控制算法等,构成了工程实践中不可或缺的方法体系。理解其数学原理、适用条件与调参逻辑,是评估系统稳定性、动态响应与抗扰能力的基础。在无人机飞控、云台增稳、车载路径跟踪等典型场景中,这些算法直接决定了设备的实际性能表现。大疆等企业相关岗位的笔试,正是围绕上述核心知识点,考查候选人对控制系统本质的理解、数学推导能力以及工程实现素养。本文整理了一套覆盖理论基石、高频

weixin_33178839的博客 359

利用易特天下 ipbox&零层壹号 sdwan 组网盒子实现异地组网

一款支持zerotier的异地组网盒子

v808v808的博客 3350

SpringBoot整合Quartz并持久化任务

前言:在开发过程中我们会遇到一些定时任务,对于这些任务我们需要对其进行管理,此时使用 Spring自带的定时任务无法满足我们的需求,我们可以使用Quartz定时任务框架。多的不说了,直接上代码 SpringBoot整合Quartz: 1、pom文件中添加依赖 2、添加配置文件(.properties或者.yml) pom.xml文件 <!-- quartz开始 --> ...

qq_41354978的博客 824

双目视觉入门实战:用Matlab标定相机,再到Python OpenCV完成测距的完整链路

本文详细介绍了双目视觉技术的完整实现流程,从Matlab相机标定到Python OpenCV测距的全链路实践。重点解析了Matlab与OpenCV的参数转换技巧,以及立体校正、视差计算等关键步骤的代码实现,帮助开发者快速掌握双目测距系统的搭建方法。

weixin_29166013的博客 446

SpringBoot整合Quartz实现定时任务

1、Quartz简介 Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。 1.1 Quartz的三大核心组件 调度器:Scheduler。 任务:JobDetail。 触发器:Trigger,包括 SimpleTrigger 和 CronTrigger。 (1)Jo

pan_junbiao的博客 3万+

PyTorch生成式人工智能(25)——基于Transformer实现机器翻译

不同于循环神经网络 (RNN) 按顺序处理数据,Transformer 以并行的方式处理输入数据(例如句子)。这种并行处理提高了效率,但并未使其能够识别输入的顺序。为了解决这个问题,Transformer 向输入的词嵌入中添加了位置编码。这些位置编码是分配给输入序列中每个位置的独特向量,其维度与输入词嵌入对齐。本节将以英语到法语的翻译为例,通过介绍如何训练 Transformer 模型将英语句子转换为法语,深入理解 Transformer 的架构及自注意力机制的运作方式。

盼小辉丶的博客 2752

MetaGPT核心模块:Data Interpreter 上手实战 - 数据分析和可视化(附运行过程详解)

上篇文章我们详细解读了 DataInterpreter 的实现原理(论文),本文将开始上手实操,开始写代码用上 DataInterpreter。从最简单的例子开始,先给大家看下其运行过程,看下DataInterpreter是如何自动拆解任务,完成任务的,帮助大家构建直观认识。

同学小张的博客 371

一、springboot与quartz的整合

一、背景 1.因为需求需要,所以我们用到了定时任务,但是之前使用的定时任务是基于spring的xml形式,但是在微服务的模块中这显然不太合适,因为单独的模块,做成了独立的服务,所以我最终选择了基于注解的方式来完成我们的需求。 2.所以我写了一个小demo来让大家借鉴先怎么使用springboot与quartz的合起来使用。下面我们就进入今天的学习内容。 二、quartz的简介 1.Quar...

码农小默 4万+

maya导入导出bvh 自动 脚本

maya打开bvh脚本

jacke121的专栏 1551

Springboot 整合Quartz

springboot整合quartz相关基本配置

yang_fei9264的博客 8119

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

上一篇: quartz - 宕机后的设置
下一篇: vue - 结合腾讯地图时绑定监听要使用箭头函数不然无法绑定
Prometheus_xiao
博客等级 码龄9年 3粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值