diff --git "a/blog-site/content/posts/essays/\345\256\232\346\227\266\344\273\273\345\212\241\345\217\257\350\247\206\345\214\226\347\256\241\347\220\206.md" "b/blog-site/content/posts/codes/Java\345\256\232\346\227\266\344\273\273\345\212\241\345\217\257\350\247\206\345\214\226\347\256\241\347\220\206.md" similarity index 99% rename from "blog-site/content/posts/essays/\345\256\232\346\227\266\344\273\273\345\212\241\345\217\257\350\247\206\345\214\226\347\256\241\347\220\206.md" rename to "blog-site/content/posts/codes/Java\345\256\232\346\227\266\344\273\273\345\212\241\345\217\257\350\247\206\345\214\226\347\256\241\347\220\206.md" index 7ff6eddc..a5e61568 100644 --- "a/blog-site/content/posts/essays/\345\256\232\346\227\266\344\273\273\345\212\241\345\217\257\350\247\206\345\214\226\347\256\241\347\220\206.md" +++ "b/blog-site/content/posts/codes/Java\345\256\232\346\227\266\344\273\273\345\212\241\345\217\257\350\247\206\345\214\226\347\256\241\347\220\206.md" @@ -1,8 +1,8 @@ --- -title: "定时任务可视化管理" +title: "Java定时任务可视化管理" date: 2023-09-09 draft: false -tags: ["应用","设计"] +tags: ["应用","设计","Java","小程序"] slug: "scheduled-job" --- diff --git "a/blog-site/content/posts/essays/IDEA\345\270\270\347\224\250\351\205\215\347\275\256\345\217\212\344\275\277\347\224\250\346\212\200\345\267\247.md" "b/blog-site/content/posts/essays/IDEA\345\270\270\347\224\250\351\205\215\347\275\256\345\217\212\344\275\277\347\224\250\346\212\200\345\267\247.md" index 369d481e..d233d2db 100644 --- "a/blog-site/content/posts/essays/IDEA\345\270\270\347\224\250\351\205\215\347\275\256\345\217\212\344\275\277\347\224\250\346\212\200\345\267\247.md" +++ "b/blog-site/content/posts/essays/IDEA\345\270\270\347\224\250\351\205\215\347\275\256\345\217\212\344\275\277\347\224\250\346\212\200\345\267\247.md" @@ -2,7 +2,7 @@ title: "IDEA常用配置及使用技巧" date: 2022-12-16 draft: false -tags: ["技巧"] +tags: ["随笔"] slug: "dev-idea" --- ## 下载 diff --git "a/blog-site/content/posts/essays/Java\344\270\255\345\270\270\347\224\250\347\272\277\347\250\213\345\256\211\345\205\250\347\232\204\351\233\206\345\220\210.md" "b/blog-site/content/posts/essays/Java\344\270\255\345\270\270\347\224\250\347\272\277\347\250\213\345\256\211\345\205\250\347\232\204\351\233\206\345\220\210.md" index 9cd5696b..1e11ce9c 100644 --- "a/blog-site/content/posts/essays/Java\344\270\255\345\270\270\347\224\250\347\272\277\347\250\213\345\256\211\345\205\250\347\232\204\351\233\206\345\220\210.md" +++ "b/blog-site/content/posts/essays/Java\344\270\255\345\270\270\347\224\250\347\272\277\347\250\213\345\256\211\345\205\250\347\232\204\351\233\206\345\220\210.md" @@ -2,7 +2,7 @@ title: "Java中常用线程安全的集合" date: 2020-04-05 draft: false -tags: ["线程", "Java", "集合"] +tags: ["多线程", "Java", "集合","随笔"] slug: "java-thread-collection" --- diff --git "a/blog-site/content/posts/essays/Java\344\270\255\345\270\270\350\247\201\347\232\204\350\257\255\346\263\225\347\263\226.md" "b/blog-site/content/posts/essays/Java\344\270\255\345\270\270\350\247\201\347\232\204\350\257\255\346\263\225\347\263\226.md" index 5236e4ca..7742d11b 100644 --- "a/blog-site/content/posts/essays/Java\344\270\255\345\270\270\350\247\201\347\232\204\350\257\255\346\263\225\347\263\226.md" +++ "b/blog-site/content/posts/essays/Java\344\270\255\345\270\270\350\247\201\347\232\204\350\257\255\346\263\225\347\263\226.md" @@ -2,7 +2,7 @@ title: "Java中常见的语法糖" date: 2024-07-14 draft: false -tags: ["Java"] +tags: ["Java","随笔"] slug: "java-syntax-sugar" --- diff --git "a/blog-site/content/posts/essays/Java\344\270\255\347\232\204\351\224\201\351\203\275\346\234\211\344\273\200\344\271\210.md" "b/blog-site/content/posts/essays/Java\344\270\255\347\232\204\351\224\201\351\203\275\346\234\211\344\273\200\344\271\210.md" index 75a49904..cd9f5635 100644 --- "a/blog-site/content/posts/essays/Java\344\270\255\347\232\204\351\224\201\351\203\275\346\234\211\344\273\200\344\271\210.md" +++ "b/blog-site/content/posts/essays/Java\344\270\255\347\232\204\351\224\201\351\203\275\346\234\211\344\273\200\344\271\210.md" @@ -2,7 +2,7 @@ title: "Java中的锁都有什么" date: 2020-04-07 draft: false -tags: ["线程", "Java"] +tags: ["多线程", "Java","随笔"] slug: "java-locks" --- diff --git "a/blog-site/content/posts/essays/Vue2.0\345\237\272\347\241\200\345\205\245\351\227\250\347\254\224\350\256\260.md" "b/blog-site/content/posts/essays/Vue2.0\345\237\272\347\241\200\345\205\245\351\227\250\347\254\224\350\256\260.md" index 027542e6..1a8e0ad9 100644 --- "a/blog-site/content/posts/essays/Vue2.0\345\237\272\347\241\200\345\205\245\351\227\250\347\254\224\350\256\260.md" +++ "b/blog-site/content/posts/essays/Vue2.0\345\237\272\347\241\200\345\205\245\351\227\250\347\254\224\350\256\260.md" @@ -2,7 +2,7 @@ title: "Vue2.0基础入门笔记" date: 2019-05-23 draft: false -tags: ["Vue","笔记"] +tags: ["随笔"] slug: "vue2-note" --- diff --git "a/blog-site/content/posts/essays/\344\275\277\347\224\250Hugo\343\200\201Github Pages\346\220\255\345\273\272\350\207\252\345\267\261\347\232\204\345\215\232\345\256\242.md" "b/blog-site/content/posts/essays/\344\275\277\347\224\250Hugo\343\200\201Github Pages\346\220\255\345\273\272\350\207\252\345\267\261\347\232\204\345\215\232\345\256\242.md" index 25933e95..21cabff8 100644 --- "a/blog-site/content/posts/essays/\344\275\277\347\224\250Hugo\343\200\201Github Pages\346\220\255\345\273\272\350\207\252\345\267\261\347\232\204\345\215\232\345\256\242.md" +++ "b/blog-site/content/posts/essays/\344\275\277\347\224\250Hugo\343\200\201Github Pages\346\220\255\345\273\272\350\207\252\345\267\261\347\232\204\345\215\232\345\256\242.md" @@ -2,7 +2,7 @@ title: "使用Hugo、Github Pages搭建自己的博客" date: 2024-04-15 draft: false -tags: ["其他"] +tags: ["随笔"] slug: "build-blog" --- diff --git "a/blog-site/content/posts/essays/\345\246\202\344\275\225\345\274\272\345\210\266\345\244\215\345\210\266\347\275\221\347\253\231\346\226\207\345\255\227.md" "b/blog-site/content/posts/essays/\345\246\202\344\275\225\345\274\272\345\210\266\345\244\215\345\210\266\347\275\221\347\253\231\346\226\207\345\255\227.md" index 6aa66423..36e28b51 100644 --- "a/blog-site/content/posts/essays/\345\246\202\344\275\225\345\274\272\345\210\266\345\244\215\345\210\266\347\275\221\347\253\231\346\226\207\345\255\227.md" +++ "b/blog-site/content/posts/essays/\345\246\202\344\275\225\345\274\272\345\210\266\345\244\215\345\210\266\347\275\221\347\253\231\346\226\207\345\255\227.md" @@ -2,7 +2,7 @@ title: "如何强制复制网站上的文字" date: 2024-03-14 draft: false -tags: ["其他"] +tags: ["随笔"] slug: "force-copy-website-text" --- diff --git "a/blog-site/content/posts/essays/\345\277\253\351\200\237\346\211\223\345\274\200Github.md" "b/blog-site/content/posts/essays/\345\246\202\344\275\225\345\277\253\351\200\237\346\211\223\345\274\200Github.md" similarity index 98% rename from "blog-site/content/posts/essays/\345\277\253\351\200\237\346\211\223\345\274\200Github.md" rename to "blog-site/content/posts/essays/\345\246\202\344\275\225\345\277\253\351\200\237\346\211\223\345\274\200Github.md" index aebd7867..955eb17e 100644 --- "a/blog-site/content/posts/essays/\345\277\253\351\200\237\346\211\223\345\274\200Github.md" +++ "b/blog-site/content/posts/essays/\345\246\202\344\275\225\345\277\253\351\200\237\346\211\223\345\274\200Github.md" @@ -1,11 +1,12 @@ --- -title: "快速打开Github" +title: "如何快速打开Github" date: 2024-03-21 draft: false -tags: ["其他"] +tags: ["随笔"] slug: "accelerate-access-github" --- + 为什么我们打开Github速度很慢?很卡?甚至于访问不了,原因是中间有个域名通过DNS解析的过程,将域名解析为对应的ip地址,主要时间都花在了DNS解析上。 我们在浏览器输入 GitHub 的网址时,会向 DNS 服务器发送一个请求,获取到 GitHub 网站所在的服务器 IP 地址,从而进行访问。如果 DNS 告诉了你错误的地址、或者请求被拦截、再或者 DNS 挂了,都会导致你无法访问网站。 diff --git "a/blog-site/content/posts/essays/\347\250\213\345\272\217\350\204\232\346\234\254\346\200\273\347\273\223.md" "b/blog-site/content/posts/essays/\347\250\213\345\272\217\350\204\232\346\234\254\346\200\273\347\273\223.md" index 08d6e1f5..f5741d99 100644 --- "a/blog-site/content/posts/essays/\347\250\213\345\272\217\350\204\232\346\234\254\346\200\273\347\273\223.md" +++ "b/blog-site/content/posts/essays/\347\250\213\345\272\217\350\204\232\346\234\254\346\200\273\347\273\223.md" @@ -2,7 +2,7 @@ title: "程序脚本总结" date: 2024-05-27 draft: false -tags: ["脚本","Java"] +tags: ["脚本","Java","随笔"] slug: "program-script" --- diff --git "a/blog-site/content/posts/essays/\347\272\277\347\250\213\345\210\233\345\273\272\346\226\271\345\274\217.md" "b/blog-site/content/posts/essays/\347\272\277\347\250\213\345\210\233\345\273\272\346\226\271\345\274\217.md" index 75732169..5fb399b8 100644 --- "a/blog-site/content/posts/essays/\347\272\277\347\250\213\345\210\233\345\273\272\346\226\271\345\274\217.md" +++ "b/blog-site/content/posts/essays/\347\272\277\347\250\213\345\210\233\345\273\272\346\226\271\345\274\217.md" @@ -2,7 +2,7 @@ title: "线程创建方式" date: 2020-04-20 draft: false -tags: ["线程", "Java"] +tags: ["多线程", "Java","随笔"] slug: "thread-created-way" --- diff --git "a/blog-site/content/posts/essays/\347\275\221\347\273\234\347\274\226\347\250\213.md" "b/blog-site/content/posts/essays/\347\275\221\347\273\234\347\274\226\347\250\213.md" index 71f09a4a..584e5504 100644 --- "a/blog-site/content/posts/essays/\347\275\221\347\273\234\347\274\226\347\250\213.md" +++ "b/blog-site/content/posts/essays/\347\275\221\347\273\234\347\274\226\347\250\213.md" @@ -2,10 +2,11 @@ title: "网络编程" date: 2021-11-19 draft: false -tags: ["Java", "网络"] +tags: ["Java", "随笔"] slug: "net-program-java" --- + ## 网络协议 以下内容摘自百度百科: - [https://baike.baidu.com/item/网络协议/328636](https://baike.baidu.com/item/网络协议/328636) diff --git a/blog-site/public/posts/codes/scheduled-job/index.html b/blog-site/public/posts/codes/scheduled-job/index.html new file mode 100644 index 00000000..790d031c --- /dev/null +++ b/blog-site/public/posts/codes/scheduled-job/index.html @@ -0,0 +1,1888 @@ + + + + + + + + + + + Java定时任务可视化管理 | 脚踏实地 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+
+ +
+

+ +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ 访问量 +
+
+ 访客数 +
+
+ +
+
+
+
+
+
+
+

Java定时任务可视化管理

+ 2023.09.09 + + + 阅读量次 + + +
+

代码实现

+

代码结构

+

定时任务可视化管理-01

+

pom

