不要混淆了 Quartz 的 Calendar 对象与 Java API 的 java.util.Calendar。它们是应用于不同目的不一样的组件。

Java 的 Calendar 对象是通用的日期和时间工具;许多过去由 Java 的 Date 类提供的功能现在加到了 Calendar 类中了。

Quartz 的 Calendar 专门用于屏闭一个时间区间,使 Trigger 在这个区间中不被触发。

Calendar 排除时间的粒度:

Calendar 接口方法参数的类型是 Long。这说明 Quartz Calendar 能够排除的时间细致毫秒级。你很可能永远都不需要这么细小的位度,因为大部分的 Job 只需要排除特别的日期或许会是小时。然而,假如你真需要排除到毫秒一级的,Calendar 能帮你做到

Quartz 自带的随时可用的 Calendar。

Quartz的BaseCalendar层次结构如下:

参考API:http://www.quartz-scheduler.org/api/2.2.1/index.html

Calendar 名称类用法

BaseCalendarorg.quartz.impl.calendar.BaseCalendar为高级的 Calendar 实现了基本的功能,实现了 org.quartz.Calendar 接口

AnnualCalendarorg.quartz.impl.calendar.AnnualCalendar排除年中一天或多天

CronCalendarorg.quartz.impl.calendar.CronCalendar日历的这种实现排除了由给定的CronExpression表达的时间集合。 例如,您可以使用此日历使用表达式“* * 0-7,18-23?* *”每天排除所有营业时间(上午8点至下午5点)。

如果CronTrigger具有给定的cron表达式并且与具有相同表达式的CronCalendar相关联,则日历将排除触发器包含的所有时间,并且它们将彼此抵消。

DailyCalendarorg.quartz.impl.calendar.DailyCalendar您可以使用此日历来排除营业时间(上午8点 - 5点)每天。 每个DailyCalendar仅允许指定单个时间范围,并且该时间范围可能不会跨越每日边界(即,您不能指定从上午8点至凌晨5点的时间范围)。 如果属性invertTimeRange为false(默认),则时间范围定义触发器不允许触发的时间范围。 如果invertTimeRange为true,则时间范围被反转 - 也就是排除在定义的时间范围之外的所有时间。

HolidayCalendarorg.quartz.impl.calendar.HolidayCalendar特别的用于从 Trigger 中排除节假日

MonthlyCalendarorg.quartz.impl.calendar.MonthlyCalendar排除月份中的指定数天,例如,可用于排除每月的最后一天

WeeklyCalendarorg.quartz.impl.calendar.WeeklyCalendar排除星期中的任意周几,例如,可用于排除周末,默认周六和周日

注意,所有的Calendar既可以是排除,也可以是包含,取决于:AnnualCalendar:指定每年的哪一天。使用方式如上例。精度是【天】

CronCalendar:指定Cron表达式。精度取决于Cron表达式,也就是最大精度可以【到秒】

DailyCalendar:指定每天的时间段(rangeStartingTime, rangeEndingTime),格式是HH:MM[:SS[:mmm]]。也就是最大精度可以【到毫秒】

HolidayCalendar:指定特定的日期,比如20140613。精度到【天】

MonthlyCalendar:指定每月的几号。可选值为1-31。精度是【天】

WeeklyCalendar:指定每星期的星期几,可选值比如为java.util.Calendar.SUNDAY。精度是【天】

使用 Quartz 的 Calendar源码示例

要使用 Quartz Calendar,你只需简单的实例化,并加入你要排除的日期,然后用 Scheduler 注册它。最后把这个 Calendar 实例与你想要使用该Calendar 的每一个 Trigger 实例关联起来

AnnualCalendar

示例:import org.quartz.*;

import org.quartz.impl.StdSchedulerFactory;

import org.quartz.impl.calendar.AnnualCalendar;

import java.text.SimpleDateFormat;

import java.util.Calendar;

import java.util.Date;

import java.util.GregorianCalendar;

import static org.quartz.DateBuilder.dateOf;

import static org.quartz.JobBuilder.newJob;

import static org.quartz.SimpleScheduleBuilder.simpleSchedule;

import static org.quartz.TriggerBuilder.newTrigger;

/**

* 此示例将演示如何使用日历来排除不应该进行调度的时间段。

*/

