【Quartz】深入Job、JobDetail、JobDataMap、Trigger

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。

Quartz API核心接口有:

  • Scheduler – 與scheduler交互的主要API;
  • Job – 你通過scheduler執行任務,你的任務類需要實現的接口;
  • JobDetail – 定義Job的實例;
  • Trigger – 觸發Job的執行;
  • JobBuilder – 定義和創建JobDetail實例的接口;
  • TriggerBuilder – 定義和創建Trigger實例的接口;
  • ?

本文工程免費下載

一、Job

?

??????? 在上一節中,Job中定義了實際的業務邏輯,而JobDetail包含Job相關的配置信息。在Quartz中,每次Scheduler執行Job時,在調用其execute()方法之前,它需要先根據JobDetail提供的Job類型創建一個Job class的實例,在任務執行完以后,Job class的實例會被丟棄,Jvm的垃圾回收器會將它們回收。因此編寫Job的具體實現時,需要注意:

(1) 它必須具有一個無參數的構造函數;

(2) 它不應該有靜態數據類型,因為每次Job執行完以后便被回收,因此在多次執行時靜態數據沒法被維護。

??????? 在JobDetail中有這么一個成員JobDataMap,JobDataMap是Java Map接口的具體實現,并添加了一些便利的方法用于存儲與讀取原生類型數據,里面包含了當Job實例運行時,你希望提供給它的所有數據對象。

???????? 可以借助JobDataMap為Job實例提供屬性/配置,可以通過它來追蹤Job的執行狀態等等。對于第一種情況,可以在創建Job時,添加JobDataMap數據,在Job的execute()中獲取數據,第二種,則可以在Listener中通過獲取JobDataMap中存儲的狀態數據追蹤Job的執行狀態。

一個實現了Job接口的Java類就能夠被調度器執行。接口如下:

?

 
  1. packageorg.quartz;
  2. publicinterface Job {
  3. public void execute(JobExecutionContext context) throwsJobExecutionException;
  4. }


??????? 很簡的,當Job的trigger觸發時,Job的execute(..)方法就會被調度器調用。被傳遞到這個方法里來的JobExecutionContext對象提供了帶有job運行時的信息:執行它的調度器句柄、觸發它的觸發器句柄、job的JobDetail對象和一些其他的項。JobDetail對象是Job在被加到調度器里時所創建的,它包含有很多的Job屬性設置,和JobDataMap一樣,可以用來存儲job實例時的一些狀態信息。

?

比如如下任務類

?

?

?

 
[java]?view plain?copy
  1. <code?class="language-java">package?com.mucfc;??
  2. ??
  3. import?java.util.Date;??
  4. ??
  5. import?org.apache.commons.logging.Log;??
  6. import?org.apache.commons.logging.LogFactory;??
  7. import?org.quartz.Job;??
  8. import?org.quartz.JobDetail;??
  9. import?org.quartz.JobExecutionContext;??
  10. import?org.quartz.JobExecutionException;??
  11. ??
  12. public?class?NewJob?implements?Job{??
  13. ?????static?Log?logger?=?LogFactory.getLog(NewJob.class);?????
  14. ????@Override??
  15. ????public?void?execute(JobExecutionContext?context)?throws?JobExecutionException?{??
  16. ?????????System.err.println("Hello!??NewJob?is?executing."+new?Date()?);??
  17. ????//取得job詳情??
  18. ?????????JobDetail?jobDetail?=?context.getJobDetail();?????
  19. ?????????//?取得job名稱??
  20. ?????????String?jobName?=?jobDetail.getClass().getName();??
  21. ?????????logger.info("Name:?"?+?jobDetail.getClass().getSimpleName());?????
  22. ?????????//取得job的類??
  23. ?????????logger.info("Job?Class:?"?+?jobDetail.getJobClass());?????
  24. ?????????//取得job開始時間??
  25. ?????????logger.info(jobName?+?"?fired?at?"?+?context.getFireTime());?????
  26. ????????logger.info("Next?fire?time?"?+?context.getNextFireTime());???
  27. ????}??
  28. ??
  29. }??
  30. </code>??