+
<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-security</artifactId>
+</dependency>
+
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-web</artifactId>
+</dependency>
+
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-quartz</artifactId>
+</dependency>
+
+<dependency>
+    <groupId>org.projectlombok</groupId>
+    <artifactId>lombok</artifactId>
+</dependency>
+
+<dependency>
+    <groupId>cn.hutool</groupId>
+    <artifactId>hutool-all</artifactId>
+</dependency>
+

库表结构

+
-- ----------------------------
+-- 定时任务调度表
+-- ----------------------------
+drop table if exists sys_job;
+create table sys_job (
+  job_id              bigint(20)    not null auto_increment    comment '任务ID',
+  job_name            varchar(64)   default ''                 comment '任务名称',
+  job_group           varchar(64)   default 'DEFAULT'          comment '任务组名',
+  invoke_target       varchar(500)  not null                   comment '调用目标字符串',
+  cron_expression     varchar(255)  default ''                 comment 'cron执行表达式',
+  misfire_policy      varchar(20)   default '3'                comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
+  concurrent          char(1)       default '1'                comment '是否并发执行(0允许 1禁止)',
+  status              char(1)       default '0'                comment '状态(0正常 1暂停)',
+  create_by           varchar(64)   default ''                 comment '创建者',
+  create_time         datetime                                 comment '创建时间',
+  update_by           varchar(64)   default ''                 comment '更新者',
+  update_time         datetime                                 comment '更新时间',
+  remark              varchar(500)  default ''                 comment '备注信息',
+  primary key (job_id, job_name, job_group)
+) engine=innodb auto_increment=100 comment = '定时任务调度表';
+
+
+-- ----------------------------
+-- 定时任务调度日志表
+-- ----------------------------
+drop table if exists sys_job_log;
+create table sys_job_log (
+  job_log_id          bigint(20)     not null auto_increment    comment '任务日志ID',
+  job_name            varchar(64)    not null                   comment '任务名称',
+  job_group           varchar(64)    not null                   comment '任务组名',
+  invoke_target       varchar(500)   not null                   comment '调用目标字符串',
+  job_message         varchar(500)                              comment '日志信息',
+  status              char(1)        default '0'                comment '执行状态(0正常 1失败)',
+  exception_info      varchar(2000)  default ''                 comment '异常信息',
+  create_time         datetime                                  comment '创建时间',
+  primary key (job_log_id)
+) engine=innodb comment = '定时任务调度日志表';
+

JobManagerController

+
/**
+ * @author: whitepure
+ * @date: 2023/7/20 13:35
+ * @description: JobIndexController
+ */
+@Controller
+public class JobManagerController {
+
+    @RequestMapping({"/","/index"})
+    public String index(){
+        return "index.html";
+    }
+
+}
+

SysJobController

+
@RestController
+@RequestMapping("/main")
+public class SysJobController  {
+    @Autowired
+    private ISysJobService jobService;
+
+    /**
+     * 查询定时任务列表
+     */
+    @GetMapping("/list")
+    public R<List<SysJob>> list(SysJob sysJob) {
+        return R.ok(jobService.selectJobList(sysJob));
+    }
+
+    /**
+     * 获取定时任务详细信息
+     */
+    @GetMapping(value = "/getInfo")
+    public R<SysJob> getInfo(Long jobId) {
+        return R.ok(jobService.selectJobById(jobId));
+    }
+
+    /**
+     * 新增定时任务
+     */
+    @PostMapping("/add")
+    public R<Boolean> add(@RequestBody SysJob job) throws SchedulerException, TaskException {
+        if (!CronUtils.isValid(job.getCronExpression())) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确");
+        } else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), ScheduleConstants.LOOKUP_RMI)) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{ScheduleConstants.LOOKUP_LDAP, ScheduleConstants.LOOKUP_LDAPS})) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{ScheduleConstants.HTTP, ScheduleConstants.HTTPS})) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), ScheduleConstants.JOB_ERROR_STR)) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
+        } else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
+        }
+        return R.ok(jobService.insertJob(job) > 0);
+    }
+
+    /**
+     * 修改定时任务
+     */
+    @PostMapping("/edit")
+    public R<Boolean> edit(@RequestBody SysJob job) throws SchedulerException, TaskException {
+        if (!CronUtils.isValid(job.getCronExpression())) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确");
+        } else if (StrUtil.containsIgnoreCase(job.getInvokeTarget(), ScheduleConstants.LOOKUP_RMI)) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{ScheduleConstants.LOOKUP_LDAP, ScheduleConstants.LOOKUP_LDAPS})) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{ScheduleConstants.HTTP, ScheduleConstants.HTTPS})) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), ScheduleConstants.JOB_ERROR_STR)) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
+        } else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
+        }
+        return R.ok(jobService.updateJob(job) > 0);
+    }
+
+    /**
+     * 定时任务状态修改
+     */
+    @PostMapping("/changeStatus")
+    public R<Boolean> changeStatus(@RequestBody SysJob job) throws SchedulerException {
+        SysJob newJob = jobService.selectJobById(job.getJobId());
+        newJob.setStatus(job.getStatus());
+        return R.ok(jobService.changeStatus(newJob) > 0);
+    }
+
+    /**
+     * 定时任务立即执行一次
+     */
+    @GetMapping("/run")
+    public R<Boolean> run(Long jobId) throws SchedulerException {
+        boolean result = jobService.run(jobId);
+        return result ? R.ok(true): R.failed("任务不存在或已过期!");
+    }
+
+    /**
+     * 删除定时任务
+     */
+    @GetMapping("/remove")
+    public R<Boolean> remove(Long jobId) throws SchedulerException {
+        jobService.deleteJobByIds(new Long[]{jobId});
+        return R.ok(true);
+    }
+}
+

SysJobLogController

+
@RestController
+@RequestMapping("/jobLog")
+public class SysJobLogController {
+    @Autowired
+    private ISysJobLogService jobLogService;
+
+    /**
+     * 查询定时任务调度日志列表
+     */
+    @GetMapping("/list")
+    public R<List<SysJobLog>> list(SysJobLog sysJobLog) {
+        return R.ok(jobLogService.selectJobLogList(sysJobLog));
+    }
+
+
+    /**
+     * 根据调度编号获取详细信息
+     */
+    @GetMapping(value = "/getInfo")
+    public R<SysJobLog> getInfo(Long logId) {
+        return R.ok(jobLogService.selectJobLogById(logId));
+    }
+
+
+    /**
+     * 删除定时任务调度日志
+     */
+    @PostMapping("/{jobLogIds}")
+    public R<Boolean> remove(@PathVariable Long[] jobLogIds) {
+        return R.ok(jobLogService.deleteJobLogByIds(jobLogIds) > 0);
+    }
+
+    /**
+     * 清空定时任务调度日志
+     */
+    @GetMapping("/clean")
+    public R<Boolean> clean() {
+        jobLogService.cleanJobLog();
+        return R.ok(true);
+    }
+
+}
+

JobExceptionHandler

+
@Slf4j
+@RestControllerAdvice("com.chenglian.scheduled")
+public class JobExceptionHandler {
+
+
+    @ExceptionHandler(Exception.class)
+    public R<Boolean> globalHandler(Exception exception) {
+        log.error("定时任务程序发生异常.", exception);
+        return R.failed(exception.getMessage());
+    }
+
+
+}
+

TaskException

+
public class TaskException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    private final Code code;
+
+    public TaskException(String msg, Code code) {
+        this(msg, code, null);
+    }
+
+    public TaskException(String msg, Code code, Exception nestedEx) {
+        super(msg, nestedEx);
+        this.code = code;
+    }
+
+    public Code getCode() {
+        return code;
+    }
+
+    public enum Code {
+        TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE
+    }
+}
+

IErrorCode

+
public interface IErrorCode {
+    long getCode();
+
+    String getMsg();
+}
+

ApiErrorCode

+
@Getter
+@ToString
+public enum ApiErrorCode implements IErrorCode {
+    FAILED(-1L, "操作失败"),
+    SUCCESS(0L, "执行成功");
+
+    private final long code;
+    private final String msg;
+
+    ApiErrorCode(final long code, final String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public static ApiErrorCode fromCode(long code) {
+        ApiErrorCode[] ecs = values();
+        ApiErrorCode[] var3 = ecs;
+        int var4 = ecs.length;
+
+        for(int var5 = 0; var5 < var4; ++var5) {
+            ApiErrorCode ec = var3[var5];
+            if (ec.getCode() == code) {
+                return ec;
+            }
+        }
+
+        return SUCCESS;
+    }
+}
+

R

+
@Data
+@EqualsAndHashCode
+public class R<T> implements Serializable  {
+
+    private static final long serialVersionUID = 1L;
+    private long code;
+    private T data;
+    private String msg;
+
+    public R() {
+    }
+
+    public R(IErrorCode errorCode) {
+        errorCode = (IErrorCode) Optional.ofNullable(errorCode).orElse(ApiErrorCode.FAILED);
+        this.code = errorCode.getCode();
+        this.msg = errorCode.getMsg();
+    }
+
+    public static <T> R<T> ok(T data) {
+        ApiErrorCode aec = ApiErrorCode.SUCCESS;
+        if (data instanceof Boolean && Boolean.FALSE.equals(data)) {
+            aec = ApiErrorCode.FAILED;
+        }
+
+        return restResult(data, aec);
+    }
+
+    public static <T> R<T> failed(String msg) {
+        return restResult(null, ApiErrorCode.FAILED.getCode(), msg);
+    }
+
+    public static <T> R<T> failed(IErrorCode errorCode) {
+        return restResult(null, errorCode);
+    }
+
+    public static <T> R<T> restResult(T data, IErrorCode errorCode) {
+        return restResult(data, errorCode.getCode(), errorCode.getMsg());
+    }
+
+    private static <T> R<T> restResult(T data, long code, String msg) {
+        R<T> apiResult = new R();
+        apiResult.setCode(code);
+        apiResult.setData(data);
+        apiResult.setMsg(msg);
+        return apiResult;
+    }
+
+    public boolean ok() {
+        return ApiErrorCode.SUCCESS.getCode() == this.code;
+    }
+}
+

ISysJobLogService

+
public interface ISysJobLogService {
+    /**
+     * 获取quartz调度器日志的计划任务
+     *
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    List<SysJobLog> selectJobLogList(SysJobLog jobLog);
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     *
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    SysJobLog selectJobLogById(Long jobLogId);
+
+    /**
+     * 新增任务日志
+     *
+     * @param jobLog 调度日志信息
+     */
+    void addJobLog(SysJobLog jobLog);
+
+    /**
+     * 批量删除调度日志信息
+     *
+     * @param logIds 需要删除的日志ID
+     * @return 结果
+     */
+    int deleteJobLogByIds(Long[] logIds);
+
+    /**
+     * 删除任务日志
+     *
+     * @param jobId 调度日志ID
+     * @return 结果
+     */
+    int deleteJobLogById(Long jobId);
+
+    /**
+     * 清空任务日志
+     */
+    void cleanJobLog();
+}
+

ISysJobService

+
public interface ISysJobService {
+    /**
+     * 获取quartz调度器的计划任务
+     *
+     * @param job 调度信息
+     * @return 调度任务集合
+     */
+    List<SysJob> selectJobList(SysJob job);
+
+    /**
+     * 通过调度任务ID查询调度信息
+     *
+     * @param jobId 调度任务ID
+     * @return 调度任务对象信息
+     */
+    SysJob selectJobById(Long jobId);
+
+    /**
+     * 暂停任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int pauseJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 恢复任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int resumeJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 删除任务后,所对应的trigger也将被删除
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int deleteJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 批量删除调度信息
+     *
+     * @param jobIds 需要删除的任务ID
+     * @return 结果
+     */
+    void deleteJobByIds(Long[] jobIds) throws SchedulerException;
+
+    /**
+     * 任务调度状态修改
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int changeStatus(SysJob job) throws SchedulerException;
+
+    /**
+     * 立即运行任务
+     *
+     * @param jobId 调度任务ID
+     * @return 结果
+     */
+    boolean run(Long jobId) throws SchedulerException;
+
+    /**
+     * 新增任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int insertJob(SysJob job) throws SchedulerException, TaskException;
+
+    /**
+     * 更新任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int updateJob(SysJob job) throws SchedulerException, TaskException, TaskException;
+
+    /**
+     * 校验cron表达式是否有效
+     *
+     * @param cronExpression 表达式
+     * @return 结果
+     */
+    boolean checkCronExpressionIsValid(String cronExpression);
+}
+

AbstractQuartzJob

+
public abstract class AbstractQuartzJob implements Job {
+    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
+
+    /**
+     * 线程本地变量
+     */
+    private static final ThreadLocal<Date> threadLocal = new ThreadLocal<>();
+
+    @Override
+    public void execute(JobExecutionContext context) {
+        SysJob sysJob = new SysJob();
+        BeanUtil.copyProperties(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES),sysJob);
+        try {
+            before(context, sysJob);
+            if (sysJob.getJobId() != null) {
+                doExecute(context, sysJob);
+            }
+            after(context, sysJob, null);
+        } catch (Exception e) {
+            log.error("任务执行异常  - :", e);
+            after(context, sysJob, e);
+        }
+    }
+
+    /**
+     * 执行前
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob  系统计划任务
+     */
+    protected void before(JobExecutionContext context, SysJob sysJob) {
+        threadLocal.set(new Date());
+    }
+
+    /**
+     * 执行后
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob  系统计划任务
+     */
+    protected void after(JobExecutionContext context, SysJob sysJob, Exception e) {
+        Date startTime = threadLocal.get();
+        threadLocal.remove();
+
+        final SysJobLog sysJobLog = new SysJobLog();
+        sysJobLog.setJobName(sysJob.getJobName());
+        sysJobLog.setJobGroup(sysJob.getJobGroup());
+        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
+        sysJobLog.setStartTime(startTime);
+        sysJobLog.setStopTime(new Date());
+        long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();
+        sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
+        if (e != null) {
+            sysJobLog.setStatus(ScheduleConstants.FAIL);
+            String errorMsg = StringUtils.substring(getExceptionMessage(e), 0, 2000);
+            sysJobLog.setExceptionInfo(errorMsg);
+        } else {
+            sysJobLog.setStatus(ScheduleConstants.SUCCESS);
+        }
+
+        // 写入数据库当中
+        SpringUtil.getBean(ISysJobLogService.class).addJobLog(sysJobLog);
+    }
+
+
+    public static String getExceptionMessage(Throwable e) {
+        StringWriter sw = new StringWriter();
+        e.printStackTrace(new PrintWriter(sw, true));
+        return sw.toString();
+    }
+
+    /**
+     * 执行方法,由子类重载
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob  系统计划任务
+     * @throws Exception 执行过程中的异常
+     */
+    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
+}
+