public class CalendarExample {

public static void main(String[] args) throws Exception {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println("-------  初始化 ----------");

SchedulerFactory sf = new StdSchedulerFactory();

Scheduler sched = sf.getScheduler();

// 声明一个节假日 holidayCalendar,标明要排除的日期

// 法定节日是以每年为周期的,所以使用AnnualCalendar而不是HolidayCalendar

AnnualCalendar holidays = new AnnualCalendar();

Calendar fourthOfJuly = new GregorianCalendar(2017, 6, 4);  // fourth of July (July 4) 七月四日

holidays.setDayExcluded(fourthOfJuly, true);

System.out.println("第一个节假日:" + sdf.format(fourthOfJuly.getTime()));

Calendar halloween = new GregorianCalendar(2017, 9, 31);    // halloween (Oct 31) 万圣节(10月31日)

holidays.setDayExcluded(halloween, true);

System.out.println("第二节假日:" + sdf.format(halloween.getTime()));

Calendar christmas = new GregorianCalendar(2017, 11, 25);   // christmas (Dec 25) christmas (Dec 25)

holidays.setDayExcluded(christmas, true);

System.out.println("第三个节假日:" + sdf.format(christmas.getTime()));

sched.addCalendar("holidays", holidays, false, false);      // 节假日加入schedule调度器

// 开始在万圣节前夜上午10点,开始任务

Date runDate = dateOf(0, 0, 10, 31, 10);

System.out.println("任务开始时间:" + sdf.format(runDate));

JobDetail job = newJob(SimpleJob.class).withIdentity("job1", "group1").build();

SimpleTrigger trigger = newTrigger()

.withIdentity("trigger1", "group1")

.startAt(runDate)

.withSchedule(simpleSchedule()

.withIntervalInHours(1).repeatForever())

.modifiedByCalendar("holidays")

.build();

Date firstRunTime = sched.scheduleJob(job, trigger);

// 注意:万圣节(10月31日)是假期,所以直到第二天才会运行! (11月1日)

System.out.println(job.getKey() + " 将运行于:" + firstRunTime + " 并重复:" + trigger.getRepeatCount() + " 次, 间隔 " + trigger.getRepeatInterval() / 1000 + " 秒");

System.out.println("------- 开始 Scheduler ----------------");

sched.start();

System.out.println("------- 等待 30 秒... --------------");

try {

Thread.sleep(30L * 1000L);

} catch (Exception e) {

}

sched.shutdown(true);

System.out.println("------- 关闭调度器 -----------------");

SchedulerMetaData metaData = sched.getMetaData();

System.out.println("执行了: " + metaData.getNumberOfJobsExecuted() + " 个jobs.");

}

}

CronCalendar

示例import org.quartz.*;

import org.quartz.impl.StdSchedulerFactory;

import org.quartz.impl.calendar.CronCalendar;

import java.text.SimpleDateFormat;

import java.util.Date;

import static org.quartz.JobBuilder.newJob;

import static org.quartz.SimpleScheduleBuilder.simpleSchedule;

import static org.quartz.TriggerBuilder.newTrigger;

public class SecondExample {

public static void main(String[] args) throws Exception {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println("-------  初始化 ----------");

SchedulerFactory sf = new StdSchedulerFactory();

Scheduler sched = sf.getScheduler();

// 允许执行的时间, 星期参数:"7" = "SAT",2 = MON

// 【秒】 【分钟】 【小时】 【月中天】 【月】 【周中天(1-7)】 [【年(可省略)】]

String excludeExpression;

// 这里设置禁用时间段为,每0-20之间,40-59之间不执行

excludeExpression = "0-20,40-59 * * * * ?";

CronCalendar cronCalendar = new CronCalendar(excludeExpression);

// 标明要排除的日期 每天的17点10分

sched.addCalendar("cronCalendar", cronCalendar, false, false);      // 节假日加入schedule调度器

Date runDate = new Date();

System.out.println("任务开始时间:" + sdf.format(runDate));

// 任务每10秒执行一次

JobDetail job = newJob(SimpleJob.class).withIdentity("job1", "group1").build();

SimpleTrigger trigger = newTrigger()

.withIdentity("trigger1", "group1")

.startAt(runDate)

.withSchedule(simpleSchedule()

.withIntervalInSeconds(10).repeatForever())

.modifiedByCalendar("cronCalendar")

.build();

// 触发器加入调度器

Date firstRunTime = sched.scheduleJob(job, trigger);

System.out.println(job.getKey() + " 将运行于:" + sdf.format(firstRunTime) + " 并重复:" + trigger.getRepeatCount() + " 次, 间隔 " + trigger.getRepeatInterval() / 1000 + " 秒");

System.out.println("------- 开始 Scheduler ----------------");

sched.start();

try {

System.out.println("------- 等待 120 秒(2分钟)... --------------");

Thread.sleep(120L * 1000L);

// do something

} catch (Exception e) {

}

sched.shutdown(true);

System.out.println("------- 关闭调度器 -----------------");

SchedulerMetaData metaData = sched.getMetaData();

System.out.println("~~~~~~~~~~  执行了 " + metaData.getNumberOfJobsExecuted() + " 个 jobs.");

}

}