?


??????? 當 Scheduler 調用一個 Job,一個 JobexecutionContext 傳遞給 execute() 方法。JobExecutionContext 對象讓 Job 能訪問 Quartz 運行時候環境和 Job 本身的明細數據。這就類似于在 Java Web 應用中的 servlet 訪問 ServletContext 那樣。通過 JobExecutionContext,Job 可訪問到所處環境的所有信息,包括注冊到 Scheduler 上與該 Job 相關聯的 JobDetail 和 Triiger。

?

?

?

?

二、JobDetail?

?

JobDetail實例是通過JobBuilder類創建的

可以通過導入該類下的所有靜態方法

       import static org.quartz.JobBuilder.*;

然后是創建:

 
  1. 創建一個JobDetail實例
  2. JobDetail jobDetail = newJob(NewJob.class).withIdentity("job1_1", "jGroup1").build();

如果不導入靜態包:

那么就要用:

 
  1. 創建一個JobDetail實例
  2. obDetail jobDetail = JobBuilder.newJob(NewJob.class).withIdentity("job1_1", "jGroup1").build();

?

對于部署在 Scheduler 上的每一個 Job 只創建了一個 JobDetail 實例。JobDetail 是作為 Job 實例進行定義的。注意到在代碼 中不是把 Job 對象注冊到 Scheduler;實際注冊的是一個 JobDetail 實例。

?

 
  1. public void startSchedule() {
  2. try {
  3. // 1、創建一個JobDetail實例,指定Quartz
  4. JobDetail jobDetail = JobBuilder.newJob(NewJob.class) // 任務執行類
  5. .withIdentity("job1_1", "jGroup1")// 任務名,任務組
  6. .build();
  7. //2、創建Trigger
  8. SimpleScheduleBuilder builder=SimpleScheduleBuilder.simpleSchedule()
  9. .withIntervalInSeconds(5) //設置間隔執行時間
  10. .repeatSecondlyForTotalCount(5);//設置執行次數
  11. Trigger trigger=TriggerBuilder.newTrigger().withIdentity(
  12. "trigger1_1","tGroup1").startNow().withSchedule(builder).build();
  13. //3、創建Scheduler
  14. Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
  15. //4、調度執行
  16. scheduler.scheduleJob(jobDetail, trigger);
  17. scheduler.start();
  18. } catch (SchedulerException e) {
  19. e.printStackTrace();
  20. }
  21. }

結果:

?

從上面的代碼中可以看JobDetail 被加到 Scheduler 中了,而不是 job。Job 類是作為 JobDetail 的一部份,但是它直到 Scheduler 準備要執行它的時候才會被實例化的。

?

直到執行時才會創建 Job 實例?

Job 的實例要到該執行它們的時候才會實例化出來。每次 Job 被執行,一個新的 Job 實例會被創建。其中暗含的意思就是你的 Job 不必擔心線程安全性,因為同一時刻僅有一個線程去執行給定 Job 類的實例,甚至是并發執行同一 Job 也是如此。

?

?

?

?????? 可以看到,我們傳給scheduler一個JobDetail實例,因為我們在創建JobDetail時,將要執行的job的類名傳給了JobDetail,所以scheduler就知道了要執行何種類型的job;每次當scheduler執行job時,在調用其execute(…)方法之前會創建該類的一個新的實例;執行完畢,對該實例的引用就被丟棄了,實例會被垃圾回收;這種執行策略帶來的一個后果是,job必須有一個無參的構造函數(當使用默認的JobFactory時);另一個后果是,在job類中,不應該定義有狀態的數據屬性,因為在job的多次執行中,這些屬性的值不會保留。

??????? 那么如何給job實例增加屬性或配置呢?如何在job的多次執行中,跟蹤job的狀態呢?答案就是:JobDataMap,JobDetail對象的一部分。

?

三、JobDataMap

???????? JobDataMap中可以包含不限量的(序列化的)數據對象,在job實例執行的時候,可以使用其中的數據;JobDataMap是Java Map接口的一個實現,額外增加了一些便于存取基本類型的數據的方法。