CronUtils

+
public class CronUtils {
+    /**
+     * 返回一个布尔值代表一个给定的Cron表达式的有效性
+     *
+     * @param cronExpression Cron表达式
+     * @return boolean 表达式是否有效
+     */
+    public static boolean isValid(String cronExpression) {
+        return CronExpression.isValidExpression(cronExpression);
+    }
+
+    /**
+     * 返回一个字符串值,表示该消息无效Cron表达式给出有效性
+     *
+     * @param cronExpression Cron表达式
+     * @return String 无效时返回表达式错误描述,如果有效返回null
+     */
+    public static String getInvalidMessage(String cronExpression) {
+        try {
+            new CronExpression(cronExpression);
+            return null;
+        } catch (ParseException pe) {
+            return pe.getMessage();
+        }
+    }
+
+    /**
+     * 返回下一个执行时间根据给定的Cron表达式
+     *
+     * @param cronExpression Cron表达式
+     * @return Date 下次Cron表达式执行时间
+     */
+    public static Date getNextExecution(String cronExpression) {
+        try {
+            CronExpression cron = new CronExpression(cronExpression);
+            return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
+        } catch (ParseException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+}
+

JobInvokeUtil

+
public class JobInvokeUtil {
+    /**
+     * 执行方法
+     *
+     * @param sysJob 系统任务
+     */
+    public static void invokeMethod(SysJob sysJob) throws Exception {
+        String invokeTarget = sysJob.getInvokeTarget();
+        String beanName = getBeanName(invokeTarget);
+        String methodName = getMethodName(invokeTarget);
+        List<Object[]> methodParams = getMethodParams(invokeTarget);
+
+        if (!isValidClassName(beanName)) {
+            Object bean = SpringUtil.getBean(beanName);
+            invokeMethod(bean, methodName, methodParams);
+        } else {
+            Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
+            invokeMethod(bean, methodName, methodParams);
+        }
+    }
+
+    /**
+     * 调用任务方法
+     *
+     * @param bean         目标对象
+     * @param methodName   方法名称
+     * @param methodParams 方法参数
+     */
+    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
+            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
+            InvocationTargetException {
+        if (ObjectUtil.isNotEmpty(methodParams) && !methodParams.isEmpty()) {
+            Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
+            method.invoke(bean, getMethodParamsValue(methodParams));
+        } else {
+            Method method = bean.getClass().getMethod(methodName);
+            method.invoke(bean);
+        }
+    }
+
+    /**
+     * 校验是否为为class包名
+     *
+     * @param invokeTarget 名称
+     * @return true是 false否
+     */
+    public static boolean isValidClassName(String invokeTarget) {
+        return StringUtils.countMatches(invokeTarget, ".") > 1;
+    }
+
+    /**
+     * 获取bean名称
+     *
+     * @param invokeTarget 目标字符串
+     * @return bean名称
+     */
+    public static String getBeanName(String invokeTarget) {
+        String beanName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringBeforeLast(beanName, ".");
+    }
+
+    /**
+     * 获取bean方法
+     *
+     * @param invokeTarget 目标字符串
+     * @return method方法
+     */
+    public static String getMethodName(String invokeTarget) {
+        String methodName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringAfterLast(methodName, ".");
+    }
+
+    /**
+     * 获取method方法参数相关列表
+     *
+     * @param invokeTarget 目标字符串
+     * @return method方法相关参数列表
+     */
+    public static List<Object[]> getMethodParams(String invokeTarget) {
+        String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
+        if (StringUtils.isEmpty(methodStr)) {
+            return null;
+        }
+        String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
+        List<Object[]> classs = new LinkedList<>();
+        for (int i = 0; i < methodParams.length; i++) {
+            String str = StringUtils.trimToEmpty(methodParams[i]);
+            // String字符串类型,以'或"开头
+            if (StringUtils.startsWithAny(str, "'", "\"")) {
+                classs.add(new Object[]{StringUtils.substring(str, 1, str.length() - 1), String.class});
+            }
+            // boolean布尔类型,等于true或者false
+            else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) {
+                classs.add(new Object[]{Boolean.valueOf(str), Boolean.class});
+            }
+            // long长整形,以L结尾
+            else if (StringUtils.endsWith(str, "L")) {
+                classs.add(new Object[]{Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class});
+            }
+            // double浮点类型,以D结尾
+            else if (StringUtils.endsWith(str, "D")) {
+                classs.add(new Object[]{Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class});
+            }
+            // 其他类型归类为整形
+            else {
+                classs.add(new Object[]{Integer.valueOf(str), Integer.class});
+            }
+        }
+        return classs;
+    }
+
+    /**
+     * 获取参数类型
+     *
+     * @param methodParams 参数相关列表
+     * @return 参数类型列表
+     */
+    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {
+        Class<?>[] classs = new Class<?>[methodParams.size()];
+        int index = 0;
+        for (Object[] os : methodParams) {
+            classs[index] = (Class<?>) os[1];
+            index++;
+        }
+        return classs;
+    }
+
+    /**
+     * 获取参数值
+     *
+     * @param methodParams 参数相关列表
+     * @return 参数值列表
+     */
+    public static Object[] getMethodParamsValue(List<Object[]> methodParams) {
+        Object[] classs = new Object[methodParams.size()];
+        int index = 0;
+        for (Object[] os : methodParams) {
+            classs[index] = os[0];
+            index++;
+        }
+        return classs;
+    }
+}
+

QuartzDisallowConcurrentExecution

+
@DisallowConcurrentExecution
+public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob {
+    @Override
+    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception {
+        JobInvokeUtil.invokeMethod(sysJob);
+    }
+}
+

QuartzJobExecution

+
public class QuartzJobExecution extends AbstractQuartzJob {
+    @Override
+    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception {
+        JobInvokeUtil.invokeMethod(sysJob);
+    }
+}
+

ScheduleConstants

+
public class ScheduleConstants {
+    public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
+
+    /**
+     * 执行目标key
+     */
+    public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
+
+    /**
+     * 默认
+     */
+    public static final String MISFIRE_DEFAULT = "0";
+
+    /**
+     * 立即触发执行
+     */
+    public static final String MISFIRE_IGNORE_MISFIRES = "1";
+
+    /**
+     * 触发一次执行
+     */
+    public static final String MISFIRE_FIRE_AND_PROCEED = "2";
+
+    /**
+     * 不触发立即执行
+     */
+    public static final String MISFIRE_DO_NOTHING = "3";
+
+    public enum Status {
+        /**
+         * 正常
+         */
+        NORMAL("0"),
+        /**
+         * 暂停
+         */
+        PAUSE("1");
+
+        private final String value;
+
+        Status(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+
+
+
+
+
+    /**
+     * http请求
+     */
+    public static final String HTTP = "http://";
+
+    /**
+     * https请求
+     */
+    public static final String HTTPS = "https://";
+
+    /**
+     * 通用成功标识
+     */
+    public static final String SUCCESS = "0";
+
+    /**
+     * 通用失败标识
+     */
+    public static final String FAIL = "1";
+
+
+    /**
+     * RMI 远程方法调用
+     */
+    public static final String LOOKUP_RMI = "rmi:";
+
+    /**
+     * LDAP 远程方法调用
+     */
+    public static final String LOOKUP_LDAP = "ldap:";
+
+    /**
+     * LDAPS 远程方法调用
+     */
+    public static final String LOOKUP_LDAPS = "ldaps:";
+
+    /**
+     * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
+     */
+    public static final String[] JOB_WHITELIST_STR = {"com.chenglian"};
+
+    /**
+     * 定时任务违规的字符
+     */
+    public static final String[] JOB_ERROR_STR = {"java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
+            "org.springframework", "org.apache", "com.chenglian.common.utils.file", "com.chenglian.common.config"};
+
+
+}
+

ScheduleUtils

+
public class ScheduleUtils {
+    /**
+     * 得到quartz任务类
+     *
+     * @param sysJob 执行计划
+     * @return 具体执行任务类
+     */
+    private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) {
+        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
+        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
+    }
+
+    /**
+     * 构建任务触发对象
+     */
+    public static TriggerKey getTriggerKey(Long jobId, String jobGroup) {
+        return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
+    }
+
+    /**
+     * 构建任务键对象
+     */
+    public static JobKey getJobKey(Long jobId, String jobGroup) {
+        return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
+    }
+
+    /**
+     * 创建定时任务
+     */
+    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException {
+        Class<? extends Job> jobClass = getQuartzJobClass(job);
+        // 构建job信息
+        Long jobId = job.getJobId();
+        String jobGroup = job.getJobGroup();
+        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
+
+        // 表达式调度构建器
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
+        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
+
+        // 按新的cronExpression表达式构建一个新的trigger
+        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
+                .withSchedule(cronScheduleBuilder).build();
+
+        // 放入参数,运行时的方法可以获取
+        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
+
+        // 判断是否存在
+        if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {
+            // 防止创建时存在数据问题 先移除,然后在执行创建操作
+            scheduler.deleteJob(getJobKey(jobId, jobGroup));
+        }
+
+        // 判断任务是否过期
+        if (Objects.nonNull(CronUtils.getNextExecution(job.getCronExpression()))) {
+            // 执行调度任务
+            scheduler.scheduleJob(jobDetail, trigger);
+        }
+
+        // 暂停任务
+        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {
+            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+        }
+    }
+
+    /**
+     * 设置定时任务策略
+     */
+    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)
+            throws TaskException {
+        switch (job.getMisfirePolicy()) {
+            case ScheduleConstants.MISFIRE_DEFAULT:
+                return cb;
+            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
+                return cb.withMisfireHandlingInstructionIgnoreMisfires();
+            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
+                return cb.withMisfireHandlingInstructionFireAndProceed();
+            case ScheduleConstants.MISFIRE_DO_NOTHING:
+                return cb.withMisfireHandlingInstructionDoNothing();
+            default:
+                throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
+                        + "' cannot be used in cron schedule tasks", TaskException.Code.CONFIG_ERROR);
+        }
+    }
+
+    /**
+     * 检查包名是否为白名单配置
+     *
+     * @param invokeTarget 目标字符串
+     * @return 结果
+     */
+    public static boolean whiteList(String invokeTarget) {
+        String packageName = StringUtils.substringBefore(invokeTarget, "(");
+        int count = StringUtils.countMatches(packageName, ".");
+        if (count > 1) {
+            return CharSequenceUtil.containsAnyIgnoreCase(invokeTarget, ScheduleConstants.JOB_WHITELIST_STR);
+        }
+        Object obj = SpringUtil.getBean(StringUtils.split(invokeTarget, ".")[0]);
+        String beanPackageName = obj.getClass().getPackage().getName();
+        return CharSequenceUtil.containsAnyIgnoreCase(beanPackageName, ScheduleConstants.JOB_WHITELIST_STR)
+                && !CharSequenceUtil.containsAnyIgnoreCase(beanPackageName, ScheduleConstants.JOB_ERROR_STR);
+    }
+}
+
+ +
+ + + +
+
发表评论
+
+
+ + + + + + + + +
+
+
+ + + + +
+ + +
+
+ + + + +
+ + + + + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/blog-site/public/posts/essays/java-locks/index.html b/blog-site/public/posts/essays/java-locks/index.html index dde32a86..af35edc2 100644 --- a/blog-site/public/posts/essays/java-locks/index.html +++ b/blog-site/public/posts/essays/java-locks/index.html @@ -1405,7 +1405,7 @@

可中断锁

- 线程 + 多线程 Java diff --git a/blog-site/public/posts/essays/java-thread-collection/index.html b/blog-site/public/posts/essays/java-thread-collection/index.html index 233fe4cc..72fdd2dd 100644 --- a/blog-site/public/posts/essays/java-thread-collection/index.html +++ b/blog-site/public/posts/essays/java-thread-collection/index.html @@ -844,7 +844,7 @@