执行结果------- 等待 120 秒(2分钟)... --------------

任务key group1.job1执行时间:2017-09-13 12:10:28

任务key group1.job1执行时间:2017-09-13 12:10:38

任务key group1.job1执行时间:2017-09-13 12:11:28

任务key group1.job1执行时间:2017-09-13 12:11:38

[INFO] 13 九月 12:12:18.158 下午 main [org.quartz.core.QuartzScheduler]

Scheduler MyScheduler_$_NON_CLUSTERED shutting down.

[INFO] 13 九月 12:12:18.158 下午 main [org.quartz.core.QuartzScheduler]

Scheduler MyScheduler_$_NON_CLUSTERED paused.

[INFO] 13 九月 12:12:18.493 下午 main [org.quartz.core.QuartzScheduler]

Scheduler MyScheduler_$_NON_CLUSTERED shutdown complete.

------- 关闭调度器 -----------------

~~~~~~~~~~  执行了 4 个 jobs.

DailyCalendar

注意:dailyCalendar.setInvertTimeRange(true); // 时间反转,为true表示只有这次时间段才会被执行,为false表示排除这时间段import org.quartz.*;

import org.quartz.impl.StdSchedulerFactory;

import org.quartz.impl.calendar.DailyCalendar;

import java.text.SimpleDateFormat;

import java.util.Date;

import static org.quartz.JobBuilder.newJob;

import static org.quartz.SimpleScheduleBuilder.simpleSchedule;

import static org.quartz.TriggerBuilder.newTrigger;

public class DailyCalendarExample {

public static void main(String[] args) throws Exception {

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println("-------  初始化 ----------");

SchedulerFactory sf = new StdSchedulerFactory();

Scheduler sched = sf.getScheduler();

DailyCalendar dailyCalendar = new DailyCalendar("12:17:30", "12:18:20");

dailyCalendar.setInvertTimeRange(true); // 时间反转,为true表示只有这次时间段才会被执行,为false表示排除这时间段

// 标明要排除的日期 每天的17点10分

sched.addCalendar("dailyCalendar", dailyCalendar, false, false);      // 节假日加入schedule调度器

Date runDate = new Date();

System.out.println("任务开始时间:" + sdf.format(runDate));

// 任务每10秒执行一次

JobDetail job = newJob(SimpleJob.class).withIdentity("job1", "group1").build();

SimpleTrigger trigger = newTrigger()

.withIdentity("trigger1", "group1")

.startAt(runDate)

.withSchedule(simpleSchedule()

.withIntervalInSeconds(10).repeatForever())

.modifiedByCalendar("dailyCalendar")

.build();

Date firstRunTime = sched.scheduleJob(job, trigger);

System.out.println(job.getKey() + " 将运行于:" + sdf.format(firstRunTime) + " 并重复:" + trigger.getRepeatCount() + " 次, 间隔 " + trigger.getRepeatInterval() / 1000 + " 秒");

System.out.println("------- 开始 Scheduler ----------------");

sched.start();

System.out.println("------- 等待 360 秒(3分钟)... --------------");

try {

Thread.sleep(360L * 1000L);

// do something

} catch (Exception e) {

}

sched.shutdown(true);

System.out.println("------- 关闭调度器 -----------------");

SchedulerMetaData metaData = sched.getMetaData();

System.out.println("~~~~~~~~~~  执行了 " + metaData.getNumberOfJobsExecuted() + " 个 jobs.");

}

}

执行结果任务开始时间:2017-09-13 12:16:37

