• Asp.Net Core2.0 基于QuartzNet任务管理系统


    Quartz.NET官网地址:https://www.quartz-scheduler.net/

    Quartz.NET文档地址:https://www.quartz-scheduler.net/documentation/index.html

    Quartz.NET是一个开源的作业调度框架,是OpenSymphonyQuartz API的.NET移植,它用C#写成,可用于winformasp.net应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度。它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等。

    现在Quartz.NET3.0已支持Asp.Net Core,3.0新功能如下:

    新功能

    • 具有异步/等待支持的基于任务的作业,内部以异步/等待方式工作
    • 支持.NET Core / netstandard 2.0和.NET Framework 4.5.2及更高版本
    • 通过提供程序名称SQLite-Microsoft支持Microsoft.Data.Sqlite,旧的提供程序SQLite也仍然有效
    • 增加了SQL Server内存优化表和Quartz.Impl.AdoJobStore.UpdateLockRowSemaphoreMOT的初步支持
    • Common.Logging从相关性中删除
    • ILMerge进程中删除的C5集合不再需要
    • 在插件启动时添加对作业调度XML文件的急切验证的支持
    • TimeZoneUtil中添加对额外的自定义时区解析器功能的支持

    变化

    • 作业和插件现在位于独立的程序集NuGetQuartz.JobsQuartz.Plugins
    • ADO.NET提供者名称已被简化,提供者名称没有版本,例如SqlServer-20 => SqlServer
    • API方法已被重新使用,主要使用IReadOnlyCollection,这隐藏了两个HashSets和List小号
    • LibLog一直隐藏于内部(ILog等),就像它原本打算的那样
    • SimpleThreadPool消失了,旧的拥有的线程消失了
    • 调度程序方法已更改为基于任务,请记住等待它们
    • IJob接口现在返回一个任务
    • 一些IList属性已更改为IReadOnlyList以正确反映意图
    • SQL Server CE支持已被删除
    • DailyCalendar现在将日期时间用于排除的日期,并具有ISet接口来访问它们
    • IObjectSerializer有新的方法,void Initialize(),必须实现
    • IInterruptableJob取消了上下文的CancellationToken

    Quartz API的关键接口和类是

    • IScheduler - 与调度程序交互的主要API。
    • IJob - 您希望由调度程序执行的组件实现的接口。
    • IJobDetail - 用于定义作业的实例。
    • ITrigger - 定义执行给定Job的时间表的组件。
    • JobBuilder - 用于定义/构建定义作业实例的JobDetail实例。
    • TriggerBuilder - 用于定义/构建触发器实例

    一、Quartz.NET基本使用

    1、新建Asp.Net Core 项目,使用NuGet添加Quartz,或使用程序包管理器引用,命令如下:
    Install-Package Quartz

     如果你想添加JSON序列化,只需要以同样的方式添加Quartz.Serialization.Json包。

    2、简单实例,代码如下:
    using Five.QuartzNetJob.ExecuteJobTask.Service;
    using Quartz;
    using Quartz.Impl;
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Five.QuartzNetJob.Web.Controllers
    {
        public class TestTask
        {
            public async Task StartTestAsync() 
            {
                try
                {
                    // 从工厂中获取调度程序实例
                    NameValueCollection props = new NameValueCollection
                    {
                        { "quartz.serializer.type", "binary" }
                    };
                    StdSchedulerFactory factory = new StdSchedulerFactory(props);
                    IScheduler scheduler = await factory.GetScheduler();
                   
                    // 开启调度器
                    await scheduler.Start();
    
                    // 定义这个工作,并将其绑定到我们的IJob实现类
                    IJobDetail job = JobBuilder.Create<HelloJob>()
                        .WithIdentity("job1", "group1")
                        .Build();
    
                    // 触发作业立即运行,然后每10秒重复一次,无限循环
                    ITrigger trigger = TriggerBuilder.Create()
                        .WithIdentity("trigger1", "group1")
                        .StartNow()
                        .WithSimpleSchedule(x => x
                            .WithIntervalInSeconds(10)
                            .RepeatForever())
                        .Build();
    
                    // 告诉Quartz使用我们的触发器来安排作业
                    await scheduler.ScheduleJob(job, trigger);
    
                    // 等待60秒
                    await Task.Delay(TimeSpan.FromSeconds(60));
    
                    // 关闭调度程序
                    await scheduler.Shutdown();
                }
                catch (SchedulerException se)
                {
                    await Console.Error.WriteLineAsync(se.ToString());
                }
            }
        }
    }

     HelloJob内容如下:

    using Quartz;
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Five.QuartzNetJob.ExecuteJobTask.Service
    {
        public class HelloJob : IJob
        {
            public  Task Execute(IJobExecutionContext context)
            {
                 Console.Out.WriteLineAsync("Greetings from HelloJob!");
                return Task.CompletedTask;
            }
        }
    }

    执行效果如下:

    Quartz的版本3.0.3中删除了IJob实现的异地调用,也就是不支持asyncawait异步调用,3.0.2版本支持异步调用。

    二、触发器类型

     1、SimpleTrigger触发器(简单触发器)

    SimpleTrigger的属性包括:开始时间和结束时间,重复计数和重复间隔。重复计数可以是零,一个正整数或常数值SimpleTrigger.RepeatIndefinitely。重复时间间隔属性必须是TimeSpan.Zero或正的TimeSpan值。请注意,重复间隔为0会导致触发器的“重复计数”触发同时发生。

    SimpleTrigger实例使用TriggerBuilder(用于触发器的主属性)和WithSimpleSchedule扩展方法(用于SimpleTrigger特定的属性)构建。

    在特定的时间内建立触发器,无需重复,代码如下:

    // 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger
    ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create()
        .WithIdentity("trigger1", "group1")
        .StartAt(DateTime.Now) //指定开始时间为当前系统时间
        .ForJob("job1", "group1") //通过JobKey识别作业
        .Build();

    在特定的时间建立触发器,然后每十秒钟重复十次:

    // 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger
    ITrigger trigger = trigger = TriggerBuilder.Create()
       .WithIdentity("trigger2", "group2")
       .StartAt(DateTime.Now) // 指定开始时间
       .WithSimpleSchedule(x => x
       .WithIntervalInSeconds(10)
       .WithRepeatCount(10)) // 请注意,重复10次将总共重复11次
       .ForJob("job2", "group2") //通过JobKey识别作业                   
       .Build();

    构建一个触发器,将在未来五分钟内触发一次:

    // 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger
    ITrigger trigger = trigger = (ISimpleTrigger)TriggerBuilder.Create()
       .WithIdentity("trigger3", "group3")
       .StartAt(DateBuilder.FutureDate(5, IntervalUnit.Minute)) //使用DateBuilder将来创建一个时间日期
       .ForJob("job3", "group3") //通过JobKey识别作业
       .Build();

    建立一个现在立即触发的触发器,然后每隔五分钟重复一次,直到22:00:

    // 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger
    ITrigger trigger = trigger = TriggerBuilder.Create()
       .WithIdentity("trigger4", "group4")
       .WithSimpleSchedule(x => x
            .WithIntervalInMinutes(5)//每5秒执行一次
            .RepeatForever())
       .EndAt(DateBuilder.DateOf(22, 0, 0))//晚上22点结束
       .Build();

    建立一个触发器,在一个小时后触发,然后每2小时重复一次:

    // 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger
    ITrigger  trigger = TriggerBuilder.Create()
       .WithIdentity("trigger5") // 由于未指定组,因此“trigger5”将位于默认分组中
       .StartAt(DateBuilder.EvenHourDate(null)) // 获取下个一小时时间                 
       .WithSimpleSchedule(x => x
            .WithIntervalInHours(2)//执行间隔2小时
            .RepeatForever())
       .Build(); 

    因此简单的任务调度使用SimpleTrigger完全够用,如果SimpleTrigger还是不能满足您的需求请往下看。

    2、CronTrigger触发器

    如果你需要一个基于类似日历的概念而不是精确指定的SimpleTrigger时间间隔的工作调度计划,CronTriggers通常比SimpleTrigger更有用。

    使用CronTrigger,您可以在每周一,周三的上午9点至上午10点之间指定开始时间表,例如“每星期五中午”或“每个工作日和上午9点30分”,或者“每5分钟”和星期五”。

    即使如此,就像SimpleTrigger一样,CronTrigger有一个startTime,它指定了时间表的生效时间,还有一个(可选的)endTime,用于指定应该停止时间表的时间。

    这里不在详细介绍Cron

    Cron表达式在线生成器:http://cron.qqe2.com/

    Cron表达式详细介绍:https://www.jianshu.com/p/e9ce1a7e1ed1

    每天早上8点到下午5点建立一个触发器,每隔一分钟就会触发一次:

    // 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger
    ITrigger trigger = TriggerBuilder.Create()
       .WithIdentity("Job1", "group1")
       .WithCronSchedule("0 0/2 8-17 * * ?")//使用Cron表达式
       .ForJob("Job1", "group1")
       .Build();

    建立一个触发器,每天在上午10:42开始执行:

    // 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger
    ITrigger trigger = TriggerBuilder.Create()
       .WithIdentity("Job2", "group2")
       .WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(10, 42)) // 在这里使用CronScheduleBuilder的静态辅助方法
       .ForJob("Job2", "group2")
       .Build();

    构建一个触发器,将在星期三上午10:42在除系统默认值之外的TimeZone中触发:

    // 触发器构建器默认创建一个简单的触发器,实际上返回一个ITrigger
    ITrigger trigger = TriggerBuilder.Create()
       .WithIdentity("Job3", "group3")
       .WithCronSchedule("0 42 10 ? * WED", x => x
       .InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time")))
       .ForJob("Job3", "group3")
       .Build();

    总结: Quartz.NET的3.0版本跟之前的版本api接口变化并不大。只是在3.0版本中添加了异步调用,并支持.net core。简单的任务调度使用官网中的实例即可满足需求。

    三、后端项目管理

    在网上找到很多关于asp.net 的任务管理,但没有找到.net core 相关的后端任务管理。

    我就根据官网还有网上dalao开源分享的项目实现了个简单的后端任务。

    项目地址:https://github.com/Potato-MC/QuartzNetJob

    项目效果图请看:http://www.cnblogs.com/miskis/p/8484252.html

    项目结构

    项目使用asp.net core 2.0--->adminlte-2.4.2-->SqlSugar-4.6.4.3。

    数据库表可使用SqlSugar来生成。

    public IActionResult Index()
    {
        //生成表
        //var db = DataHelper.GetInstance();
        //db.CodeFirst.InitTables(typeof(OperateLog), typeof(OperateLog));
        return View();
     }

    结构如下:

    Five.QuartzNetJob.DataService.DataHelper----------------------------------是ORM层,使用的是开源框架SqlSugar(官网地址:http://www.codeisbug.com/Doc/8

    Five.QuartzNetJob.DataService.Models---------------------------------------是实体类

    Five.QuartzNetJob.ExecuteJobTask.Service---------------------------------IJob实现层

    QuartzNet.Entity---------------------------------------------------------------------调度中心相关实体类

    QuartzNet2.Core--------------------------------------------------------------------非.Net Core版本的调度管理中心,使用的是.net framework 4.6

    Five.QuartzNetJob.Utils.Tool-----------------------------------------------------通用工具类库

    Five.QuartzNetJob.Web-----------------------------------------------------------后端

    项目很简单,就只实现了增删改查。

    统一管理任务调度,项目运行时开启任务调度并执行已开启的任务。

    因为项目太过于简单,就不在详细介绍。

    下面贴出任务调度中心代码,欢迎各位dalao发表意见:

    using QuartzNet.Entity;
    using Quartz;
    using Quartz.Impl;
    using System;
    using System.Collections.Specialized;
    using System.Threading.Tasks;
    using Five.QuartzNetJob.Utils.Tool;
    using System.Reflection;
    using System.Collections.Generic;
    
    namespace QuartzNet3.Core
    {
        /// <summary>
        /// 任务调度中心
        /// </summary>
        public class SchedulerCenter
        {
            /// <summary>
            /// 任务调度对象
            /// </summary>
            public static readonly SchedulerCenter Instance;
            static SchedulerCenter()
            {
                Instance = new SchedulerCenter();
            }
            private Task<IScheduler> _scheduler;
    
            /// <summary>
            /// 返回任务计划(调度器)
            /// </summary>
            /// <returns></returns>
            private Task<IScheduler> Scheduler
            {
                get
                {
                    if (this._scheduler != null)
                    {
                        return this._scheduler;
                    }
                    // 从Factory中获取Scheduler实例
                    NameValueCollection props = new NameValueCollection
                    {
                        { "quartz.serializer.type", "binary" },
                        //以下配置需要数据库表配合使用,表结构sql地址:https://github.com/quartznet/quartznet/tree/master/database/tables
                        //{ "quartz.jobStore.type","Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"},
                        //{ "quartz.jobStore.driverDelegateType","Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz"},
                        //{ "quartz.jobStore.tablePrefix","QRTZ_"},
                        //{ "quartz.jobStore.dataSource","myDS"},
                        //{ "quartz.dataSource.myDS.connectionString",AppSettingHelper.MysqlConnection},//连接字符串
                        //{ "quartz.dataSource.myDS.provider","MySql"},
                        //{ "quartz.jobStore.useProperties","true"}
    
                    };
                    StdSchedulerFactory factory = new StdSchedulerFactory(props);
                    return this._scheduler = factory.GetScheduler();
                }
            }
          
            /// <summary>
            /// 运行指定的计划(映射处理IJob实现类)
            /// </summary>
            /// <param name="jobGroup">任务分组</param>
            /// <param name="jobName">任务名称</param>
            /// <returns></returns>
            public async Task<BaseQuartzNetResult> RunScheduleJob<T>(string jobGroup, string jobName) where T : ScheduleManage
            {
                BaseQuartzNetResult result;
                //开启调度器
                await this.Scheduler.Result.Start();
                //创建指定泛型类型参数指定的类型实例
                T t = Activator.CreateInstance<T>();
                //获取任务实例
                ScheduleEntity scheduleModel = t.GetScheduleModel(jobGroup, jobName);
                //添加任务
                var addResult = AddScheduleJob(scheduleModel).Result;
                if (addResult.Code == 1000)
                {
                    scheduleModel.Status = EnumType.JobStatus.已启用;
                    t.UpdateScheduleStatus(scheduleModel);
                    //用给定的密钥恢复(取消暂停)IJobDetail
                    await this.Scheduler.Result.ResumeJob(new JobKey(jobName, jobGroup));
                    result = new BaseQuartzNetResult
                    {
                        Code = 1000,
                        Msg = "启动成功"
                    };
                }
                else
                {
                    result = new BaseQuartzNetResult
                    {
                        Code = -1
                    };
                }
                return result;
            }
            /// <summary>
            /// 添加一个工作调度(映射程序集指定IJob实现类)
            /// </summary>
            /// <param name="m"></param>
            /// <returns></returns>
            private async Task<BaseQuartzNetResult> AddScheduleJob(ScheduleEntity m)
            {
                var result = new BaseQuartzNetResult();
                try
                {
    
                    //检查任务是否已存在
                    var jk = new JobKey(m.JobName, m.JobGroup);
                    if (await this.Scheduler.Result.CheckExists(jk))
                    {
                        //删除已经存在任务
                        await this.Scheduler.Result.DeleteJob(jk);
                    }
                    //反射获取任务执行类
                    var jobType = FileHelper.GetAbsolutePath(m.AssemblyName, m.AssemblyName + "." + m.ClassName);
                    // 定义这个工作,并将其绑定到我们的IJob实现类
                    IJobDetail job = new JobDetailImpl(m.JobName, m.JobGroup, jobType);
                    //IJobDetail job = JobBuilder.CreateForAsync<T>().WithIdentity(m.JobName, m.JobGroup).Build();
                    // 创建触发器
                    ITrigger trigger;
                    //校验是否正确的执行周期表达式
                    if (!string.IsNullOrEmpty(m.Cron) && CronExpression.IsValidExpression(m.Cron))
                    {
                        trigger = CreateCronTrigger(m);
                    }
                    else
                    {
                        trigger = CreateSimpleTrigger(m);
                    }
    
                    // 告诉Quartz使用我们的触发器来安排作业
                    await this.Scheduler.Result.ScheduleJob(job, trigger);
    
                    result.Code = 1000;
                }
                catch (Exception ex)
                {
                    await Console.Out.WriteLineAsync(string.Format("添加任务出错{0}", ex.Message));
                    result.Code = 1001;
                    result.Msg = ex.Message;
                }
                return result;
            }
            /// <summary>
            /// 运行指定的计划(泛型指定IJob实现类)
            /// </summary>
            /// <param name="jobGroup">任务分组</param>
            /// <param name="jobName">任务名称</param>
            /// <returns></returns>
            public async Task<BaseQuartzNetResult> RunScheduleJob<T, V>(string jobGroup, string jobName) where T : ScheduleManage, new() where V : IJob
            {
                BaseQuartzNetResult result;
                //开启调度器
                await this.Scheduler.Result.Start();
                //创建指定泛型类型参数指定的类型实例
                T t = Activator.CreateInstance<T>();
                //获取任务实例
                ScheduleEntity scheduleModel = t.GetScheduleModel(jobGroup, jobName);
                //添加任务
                var addResult = AddScheduleJob<V>(scheduleModel).Result;
                if (addResult.Code == 1000)
                {
                    scheduleModel.Status = EnumType.JobStatus.已启用;
                    t.UpdateScheduleStatus(scheduleModel);
                    //用给定的密钥恢复(取消暂停)IJobDetail
                    await this.Scheduler.Result.ResumeJob(new JobKey(jobName, jobGroup));
                    result = new BaseQuartzNetResult
                    {
                        Code = 1000,
                        Msg = "启动成功"
                    };
                }
                else
                {
                    result = new BaseQuartzNetResult
                    {
                        Code = -1
                    };
                }
                return result;
            }
            /// <summary>
            /// 添加任务调度(指定IJob实现类)
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="m"></param>
            /// <returns></returns>
            private async Task<BaseQuartzNetResult> AddScheduleJob<T>(ScheduleEntity m) where T : IJob
            {
                var result = new BaseQuartzNetResult();
                try
                {
    
                    //检查任务是否已存在
                    var jk = new JobKey(m.JobName, m.JobGroup);
                    if (await this.Scheduler.Result.CheckExists(jk))
                    {
                        //删除已经存在任务
                        await this.Scheduler.Result.DeleteJob(jk);
                    }
                    //反射获取任务执行类
                    // var jobType = FileHelper.GetAbsolutePath(m.AssemblyName, m.AssemblyName + "." + m.ClassName);
                    // 定义这个工作,并将其绑定到我们的IJob实现类
                    //IJobDetail job = new JobDetailImpl(m.JobName, m.JobGroup, jobType);
                    IJobDetail job = JobBuilder.CreateForAsync<T>().WithIdentity(m.JobName, m.JobGroup).Build();
                    // 创建触发器
                    ITrigger trigger;
                    //校验是否正确的执行周期表达式
                    if (!string.IsNullOrEmpty(m.Cron) && CronExpression.IsValidExpression(m.Cron))
                    {
                        trigger = CreateCronTrigger(m);
                    }
                    else
                    {
                        trigger = CreateSimpleTrigger(m);
                    }
    
                    // 告诉Quartz使用我们的触发器来安排作业
                    await this.Scheduler.Result.ScheduleJob(job, trigger);
    
                    result.Code = 1000;
                }
                catch (Exception ex)
                {
                    await Console.Out.WriteLineAsync(string.Format("添加任务出错", ex.Message));
                    result.Code = 1001;
                    result.Msg = ex.Message;
                }
                return result;
            }
            /// <summary>
            /// 暂停指定的计划
            /// </summary>
            /// <param name="jobGroup">任务分组</param>
            /// <param name="jobName">任务名称</param>
            /// <param name="isDelete">停止并删除任务</param>
            /// <returns></returns>
            public BaseQuartzNetResult StopScheduleJob<T>(string jobGroup, string jobName, bool isDelete = false) where T : ScheduleManage, new()
            {
                BaseQuartzNetResult result;
                try
                {
                    this.Scheduler.Result.PauseJob(new JobKey(jobName, jobGroup));
                    if (isDelete)
                    {
                        Activator.CreateInstance<T>().RemoveScheduleModel(jobGroup, jobName);
                    }
                    result = new BaseQuartzNetResult
                    {
                        Code = 1000,
                        Msg = "停止任务计划成功!"
                    };
                }
                catch (Exception ex)
                {
                    result = new BaseQuartzNetResult
                    {
                        Code = -1,
                        Msg = "停止任务计划失败"
                    };
                }
                return result;
            }
            /// <summary>
            /// 恢复运行暂停的任务
            /// </summary>
            /// <param name="jobName">任务名称</param>
            /// <param name="jobGroup">任务分组</param>
            public async void ResumeJob(string jobName, string jobGroup)
            {
                try
                {
                    //检查任务是否存在
                    var jk = new JobKey(jobName, jobGroup);
                    if (await this.Scheduler.Result.CheckExists(jk))
                    {
                        //任务已经存在则暂停任务
                        await this.Scheduler.Result.ResumeJob(jk);
                        await Console.Out.WriteLineAsync(string.Format("任务“{0}”恢复运行", jobName));
                    }
                }
                catch (Exception ex)
                {
                    await Console.Out.WriteLineAsync(string.Format("恢复任务失败!{0}", ex));
                }
            }
           
            /// <summary>
            /// 停止任务调度
            /// </summary>
            public async void StopScheduleAsync()
            {
                try
                {
                    //判断调度是否已经关闭
                    if (!this.Scheduler.Result.IsShutdown)
                    {
                        //等待任务运行完成
                        await this.Scheduler.Result.Shutdown();
                        await Console.Out.WriteLineAsync("任务调度停止!");
                    }
                }
                catch (Exception ex)
                {
                    await Console.Out.WriteLineAsync(string.Format("任务调度停止失败!", ex));
                }
            }
            /// <summary>
            /// 创建类型Simple的触发器
            /// </summary>
            /// <param name="m"></param>
            /// <returns></returns>
            private ITrigger CreateSimpleTrigger(ScheduleEntity m)
            {
                //作业触发器
                if (m.RunTimes > 0)
                {
                    return TriggerBuilder.Create()
                   .WithIdentity(m.JobName, m.JobGroup)
                   .StartAt(m.BeginTime)//开始时间
                   .EndAt(m.EndTime)//结束数据
                   .WithSimpleSchedule(x => x
                       .WithIntervalInSeconds(m.IntervalSecond)//执行时间间隔,单位秒
                       .WithRepeatCount(m.RunTimes))//执行次数、默认从0开始
                       .ForJob(m.JobName, m.JobGroup)//作业名称
                   .Build();
                }
                else
                {
                    return TriggerBuilder.Create()
                   .WithIdentity(m.JobName, m.JobGroup)
                   .StartAt(m.BeginTime)//开始时间
                   .EndAt(m.EndTime)//结束数据
                   .WithSimpleSchedule(x => x
                       .WithIntervalInSeconds(m.IntervalSecond)//执行时间间隔,单位秒
                       .RepeatForever())//无限循环
                       .ForJob(m.JobName, m.JobGroup)//作业名称
                   .Build();
                }
    
            }
            /// <summary>
            /// 创建类型Cron的触发器
            /// </summary>
            /// <param name="m"></param>
            /// <returns></returns>
            private ITrigger CreateCronTrigger(ScheduleEntity m)
            {
                // 作业触发器
                return TriggerBuilder.Create()
                       .WithIdentity(m.JobName, m.JobGroup)
                       .StartAt(m.BeginTime)//开始时间
                       .EndAt(m.EndTime)//结束时间
                       .WithCronSchedule(m.Cron)//指定cron表达式
                       .ForJob(m.JobName, m.JobGroup)//作业名称
                       .Build();
            }
        }
    }
    View Code

     总结:

    开发已个小项目搞了好久才搞完,期间零零散散的开发,还是太懒散了!

    平时积累不够,还是太菜了!!!!!

  • 相关阅读:
    C++实现数字媒体三维图像渲染
    C++实现数字媒体三维图像变换
    C++实现数字媒体二维图像变换
    C++实现glut绘制点、直线、多边形、圆
    语音识别之梅尔频谱倒数MFCC(Mel Frequency Cepstrum Coefficient)
    Java中的BigDecimal类精度问题
    spring 手册
    bootstrap 参考文档
    springBoot入门文章
    JNDI
  • 原文地址:https://www.cnblogs.com/miskis/p/8487634.html
Copyright © 2020-2023  润新知