JDK1.7

- 线程 + 多线程 Java diff --git a/blog-site/public/posts/index.html b/blog-site/public/posts/index.html index 410e8f1d..ff5868d3 100644 --- a/blog-site/public/posts/index.html +++ b/blog-site/public/posts/index.html @@ -685,7 +685,7 @@

- 定时任务可视化管理 + Java定时任务可视化管理
09-09
diff --git a/blog-site/public/posts/index.xml b/blog-site/public/posts/index.xml index 3e5ef87e..11ec03a1 100644 --- a/blog-site/public/posts/index.xml +++ b/blog-site/public/posts/index.xml @@ -527,10 +527,10 @@ 自我介绍 1998 · 李济芝 河北唐山 15176733539 &nbsp;m15176733539@163.com 本人有严谨的工作态度与高质量意识;能查阅各种开发技术手册,具有独立解决问题的能力。具备扎实的Java基础和四年开发经验,有良好的编 - 定时任务可视化管理 - http://localhost:1313/iblog/posts/essays/scheduled-job/ + Java定时任务可视化管理 + http://localhost:1313/iblog/posts/codes/scheduled-job/ Sat, 09 Sep 2023 00:00:00 +0000 - http://localhost:1313/iblog/posts/essays/scheduled-job/ + http://localhost:1313/iblog/posts/codes/scheduled-job/ 代码实现 代码结构 pom &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-quartz&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.projectlombok&lt;/groupId&gt; &lt;artifactId&gt;lombok&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;cn.hutool&lt;/groupId&gt; &lt;artifactId&gt;hutool-all&lt;/artifactId&gt; &lt;/dependency&gt; 库表结构 -- ---------------------------- -- 定时任务调度表 -- ---------------------------- drop table if exists sys_job; create table sys_job ( job_id bigint(20) not null auto_increment comment &#39;任务ID&#39;, job_name varchar(64) default &#39;&#39; comment diff --git a/docs/index.html b/docs/index.html index b97ba615..13a38529 100644 --- a/docs/index.html +++ b/docs/index.html @@ -220,6 +220,8 @@

Java中常见的语法糖Java + 随笔 + @@ -459,6 +461,8 @@

程序脚本总结

Java + 随笔 + diff --git a/docs/index.xml b/docs/index.xml index 2f398cc6..ba139a3d 100644 --- a/docs/index.xml +++ b/docs/index.xml @@ -450,7 +450,7 @@ 概述 欲取天下先治己身,做大事先提高修养,而自我修养最开始就是情绪管理。 不能着急,不能上火,不能拍桌子乱发脾气,事到临头能忍得住,能化解的了。才能体现一个人真正的
- 快速打开Github + 如何快速打开Github https://whiteppure.github.io/iblog/posts/essays/accelerate-access-github/ Thu, 21 Mar 2024 00:00:00 +0000 https://whiteppure.github.io/iblog/posts/essays/accelerate-access-github/ @@ -527,10 +527,10 @@ 自我介绍 1998 · 李济芝 河北唐山 15176733539 &nbsp;m15176733539@163.com 本人有严谨的工作态度与高质量意识;能查阅各种开发技术手册,具有独立解决问题的能力。具备扎实的Java基础和四年开发经验,有良好的编 - 定时任务可视化管理 - https://whiteppure.github.io/iblog/posts/essays/scheduled-job/ + Java定时任务可视化管理 + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ Sat, 09 Sep 2023 00:00:00 +0000 - https://whiteppure.github.io/iblog/posts/essays/scheduled-job/ + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ 代码实现 代码结构 pom &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-quartz&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.projectlombok&lt;/groupId&gt; &lt;artifactId&gt;lombok&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;cn.hutool&lt;/groupId&gt; &lt;artifactId&gt;hutool-all&lt;/artifactId&gt; &lt;/dependency&gt; 库表结构 -- ---------------------------- -- 定时任务调度表 -- ---------------------------- drop table if exists sys_job; create table sys_job ( job_id bigint(20) not null auto_increment comment &#39;任务ID&#39;, job_name varchar(64) default &#39;&#39; comment diff --git a/docs/page/10/index.html b/docs/page/10/index.html index 6b5a0a5c..5093ebf3 100644 --- a/docs/page/10/index.html +++ b/docs/page/10/index.html @@ -284,9 +284,7 @@

Vue2.0基础入门笔记

- Vue - - 笔记 + 随笔 diff --git a/docs/page/3/index.html b/docs/page/3/index.html index 373b98bb..4fc578ca 100644 --- a/docs/page/3/index.html +++ b/docs/page/3/index.html @@ -447,7 +447,7 @@

使用Hugo、Github Pages搭建自 - 其他 + 随笔 diff --git a/docs/page/5/index.html b/docs/page/5/index.html index 9fbf1b6c..41dae8ce 100644 --- a/docs/page/5/index.html +++ b/docs/page/5/index.html @@ -229,7 +229,7 @@

赵玉平-自我管理-
-

快速打开Github

+

如何快速打开Github

@@ -249,7 +249,7 @@

快速打开Github - 其他 + 随笔 @@ -439,7 +439,7 @@

如何强制复制网 - 其他 + 随笔 @@ -576,7 +576,7 @@

Java20230915简历
-

定时任务可视化管理

+

Java定时任务可视化管理

@@ -600,6 +600,10 @@

定时任务可视化管理 设计 + Java + + 小程序 +

diff --git a/docs/page/6/index.html b/docs/page/6/index.html index 21543917..4593cd89 100644 --- a/docs/page/6/index.html +++ b/docs/page/6/index.html @@ -527,7 +527,7 @@

IDEA常用配置及使用技巧< - 技巧 + 随笔 diff --git a/docs/page/7/index.html b/docs/page/7/index.html index 80ea8185..f459da1d 100644 --- a/docs/page/7/index.html +++ b/docs/page/7/index.html @@ -251,7 +251,7 @@

网络编程

Java - 网络 + 随笔 diff --git a/docs/page/9/index.html b/docs/page/9/index.html index 11edbfdc..7c7a1a0f 100644 --- a/docs/page/9/index.html +++ b/docs/page/9/index.html @@ -517,10 +517,12 @@

线程创建方式

- 线程 + 多线程 Java + 随笔 +
@@ -583,10 +585,12 @@

Java中的锁都有什么

- 线程 + 多线程 Java + 随笔 +
@@ -616,12 +620,14 @@

Java中常用线程安 - 线程 + 多线程 Java 集合 + 随笔 +

diff --git a/docs/posts/codes/scheduled-job/index.html b/docs/posts/codes/scheduled-job/index.html new file mode 100644 index 00000000..792f6ef6 --- /dev/null +++ b/docs/posts/codes/scheduled-job/index.html @@ -0,0 +1,1892 @@ + + + + + + + + + + + Java定时任务可视化管理 | 脚踏实地 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+
+ +
+

+ +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+ 访问量 +
+
+ 访客数 +
+
+ +
+
+
+
+
+
+
+

Java定时任务可视化管理

+ 2023.09.09 + + + 阅读量次 + + +
+

代码实现

+

代码结构

+

定时任务可视化管理-01

+

pom

+
<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-security</artifactId>
+</dependency>
+
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-web</artifactId>
+</dependency>
+
+<dependency>
+    <groupId>org.springframework.boot</groupId>
+    <artifactId>spring-boot-starter-quartz</artifactId>
+</dependency>
+
+<dependency>
+    <groupId>org.projectlombok</groupId>
+    <artifactId>lombok</artifactId>
+</dependency>
+
+<dependency>
+    <groupId>cn.hutool</groupId>
+    <artifactId>hutool-all</artifactId>
+</dependency>
+

库表结构

+
-- ----------------------------
+-- 定时任务调度表
+-- ----------------------------
+drop table if exists sys_job;
+create table sys_job (
+  job_id              bigint(20)    not null auto_increment    comment '任务ID',
+  job_name            varchar(64)   default ''                 comment '任务名称',
+  job_group           varchar(64)   default 'DEFAULT'          comment '任务组名',
+  invoke_target       varchar(500)  not null                   comment '调用目标字符串',
+  cron_expression     varchar(255)  default ''                 comment 'cron执行表达式',
+  misfire_policy      varchar(20)   default '3'                comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
+  concurrent          char(1)       default '1'                comment '是否并发执行(0允许 1禁止)',
+  status              char(1)       default '0'                comment '状态(0正常 1暂停)',
+  create_by           varchar(64)   default ''                 comment '创建者',
+  create_time         datetime                                 comment '创建时间',
+  update_by           varchar(64)   default ''                 comment '更新者',
+  update_time         datetime                                 comment '更新时间',
+  remark              varchar(500)  default ''                 comment '备注信息',
+  primary key (job_id, job_name, job_group)
+) engine=innodb auto_increment=100 comment = '定时任务调度表';
+
+
+-- ----------------------------
+-- 定时任务调度日志表
+-- ----------------------------
+drop table if exists sys_job_log;
+create table sys_job_log (
+  job_log_id          bigint(20)     not null auto_increment    comment '任务日志ID',
+  job_name            varchar(64)    not null                   comment '任务名称',
+  job_group           varchar(64)    not null                   comment '任务组名',
+  invoke_target       varchar(500)   not null                   comment '调用目标字符串',
+  job_message         varchar(500)                              comment '日志信息',
+  status              char(1)        default '0'                comment '执行状态(0正常 1失败)',
+  exception_info      varchar(2000)  default ''                 comment '异常信息',
+  create_time         datetime                                  comment '创建时间',
+  primary key (job_log_id)
+) engine=innodb comment = '定时任务调度日志表';
+

JobManagerController

+
/**
+ * @author: whitepure
+ * @date: 2023/7/20 13:35
+ * @description: JobIndexController
+ */
+@Controller
+public class JobManagerController {
+
+    @RequestMapping({"/","/index"})
+    public String index(){
+        return "index.html";
+    }
+
+}
+

SysJobController

+
@RestController
+@RequestMapping("/main")
+public class SysJobController  {
+    @Autowired
+    private ISysJobService jobService;
+
+    /**
+     * 查询定时任务列表
+     */
+    @GetMapping("/list")
+    public R<List<SysJob>> list(SysJob sysJob) {
+        return R.ok(jobService.selectJobList(sysJob));
+    }
+
+    /**
+     * 获取定时任务详细信息
+     */
+    @GetMapping(value = "/getInfo")
+    public R<SysJob> getInfo(Long jobId) {
+        return R.ok(jobService.selectJobById(jobId));
+    }
+
+    /**
+     * 新增定时任务
+     */
+    @PostMapping("/add")
+    public R<Boolean> add(@RequestBody SysJob job) throws SchedulerException, TaskException {
+        if (!CronUtils.isValid(job.getCronExpression())) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确");
+        } else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), ScheduleConstants.LOOKUP_RMI)) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{ScheduleConstants.LOOKUP_LDAP, ScheduleConstants.LOOKUP_LDAPS})) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{ScheduleConstants.HTTP, ScheduleConstants.HTTPS})) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), ScheduleConstants.JOB_ERROR_STR)) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
+        } else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) {
+            return R.failed("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
+        }
+        return R.ok(jobService.insertJob(job) > 0);
+    }
+
+    /**
+     * 修改定时任务
+     */
+    @PostMapping("/edit")
+    public R<Boolean> edit(@RequestBody SysJob job) throws SchedulerException, TaskException {
+        if (!CronUtils.isValid(job.getCronExpression())) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确");
+        } else if (StrUtil.containsIgnoreCase(job.getInvokeTarget(), ScheduleConstants.LOOKUP_RMI)) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{ScheduleConstants.LOOKUP_LDAP, ScheduleConstants.LOOKUP_LDAPS})) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), new String[]{ScheduleConstants.HTTP, ScheduleConstants.HTTPS})) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
+        } else if (StrUtil.containsAnyIgnoreCase(job.getInvokeTarget(), ScheduleConstants.JOB_ERROR_STR)) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
+        } else if (!ScheduleUtils.whiteList(job.getInvokeTarget())) {
+            return R.failed("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
+        }
+        return R.ok(jobService.updateJob(job) > 0);
+    }
+
+    /**
+     * 定时任务状态修改
+     */
+    @PostMapping("/changeStatus")
+    public R<Boolean> changeStatus(@RequestBody SysJob job) throws SchedulerException {
+        SysJob newJob = jobService.selectJobById(job.getJobId());
+        newJob.setStatus(job.getStatus());
+        return R.ok(jobService.changeStatus(newJob) > 0);
+    }
+
+    /**
+     * 定时任务立即执行一次
+     */
+    @GetMapping("/run")
+    public R<Boolean> run(Long jobId) throws SchedulerException {
+        boolean result = jobService.run(jobId);
+        return result ? R.ok(true): R.failed("任务不存在或已过期!");
+    }
+
+    /**
+     * 删除定时任务
+     */
+    @GetMapping("/remove")
+    public R<Boolean> remove(Long jobId) throws SchedulerException {
+        jobService.deleteJobByIds(new Long[]{jobId});
+        return R.ok(true);
+    }
+}
+

SysJobLogController