group1.job1 将运行于:2017-09-13 12:17:37 并重复:-1 次, 间隔 10 秒

------- 开始 Scheduler ----------------

[INFO] 13 九月 12:16:37.409 下午 main [org.quartz.core.QuartzScheduler]

Scheduler MyScheduler_$_NON_CLUSTERED started.

------- 等待 360 秒(3分钟)... --------------

任务key group1.job1执行时间:2017-09-13 12:17:37

任务key group1.job1执行时间:2017-09-13 12:17:47

任务key group1.job1执行时间:2017-09-13 12:17:57

任务key group1.job1执行时间:2017-09-13 12:18:07

任务key group1.job1执行时间:2017-09-13 12:18:17

[INFO] 13 九月 12:22:37.413 下午 main [org.quartz.core.QuartzScheduler]

Scheduler MyScheduler_$_NON_CLUSTERED shutting down.

[INFO] 13 九月 12:22:37.413 下午 main [org.quartz.core.QuartzScheduler]

Scheduler MyScheduler_$_NON_CLUSTERED paused.

[INFO] 13 九月 12:22:37.769 下午 main [org.quartz.core.QuartzScheduler]

Scheduler MyScheduler_$_NON_CLUSTERED shutdown complete.

------- 关闭调度器 -----------------

~~~~~~~~~~  执行了 5 个 jobs.

HolidayCalendar

示例HolidayCalendar holidayCalendar = new HolidayCalendar();

Calendar calendar = new GregorianCalendar(2017, 10, 1);    // 2017年10月1日

holidayCalendar.addExcludedDate(calendar.getTime());

calendar = new GregorianCalendar(2018, 10, 2);            // 2018年10月2日

holidayCalendar.addExcludedDate(calendar.getTime());

holidayCalendar.getExcludedDates().forEach(date -> {

System.out.println("假期日:"+ sdf.format(date));

});

sched.addCalendar("holidays", holidayCalendar, false, false);      // 节假日加入schedule调度器

MonthlyCalendar

月日历,你可以定义一个月当中的若干天,例如你可以设置每个月的第一天触发器不进行触发,当然你还可以定义一个月当中的任何一天。// 设置2,3,4月不触发任务

MonthlyCalendar monthlyCalendar = new MonthlyCalendar();

monthlyCalendar.setDayExcluded(2, true);

monthlyCalendar.setDayExcluded(3, true);

monthlyCalendar.setDayExcluded(4, true);

sched.addCalendar("monthlys", monthlyCalendar, false, false);      // 节假日加入schedule调度器

WeeklyCalendar

星期日历,可以定义在一个星期当中的星期几几几 是不触发的日期,例如你可以定义么每个周末(星期天)触发器不触发,你也可以定义一周当中的任何一天或是几天。默认情况SATURDAY ,SUNDAY 这两天是没排除的。

下面的例子设置了每个星期四触发器不触发,并且默认情况周六和周天也是不触发的,这个是默认设置。如果需要周六周日也触发,那么把它清掉就可以了(weeklyCalendar.setDayExcluded(Calendar.SATURDAY , false)像这样)。一个需要注意的地方就是传入参数不能直接写数字星期几,因为老外的日子计算的与我们不一样,需要传入(java.util.Calendar)的常量字段,这样才准确。WeeklyCalendar weeklyCalendar = new WeeklyCalendar();

weeklyCalendar.setDayExcluded(Calendar.THURSDAY, true);

sched.addCalendar("weeklys", weeklyCalendar, false, false);      // 节假日加入schedule调度器

组合日历的使用

上面的例子都是每一个触发器(trigger)关联一个日历的例子,我们在构建触发器的时候通过.modifiedByCalendar("日历的key")关联一个注册到引擎当中的日历,这种情况已经能够满足我们大部分的需求。

但是系统的需求往往是复杂多变的,假设有这样一种情况,需要一个触发器在 每周一到周五,早8点-晚晚5点 每隔1小时执行,那么该如何使用日历呢?

其实我们不用日历,使用一个CronTrigger也是可以搞定的,我们这里只不过是抛砖引玉而已。

那让我们来写一个组合日历使用的例子:DailyCalendar dailyCalendar = new DailyCalendar("8:00:00", "17:00:00");

dailyCalendar.setInvertTimeRange(false);

WeeklyCalendar weeklyCalendar = new WeeklyCalendar(dailyCalendar);