將job加入到scheduler之前,在構建JobDetail時,可以將數據放入JobDataMap,如下示例:

?

?

 
  1. package com.mucfc;
  2. import org.quartz.Job;
  3. import org.quartz.JobDataMap;
  4. import org.quartz.JobExecutionContext;
  5. import org.quartz.JobExecutionException;
  6. import org.quartz.JobKey;
  7. public class NewJob2 implements Job{
  8. @Override
  9. public void execute(JobExecutionContext context) throws JobExecutionException {
  10. JobKey key = context.getJobDetail().getKey();
  11. JobDataMap dataMap = context.getJobDetail().getJobDataMap();
  12. String jobSays = dataMap.getString("jobSays");
  13. float myFloatValue = dataMap.getFloat("myFloatValue");
  14. System.out.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
  15. }
  16. }

?

在job的執行過程中,可以從JobDataMap中取出數據,如下示例:

?

 
  1. package com.mucfc;
  2. import org.quartz.JobBuilder;
  3. import org.quartz.JobDetail;
  4. import org.quartz.Scheduler;
  5. import org.quartz.SchedulerException;
  6. import org.quartz.SimpleScheduleBuilder;
  7. import org.quartz.Trigger;
  8. import org.quartz.TriggerBuilder;
  9. import org.quartz.impl.StdSchedulerFactory;
  10. public class Test {
  11. public void startSchedule() {
  12. try {
  13. // 1、創建一個JobDetail實例,指定Quartz
  14. JobDetail jobDetail = JobBuilder.newJob(NewJob.class) // 任務執行類
  15. .withIdentity("job1_1", "jGroup1")// 任務名,任務組
  16. .build();
  17. JobDetail jobDetail2 = JobBuilder.newJob(NewJob2.class)
  18. .withIdentity("job1_2", "jGroup1")
  19. .usingJobData("jobSays", "Hello World!")
  20. .usingJobData("myFloatValue", 3.141f)
  21. .build();
  22. //2、創建Trigger
  23. SimpleScheduleBuilder builder=SimpleScheduleBuilder.simpleSchedule()
  24. .withIntervalInSeconds(5) //設置間隔執行時間
  25. .repeatSecondlyForTotalCount(5);//設置執行次數
  26. Trigger trigger=TriggerBuilder.newTrigger().withIdentity(
  27. "trigger1_1","tGroup1").startNow().withSchedule(builder).build();
  28. //3、創建Scheduler
  29. Scheduler scheduler=StdSchedulerFactory.getDefaultScheduler();
  30. //4、調度執行
  31. scheduler.scheduleJob(jobDetail2, trigger);
  32. scheduler.start();
  33. } catch (SchedulerException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. public static void main(String[] args) {
  38. Test test=new Test();
  39. test.startSchedule();
  40. }
  41. }


結果:

?

?

四、 Trigger

??????? Trigger對象是用來觸發執行Job的。當調度一個job時,我們實例一個觸發器然后調整它的屬性來滿足job執行的條件。觸發器也有一個和它相關的JobDataMap,它是用來給被觸發器觸發的job傳參數的。Quartz有一些不同的觸發器類型,不過,用得最多的是SimpleTrigger和CronTrigger。

??????? 如果我們需要在給定時刻執行一次job或者在給定時刻觸發job隨后間斷一定時間不停的執行的話,SimpleTrigger是個簡單的解決辦法;如果我們想基于類似日歷調度的觸發job的話,比如說,在每個星期五的中午或者在每個月第10天的10:15觸發job時,CronTrigger是很有用的。

???????? 為什么用jobs和triggers呢?很多任務調度器并沒有任務和觸發器的概念,一些任務調度器簡單定義一個“job”為在一個執行時間伴隨一些小任務標示,其他的更像Quartz里job和trigger對象的聯合體。在開發Quartz時,開發者們決定,在調度時間表和在這上面運行的工作應該分開。這是很有用的。

??????? 例如,job能夠獨立于觸發器被創建和儲存在任務調度器里,并且,很多的觸發器能夠與同一個job關聯起來。這個松耦合的另一個好處就是在與jobs關聯的觸發器終止后,我們能夠再次配置保留在調度器里的jobs,這樣的話,我們能夠再次調度這些jobs而不需要重新定義他們。我們也可以在不重新定義一個關聯到job的觸發器的情況下,修改或替代它。

???????? 當Jobs和triggers被注冊到Quartz的調度器里時,他們就有了唯一標示符。他們也可以被放到“groups”里,Groups是用來組織分類jobs和triggers的,以便今后的維護。在一個組里的job和trigger的名字必須是唯一的,換句話說,一個job和trigger的全名為他們的名字加上組名。如果把組名置為”null”,系統會自動給它置為Scheduler.DEFAULT_GROUP

?

Scheduler在使用之前需要實例化。一般通過SchedulerFactory來創建一個實例。有些用戶將factory的實例保存在JNDI中,但直接初始化,然后使用該實例也許更簡單(見下面的示例)。

scheduler實例化后,可以啟動(start)、暫停(stand-by)、停止(shutdown)。注意:scheduler被停止后,除非重新實例化,否則不能重新啟動;只有當scheduler啟動后,即使處于暫停狀態也不行,trigger才會被觸發(job才會被執行)。

?

五、SimpleTrigger的介紹

正如其名所示,SimpleTrigger對于設置和使用是最為簡單的一種 QuartzTrigger。它是為那種需要在特定的日期/時間啟動,且以一個可能的間隔時間重復執行 n 次的 Job 所設計的。
我們前面已經在一個簡單的Quartz的例子里使用過了SimpleTrigger,我們通過

 
  1. SimpleScheduleBuilder builder=SimpleScheduleBuilder.simpleSchedule()
  2. //設置間隔執行時間
  3. .withIntervalInSeconds(5)
  4. //設置執行次數
  5. .withRepeatCount(4);
 
  1. Trigger trigger=TriggerBuilder.newTrigger().withIdentity(
  2. "trigger1_1","tGroup1").startNow().withSchedule(builder).build();


或者無限執行

?

?

 
  1. SimpleScheduleBuilder builder=SimpleScheduleBuilder.simpleSchedule()
  2. //設置間隔執行時間
  3. .withIntervalInSeconds(5)
  4. //設置執行次數
  5. .repeatForever();
  6. Trigger trigger=TriggerBuilder.newTrigger().withIdentity(
  7. "trigger1_1","tGroup1").startNow().withSchedule(builder).build();


對于Quartz而言,它還不能滿足我們的觸發情況,所以它僅僅是用于一些簡單的觸發情況;

?

?

?

六、CronTrigger

??????? CronTrigger 允許設定非常復雜的觸發時間表。然而有時也許不得不使用兩個或多個 SimpleTrigger來滿足你的觸發需求,這時候,你僅僅需要一個 CronTrigger 實例就夠了。顧名思義,CronTrigger 是基于 Unix類似于 cron 的表達式。例如,你也許有一個 Job,要它在星期一和星期五的上午 8:00-9:00間每五分鐘執行一次。假如你試圖用 SimpleTrigger 來實現,你或許要為這個 Job 配置多個Trigger。然而,你可以使用如下的表達式來產生一個遵照這個時間表觸發的 Trigger;
比如:

?

?

 
  1. // 創建Trigger
  2. CronScheduleBuilder builder2 = CronScheduleBuilder.cronSchedule("0 0/5 8 * * *");//8:00-8:55,每隔5分鐘執行
  3. /**
  4. builder2 = CronScheduleBuilder.dailyAtHourAndMinute(12, 30);
  5. **/
  6. Trigger trigger=TriggerBuilder.newTrigger().withIdentity("trigger1_1","tGroup1").startNow().withSchedule(builder2).build();

?

?

??????? 因為 CronTrigger內建的如此強的靈活性,也與生俱來可用于創建幾乎無所限制的表達式,且因為支持unix的cron表達式,則做為企業應用,我們的操作系統一般也都以unxi操作系統為主,所以掌握CronTrigger的使用費用有必要,我們將在后面對CronTrigger 進行詳細的介紹。cron 表達式的格式見下一節。

七、Job與Trigger的關系

??????? 大家都知道,一個作業,比較重要的三個要素就是Schduler,jobDetail,Trigger;而Trigger對于job而言就好比一個驅動器;沒有觸發器來定時驅動作業,作業就無法運行;對于Job而言,一個job可以對應多個Trigger,但對于Trigger而言,一個Trigger只能對應一個job;所以一個Trigger 只能被指派給一個 Job;如果你需要一個更復雜的觸發計劃,你可以創建多個 Trigger 并指派它們給同一個 Job。Scheduler 是基于配置在 Job上的 Trigger 來決定正確的執行計劃的,下面就是為同一個 JobDetail 使用多個Trigger;

?

轉自:http://blog.csdn.net/evankaka

本文工程免費下載

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/448968.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/448968.shtml
英文地址,請注明出處:http://en.pswp.cn/news/448968.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Apache Accumulo 1.9.3 發布,高性能 K/V 存儲方案

Apache Accumulo 1.9.3 發布了&#xff0c;Apache Accumulo 是一個可靠的、可伸縮的、高性能的排序分布式的 Key-Value 存儲解決方案&#xff0c;基于單元訪問控制以及可定制的服務器端處理。使用 Google BigTable 設計思路&#xff0c;基于 Apache Hadoop、Zookeeper 和 Thrif…

圖形界面上機作業

1、 制作一個如圖所示的界面&#xff08;使用FlowLayout布局&#xff09;&#xff0c;不要求實現功能。 2、設計一個用標簽、文本行與按鈕來登錄的界面&#xff08;用GridLayout布局方式&#xff09;。如圖所示。 轉載于:https://www.cnblogs.com/quan-2723365710/p/10881691.h…

【Quartz】Spring3.2.9 + Quqrtz2.2.1 實現定時實例

一、工程創建 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1、新建一個工程&#xff0c;導入相應的包Spring3.2.9Quqrtz2.2.1commons-logging 集成起來比較簡單,對線程無需任何理解&a…

第七次發博不知道用什么標題好

一、this關鍵字,想起之前總是搞不懂this.name是where.name,嗯&#xff01;第二個name就是形參name,所以這句話就是講形參name的值傳給成員變量name private void setName(String name ){ this.namename; } 二、構造方法&#xff1a;1.沒有返回值 2.名稱要與本類名稱相同&#x…

Django框架之Filters(過濾器)、母版的使用

在Django的模板語言中&#xff0c;通過使用 過濾器 來改變變量的顯示。 過濾器的語法&#xff1a; {{ value|filter_name:參數 }} 使用管道符"|"來應用過濾器。 注意事項&#xff1a; 過濾器支持“鏈式”操作。即一個過濾器的輸出作為另一個過濾器的輸入。過濾器可以…

不花錢就補足營養的8妙招

如今&#xff0c;人們越來越注重保健&#xff0c;為了補充營養&#xff0c;一些人不惜花重金買各種名貴保健品食用。其實&#xff0c;人體所需要的很多營養素就在我們身邊&#xff0c;它們既不昂貴&#xff0c;也不稀缺&#xff0c;只需我們信手拈來。 葉酸 每人每日應補充…

PostgreSQL 自定義復合類型(composite type) deform引入的額外開銷

標簽 PostgreSQL , UDT , 自定義類型 背景 PG 允許用戶自定義復合類型&#xff0c;自定義復合類型由多個類型組成&#xff0c;使用時會引入一些deform的開銷。 例子 postgres# create unlogged table t(id int, c1 tp1, c2 int); CREATE TABLE postgres# insert into t sele…

第十二周作業

這個作業屬于那個課程c語言這個作業要求在哪里https://edu.cnblogs.com/campus/zswxy/computer-scienceclass4-2018/homework/3236我在這個課程的目標是學習掌握單向鏈表&#xff0c;掌握二級指針的概念&#xff0c;以及指針數組這個作業在哪個具體方面幫助我實現目標前面3道題…

職場上的「小人」教我的事

很多人的小指頭都會帶一個尾戒&#xff0c;不是白金就是黃金&#xff0c;大部份是簡單的一環&#xff0c;沒有太多裝飾&#xff0c;也很少鑲寶石&#xff0c;目的不在于當作飾品&#xff0c;而是保命之用。 也有人不習慣戴尾戒&#xff0c;而是把指甲留得長長的&#xff0c;長到…

【Quartz】插件的使用

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 Quartz 框架提供了幾種用于擴展平臺能力的方式。通過使用各種 "鉤子" (通常指的就是擴展點)&#xff0c;Quartz 變得很容易被擴…

自動化運維平臺(前端vue)

前端的大體流程&#xff1a;首先是Login登錄組件&#xff0c;當輸入用戶名和密碼之后&#xff0c;發送post請求到后端&#xff0c;然后根據返回的數據的是否正常&#xff0c;如果正常&#xff0c;將返回的token以及用戶名保存到sessionStorage中&#xff0c;并使用導航守衛進行…

老程序員的下場

長期從事編程活動的程序員都期望在50多歲時能爬到一個足夠高的職位&#xff0c;或者能順利的退休。 但我在這里討論的可能是一個你還沒有想過的問題&#xff1a;如果到那時你失業了呢&#xff1f; 50多歲時你的職業仕途會成為一個問題。如果你有很好的技術&#xff0c;有人雇…

Quartz 之入門示例

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 環境:XPMyeclipse6.5JDK1.6 quartz官網:http://www.quartz-scheduler.org/ 參考資料 1 Quartz任務調度快速入門 http://www.blogjava…

CSS3最顛覆性的動畫效果,基本屬性[3D]

和2D一樣也是transform 即變形 1)rotateX rotateY rotateZ&#xff08;也可以用transform-origin來設置旋轉中心點&#xff09; 2)透視(perspective) 給父親加透視&#xff0c;透視就是模擬眼睛到物體的距離&#xff0c;近大遠小&#xff0c;即數值越小&#xff0c;3D越明顯 理…

解決報錯 :A component required a bean of type ‘gentle.test.Show‘ that could not be found

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 啟動工程失敗&#xff0c;報錯如題&#xff1a; A component required a bean of type gentle.test.Show that could not be found.…

30天提升技術人的寫作力-第十七天

約束作者在漫長的創作過程中&#xff0c;不偏離寫作目標。當寫的字數在十幾萬以上時&#xff0c;沒有先規劃&#xff0c;就會陷入混亂&#xff0c;發生注入重復、疏漏、相關知識未講解等問題。制作長文章或書籍的大綱&#xff0c;需要使用發散收斂工具。所謂發散是多方向、多思…

白領必看的十種職場致命毒藥

找到一個合適的工作可能需要3到15個月不等的時間——然而丟掉飯碗只需要幾天或幾周。下面是10種職場毒藥的特點&#xff1a;       1、人際交往技能不佳       討人喜歡會大有幫助。研究均表明和那些能力強而呆板的人相比&#xff0c;人們一致而且不可遏制地更喜歡和…

eclipse中folder、source folder和package的區別

今天做ssm項目時&#xff0c;突然發現了這個問題&#xff0c;特別好奇&#xff0c;sqlSessionFactory.xml文件如何找到&#xff1a; 1、放在src/hello目錄下&#xff1a; InputStream inputStream Resources.getResourceAsStream("./hello/sqlMapperConfig.xml"); 2…

解決.quartz.ObjectAlreadyExistsException: Unable to store Job : ‘jyGroup.jyJob‘, because one already

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 1. 報錯如題&#xff1a; 定時任務出現異常 &#xff1a; org.quartz.ObjectAlreadyExistsException: Unable to store Job : jyGroup.…

WeMos-D1R2的使用

2019獨角獸企業重金招聘Python工程師標準>>> WeMos介紹 WeMos-D1R2一個基于ESP8266-12 Wifi模塊的Arduino-UNO開發板。也就是說&#xff0c;WeMos-D1R2是一個具有wifi功能的Arduino開發板&#xff0c;但WeMos-D1R2與Arduino-UNO的引腳不是一一對應的&#xff0c;其對…