+
@RestController
+@RequestMapping("/jobLog")
+public class SysJobLogController {
+    @Autowired
+    private ISysJobLogService jobLogService;
+
+    /**
+     * 查询定时任务调度日志列表
+     */
+    @GetMapping("/list")
+    public R<List<SysJobLog>> list(SysJobLog sysJobLog) {
+        return R.ok(jobLogService.selectJobLogList(sysJobLog));
+    }
+
+
+    /**
+     * 根据调度编号获取详细信息
+     */
+    @GetMapping(value = "/getInfo")
+    public R<SysJobLog> getInfo(Long logId) {
+        return R.ok(jobLogService.selectJobLogById(logId));
+    }
+
+
+    /**
+     * 删除定时任务调度日志
+     */
+    @PostMapping("/{jobLogIds}")
+    public R<Boolean> remove(@PathVariable Long[] jobLogIds) {
+        return R.ok(jobLogService.deleteJobLogByIds(jobLogIds) > 0);
+    }
+
+    /**
+     * 清空定时任务调度日志
+     */
+    @GetMapping("/clean")
+    public R<Boolean> clean() {
+        jobLogService.cleanJobLog();
+        return R.ok(true);
+    }
+
+}
+

JobExceptionHandler

+
@Slf4j
+@RestControllerAdvice("com.chenglian.scheduled")
+public class JobExceptionHandler {
+
+
+    @ExceptionHandler(Exception.class)
+    public R<Boolean> globalHandler(Exception exception) {
+        log.error("定时任务程序发生异常.", exception);
+        return R.failed(exception.getMessage());
+    }
+
+
+}
+

TaskException

+
public class TaskException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    private final Code code;
+
+    public TaskException(String msg, Code code) {
+        this(msg, code, null);
+    }
+
+    public TaskException(String msg, Code code, Exception nestedEx) {
+        super(msg, nestedEx);
+        this.code = code;
+    }
+
+    public Code getCode() {
+        return code;
+    }
+
+    public enum Code {
+        TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE
+    }
+}
+

IErrorCode

+
public interface IErrorCode {
+    long getCode();
+
+    String getMsg();
+}
+

ApiErrorCode

+
@Getter
+@ToString
+public enum ApiErrorCode implements IErrorCode {
+    FAILED(-1L, "操作失败"),
+    SUCCESS(0L, "执行成功");
+
+    private final long code;
+    private final String msg;
+
+    ApiErrorCode(final long code, final String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public static ApiErrorCode fromCode(long code) {
+        ApiErrorCode[] ecs = values();
+        ApiErrorCode[] var3 = ecs;
+        int var4 = ecs.length;
+
+        for(int var5 = 0; var5 < var4; ++var5) {
+            ApiErrorCode ec = var3[var5];
+            if (ec.getCode() == code) {
+                return ec;
+            }
+        }
+
+        return SUCCESS;
+    }
+}
+

R

+
@Data
+@EqualsAndHashCode
+public class R<T> implements Serializable  {
+
+    private static final long serialVersionUID = 1L;
+    private long code;
+    private T data;
+    private String msg;
+
+    public R() {
+    }
+
+    public R(IErrorCode errorCode) {
+        errorCode = (IErrorCode) Optional.ofNullable(errorCode).orElse(ApiErrorCode.FAILED);
+        this.code = errorCode.getCode();
+        this.msg = errorCode.getMsg();
+    }
+
+    public static <T> R<T> ok(T data) {
+        ApiErrorCode aec = ApiErrorCode.SUCCESS;
+        if (data instanceof Boolean && Boolean.FALSE.equals(data)) {
+            aec = ApiErrorCode.FAILED;
+        }
+
+        return restResult(data, aec);
+    }
+
+    public static <T> R<T> failed(String msg) {
+        return restResult(null, ApiErrorCode.FAILED.getCode(), msg);
+    }
+
+    public static <T> R<T> failed(IErrorCode errorCode) {
+        return restResult(null, errorCode);
+    }
+
+    public static <T> R<T> restResult(T data, IErrorCode errorCode) {
+        return restResult(data, errorCode.getCode(), errorCode.getMsg());
+    }
+
+    private static <T> R<T> restResult(T data, long code, String msg) {
+        R<T> apiResult = new R();
+        apiResult.setCode(code);
+        apiResult.setData(data);
+        apiResult.setMsg(msg);
+        return apiResult;
+    }
+
+    public boolean ok() {
+        return ApiErrorCode.SUCCESS.getCode() == this.code;
+    }
+}
+

ISysJobLogService

+
public interface ISysJobLogService {
+    /**
+     * 获取quartz调度器日志的计划任务
+     *
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    List<SysJobLog> selectJobLogList(SysJobLog jobLog);
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     *
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    SysJobLog selectJobLogById(Long jobLogId);
+
+    /**
+     * 新增任务日志
+     *
+     * @param jobLog 调度日志信息
+     */
+    void addJobLog(SysJobLog jobLog);
+
+    /**
+     * 批量删除调度日志信息
+     *
+     * @param logIds 需要删除的日志ID
+     * @return 结果
+     */
+    int deleteJobLogByIds(Long[] logIds);
+
+    /**
+     * 删除任务日志
+     *
+     * @param jobId 调度日志ID
+     * @return 结果
+     */
+    int deleteJobLogById(Long jobId);
+
+    /**
+     * 清空任务日志
+     */
+    void cleanJobLog();
+}
+

ISysJobService

+
public interface ISysJobService {
+    /**
+     * 获取quartz调度器的计划任务
+     *
+     * @param job 调度信息
+     * @return 调度任务集合
+     */
+    List<SysJob> selectJobList(SysJob job);
+
+    /**
+     * 通过调度任务ID查询调度信息
+     *
+     * @param jobId 调度任务ID
+     * @return 调度任务对象信息
+     */
+    SysJob selectJobById(Long jobId);
+
+    /**
+     * 暂停任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int pauseJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 恢复任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int resumeJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 删除任务后,所对应的trigger也将被删除
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int deleteJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 批量删除调度信息
+     *
+     * @param jobIds 需要删除的任务ID
+     * @return 结果
+     */
+    void deleteJobByIds(Long[] jobIds) throws SchedulerException;
+
+    /**
+     * 任务调度状态修改
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int changeStatus(SysJob job) throws SchedulerException;
+
+    /**
+     * 立即运行任务
+     *
+     * @param jobId 调度任务ID
+     * @return 结果
+     */
+    boolean run(Long jobId) throws SchedulerException;
+
+    /**
+     * 新增任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int insertJob(SysJob job) throws SchedulerException, TaskException;
+
+    /**
+     * 更新任务
+     *
+     * @param job 调度信息
+     * @return 结果
+     */
+    int updateJob(SysJob job) throws SchedulerException, TaskException, TaskException;
+
+    /**
+     * 校验cron表达式是否有效
+     *
+     * @param cronExpression 表达式
+     * @return 结果
+     */
+    boolean checkCronExpressionIsValid(String cronExpression);
+}
+

AbstractQuartzJob

+
public abstract class AbstractQuartzJob implements Job {
+    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
+
+    /**
+     * 线程本地变量
+     */
+    private static final ThreadLocal<Date> threadLocal = new ThreadLocal<>();
+
+    @Override
+    public void execute(JobExecutionContext context) {
+        SysJob sysJob = new SysJob();
+        BeanUtil.copyProperties(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES),sysJob);
+        try {
+            before(context, sysJob);
+            if (sysJob.getJobId() != null) {
+                doExecute(context, sysJob);
+            }
+            after(context, sysJob, null);
+        } catch (Exception e) {
+            log.error("任务执行异常  - :", e);
+            after(context, sysJob, e);
+        }
+    }
+
+    /**
+     * 执行前
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob  系统计划任务
+     */
+    protected void before(JobExecutionContext context, SysJob sysJob) {
+        threadLocal.set(new Date());
+    }
+
+    /**
+     * 执行后
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob  系统计划任务
+     */
+    protected void after(JobExecutionContext context, SysJob sysJob, Exception e) {
+        Date startTime = threadLocal.get();
+        threadLocal.remove();
+
+        final SysJobLog sysJobLog = new SysJobLog();
+        sysJobLog.setJobName(sysJob.getJobName());
+        sysJobLog.setJobGroup(sysJob.getJobGroup());
+        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
+        sysJobLog.setStartTime(startTime);
+        sysJobLog.setStopTime(new Date());
+        long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();
+        sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
+        if (e != null) {
+            sysJobLog.setStatus(ScheduleConstants.FAIL);
+            String errorMsg = StringUtils.substring(getExceptionMessage(e), 0, 2000);
+            sysJobLog.setExceptionInfo(errorMsg);
+        } else {
+            sysJobLog.setStatus(ScheduleConstants.SUCCESS);
+        }
+
+        // 写入数据库当中
+        SpringUtil.getBean(ISysJobLogService.class).addJobLog(sysJobLog);
+    }
+
+
+    public static String getExceptionMessage(Throwable e) {
+        StringWriter sw = new StringWriter();
+        e.printStackTrace(new PrintWriter(sw, true));
+        return sw.toString();
+    }
+
+    /**
+     * 执行方法,由子类重载
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob  系统计划任务
+     * @throws Exception 执行过程中的异常
+     */
+    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
+}
+

CronUtils