sched.addCalendar("weeklyCalendar", weeklyCalendar, false, false);

我们写一个时间间隔的日历dailyCalendar,将其作为参数传递给weeklyCalendar就可以了,这样引擎在计算日历日期的时候会先判断dailyCalendar的时间范围,然后再判断weeklyCalendar是时间范围,当条件都满足的是否,触发器才会被触发,我们分析一下源码:@Override

public boolean isTimeIncluded(long timeStamp) {

if (excludeAll == true) {

return false;

}

// Test the base calendar first. Only if the base calendar not already

// excludes the time/date, continue evaluating this calendar instance.

if (super.isTimeIncluded(timeStamp) == false) { return false; }

java.util.Calendar cl = createJavaCalendar(timeStamp);

int wday = cl.get(java.util.Calendar.DAY_OF_WEEK);

return !(isDayExcluded(wday));

}

我们发现它首先调用if (super.isTimeIncluded(timeStamp) == false) { return false; }奥秘就在这里,我们继续看。public boolean isTimeIncluded(long timeStamp) {

if (timeStamp <= 0) {

throw new IllegalArgumentException(

"timeStamp must be greater 0");

}

if (baseCalendar != null) {

if (baseCalendar.isTimeIncluded(timeStamp) == false) { return false; }

}

return true;

}

这里先判断了baseCalendar,这个对象就是在构造参数传递进去的dailyCalendar , 也就是它先试用dailyCalendar 进行日期计算,然后自己在计算,这样就完成了日历的组合使用。

最后在补充说明一下往quartz的引擎中注册日历的方法。

addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)

这个方法有四个参数calName: 日历的名字,在构建触发器时通过modifiedByCalendar("")这里使用。

calendar:日历对象。

replace:当日历已经存在的情况下是否替换,true=替换, false=不替换 如果不替换还出现重复的情况会抛出异常。

updateTriggers:这个参数比较重要,它的意思是当一个已经存在与调度引擎中的触发器,并且已经引用了一个日历,比如:一个(触发器A)关联了一个日历,这个日历过滤每个星期日。现在过了一段时间这个日历更新了(星期六也过滤),那么这个属性是用来指示触发器是否使用新的日历。不然的话(触发器A)仍然使用旧版本的日历,如果在有新添加到引擎中的触发器才会使用新日历。

我们看一下源码:RAMJobStore 还有其它的Store原理也都一样。public void storeCalendar(String name,

Calendar calendar, boolean replaceExisting, boolean updateTriggers)

throws ObjectAlreadyExistsException {

calendar = (Calendar) calendar.clone();

synchronized (lock) {

Object obj = calendarsByName.get(name);

if (obj != null && replaceExisting == false) {

throw new ObjectAlreadyExistsException(

"Calendar with name '" + name + "' already exists.");

} else if (obj != null) {

calendarsByName.remove(name);

}

calendarsByName.put(name, calendar);

if(obj != null && updateTriggers) {

Iterator trigs = getTriggerWrappersForCalendar(name).iterator();

while (trigs.hasNext()) {

TriggerWrapper tw = trigs.next();

OperableTrigger trig = tw.getTrigger();

boolean removed = timeTriggers.remove(tw);

trig.updateWithNewCalendar(calendar, getMisfireThreshold());

if(removed) {

timeTriggers.add(tw);

}

}

}

}

}

参考文章:http://www.cnblogs.com/daxin/p/3925619.html