+
public class CronUtils {
+    /**
+     * 返回一个布尔值代表一个给定的Cron表达式的有效性
+     *
+     * @param cronExpression Cron表达式
+     * @return boolean 表达式是否有效
+     */
+    public static boolean isValid(String cronExpression) {
+        return CronExpression.isValidExpression(cronExpression);
+    }
+
+    /**
+     * 返回一个字符串值,表示该消息无效Cron表达式给出有效性
+     *
+     * @param cronExpression Cron表达式
+     * @return String 无效时返回表达式错误描述,如果有效返回null
+     */
+    public static String getInvalidMessage(String cronExpression) {
+        try {
+            new CronExpression(cronExpression);
+            return null;
+        } catch (ParseException pe) {
+            return pe.getMessage();
+        }
+    }
+
+    /**
+     * 返回下一个执行时间根据给定的Cron表达式
+     *
+     * @param cronExpression Cron表达式
+     * @return Date 下次Cron表达式执行时间
+     */
+    public static Date getNextExecution(String cronExpression) {
+        try {
+            CronExpression cron = new CronExpression(cronExpression);
+            return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
+        } catch (ParseException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+}
+

JobInvokeUtil

+
public class JobInvokeUtil {
+    /**
+     * 执行方法
+     *
+     * @param sysJob 系统任务
+     */
+    public static void invokeMethod(SysJob sysJob) throws Exception {
+        String invokeTarget = sysJob.getInvokeTarget();
+        String beanName = getBeanName(invokeTarget);
+        String methodName = getMethodName(invokeTarget);
+        List<Object[]> methodParams = getMethodParams(invokeTarget);
+
+        if (!isValidClassName(beanName)) {
+            Object bean = SpringUtil.getBean(beanName);
+            invokeMethod(bean, methodName, methodParams);
+        } else {
+            Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
+            invokeMethod(bean, methodName, methodParams);
+        }
+    }
+
+    /**
+     * 调用任务方法
+     *
+     * @param bean         目标对象
+     * @param methodName   方法名称
+     * @param methodParams 方法参数
+     */
+    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
+            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
+            InvocationTargetException {
+        if (ObjectUtil.isNotEmpty(methodParams) && !methodParams.isEmpty()) {
+            Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
+            method.invoke(bean, getMethodParamsValue(methodParams));
+        } else {
+            Method method = bean.getClass().getMethod(methodName);
+            method.invoke(bean);
+        }
+    }
+
+    /**
+     * 校验是否为为class包名
+     *
+     * @param invokeTarget 名称
+     * @return true是 false否
+     */
+    public static boolean isValidClassName(String invokeTarget) {
+        return StringUtils.countMatches(invokeTarget, ".") > 1;
+    }
+
+    /**
+     * 获取bean名称
+     *
+     * @param invokeTarget 目标字符串
+     * @return bean名称
+     */
+    public static String getBeanName(String invokeTarget) {
+        String beanName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringBeforeLast(beanName, ".");
+    }
+
+    /**
+     * 获取bean方法
+     *
+     * @param invokeTarget 目标字符串
+     * @return method方法
+     */
+    public static String getMethodName(String invokeTarget) {
+        String methodName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringAfterLast(methodName, ".");
+    }
+
+    /**
+     * 获取method方法参数相关列表
+     *
+     * @param invokeTarget 目标字符串
+     * @return method方法相关参数列表
+     */
+    public static List<Object[]> getMethodParams(String invokeTarget) {
+        String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
+        if (StringUtils.isEmpty(methodStr)) {
+            return null;
+        }
+        String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
+        List<Object[]> classs = new LinkedList<>();
+        for (int i = 0; i < methodParams.length; i++) {
+            String str = StringUtils.trimToEmpty(methodParams[i]);
+            // String字符串类型,以'或"开头
+            if (StringUtils.startsWithAny(str, "'", "\"")) {
+                classs.add(new Object[]{StringUtils.substring(str, 1, str.length() - 1), String.class});
+            }
+            // boolean布尔类型,等于true或者false
+            else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) {
+                classs.add(new Object[]{Boolean.valueOf(str), Boolean.class});
+            }
+            // long长整形,以L结尾
+            else if (StringUtils.endsWith(str, "L")) {
+                classs.add(new Object[]{Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class});
+            }
+            // double浮点类型,以D结尾
+            else if (StringUtils.endsWith(str, "D")) {
+                classs.add(new Object[]{Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class});
+            }
+            // 其他类型归类为整形
+            else {
+                classs.add(new Object[]{Integer.valueOf(str), Integer.class});
+            }
+        }
+        return classs;
+    }
+
+    /**
+     * 获取参数类型
+     *
+     * @param methodParams 参数相关列表
+     * @return 参数类型列表
+     */
+    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {
+        Class<?>[] classs = new Class<?>[methodParams.size()];
+        int index = 0;
+        for (Object[] os : methodParams) {
+            classs[index] = (Class<?>) os[1];
+            index++;
+        }
+        return classs;
+    }
+
+    /**
+     * 获取参数值
+     *
+     * @param methodParams 参数相关列表
+     * @return 参数值列表
+     */
+    public static Object[] getMethodParamsValue(List<Object[]> methodParams) {
+        Object[] classs = new Object[methodParams.size()];
+        int index = 0;
+        for (Object[] os : methodParams) {
+            classs[index] = os[0];
+            index++;
+        }
+        return classs;
+    }
+}
+

QuartzDisallowConcurrentExecution

+
@DisallowConcurrentExecution
+public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob {
+    @Override
+    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception {
+        JobInvokeUtil.invokeMethod(sysJob);
+    }
+}
+

QuartzJobExecution

+
public class QuartzJobExecution extends AbstractQuartzJob {
+    @Override
+    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception {
+        JobInvokeUtil.invokeMethod(sysJob);
+    }
+}
+

ScheduleConstants

+
public class ScheduleConstants {
+    public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
+
+    /**
+     * 执行目标key
+     */
+    public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
+
+    /**
+     * 默认
+     */
+    public static final String MISFIRE_DEFAULT = "0";
+
+    /**
+     * 立即触发执行
+     */
+    public static final String MISFIRE_IGNORE_MISFIRES = "1";
+
+    /**
+     * 触发一次执行
+     */
+    public static final String MISFIRE_FIRE_AND_PROCEED = "2";
+
+    /**
+     * 不触发立即执行
+     */
+    public static final String MISFIRE_DO_NOTHING = "3";
+
+    public enum Status {
+        /**
+         * 正常
+         */
+        NORMAL("0"),
+        /**
+         * 暂停
+         */
+        PAUSE("1");
+
+        private final String value;
+
+        Status(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+
+
+
+
+
+    /**
+     * http请求
+     */
+    public static final String HTTP = "http://";
+
+    /**
+     * https请求
+     */
+    public static final String HTTPS = "https://";
+
+    /**
+     * 通用成功标识
+     */
+    public static final String SUCCESS = "0";
+
+    /**
+     * 通用失败标识
+     */
+    public static final String FAIL = "1";
+
+
+    /**
+     * RMI 远程方法调用
+     */
+    public static final String LOOKUP_RMI = "rmi:";
+
+    /**
+     * LDAP 远程方法调用
+     */
+    public static final String LOOKUP_LDAP = "ldap:";
+
+    /**
+     * LDAPS 远程方法调用
+     */
+    public static final String LOOKUP_LDAPS = "ldaps:";
+
+    /**
+     * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
+     */
+    public static final String[] JOB_WHITELIST_STR = {"com.chenglian"};
+
+    /**
+     * 定时任务违规的字符
+     */
+    public static final String[] JOB_ERROR_STR = {"java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
+            "org.springframework", "org.apache", "com.chenglian.common.utils.file", "com.chenglian.common.config"};
+
+
+}
+

ScheduleUtils

+
public class ScheduleUtils {
+    /**
+     * 得到quartz任务类
+     *
+     * @param sysJob 执行计划
+     * @return 具体执行任务类
+     */
+    private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) {
+        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
+        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
+    }
+
+    /**
+     * 构建任务触发对象
+     */
+    public static TriggerKey getTriggerKey(Long jobId, String jobGroup) {
+        return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
+    }
+
+    /**
+     * 构建任务键对象
+     */
+    public static JobKey getJobKey(Long jobId, String jobGroup) {
+        return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
+    }
+
+    /**
+     * 创建定时任务
+     */
+    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException {
+        Class<? extends Job> jobClass = getQuartzJobClass(job);
+        // 构建job信息
+        Long jobId = job.getJobId();
+        String jobGroup = job.getJobGroup();
+        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
+
+        // 表达式调度构建器
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
+        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
+
+        // 按新的cronExpression表达式构建一个新的trigger
+        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
+                .withSchedule(cronScheduleBuilder).build();
+
+        // 放入参数,运行时的方法可以获取
+        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
+
+        // 判断是否存在
+        if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {
+            // 防止创建时存在数据问题 先移除,然后在执行创建操作
+            scheduler.deleteJob(getJobKey(jobId, jobGroup));
+        }
+
+        // 判断任务是否过期
+        if (Objects.nonNull(CronUtils.getNextExecution(job.getCronExpression()))) {
+            // 执行调度任务
+            scheduler.scheduleJob(jobDetail, trigger);
+        }
+
+        // 暂停任务
+        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {
+            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+        }
+    }
+
+    /**
+     * 设置定时任务策略
+     */
+    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)
+            throws TaskException {
+        switch (job.getMisfirePolicy()) {
+            case ScheduleConstants.MISFIRE_DEFAULT:
+                return cb;
+            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
+                return cb.withMisfireHandlingInstructionIgnoreMisfires();
+            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
+                return cb.withMisfireHandlingInstructionFireAndProceed();
+            case ScheduleConstants.MISFIRE_DO_NOTHING:
+                return cb.withMisfireHandlingInstructionDoNothing();
+            default:
+                throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
+                        + "' cannot be used in cron schedule tasks", TaskException.Code.CONFIG_ERROR);
+        }
+    }
+
+    /**
+     * 检查包名是否为白名单配置
+     *
+     * @param invokeTarget 目标字符串
+     * @return 结果
+     */
+    public static boolean whiteList(String invokeTarget) {
+        String packageName = StringUtils.substringBefore(invokeTarget, "(");
+        int count = StringUtils.countMatches(packageName, ".");
+        if (count > 1) {
+            return CharSequenceUtil.containsAnyIgnoreCase(invokeTarget, ScheduleConstants.JOB_WHITELIST_STR);
+        }
+        Object obj = SpringUtil.getBean(StringUtils.split(invokeTarget, ".")[0]);
+        String beanPackageName = obj.getClass().getPackage().getName();
+        return CharSequenceUtil.containsAnyIgnoreCase(beanPackageName, ScheduleConstants.JOB_WHITELIST_STR)
+                && !CharSequenceUtil.containsAnyIgnoreCase(beanPackageName, ScheduleConstants.JOB_ERROR_STR);
+    }
+}
+
+ +
+ + + +
+
发表评论
+
+
+ + + + + + + + +
+
+
+ + + + +
+ +
    +
    +
    + + + + +
    + + + + + + +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/posts/essays/accelerate-access-github/index.html b/docs/posts/essays/accelerate-access-github/index.html index 92d6dca5..612260e2 100644 --- a/docs/posts/essays/accelerate-access-github/index.html +++ b/docs/posts/essays/accelerate-access-github/index.html @@ -8,7 +8,7 @@ - 快速打开Github | 脚踏实地 + 如何快速打开Github | 脚踏实地 @@ -140,7 +140,7 @@

    -

    快速打开Github

    +

    如何快速打开Github

    2024.03.21 @@ -217,7 +217,7 @@

    快速打开Github

    - 其他 + 随笔
    diff --git a/docs/posts/essays/build-blog/index.html b/docs/posts/essays/build-blog/index.html index 6c9fca8a..70bae33c 100644 --- a/docs/posts/essays/build-blog/index.html +++ b/docs/posts/essays/build-blog/index.html @@ -353,7 +353,7 @@

    使用Github Pages部署博客

    - 其他 + 随笔 diff --git a/docs/posts/essays/dev-idea/index.html b/docs/posts/essays/dev-idea/index.html index e2c119c5..21b2a80c 100644 --- a/docs/posts/essays/dev-idea/index.html +++ b/docs/posts/essays/dev-idea/index.html @@ -1011,7 +1011,7 @@

    快速开发

    - 技巧 + 随笔 diff --git a/docs/posts/essays/force-copy-website-text/index.html b/docs/posts/essays/force-copy-website-text/index.html index 56124f68..88be494b 100644 --- a/docs/posts/essays/force-copy-website-text/index.html +++ b/docs/posts/essays/force-copy-website-text/index.html @@ -314,7 +314,7 @@

    利用js脚本

    - 其他 + 随笔 diff --git a/docs/posts/essays/java-locks/index.html b/docs/posts/essays/java-locks/index.html index 8070a1cd..3b9d041c 100644 --- a/docs/posts/essays/java-locks/index.html +++ b/docs/posts/essays/java-locks/index.html @@ -1405,10 +1405,12 @@

    可中断锁

    - 线程 + 多线程 Java + 随笔 +
    diff --git a/docs/posts/essays/java-syntax-sugar/index.html b/docs/posts/essays/java-syntax-sugar/index.html index b5d812c3..6fd9e0ef 100644 --- a/docs/posts/essays/java-syntax-sugar/index.html +++ b/docs/posts/essays/java-syntax-sugar/index.html @@ -603,6 +603,8 @@

    Java中常见的语法糖

    Java + 随笔 +
    diff --git a/docs/posts/essays/java-thread-collection/index.html b/docs/posts/essays/java-thread-collection/index.html index 6188a821..ec228871 100644 --- a/docs/posts/essays/java-thread-collection/index.html +++ b/docs/posts/essays/java-thread-collection/index.html @@ -844,12 +844,14 @@

    JDK1.7

    - 线程 + 多线程 Java 集合 + 随笔 +
    diff --git a/docs/posts/essays/net-program-java/index.html b/docs/posts/essays/net-program-java/index.html index 528ce3b7..57befc90 100644 --- a/docs/posts/essays/net-program-java/index.html +++ b/docs/posts/essays/net-program-java/index.html @@ -526,7 +526,7 @@

    粘包、拆包

    Java - 网络 + 随笔 diff --git a/docs/posts/essays/program-script/index.html b/docs/posts/essays/program-script/index.html index 19c54c8d..be5387a0 100644 --- a/docs/posts/essays/program-script/index.html +++ b/docs/posts/essays/program-script/index.html @@ -360,6 +360,8 @@

    程序脚本总结

    Java + 随笔 + diff --git a/docs/posts/essays/thread-created-way/index.html b/docs/posts/essays/thread-created-way/index.html index a2c49de4..4fd182a6 100644 --- a/docs/posts/essays/thread-created-way/index.html +++ b/docs/posts/essays/thread-created-way/index.html @@ -863,10 +863,12 @@

    合理配置线程池参数

    - 线程 + 多线程 Java + 随笔 + diff --git a/docs/posts/essays/vue2-note/index.html b/docs/posts/essays/vue2-note/index.html index 2ea26b05..38aa3037 100644 --- a/docs/posts/essays/vue2-note/index.html +++ b/docs/posts/essays/vue2-note/index.html @@ -3362,9 +3362,7 @@

    1.helloWorld.html

    - Vue - - 笔记 + 随笔 diff --git a/docs/posts/index.html b/docs/posts/index.html index db3ae9e3..e9c33d93 100644 --- a/docs/posts/index.html +++ b/docs/posts/index.html @@ -603,7 +603,7 @@

    @@ -685,7 +685,7 @@

    diff --git a/docs/posts/index.xml b/docs/posts/index.xml index b3a74f44..1e613fa5 100644 --- a/docs/posts/index.xml +++ b/docs/posts/index.xml @@ -450,7 +450,7 @@ 概述 欲取天下先治己身,做大事先提高修养,而自我修养最开始就是情绪管理。 不能着急,不能上火,不能拍桌子乱发脾气,事到临头能忍得住,能化解的了。才能体现一个人真正的 - 快速打开Github + 如何快速打开Github https://whiteppure.github.io/iblog/posts/essays/accelerate-access-github/ Thu, 21 Mar 2024 00:00:00 +0000 https://whiteppure.github.io/iblog/posts/essays/accelerate-access-github/ @@ -527,10 +527,10 @@ 自我介绍 1998 · 李济芝 河北唐山 15176733539 &nbsp;m15176733539@163.com 本人有严谨的工作态度与高质量意识;能查阅各种开发技术手册,具有独立解决问题的能力。具备扎实的Java基础和四年开发经验,有良好的编 - 定时任务可视化管理 - https://whiteppure.github.io/iblog/posts/essays/scheduled-job/ + Java定时任务可视化管理 + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ Sat, 09 Sep 2023 00:00:00 +0000 - https://whiteppure.github.io/iblog/posts/essays/scheduled-job/ + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ 代码实现 代码结构 pom &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-quartz&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.projectlombok&lt;/groupId&gt; &lt;artifactId&gt;lombok&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;cn.hutool&lt;/groupId&gt; &lt;artifactId&gt;hutool-all&lt;/artifactId&gt; &lt;/dependency&gt; 库表结构 -- ---------------------------- -- 定时任务调度表 -- ---------------------------- drop table if exists sys_job; create table sys_job ( job_id bigint(20) not null auto_increment comment &#39;任务ID&#39;, job_name varchar(64) default &#39;&#39; comment diff --git a/docs/tags/index.html b/docs/tags/index.html index 83ca4a67..72321ea2 100644 --- a/docs/tags/index.html +++ b/docs/tags/index.html @@ -132,7 +132,7 @@

  • - java 47 + java 48
  • @@ -140,7 +140,7 @@

  • - 笔记 39 + 笔记 38
  • @@ -172,7 +172,7 @@

  • - 小程序 13 + 小程序 14
  • @@ -194,6 +194,14 @@

    +
  • + + 随笔 11 + +
  • + + +
  • java基础 10 @@ -258,6 +266,14 @@

    +
  • + + 多线程 7 + +
  • + + +
  • 社交礼仪 7 @@ -290,14 +306,6 @@

    -
  • - - 多线程 4 - -
  • - - -
  • 就业 4 @@ -314,14 +322,6 @@

    -
  • - - 其他 3 - -
  • - - -
  • 持续更新 3 @@ -330,14 +330,6 @@

    -
  • - - 线程 3 - -
  • - - -
  • 集合 3 @@ -426,14 +418,6 @@

    -
  • - - vue 1 - -
  • - - -
  • 事务 1 @@ -458,14 +442,6 @@

    -
  • - - 技巧 1 - -
  • - - -
  • 数据库 1 @@ -474,14 +450,6 @@

    -
  • - - 网络 1 - -
  • - - -
  • 脚本 1 diff --git a/docs/tags/index.xml b/docs/tags/index.xml index beb3ff11..5e7da363 100644 --- a/docs/tags/index.xml +++ b/docs/tags/index.xml @@ -43,6 +43,13 @@ https://whiteppure.github.io/iblog/tags/java%E5%9F%BA%E7%A1%80/ + + 随笔 + https://whiteppure.github.io/iblog/tags/%E9%9A%8F%E7%AC%94/ + Sun, 14 Jul 2024 00:00:00 +0000 + https://whiteppure.github.io/iblog/tags/%E9%9A%8F%E7%AC%94/ + + 多线程 https://whiteppure.github.io/iblog/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/ @@ -141,13 +148,6 @@ https://whiteppure.github.io/iblog/tags/%E7%AC%94%E8%AE%B0/ - - 其他 - https://whiteppure.github.io/iblog/tags/%E5%85%B6%E4%BB%96/ - Mon, 15 Apr 2024 00:00:00 +0000 - https://whiteppure.github.io/iblog/tags/%E5%85%B6%E4%BB%96/ - - 就业 https://whiteppure.github.io/iblog/tags/%E5%B0%B1%E4%B8%9A/ @@ -218,6 +218,13 @@ https://whiteppure.github.io/iblog/tags/%E8%AE%BE%E8%AE%A1/ + + 小程序 + https://whiteppure.github.io/iblog/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/ + Sat, 09 Sep 2023 00:00:00 +0000 + https://whiteppure.github.io/iblog/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/ + + 应用 https://whiteppure.github.io/iblog/tags/%E5%BA%94%E7%94%A8/ @@ -232,13 +239,6 @@ https://whiteppure.github.io/iblog/tags/nacos/ - - 小程序 - https://whiteppure.github.io/iblog/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/ - Fri, 11 Aug 2023 00:00:00 +0000 - https://whiteppure.github.io/iblog/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/ - - Elasticsearch https://whiteppure.github.io/iblog/tags/elasticsearch/ @@ -246,20 +246,6 @@ https://whiteppure.github.io/iblog/tags/elasticsearch/ - - 技巧 - https://whiteppure.github.io/iblog/tags/%E6%8A%80%E5%B7%A7/ - Fri, 16 Dec 2022 00:00:00 +0000 - https://whiteppure.github.io/iblog/tags/%E6%8A%80%E5%B7%A7/ - - - - 网络 - https://whiteppure.github.io/iblog/tags/%E7%BD%91%E7%BB%9C/ - Fri, 19 Nov 2021 00:00:00 +0000 - https://whiteppure.github.io/iblog/tags/%E7%BD%91%E7%BB%9C/ - - Kafka https://whiteppure.github.io/iblog/tags/kafka/ @@ -309,20 +295,6 @@ https://whiteppure.github.io/iblog/tags/docker/ - - 线程 - https://whiteppure.github.io/iblog/tags/%E7%BA%BF%E7%A8%8B/ - Mon, 20 Apr 2020 00:00:00 +0000 - https://whiteppure.github.io/iblog/tags/%E7%BA%BF%E7%A8%8B/ - - - - Vue - https://whiteppure.github.io/iblog/tags/vue/ - Thu, 23 May 2019 00:00:00 +0000 - https://whiteppure.github.io/iblog/tags/vue/ - - JS https://whiteppure.github.io/iblog/tags/js/ diff --git a/docs/tags/java/index.html b/docs/tags/java/index.html index ba38bcef..63983208 100644 --- a/docs/tags/java/index.html +++ b/docs/tags/java/index.html @@ -235,6 +235,13 @@

    2023
    + +
    Java整合文件上传功能 diff --git a/docs/tags/java/index.xml b/docs/tags/java/index.xml index 8078da21..24a708b2 100644 --- a/docs/tags/java/index.xml +++ b/docs/tags/java/index.xml @@ -78,6 +78,13 @@ https://whiteppure.github.io/iblog/posts/keepupd/valuable-resource/ 读书推荐 Java电子书 《深入理解计算机系统》 《HeadFirst设计模式》 《Java数据结构和算法》 《大话数据结构》 《Java核心技术卷I基础知识》 《Java编 + + Java定时任务可视化管理 + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ + Sat, 09 Sep 2023 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ + 代码实现 代码结构 pom &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-quartz&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.projectlombok&lt;/groupId&gt; &lt;artifactId&gt;lombok&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;cn.hutool&lt;/groupId&gt; &lt;artifactId&gt;hutool-all&lt;/artifactId&gt; &lt;/dependency&gt; 库表结构 -- ---------------------------- -- 定时任务调度表 -- ---------------------------- drop table if exists sys_job; create table sys_job ( job_id bigint(20) not null auto_increment comment &#39;任务ID&#39;, job_name varchar(64) default &#39;&#39; comment + Java整合文件上传功能 https://whiteppure.github.io/iblog/posts/codes/uploadfile-code/ diff --git "a/docs/tags/\345\244\232\347\272\277\347\250\213/index.html" "b/docs/tags/\345\244\232\347\272\277\347\250\213/index.html" index 2e3680a5..b3e822ed 100644 --- "a/docs/tags/\345\244\232\347\272\277\347\250\213/index.html" +++ "b/docs/tags/\345\244\232\347\272\277\347\250\213/index.html" @@ -191,6 +191,27 @@

    2020
    +
    +
    + 线程创建方式 +
    04-20
    +
    +
    + +
    +
    + Java中的锁都有什么 +
    04-07
    +
    +
    + + +
    CAS详解 diff --git "a/docs/tags/\345\244\232\347\272\277\347\250\213/index.xml" "b/docs/tags/\345\244\232\347\272\277\347\250\213/index.xml" index 2b197fe5..e5c4cdcb 100644 --- "a/docs/tags/\345\244\232\347\272\277\347\250\213/index.xml" +++ "b/docs/tags/\345\244\232\347\272\277\347\250\213/index.xml" @@ -29,6 +29,27 @@ https://whiteppure.github.io/iblog/posts/javabasics/rookie-multi-thread/ 线程与进程 进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。一个正在运行的程序的实例就是一个进程。 线程是操作系统能够进行运算调度的最小单位。它被包 + + 线程创建方式 + https://whiteppure.github.io/iblog/posts/essays/thread-created-way/ + Mon, 20 Apr 2020 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/thread-created-way/ + 创建线程 在Java中创建一个线程,有且仅有一种方式,创建一个Thread类实例,并调用它的start方法。 Thread 最经典也是最常见的方式是通过继承Thread类,重写 + + + Java中的锁都有什么 + https://whiteppure.github.io/iblog/posts/essays/java-locks/ + Tue, 07 Apr 2020 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/java-locks/ + 锁 在Java中根据锁的特性来划分可以分为很多,锁的主要作用是确保多线程环境下的数据安全,从而保证程序的正确执行。 在Java中具体&quot;锁&quot;的实现 + + + Java中常用线程安全的集合 + https://whiteppure.github.io/iblog/posts/essays/java-thread-collection/ + Sun, 05 Apr 2020 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/java-thread-collection/ + Java中常用线程安全的集合 在多线程环境中,数据的一致性和线程的安全性是至关重要的。传统的集合类,如ArrayList、HashMap和HashSet,在并发访 + CAS详解 https://whiteppure.github.io/iblog/posts/detailed/cas-detail/ diff --git "a/docs/tags/\345\260\217\347\250\213\345\272\217/index.html" "b/docs/tags/\345\260\217\347\250\213\345\272\217/index.html" index edd0b8bb..adff6892 100644 --- "a/docs/tags/\345\260\217\347\250\213\345\272\217/index.html" +++ "b/docs/tags/\345\260\217\347\250\213\345\272\217/index.html" @@ -160,6 +160,13 @@

    2023
    + +
    Java整合文件上传功能 diff --git "a/docs/tags/\345\260\217\347\250\213\345\272\217/index.xml" "b/docs/tags/\345\260\217\347\250\213\345\272\217/index.xml" index 8409b59c..ee7fb60d 100644 --- "a/docs/tags/\345\260\217\347\250\213\345\272\217/index.xml" +++ "b/docs/tags/\345\260\217\347\250\213\345\272\217/index.xml" @@ -6,8 +6,15 @@ Recent content in 小程序 on 脚踏实地 Hugo -- gohugo.io zh - Fri, 11 Aug 2023 00:00:00 +0000 + Sat, 09 Sep 2023 00:00:00 +0000 + + Java定时任务可视化管理 + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ + Sat, 09 Sep 2023 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ + 代码实现 代码结构 pom &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-quartz&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.projectlombok&lt;/groupId&gt; &lt;artifactId&gt;lombok&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;cn.hutool&lt;/groupId&gt; &lt;artifactId&gt;hutool-all&lt;/artifactId&gt; &lt;/dependency&gt; 库表结构 -- ---------------------------- -- 定时任务调度表 -- ---------------------------- drop table if exists sys_job; create table sys_job ( job_id bigint(20) not null auto_increment comment &#39;任务ID&#39;, job_name varchar(64) default &#39;&#39; comment + Java整合文件上传功能 https://whiteppure.github.io/iblog/posts/codes/uploadfile-code/ diff --git "a/docs/tags/\345\272\224\347\224\250/index.html" "b/docs/tags/\345\272\224\347\224\250/index.html" index 70578ff3..d1eb5d1b 100644 --- "a/docs/tags/\345\272\224\347\224\250/index.html" +++ "b/docs/tags/\345\272\224\347\224\250/index.html" @@ -162,7 +162,7 @@

    diff --git "a/docs/tags/\345\272\224\347\224\250/index.xml" "b/docs/tags/\345\272\224\347\224\250/index.xml" index d313a027..46cbc9b7 100644 --- "a/docs/tags/\345\272\224\347\224\250/index.xml" +++ "b/docs/tags/\345\272\224\347\224\250/index.xml" @@ -9,10 +9,10 @@ Sat, 09 Sep 2023 00:00:00 +0000 - 定时任务可视化管理 - https://whiteppure.github.io/iblog/posts/essays/scheduled-job/ + Java定时任务可视化管理 + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ Sat, 09 Sep 2023 00:00:00 +0000 - https://whiteppure.github.io/iblog/posts/essays/scheduled-job/ + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ 代码实现 代码结构 pom &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-quartz&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.projectlombok&lt;/groupId&gt; &lt;artifactId&gt;lombok&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;cn.hutool&lt;/groupId&gt; &lt;artifactId&gt;hutool-all&lt;/artifactId&gt; &lt;/dependency&gt; 库表结构 -- ---------------------------- -- 定时任务调度表 -- ---------------------------- drop table if exists sys_job; create table sys_job ( job_id bigint(20) not null auto_increment comment &#39;任务ID&#39;, job_name varchar(64) default &#39;&#39; comment diff --git "a/docs/tags/\347\254\224\350\256\260/index.html" "b/docs/tags/\347\254\224\350\256\260/index.html" index 6b73ed34..a41d65fd 100644 --- "a/docs/tags/\347\254\224\350\256\260/index.html" +++ "b/docs/tags/\347\254\224\350\256\260/index.html" @@ -428,18 +428,6 @@

    -
    2019
    -
    - -
    -
    - Vue2.0基础入门笔记 -
    05-23
    -
    -
    - -
    -
    diff --git "a/docs/tags/\347\254\224\350\256\260/index.xml" "b/docs/tags/\347\254\224\350\256\260/index.xml" index 383bed07..e26e296c 100644 --- "a/docs/tags/\347\254\224\350\256\260/index.xml" +++ "b/docs/tags/\347\254\224\350\256\260/index.xml" @@ -274,12 +274,5 @@ https://whiteppure.github.io/iblog/posts/ideology/self-government-003/ 概述 欲取天下先治己身,做大事先提高修养,而自我修养最开始就是情绪管理。 不能着急,不能上火,不能拍桌子乱发脾气,事到临头能忍得住,能化解的了。才能体现一个人真正的 - - Vue2.0基础入门笔记 - https://whiteppure.github.io/iblog/posts/essays/vue2-note/ - Thu, 23 May 2019 00:00:00 +0000 - https://whiteppure.github.io/iblog/posts/essays/vue2-note/ - 参考资料 vue官方文档: https://cn.vuejs.org/v2/guide vue参考视频资料: https://www.bilibili.com/video/av50680998 vue菜鸟教程文档: https://www.runoob.com/vue2/vue-tutorial.html vue-组件 参考资料: https://cn.vuejs.org/v2/guide/components.html#ad 组件是可复用的 Vue 实例,且带有一个名字. 组件的出现是为了拆分vue实 - diff --git "a/docs/tags/\350\256\276\350\256\241/index.html" "b/docs/tags/\350\256\276\350\256\241/index.html" index 0eaa7475..a2d9f77d 100644 --- "a/docs/tags/\350\256\276\350\256\241/index.html" +++ "b/docs/tags/\350\256\276\350\256\241/index.html" @@ -162,7 +162,7 @@

    diff --git "a/docs/tags/\350\256\276\350\256\241/index.xml" "b/docs/tags/\350\256\276\350\256\241/index.xml" index 7ee85b2f..b2f705a6 100644 --- "a/docs/tags/\350\256\276\350\256\241/index.xml" +++ "b/docs/tags/\350\256\276\350\256\241/index.xml" @@ -9,10 +9,10 @@ Sat, 09 Sep 2023 00:00:00 +0000 - 定时任务可视化管理 - https://whiteppure.github.io/iblog/posts/essays/scheduled-job/ + Java定时任务可视化管理 + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ Sat, 09 Sep 2023 00:00:00 +0000 - https://whiteppure.github.io/iblog/posts/essays/scheduled-job/ + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ 代码实现 代码结构 pom &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-security&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-quartz&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.projectlombok&lt;/groupId&gt; &lt;artifactId&gt;lombok&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;cn.hutool&lt;/groupId&gt; &lt;artifactId&gt;hutool-all&lt;/artifactId&gt; &lt;/dependency&gt; 库表结构 -- ---------------------------- -- 定时任务调度表 -- ---------------------------- drop table if exists sys_job; create table sys_job ( job_id bigint(20) not null auto_increment comment &#39;任务ID&#39;, job_name varchar(64) default &#39;&#39; comment diff --git "a/docs/tags/\351\232\217\347\254\224/index.html" "b/docs/tags/\351\232\217\347\254\224/index.html" index a4aae57d..ba7d81e9 100644 --- "a/docs/tags/\351\232\217\347\254\224/index.html" +++ "b/docs/tags/\351\232\217\347\254\224/index.html" @@ -35,6 +35,7 @@ + @@ -123,6 +124,36 @@

    + +
    + +
    @@ -131,8 +162,98 @@

    + +
    +
    + 程序脚本总结 +
    05-27
    +
    +
    + + + +
    +
    + 如何快速打开Github +
    03-21
    +
    +
    + + + +

    + +
    2022
    +
    + + + +
    + +
    2021
    +
    + +
    +
    + 网络编程 +
    11-19
    +
    +
    + +
    + +
    2020
    +
    + +
    +
    + 线程创建方式 +
    04-20
    +
    +
    + +
    +
    + Java中的锁都有什么 +
    04-07
    +
    +
    + + + +
    + +
    2019
    +
    + + @@ -194,27 +315,40 @@

    - - - - - - - - - - - - - - - - - - - - - + diff --git "a/docs/tags/\351\232\217\347\254\224/index.xml" "b/docs/tags/\351\232\217\347\254\224/index.xml" index 7bf364bc..f08b643c 100644 --- "a/docs/tags/\351\232\217\347\254\224/index.xml" +++ "b/docs/tags/\351\232\217\347\254\224/index.xml" @@ -6,14 +6,84 @@ Recent content in 随笔 on 脚踏实地 Hugo -- gohugo.io zh - Sat, 13 Apr 2024 00:00:00 +0000 + Sun, 14 Jul 2024 00:00:00 +0000 - 程序员如何提高收入 - https://whiteppure.github.io/iblog/posts/essays/programmer-increase-income/ - Sat, 13 Apr 2024 00:00:00 +0000 - https://whiteppure.github.io/iblog/posts/essays/programmer-increase-income/ - 程序员作为副业推荐就是外包接单。怎么接单呢?以下是总结的三种方式。 第一种是靠熟人介绍。如果你做程序员时间比较长,身边总会有些比较厉害的人,他能带你玩一玩,跟这些 + Java中常见的语法糖 + https://whiteppure.github.io/iblog/posts/essays/java-syntax-sugar/ + Sun, 14 Jul 2024 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/java-syntax-sugar/ + 概览 语法糖是指编程语言中的一种语法结构,它们并不提供新的功能,而是为了让代码更易读、更易写而设计的。 语法糖使得某些常见的编程模式或操作变得更加简洁和直观,但在底 + + + 程序脚本总结 + https://whiteppure.github.io/iblog/posts/essays/program-script/ + Mon, 27 May 2024 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/program-script/ + Java程序启停shell脚本 #!/bin/sh #非特殊应用下面内存分配已经够用 HEAP_MEMORY=1024M METASPACE_SIZE=256M SERVER_HOME=&#34;$( cd &#34;$( dirname &#34;$0&#34; )&#34; &amp;&amp; pwd )&#34; APP_NAME=${@: -1} #使用说明,用来提示输入参数 help() { echo &#34;Usage: start.sh {start|stop|restart|status|help} APP_NAME.jar&#34; &gt;&amp;2 echo &#34;Examples:&#34; echo &#34; sh start.sh start APP_NAME.jar&#34; echo &#34; sh start.sh stop + + + 使用Hugo、Github Pages搭建自己的博客 + https://whiteppure.github.io/iblog/posts/essays/build-blog/ + Mon, 15 Apr 2024 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/build-blog/ + 搭建博客框架及对比 在众多的博客框架中,Hugo、Jekyll和Hexo因其出色的性能和易用性而备受推崇。 特点 Hugo Jekyll Hexo 速度 极高 中等 较高 易用性 高 中等 高(熟悉JavaS + + + 如何快速打开Github + https://whiteppure.github.io/iblog/posts/essays/accelerate-access-github/ + Thu, 21 Mar 2024 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/accelerate-access-github/ + 为什么我们打开Github速度很慢?很卡?甚至于访问不了,原因是中间有个域名通过DNS解析的过程,将域名解析为对应的ip地址,主要时间都花在了DNS解析上。 我们 + + + 如何强制复制网站上的文字 + https://whiteppure.github.io/iblog/posts/essays/force-copy-website-text/ + Thu, 14 Mar 2024 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/force-copy-website-text/ + 平时浏览网页和查找资料时,总会需要复制一些文字内容,用来引用、收藏、摘抄啊什么的,但是偶尔会遇到一些网站会禁止复制文字,一般都是让你开会员或者注册登录。 针这种情 + + + IDEA常用配置及使用技巧 + https://whiteppure.github.io/iblog/posts/essays/dev-idea/ + Fri, 16 Dec 2022 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/dev-idea/ + 下载 工欲善其事必先利其器,一个好的开发工具,能极大提高开发效率. 新UI很漂亮。IDEA 官方下载地址: https://www.jetbrains.com/zh-cn/idea/download/other.html 激活工具 百度云下载. 链接:https://pan.baid + + + 网络编程 + https://whiteppure.github.io/iblog/posts/essays/net-program-java/ + Fri, 19 Nov 2021 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/net-program-java/ + 网络协议 以下内容摘自百度百科: https://baike.baidu.com/item/网络协议/328636 https://baike.baidu.com/i + + + 线程创建方式 + https://whiteppure.github.io/iblog/posts/essays/thread-created-way/ + Mon, 20 Apr 2020 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/thread-created-way/ + 创建线程 在Java中创建一个线程,有且仅有一种方式,创建一个Thread类实例,并调用它的start方法。 Thread 最经典也是最常见的方式是通过继承Thread类,重写 + + + Java中的锁都有什么 + https://whiteppure.github.io/iblog/posts/essays/java-locks/ + Tue, 07 Apr 2020 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/java-locks/ + 锁 在Java中根据锁的特性来划分可以分为很多,锁的主要作用是确保多线程环境下的数据安全,从而保证程序的正确执行。 在Java中具体&quot;锁&quot;的实现 + + + Java中常用线程安全的集合 + https://whiteppure.github.io/iblog/posts/essays/java-thread-collection/ + Sun, 05 Apr 2020 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/java-thread-collection/ + Java中常用线程安全的集合 在多线程环境中,数据的一致性和线程的安全性是至关重要的。传统的集合类,如ArrayList、HashMap和HashSet,在并发访 + + + Vue2.0基础入门笔记 + https://whiteppure.github.io/iblog/posts/essays/vue2-note/ + Thu, 23 May 2019 00:00:00 +0000 + https://whiteppure.github.io/iblog/posts/essays/vue2-note/ + 参考资料 vue官方文档: https://cn.vuejs.org/v2/guide vue参考视频资料: https://www.bilibili.com/video/av50680998 vue菜鸟教程文档: https://www.runoob.com/vue2/vue-tutorial.html vue-组件 参考资料: https://cn.vuejs.org/v2/guide/components.html#ad 组件是可复用的 Vue 实例,且带有一个名字. 组件的出现是为了拆分vue实 diff --git a/docs/zh/sitemap.xml b/docs/zh/sitemap.xml index 614ffa78..8eae6f35 100644 --- a/docs/zh/sitemap.xml +++ b/docs/zh/sitemap.xml @@ -54,6 +54,9 @@ https://whiteppure.github.io/iblog/posts/essays/java-syntax-sugar/ 2024-07-14T00:00:00+00:00 + + https://whiteppure.github.io/iblog/tags/%E9%9A%8F%E7%AC%94/ + 2024-07-14T00:00:00+00:00 https://whiteppure.github.io/iblog/posts/javakeyword/java-keyword-synchronized/ 2024-07-11T00:00:00+00:00 @@ -204,9 +207,6 @@ https://whiteppure.github.io/iblog/posts/ideology/love-and-marriage-01/ 2024-04-17T00:00:00+00:00 - - https://whiteppure.github.io/iblog/tags/%E5%85%B6%E4%BB%96/ - 2024-04-15T00:00:00+00:00 https://whiteppure.github.io/iblog/posts/essays/build-blog/ 2024-04-15T00:00:00+00:00 @@ -340,11 +340,14 @@ https://whiteppure.github.io/iblog/posts/javaemp/interview-resume-20230915/ 2023-09-15T00:00:00+00:00 - https://whiteppure.github.io/iblog/posts/essays/scheduled-job/ + https://whiteppure.github.io/iblog/posts/codes/scheduled-job/ 2023-09-09T00:00:00+00:00 https://whiteppure.github.io/iblog/tags/%E8%AE%BE%E8%AE%A1/ 2023-09-09T00:00:00+00:00 + + https://whiteppure.github.io/iblog/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/ + 2023-09-09T00:00:00+00:00 https://whiteppure.github.io/iblog/tags/%E5%BA%94%E7%94%A8/ 2023-09-09T00:00:00+00:00 @@ -357,9 +360,6 @@ https://whiteppure.github.io/iblog/posts/codes/uploadfile-code/ 2023-08-11T00:00:00+00:00 - - https://whiteppure.github.io/iblog/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/ - 2023-08-11T00:00:00+00:00 https://whiteppure.github.io/iblog/posts/codes/pay-code/ 2023-08-10T00:00:00+00:00 @@ -393,9 +393,6 @@ https://whiteppure.github.io/iblog/posts/essays/dev-idea/ 2022-12-16T00:00:00+00:00 - - https://whiteppure.github.io/iblog/tags/%E6%8A%80%E5%B7%A7/ - 2022-12-16T00:00:00+00:00 https://whiteppure.github.io/iblog/posts/javaprogramguide/clean-code/ 2022-09-01T00:00:00+00:00 @@ -414,9 +411,6 @@ https://whiteppure.github.io/iblog/posts/javaprogramguide/java-code-rule/ 2021-11-25T00:00:00+00:00 - - https://whiteppure.github.io/iblog/tags/%E7%BD%91%E7%BB%9C/ - 2021-11-19T00:00:00+00:00 https://whiteppure.github.io/iblog/posts/essays/net-program-java/ 2021-11-19T00:00:00+00:00 @@ -555,9 +549,6 @@ https://whiteppure.github.io/iblog/posts/spring/springboot-kafka/ 2020-08-20T00:00:00+00:00 - - https://whiteppure.github.io/iblog/tags/%E7%BA%BF%E7%A8%8B/ - 2020-04-20T00:00:00+00:00 https://whiteppure.github.io/iblog/posts/essays/thread-created-way/ 2020-04-20T00:00:00+00:00 @@ -582,9 +573,6 @@ https://whiteppure.github.io/iblog/posts/worksummary/work-summary-2019/ 2019-12-01T00:00:00+00:00 - - https://whiteppure.github.io/iblog/tags/vue/ - 2019-05-23T00:00:00+00:00 https://whiteppure.github.io/iblog/posts/essays/vue2-note/ 2019-05-23T00:00:00+00:00