智能跳过节假日算法java_Quartz 定时任务使用 —— 排除指定节假日时间执行任务(十一)...相关推荐

  1. 智能跳过节假日算法java_java计算两个日期之前的天数实例(排除节假日和周末)...

    java计算两个日期之前的天数实例(排除节假日和周末) 发布时间:2020-09-02 23:07:01 来源:脚本之家 阅读:108 作者:jingxian 如题所说,计算两个日期之前的天数,排除节 ...

  2. 智能跳过节假日算法java_java计算两个日期之间的天数,排除节假日和周末

    如题所说,计算两个日期之前的天数,排除节假日和周末.这里天数的类型为double,因为该功能实现的是请假天数的计算,有请一上午假的为0.5天. 不够很坑的是每个日期都要查询数据库,感觉很浪费时间. 原 ...

  3. java中求某个时间跳过节假日和周末

    跳过节假日和周末不上班案例 方式一:{LIst数据目前需要手动维护} /*** 算出两个时间间隔天数,遇上节假日和不上班周末[可能调休需要上]往后推* @param beginTime* @param ...

  4. Java节假日接口,增加天数跳过节假日

    在项目中遇到增加天数跳过节假日的需求,网上查询各种api之后,决定自己开发一个小demo. 此处记载开发思路. 一.初始化每年的日期,并标记工作日.周末.节假日.这里每年初始化一次,然后手动更改日期的 ...

  5. 计算有效工作日(跳过节假日)

    在实际开发过程中,我们很多时候会遇到节假日处理的问题.由于前段时间工作需要,所以通过各种平台搜集资料,整理出下面的代码. 备注:主要是给定一个初始日期,然后给定一个时间范围,要求自动跳过节假日以及双休 ...

  6. 能跳过节假日的闹钟_苏宁小Biu智能闹钟体验:聪明好看,别具风格的“小物件”...

    在智能音箱领域,各家厂商都有很多代表性的产品,比如说小米小爱音箱.天猫精灵.华为小艺智能音箱.荣耀YOYO智能音箱等等,这些智能音箱产品都有一个共同的特点,它们都是以音箱的形式出现在市面上. 苏宁此前 ...

  7. 节假日api_iOS能跳过节假日的晚安闹钟捷径

    捷径作为一个非常便利的工具,作为一个不想学习的人,自习时间就会无聊到开始玩捷径.一直以来,节假日闹钟不会自动跳过的问题是困扰着iOS用户的一个问题,专门做一个捷径每天去点一遍--算了,太智障.这个问题 ...

  8. excel工作量清单计算开始、结束时间,自动跳过节假日

    工作量清单,excel转为 mpp,自动跳过非工作日 复制任务名称.工时(工作量汇总(人/日 *8)).设置第一个开始时间.资源名称.前置任务 之后会自动计算出来.

  9. 能跳过节假日的闹钟_非人哉:叫九月起床有多难?闹钟坏了许多个,哮天去叫被打了一顿...

    赖床是很多人都会有的习惯,但像九月这种,在<非人哉>的世界中独一份.那么叫九月起床到底有多难呢?就是闹钟都坏了许多个,还专门有个地方叫闹钟之墓,这里放着都是被九月丢掉的闹钟.就是哮天这种叫 ...

最新文章

  1. mysql 修改某字段的格式为 utf8mb4
  2. R语言set.seed函数的意义及实战
  3. Swift中@IBDesignable/@IBInspectable的使用
  4. alphogo 理解
  5. 【最新合集】编译原理习题(含答案)_答案全集_MOOC慕课 哈工大陈鄞
  6. python进程和线程
  7. 关于n对角矩阵数据结构_机器学习与线性代数 - 特殊矩阵
  8. 服务器虚拟化 需求,虚拟化的优势与需求分析
  9. setautocommit(false) 还是自动提交了_Hexo和GitPages搭建博客并自动发布
  10. Java当中定时器使用
  11. python 微服务 网关_关于API微服务网关
  12. 微型计算机鼠标连接,解决无线鼠标重新对码问题
  13. Loki 学习总结(1)—— Loki 中小项目日志系统的不二之选
  14. antdesign 柱状图_010-ant design pro advanced 图表
  15. html5 制作书架展示 PHP,html5制作转盘的详解及实例
  16. leetcode1646. 获取生成数组中的最大值
  17. 【JC-2 DC220V冲击继电器】
  18. 且行且走(8月22日,23日)
  19. com.jcraft.jsch.JSchException: Auth fail
  20. Window类似Alfred的搜索软件——Wox

热门文章

  1. flash player 10 音频新API使用:调节音高(pitch)
  2. 网页设计-[CSS+DIV设计实例:超酷的竖排导航栏 ]
  3. sharepoint 特别信息 --- 自个乐去吧~~
  4. 微信jssdk在iframe页面失效问题的解决措施
  5. 解决SQLite异常:library routine called out of sequence
  6. 关于mapper接口与mapper.xml文件在同包运行找不到问题解决
  7. Pycharm 加载pygame解决方案
  8. 电商指标详细介绍和推荐系统常用评估指标
  9. 【推荐实践】Flink 状态(State)管理在推荐场景中的应用
  10. 你看得懂的海明码校验和纠错原理