Commit 014f91533c049bf2445ba6107f11e87cb3197004

Authored by YunaiV
1 parent 3959aada

1. 完成 quartz 的封装

Showing 33 changed files with 440 additions and 552 deletions
bin/clean.bat deleted
1   -@echo off
2   -echo.
3   -echo [ÐÅÏ¢] ÇåÀíÉú³É·¾¶¡£
4   -echo.
5   -
6   -%~d0
7   -cd %~dp0
8   -
9   -cd ..
10   -call mvn clean
11   -
12   -pause
13 0 \ No newline at end of file
bin/package.bat deleted
1   -@echo off
2   -echo.
3   -echo [信息] 打包Web工程,生成war/jar包文件。
4   -echo.
5   -
6   -%~d0
7   -cd %~dp0
8   -
9   -cd ..
10   -call mvn clean package -Dmaven.test.skip=true
11   -
12   -pause
13 0 \ No newline at end of file
bin/run.bat deleted
1   -@echo off
2   -echo.
3   -echo [ĞÅÏ¢] ÔËĞĞWeb¹¤³Ì¡£
4   -echo.
5   -
6   -cd %~dp0
7   -cd ../ruoyi-admin/target
8   -
9   -set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
10   -
11   -java -jar %JAVA_OPTS% ruoyi-admin.jar
12   -
13   -cd bin
14   -pause
15 0 \ No newline at end of file
ruoyi-common/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java deleted
1   -package com.ruoyi.quartz.config;
2   -
3   -import org.springframework.context.annotation.Bean;
4   -import org.springframework.context.annotation.Configuration;
5   -import org.springframework.scheduling.quartz.SchedulerFactoryBean;
6   -
7   -import javax.sql.DataSource;
8   -import java.util.Properties;
9   -
10   -/**
11   - * 定时任务配置
12   - *
13   - * @author ruoyi
14   - */
15   -@Configuration
16   -public class ScheduleConfig {
17   -
18   - @Bean
19   - public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
20   - SchedulerFactoryBean factory = new SchedulerFactoryBean();
21   - factory.setDataSource(dataSource);
22   -
23   - // quartz参数
24   - Properties prop = new Properties();
25   - prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");
26   - prop.put("org.quartz.scheduler.instanceId", "AUTO");
27   - // 集群配置
28   - prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
29   - prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
30   - prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
31   -
32   - // sqlserver 启用
33   - // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
34   - prop.put("org.quartz.jobStore.misfireThreshold", "12000");
35   - factory.setQuartzProperties(prop);
36   -
37   - factory.setSchedulerName("RuoyiScheduler");
38   - // 延时启动
39   - factory.setStartupDelay(1);
40   - factory.setApplicationContextSchedulerContextKey("applicationContextKey");
41   - // 可选,QuartzScheduler
42   - // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
43   - factory.setOverwriteExistingJobs(true);
44   -
45   -
46   - return factory;
47   - }
48   -}
ruoyi-common/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java deleted
1   -package com.ruoyi.quartz.controller;
2   -
3   -import java.util.List;
4   -
5   -import org.springframework.beans.factory.annotation.Autowired;
6   -import org.springframework.security.access.prepost.PreAuthorize;
7   -import org.springframework.web.bind.annotation.DeleteMapping;
8   -import org.springframework.web.bind.annotation.GetMapping;
9   -import org.springframework.web.bind.annotation.PathVariable;
10   -import org.springframework.web.bind.annotation.RequestMapping;
11   -import org.springframework.web.bind.annotation.RestController;
12   -import com.ruoyi.common.annotation.Log;
13   -import com.ruoyi.common.core.controller.BaseController;
14   -import com.ruoyi.common.core.domain.AjaxResult;
15   -import com.ruoyi.common.core.page.TableDataInfo;
16   -import com.ruoyi.common.enums.BusinessType;
17   -import com.ruoyi.common.utils.poi.ExcelUtil;
18   -import com.ruoyi.quartz.domain.SysJobLog;
19   -import com.ruoyi.quartz.service.ISysJobLogService;
20   -
21   -/**
22   - * 调度日志操作处理
23   - *
24   - * @author ruoyi
25   - */
26   -@RestController
27   -@RequestMapping("/monitor/jobLog")
28   -public class SysJobLogController extends BaseController {
29   - @Autowired
30   - private ISysJobLogService jobLogService;
31   -
32   - /**
33   - * 查询定时任务调度日志列表
34   - */
35   - @PreAuthorize("@ss.hasPermi('monitor:job:list')")
36   - @GetMapping("/list")
37   - public TableDataInfo list(SysJobLog sysJobLog) {
38   - startPage();
39   - List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
40   - return getDataTable(list);
41   - }
42   -
43   - /**
44   - * 导出定时任务调度日志列表
45   - */
46   - @PreAuthorize("@ss.hasPermi('monitor:job:export')")
47   - @Log(title = "任务调度日志", businessType = BusinessType.EXPORT)
48   - @GetMapping("/export")
49   - public AjaxResult export(SysJobLog sysJobLog) {
50   - List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
51   - ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);
52   - return util.exportExcel(list, "调度日志");
53   - }
54   -
55   - /**
56   - * 根据调度编号获取详细信息
57   - */
58   - @PreAuthorize("@ss.hasPermi('monitor:job:query')")
59   - @GetMapping(value = "/{configId}")
60   - public AjaxResult getInfo(@PathVariable Long jobLogId) {
61   - return AjaxResult.success(jobLogService.selectJobLogById(jobLogId));
62   - }
63   -
64   -}
ruoyi-ui/src/api/infra/job.js
... ... @@ -73,3 +73,11 @@ export function runJob(jobId) {
73 73 method: 'put'
74 74 })
75 75 }
  76 +
  77 +// 获得定时任务的下 n 次执行时间
  78 +export function getJobNextTimes(jobId) {
  79 + return request({
  80 + url: '/infra/job/get_next_times?id=' + jobId,
  81 + method: 'get'
  82 + })
  83 +}
... ...
ruoyi-ui/src/api/infra/jobLog.js 0 → 100644
  1 +import request from '@/utils/request'
  2 +
  3 +// 获得定时任务
  4 +export function getJobLog(id) {
  5 + return request({
  6 + url: '/infra/job-log/get?id=' + id,
  7 + method: 'get'
  8 + })
  9 +}
  10 +
  11 +// 获得定时任务分页
  12 +export function getJobLogPage(query) {
  13 + return request({
  14 + url: '/infra/job-log/page',
  15 + method: 'get',
  16 + params: query
  17 + })
  18 +}
  19 +
  20 +// 导出定时任务 Excel
  21 +export function exportJobLogExcel(query) {
  22 + return request({
  23 + url: '/infra/job-log/export-excel',
  24 + method: 'get',
  25 + params: query,
  26 + responseType: 'blob'
  27 + })
  28 +}
... ...
ruoyi-ui/src/api/monitor/jobLog.js deleted
1   -import request from '@/utils/request'
2   -
3   -// 查询调度日志列表
4   -export function listJobLog(query) {
5   - return request({
6   - url: '/monitor/jobLog/list',
7   - method: 'get',
8   - params: query
9   - })
10   -}
11   -
12   -// 删除调度日志
13   -export function delJobLog(jobLogId) {
14   - return request({
15   - url: '/monitor/jobLog/' + jobLogId,
16   - method: 'delete'
17   - })
18   -}
19   -
20   -// 清空调度日志
21   -export function cleanJobLog() {
22   - return request({
23   - url: '/monitor/jobLog/clean',
24   - method: 'delete'
25   - })
26   -}
27   -
28   -// 导出调度日志
29   -export function exportJobLog(query) {
30   - return request({
31   - url: '/monitor/jobLog/export',
32   - method: 'get',
33   - params: query
34   - })
35   -}
36 0 \ No newline at end of file
ruoyi-ui/src/utils/dict.js
... ... @@ -18,6 +18,7 @@ export const DICT_TYPE = {
18 18  
19 19 INF_REDIS_TIMEOUT_TYPE: 'inf_redis_timeout_type',
20 20 INF_JOB_STATUS: 'inf_job_status',
  21 + INF_JOB_LOG_STATUS: 'inf_job_log_status',
21 22  
22 23 TOOL_CODEGEN_TEMPLATE_TYPE: 'tool_codegen_template_type',
23 24 }
... ...
ruoyi-ui/src/views/infra/job/index.vue
... ... @@ -30,7 +30,7 @@
30 30 </el-col>
31 31 <el-col :span="1.5">
32 32 <el-button type="info" icon="el-icon-s-operation" size="mini" @click="handleJobLog"
33   - v-hasPermi="['infra:job:query']">日志</el-button>
  33 + v-hasPermi="['infra:job:query']">执行日志</el-button>
34 34 </el-col>
35 35 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
36 36 </el-row>
... ... @@ -50,6 +50,8 @@
50 50 <template slot-scope="scope">
51 51 <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)"
52 52 v-hasPermi="['infra:job:query']">详细</el-button>
  53 + <el-button size="mini" icon="el-icon-s-operation" @click="handleJobLog(scope.row)"
  54 + v-hasPermi="['infra:job:query']">执行日志</el-button>
53 55 <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
54 56 v-hasPermi="['infra:job:update']">修改</el-button>
55 57 <el-button size="mini" type="text" icon="el-icon-check" @click="handleChangeStatus(scope.row, true)"
... ... @@ -109,13 +111,10 @@
109 111 <el-form-item label="处理器的名字:">{{ form.handlerName }}</el-form-item>
110 112 <el-form-item label="处理器的参数:">{{ form.handlerParam }}</el-form-item>
111 113 <el-form-item label="cron表达式:">{{ form.cronExpression }}</el-form-item>
112   - <el-form-item label="最后一次执行的开始时间:">{{ parseTime(form.executeBeginTime) }}</el-form-item>
113   - <el-form-item label="最后一次执行的开始时间:">{{ parseTime(form.executeEndTime) }}</el-form-item>
114   - <el-form-item label="上一次触发时间:">{{ parseTime(form.firePrevTime) }}</el-form-item>
115   - <el-form-item label="下一次触发时间:">{{ parseTime(form.fireNextTime) }}</el-form-item>
116 114 <el-form-item label="重试次数:">{{ form.retryCount }}</el-form-item>
117 115 <el-form-item label="重试间隔:">{{ form.retryInterval + " 毫秒" }}</el-form-item>
118 116 <el-form-item label="监控超时时间:">{{ form.monitorTimeout > 0 ? form.monitorTimeout + " 毫秒" : "未开启" }}</el-form-item>
  117 + <el-form-item label="后续执行时间:">{{ Array.from(nextTimes, x => parseTime(x)).join('; ')}}</el-form-item>
119 118 </el-col>
120 119 </el-row>
121 120 </el-form>
... ... @@ -128,7 +127,7 @@
128 127 </template>
129 128  
130 129 <script>
131   -import { listJob, getJob, delJob, addJob, updateJob, exportJob, runJob, updateJobStatus } from "@/api/infra/job";
  130 +import { listJob, getJob, delJob, addJob, updateJob, exportJob, runJob, updateJobStatus, getJobNextTimes } from "@/api/infra/job";
132 131 import { InfJobStatusEnum } from "@/utils/constants";
133 132  
134 133 export default {
... ... @@ -169,6 +168,7 @@ export default {
169 168 retryCount: [{ required: true, message: "重试次数不能为空", trigger: "blur" }],
170 169 retryInterval: [{ required: true, message: "重试间隔不能为空", trigger: "blur" }],
171 170 },
  171 + nextTimes: [], // 后续执行时间
172 172  
173 173 // 枚举
174 174 InfJobStatusEnum: InfJobStatusEnum
... ... @@ -204,6 +204,7 @@ export default {
204 204 retryInterval: undefined,
205 205 monitorTimeout: undefined,
206 206 };
  207 + this.nextTimes = [];
207 208 this.resetForm("form");
208 209 },
209 210 /** 搜索按钮操作 */
... ... @@ -234,10 +235,23 @@ export default {
234 235 this.form = response.data;
235 236 this.openView = true;
236 237 });
  238 + // 获取下一次执行时间
  239 + getJobNextTimes(row.id).then(response => {
  240 + this.nextTimes = response.data;
  241 + });
237 242 },
238 243 /** 任务日志列表查询 */
239   - handleJobLog() {
240   - this.$router.push("/job/log");
  244 + handleJobLog(row) {
  245 + if (row.id) {
  246 + this.$router.push({
  247 + path:"/job/log",
  248 + query:{
  249 + jobId: row.id
  250 + }
  251 + });
  252 + } else {
  253 + this.$router.push("/job/log");
  254 + }
241 255 },
242 256 /** 新增按钮操作 */
243 257 handleAdd() {
... ...
ruoyi-ui/src/views/infra/job/log.vue
1 1 <template>
2 2 <div class="app-container">
3   - <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
4   - <el-form-item label="任务名称" prop="jobName">
5   - <el-input
6   - v-model="queryParams.jobName"
7   - placeholder="请输入任务名称"
8   - clearable
9   - size="small"
10   - style="width: 240px"
11   - @keyup.enter.native="handleQuery"
12   - />
  3 + <!-- 搜索工作栏 -->
  4 + <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="120px">
  5 + <el-form-item label="处理器的名字" prop="handlerName">
  6 + <el-input v-model="queryParams.handlerName" placeholder="请输入处理器的名字" clearable size="small" @keyup.enter.native="handleQuery"/>
13 7 </el-form-item>
14   - <el-form-item label="任务组名" prop="jobGroup">
15   - <el-select
16   - v-model="queryParams.jobGroup"
17   - placeholder="请任务组名"
18   - clearable
19   - size="small"
20   - style="width: 240px"
21   - >
22   - <el-option
23   - v-for="dict in jobGroupOptions"
24   - :key="dict.dictValue"
25   - :label="dict.dictLabel"
26   - :value="dict.dictValue"
27   - />
28   - </el-select>
  8 + <el-form-item label="开始执行时间" prop="beginTime">
  9 + <el-date-picker clearable size="small" v-model="queryParams.beginTime" type="date" value-format="yyyy-MM-dd" placeholder="选择开始执行时间" />
29 10 </el-form-item>
30   - <el-form-item label="执行状态" prop="status">
31   - <el-select
32   - v-model="queryParams.status"
33   - placeholder="请选择执行状态"
34   - clearable
35   - size="small"
36   - style="width: 240px"
37   - >
38   - <el-option
39   - v-for="dict in statusOptions"
40   - :key="dict.dictValue"
41   - :label="dict.dictLabel"
42   - :value="dict.dictValue"
43   - />
44   - </el-select>
  11 + <el-form-item label="结束执行时间" prop="endTime">
  12 + <el-date-picker clearable size="small" v-model="queryParams.endTime" type="date" value-format="yyyy-MM-dd" placeholder="选择结束执行时间" />
45 13 </el-form-item>
46   - <el-form-item label="执行时间">
47   - <el-date-picker
48   - v-model="dateRange"
49   - size="small"
50   - style="width: 240px"
51   - value-format="yyyy-MM-dd"
52   - type="daterange"
53   - range-separator="-"
54   - start-placeholder="开始日期"
55   - end-placeholder="结束日期"
56   - ></el-date-picker>
  14 + <el-form-item label="任务状态" prop="status">
  15 + <el-select v-model="queryParams.status" placeholder="请选择任务状态" clearable size="small">
  16 + <el-option v-for="dict in this.getDictDatas(DICT_TYPE.INF_JOB_LOG_STATUS)"
  17 + :key="dict.value" :label="dict.label" :value="dict.value"/>
  18 + </el-select>
57 19 </el-form-item>
58 20 <el-form-item>
59   - <el-button type="cyan" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
  21 + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
60 22 <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
61 23 </el-form-item>
62 24 </el-form>
63 25  
64 26 <el-row :gutter="10" class="mb8">
65 27 <el-col :span="1.5">
66   - <el-button
67   - type="danger"
68   - icon="el-icon-delete"
69   - size="mini"
70   - :disabled="multiple"
71   - @click="handleDelete"
72   - v-hasPermi="['monitor:job:remove']"
73   - >删除</el-button>
74   - </el-col>
75   - <el-col :span="1.5">
76   - <el-button
77   - type="danger"
78   - icon="el-icon-delete"
79   - size="mini"
80   - @click="handleClean"
81   - v-hasPermi="['monitor:job:remove']"
82   - >清空</el-button>
83   - </el-col>
84   - <el-col :span="1.5">
85   - <el-button
86   - type="warning"
87   - icon="el-icon-download"
88   - size="mini"
89   - @click="handleExport"
90   - v-hasPermi="['monitor:job:export']"
91   - >导出</el-button>
  28 + <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport"
  29 + v-hasPermi="['infra:job:export']">导出</el-button>
92 30 </el-col>
93 31 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
94 32 </el-row>
95 33  
96   - <el-table v-loading="loading" :data="jobLogList" @selection-change="handleSelectionChange">
97   - <el-table-column type="selection" width="55" align="center" />
98   - <el-table-column label="日志编号" width="80" align="center" prop="jobLogId" />
99   - <el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
100   - <el-table-column label="任务组名" align="center" prop="jobGroup" :formatter="jobGroupFormat" :show-overflow-tooltip="true" />
101   - <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
102   - <el-table-column label="日志信息" align="center" prop="jobMessage" :show-overflow-tooltip="true" />
103   - <el-table-column label="执行状态" align="center" prop="status" :formatter="statusFormat" />
104   - <el-table-column label="执行时间" align="center" prop="createTime" width="180">
  34 + <el-table v-loading="loading" :data="list">
  35 + <el-table-column label="日志编号" align="center" prop="id" />
  36 + <el-table-column label="任务编号" align="center" prop="jobId" />
  37 + <el-table-column label="处理器的名字" align="center" prop="handlerName" />
  38 + <el-table-column label="处理器的参数" align="center" prop="handlerParam" />
  39 + <el-table-column label="第几次执行" align="center" prop="executeIndex" />
  40 + <el-table-column label="执行时间" align="center" width="180">
  41 + <template slot-scope="scope">
  42 + <span>{{ parseTime(scope.row.beginTime) + ' ~ ' + parseTime(scope.row.endTime) }}</span>
  43 + </template>
  44 + </el-table-column>
  45 + <el-table-column label="执行时长" align="center" prop="duration">
  46 + <template slot-scope="scope">
  47 + <span>{{ scope.row.duration + ' 毫秒' }}</span>
  48 + </template>
  49 + </el-table-column>
  50 + <el-table-column label="任务状态" align="center" prop="status">
105 51 <template slot-scope="scope">
106   - <span>{{ parseTime(scope.row.createTime) }}</span>
  52 + <span>{{ getDictDataLabel(DICT_TYPE.INF_JOB_LOG_STATUS, scope.row.status) }}</span>
107 53 </template>
108 54 </el-table-column>
109 55 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
110 56 <template slot-scope="scope">
111   - <el-button
112   - size="mini"
113   - type="text"
114   - icon="el-icon-view"
115   - @click="handleView(scope.row)"
116   - v-hasPermi="['monitor:job:query']"
117   - >详细</el-button>
  57 + <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)"
  58 + v-hasPermi="['infra:job:query']">详细</el-button>
118 59 </template>
119 60 </el-table-column>
120 61 </el-table>
121 62  
122   - <pagination
123   - v-show="total>0"
124   - :total="total"
125   - :page.sync="queryParams.pageNum"
126   - :limit.sync="queryParams.pageSize"
127   - @pagination="getList"
128   - />
  63 + <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
  64 + @pagination="getList"/>
129 65  
130 66 <!-- 调度日志详细 -->
131 67 <el-dialog title="调度日志详细" :visible.sync="open" width="700px" append-to-body>
132   - <el-form ref="form" :model="form" label-width="100px" size="mini">
  68 + <el-form ref="form" :model="form" label-width="120px" size="mini">
133 69 <el-row>
134 70 <el-col :span="12">
135   - <el-form-item label="日志序号:">{{ form.jobLogId }}</el-form-item>
136   - <el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
137   - </el-col>
138   - <el-col :span="12">
139   - <el-form-item label="任务分组:">{{ form.jobGroup }}</el-form-item>
140   - <el-form-item label="执行时间:">{{ form.createTime }}</el-form-item>
141   - </el-col>
142   - <el-col :span="24">
143   - <el-form-item label="调用方法:">{{ form.invokeTarget }}</el-form-item>
144   - </el-col>
145   - <el-col :span="24">
146   - <el-form-item label="日志信息:">{{ form.jobMessage }}</el-form-item>
147   - </el-col>
148   - <el-col :span="24">
149   - <el-form-item label="执行状态:">
150   - <div v-if="form.status == 0">正常</div>
151   - <div v-else-if="form.status == 1">失败</div>
152   - </el-form-item>
153   - </el-col>
154   - <el-col :span="24">
155   - <el-form-item label="异常信息:" v-if="form.status == 1">{{ form.exceptionInfo }}</el-form-item>
  71 + <el-form-item label="日志编号:">{{ form.id }}</el-form-item>
  72 + <el-form-item label="任务编号:">{{ form.jobId }}</el-form-item>
  73 + <el-form-item label="处理器的名字:">{{ form.handlerName }}</el-form-item>
  74 + <el-form-item label="处理器的参数:">{{ form.handlerParam }}</el-form-item>
  75 + <el-form-item label="第几次执行:">{{ form.executeIndex }}</el-form-item>
  76 + <el-form-item label="执行时间:">{{ parseTime(form.beginTime) + ' ~ ' + parseTime(form.endTime) }}</el-form-item>
  77 + <el-form-item label="执行时长:">{{ parseTime(form.duration) + ' 毫秒' }}</el-form-item>
  78 + <el-form-item label="任务状态:">{{ getDictDataLabel(DICT_TYPE.INF_JOB_LOG_STATUS, form.status) }}</el-form-item>
  79 + <el-form-item label="执行结果:">{{ form.result }}</el-form-item>
156 80 </el-col>
157 81 </el-row>
158 82 </el-form>
... ... @@ -164,7 +88,7 @@
164 88 </template>
165 89  
166 90 <script>
167   -import { listJobLog, delJobLog, exportJobLog, cleanJobLog } from "@/api/monitor/jobLog";
  91 +import { getJobLogPage, exportJobLogExcel } from "@/api/infra/jobLog";
168 92  
169 93 export default {
170 94 name: "JobLog",
... ... @@ -172,125 +96,81 @@ export default {
172 96 return {
173 97 // 遮罩层
174 98 loading: true,
175   - // 选中数组
176   - ids: [],
177   - // 非多个禁用
178   - multiple: true,
179 99 // 显示搜索条件
180 100 showSearch: true,
181 101 // 总条数
182 102 total: 0,
183 103 // 调度日志表格数据
184   - jobLogList: [],
  104 + list: [],
185 105 // 是否显示弹出层
186 106 open: false,
187   - // 日期范围
188   - dateRange: [],
189 107 // 表单参数
190 108 form: {},
191   - // 执行状态字典
192   - statusOptions: [],
193   - // 任务组名字典
194   - jobGroupOptions: [],
195 109 // 查询参数
196 110 queryParams: {
197   - pageNum: 1,
  111 + pageNo: 1,
198 112 pageSize: 10,
199   - jobName: undefined,
200   - jobGroup: undefined,
201   - status: undefined
  113 + handlerName: null,
  114 + beginTime: null,
  115 + endTime: null,
  116 + status: null,
202 117 }
203 118 };
204 119 },
205 120 created() {
  121 + this.queryParams.jobId = this.$route.query && this.$route.query.jobId;
206 122 this.getList();
207   - this.getDicts("sys_job_status").then(response => {
208   - this.statusOptions = response.data;
209   - });
210   - this.getDicts("sys_job_group").then(response => {
211   - this.jobGroupOptions = response.data;
212   - });
213 123 },
214 124 methods: {
215 125 /** 查询调度日志列表 */
216 126 getList() {
217 127 this.loading = true;
218   - listJobLog(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
219   - this.jobLogList = response.rows;
220   - this.total = response.total;
  128 + getJobLogPage({
  129 + ...this.queryParams,
  130 + beginTime: this.queryParams.beginTime ? this.queryParams.beginTime + ' 00:00:00' : undefined,
  131 + endTime: this.queryParams.endTime ? this.queryParams.endTime + ' 23:59:59' : undefined,
  132 + }).then(response => {
  133 + this.list = response.data.list;
  134 + this.total = response.data.total;
221 135 this.loading = false;
222 136 }
223 137 );
224 138 },
225   - // 执行状态字典翻译
226   - statusFormat(row, column) {
227   - return this.selectDictLabel(this.statusOptions, row.status);
228   - },
229   - // 任务组名字典翻译
230   - jobGroupFormat(row, column) {
231   - return this.selectDictLabel(this.jobGroupOptions, row.jobGroup);
232   - },
233 139 /** 搜索按钮操作 */
234 140 handleQuery() {
235   - this.queryParams.pageNum = 1;
  141 + this.queryParams.pageNo = 1;
236 142 this.getList();
237 143 },
238 144 /** 重置按钮操作 */
239 145 resetQuery() {
240   - this.dateRange = [];
241 146 this.resetForm("queryForm");
242 147 this.handleQuery();
243 148 },
244   - // 多选框选中数据
245   - handleSelectionChange(selection) {
246   - this.ids = selection.map(item => item.jobLogId);
247   - this.multiple = !selection.length;
248   - },
249 149 /** 详细按钮操作 */
250 150 handleView(row) {
251 151 this.open = true;
252 152 this.form = row;
253 153 },
254   - /** 删除按钮操作 */
255   - handleDelete(row) {
256   - const jobLogIds = this.ids;
257   - this.$confirm('是否确认删除调度日志编号为"' + jobLogIds + '"的数据项?', "警告", {
258   - confirmButtonText: "确定",
259   - cancelButtonText: "取消",
260   - type: "warning"
261   - }).then(function() {
262   - return delJobLog(jobLogIds);
263   - }).then(() => {
264   - this.getList();
265   - this.msgSuccess("删除成功");
266   - })
267   - },
268   - /** 清空按钮操作 */
269   - handleClean() {
270   - this.$confirm("是否确认清空所有调度日志数据项?", "警告", {
271   - confirmButtonText: "确定",
272   - cancelButtonText: "取消",
273   - type: "warning"
274   - }).then(function() {
275   - return cleanJobLog();
276   - }).then(() => {
277   - this.getList();
278   - this.msgSuccess("清空成功");
279   - })
280   - },
281 154 /** 导出按钮操作 */
282 155 handleExport() {
283   - const queryParams = this.queryParams;
284   - this.$confirm("是否确认导出所有调度日志数据项?", "警告", {
285   - confirmButtonText: "确定",
286   - cancelButtonText: "取消",
287   - type: "warning"
288   - }).then(function() {
289   - return exportJobLog(queryParams);
290   - }).then(response => {
291   - this.download(response.msg);
292   - })
  156 + // 处理查询参数
  157 + let params = {...this.queryParams,
  158 + beginTime: this.queryParams.beginTime ? this.queryParams.beginTime + ' 00:00:00' : undefined,
  159 + endTime: this.queryParams.endTime ? this.queryParams.endTime + ' 23:59:59' : undefined,
  160 + };
  161 + params.pageNo = undefined;
  162 + params.pageSize = undefined;
  163 + // 执行导出
  164 + this.$confirm('是否确认导出所有定时任务日志数据项?', "警告", {
  165 + confirmButtonText: "确定",
  166 + cancelButtonText: "取消",
  167 + type: "warning"
  168 + }).then(function() {
  169 + return exportJobLogExcel(params);
  170 + }).then(response => {
  171 + this.downloadExcel(response, '定时任务日志.xls');
  172 + })
293 173 }
294 174 }
295 175 };
296   -</script>
297 176 \ No newline at end of file
  177 +</script>
... ...
ry.sh deleted
1   -#!/bin/bash
2   -
3   -AppName=ruoyi-admin.jar
4   -
5   -#JVM参数
6   -JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
7   -APP_HOME=`pwd`
8   -LOG_PATH=$APP_HOME/logs/$AppName.log
9   -
10   -if [ "$1" = "" ];
11   -then
12   - echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m"
13   - exit 1
14   -fi
15   -
16   -if [ "$AppName" = "" ];
17   -then
18   - echo -e "\033[0;31m 未输入应用名 \033[0m"
19   - exit 1
20   -fi
21   -
22   -function start()
23   -{
24   - PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
25   -
26   - if [ x"$PID" != x"" ]; then
27   - echo "$AppName is running..."
28   - else
29   - nohup java -jar $JVM_OPTS target/$AppName > /dev/null 2>&1 &
30   - echo "Start $AppName success..."
31   - fi
32   -}
33   -
34   -function stop()
35   -{
36   - echo "Stop $AppName"
37   -
38   - PID=""
39   - query(){
40   - PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
41   - }
42   -
43   - query
44   - if [ x"$PID" != x"" ]; then
45   - kill -TERM $PID
46   - echo "$AppName (pid:$PID) exiting..."
47   - while [ x"$PID" != x"" ]
48   - do
49   - sleep 1
50   - query
51   - done
52   - echo "$AppName exited."
53   - else
54   - echo "$AppName already stopped."
55   - fi
56   -}
57   -
58   -function restart()
59   -{
60   - stop
61   - sleep 2
62   - start
63   -}
64   -
65   -function status()
66   -{
67   - PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l`
68   - if [ $PID != 0 ];then
69   - echo "$AppName is running..."
70   - else
71   - echo "$AppName is not running..."
72   - fi
73   -}
74   -
75   -case $1 in
76   - start)
77   - start;;
78   - stop)
79   - stop;;
80   - restart)
81   - restart;;
82   - status)
83   - status;;
84   - *)
85   -
86   -esac
src/main/java/cn/iocoder/dashboard/framework/quartz/core/util/CronUtils.java
... ... @@ -2,6 +2,11 @@ package cn.iocoder.dashboard.framework.quartz.core.util;
2 2  
3 3 import org.quartz.CronExpression;
4 4  
  5 +import java.text.ParseException;
  6 +import java.util.ArrayList;
  7 +import java.util.Date;
  8 +import java.util.List;
  9 +
5 10 /**
6 11 * Quartz Cron 表达式的工具类
7 12 *
... ... @@ -19,4 +24,31 @@ public class CronUtils {
19 24 return CronExpression.isValidExpression(cronExpression);
20 25 }
21 26  
  27 + /**
  28 + * 基于 CRON 表达式,获得下 n 个满足执行的时间
  29 + *
  30 + * @param cronExpression CRON 表达式
  31 + * @param n 数量
  32 + * @return 满足条件的执行时间
  33 + */
  34 + public static List<Date> getNextTimes(String cronExpression, int n) {
  35 + // 获得 CronExpression 对象
  36 + CronExpression cron;
  37 + try {
  38 + cron = new CronExpression(cronExpression);
  39 + } catch (ParseException e) {
  40 + throw new IllegalArgumentException(e.getMessage());
  41 + }
  42 + // 从当前开始计算,n 个满足条件的
  43 + Date now = new Date();
  44 + List<Date> nextTimes = new ArrayList<>(n);
  45 + for (int i = 0; i < n; i++) {
  46 + Date nextTime = cron.getNextValidTimeAfter(now);
  47 + nextTimes.add(nextTime);
  48 + // 切换现在,为下一个触发时间;
  49 + now = nextTime;
  50 + }
  51 + return nextTimes;
  52 + }
  53 +
22 54 }
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/InfJobController.java
... ... @@ -4,6 +4,7 @@ import cn.iocoder.dashboard.common.pojo.CommonResult;
4 4 import cn.iocoder.dashboard.common.pojo.PageResult;
5 5 import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
6 6 import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
  7 +import cn.iocoder.dashboard.framework.quartz.core.util.CronUtils;
7 8 import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.*;
8 9 import cn.iocoder.dashboard.modules.infra.convert.job.InfJobConvert;
9 10 import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobDO;
... ... @@ -22,6 +23,8 @@ import javax.servlet.http.HttpServletResponse;
22 23 import javax.validation.Valid;
23 24 import java.io.IOException;
24 25 import java.util.Collection;
  26 +import java.util.Collections;
  27 +import java.util.Date;
25 28 import java.util.List;
26 29  
27 30 import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
... ... @@ -123,4 +126,20 @@ public class InfJobController {
123 126 ExcelUtils.write(response, "定时任务.xls", "数据", InfJobExcelVO.class, datas);
124 127 }
125 128  
  129 + @GetMapping("/get_next_times")
  130 + @ApiOperation("获得定时任务的下 n 次执行时间")
  131 + @ApiImplicitParams({
  132 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class),
  133 + @ApiImplicitParam(name = "count", value = "数量", example = "5", dataTypeClass = Long.class)
  134 + })
  135 + @PreAuthorize("@ss.hasPermission('infra:job:query')")
  136 + public CommonResult<List<Date>> getJobNextTimes(@RequestParam("id") Long id,
  137 + @RequestParam(value = "count", required = false, defaultValue = "5") Integer count) {
  138 + InfJobDO job = jobService.getJob(id);
  139 + if (job == null) {
  140 + return success(Collections.emptyList());
  141 + }
  142 + return success(CronUtils.getNextTimes(job.getCronExpression(), count));
  143 + }
  144 +
126 145 }
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/InfJobLogController.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.CommonResult;
  4 +import cn.iocoder.dashboard.common.pojo.PageResult;
  5 +import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
  6 +import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
  7 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogExcelVO;
  8 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogExportReqVO;
  9 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogPageReqVO;
  10 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogRespVO;
  11 +import cn.iocoder.dashboard.modules.infra.convert.job.InfJobLogConvert;
  12 +import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobLogDO;
  13 +import cn.iocoder.dashboard.modules.infra.service.job.InfJobLogService;
  14 +import io.swagger.annotations.Api;
  15 +import io.swagger.annotations.ApiImplicitParam;
  16 +import io.swagger.annotations.ApiOperation;
  17 +import org.springframework.security.access.prepost.PreAuthorize;
  18 +import org.springframework.validation.annotation.Validated;
  19 +import org.springframework.web.bind.annotation.GetMapping;
  20 +import org.springframework.web.bind.annotation.RequestMapping;
  21 +import org.springframework.web.bind.annotation.RequestParam;
  22 +import org.springframework.web.bind.annotation.RestController;
  23 +
  24 +import javax.annotation.Resource;
  25 +import javax.servlet.http.HttpServletResponse;
  26 +import javax.validation.Valid;
  27 +import java.io.IOException;
  28 +import java.util.Collection;
  29 +import java.util.List;
  30 +
  31 +import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
  32 +import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT;
  33 +
  34 +@Api(tags = "定时任务日志")
  35 +@RestController
  36 +@RequestMapping("/infra/job-log")
  37 +@Validated
  38 +public class InfJobLogController {
  39 +
  40 + @Resource
  41 + private InfJobLogService jobLogService;
  42 +
  43 + @GetMapping("/get")
  44 + @ApiOperation("获得定时任务日志")
  45 + @ApiImplicitParam(name = "id", value = "编号", required = true, example = "1024", dataTypeClass = Long.class)
  46 + @PreAuthorize("@ss.hasPermission('infra:job:query')")
  47 + public CommonResult<InfJobLogRespVO> getJobLog(@RequestParam("id") Long id) {
  48 + InfJobLogDO jobLog = jobLogService.getJobLog(id);
  49 + return success(InfJobLogConvert.INSTANCE.convert(jobLog));
  50 + }
  51 +
  52 + @GetMapping("/list")
  53 + @ApiOperation("获得定时任务日志列表")
  54 + @ApiImplicitParam(name = "ids", value = "编号列表", required = true, example = "1024,2048", dataTypeClass = List.class)
  55 + @PreAuthorize("@ss.hasPermission('infra:job:query')")
  56 + public CommonResult<List<InfJobLogRespVO>> getJobLogList(@RequestParam("ids") Collection<Long> ids) {
  57 + List<InfJobLogDO> list = jobLogService.getJobLogList(ids);
  58 + return success(InfJobLogConvert.INSTANCE.convertList(list));
  59 + }
  60 +
  61 + @GetMapping("/page")
  62 + @ApiOperation("获得定时任务日志分页")
  63 + @PreAuthorize("@ss.hasPermission('infra:job:query')")
  64 + public CommonResult<PageResult<InfJobLogRespVO>> getJobLogPage(@Valid InfJobLogPageReqVO pageVO) {
  65 + PageResult<InfJobLogDO> pageResult = jobLogService.getJobLogPage(pageVO);
  66 + return success(InfJobLogConvert.INSTANCE.convertPage(pageResult));
  67 + }
  68 +
  69 + @GetMapping("/export-excel")
  70 + @ApiOperation("导出定时任务日志 Excel")
  71 + @PreAuthorize("@ss.hasPermission('infra:job:export')")
  72 + @OperateLog(type = EXPORT)
  73 + public void exportJobLogExcel(@Valid InfJobLogExportReqVO exportReqVO,
  74 + HttpServletResponse response) throws IOException {
  75 + List<InfJobLogDO> list = jobLogService.getJobLogList(exportReqVO);
  76 + // 导出 Excel
  77 + List<InfJobLogExcelVO> datas = InfJobLogConvert.INSTANCE.convertList02(list);
  78 + ExcelUtils.write(response, "定时任务.xls", "数据", InfJobLogExcelVO.class, datas);
  79 + }
  80 +
  81 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/job/InfJobBaseVO.java
... ... @@ -23,14 +23,14 @@ public class InfJobBaseVO {
23 23 @NotNull(message = "CRON 表达式不能为空")
24 24 private String cronExpression;
25 25  
26   - @ApiModelProperty(value = "重试次数", required = true)
  26 + @ApiModelProperty(value = "重试次数", required = true, example = "3")
27 27 @NotNull(message = "重试次数不能为空")
28 28 private Integer retryCount;
29 29  
30   - @ApiModelProperty(value = "重试间隔", required = true)
  30 + @ApiModelProperty(value = "重试间隔", required = true, example = "1000")
31 31 @NotNull(message = "重试间隔不能为空")
32 32 private Integer retryInterval;
33   -
  33 +
34 34 @ApiModelProperty(value = "监控超时时间", example = "1000")
35 35 private Integer monitorTimeout;
36 36  
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/job/InfJobRespVO.java
... ... @@ -25,18 +25,6 @@ public class InfJobRespVO extends InfJobBaseVO {
25 25 @NotNull(message = "处理器的名字不能为空")
26 26 private String handlerName;
27 27  
28   - @ApiModelProperty(value = "最后一次执行的开始时间")
29   - private Date executeBeginTime;
30   -
31   - @ApiModelProperty(value = "最后一次执行的结束时间")
32   - private Date executeEndTime;
33   -
34   - @ApiModelProperty(value = "上一次触发时间")
35   - private Date firePrevTime;
36   -
37   - @ApiModelProperty(value = "下一次触发时间")
38   - private Date fireNextTime;
39   -
40 28 @ApiModelProperty(value = "创建时间", required = true)
41 29 private Date createTime;
42 30  
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogBaseVO.java
... ... @@ -16,18 +16,18 @@ import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOU
16 16 @Data
17 17 public class InfJobLogBaseVO {
18 18  
19   - @ApiModelProperty(value = "任务编号", required = true)
  19 + @ApiModelProperty(value = "任务编号", required = true, example = "1024")
20 20 @NotNull(message = "任务编号不能为空")
21 21 private Long jobId;
22 22  
23   - @ApiModelProperty(value = "处理器的名字", required = true)
  23 + @ApiModelProperty(value = "处理器的名字", required = true, example = "sysUserSessionTimeoutJob")
24 24 @NotNull(message = "处理器的名字不能为空")
25 25 private String handlerName;
26 26  
27   - @ApiModelProperty(value = "处理器的参数")
  27 + @ApiModelProperty(value = "处理器的参数", example = "yudao")
28 28 private String handlerParam;
29 29  
30   - @ApiModelProperty(value = "第几次执行", required = true)
  30 + @ApiModelProperty(value = "第几次执行", required = true, example = "1")
31 31 @NotNull(message = "第几次执行不能为空")
32 32 private Integer executeIndex;
33 33  
... ... @@ -40,14 +40,14 @@ public class InfJobLogBaseVO {
40 40 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
41 41 private Date endTime;
42 42  
43   - @ApiModelProperty(value = "执行时长")
  43 + @ApiModelProperty(value = "执行时长", example = "123")
44 44 private Integer duration;
45 45  
46   - @ApiModelProperty(value = "任务状态", required = true)
  46 + @ApiModelProperty(value = "任务状态", required = true, example = "1", notes = "参见 InfJobLogStatusEnum 枚举")
47 47 @NotNull(message = "任务状态不能为空")
48 48 private Integer status;
49 49  
50   - @ApiModelProperty(value = "结果数据")
  50 + @ApiModelProperty(value = "结果数据", example = "执行成功")
51 51 private String result;
52 52  
53 53 }
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogExcelVO.java
1 1 package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
2 2  
  3 +import cn.iocoder.dashboard.framework.excel.core.annotations.DictFormat;
  4 +import cn.iocoder.dashboard.framework.excel.core.convert.DictConvert;
  5 +import cn.iocoder.dashboard.modules.system.enums.dict.SysDictTypeEnum;
3 6 import com.alibaba.excel.annotation.ExcelProperty;
4 7 import lombok.Data;
5 8  
... ... @@ -37,7 +40,8 @@ public class InfJobLogExcelVO {
37 40 @ExcelProperty("执行时长")
38 41 private Integer duration;
39 42  
40   - @ExcelProperty("任务状态")
  43 + @ExcelProperty(value = "任务状态", converter = DictConvert.class)
  44 + @DictFormat(SysDictTypeEnum.INF_JOB_STATUS)
41 45 private Integer status;
42 46  
43 47 @ExcelProperty("结果数据")
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogExportReqVO.java
... ... @@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
5 5 import lombok.Data;
6 6 import org.springframework.format.annotation.DateTimeFormat;
7 7  
  8 +import javax.validation.constraints.NotNull;
8 9 import java.util.Date;
9 10  
10 11 import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
... ... @@ -13,7 +14,10 @@ import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOU
13 14 @Data
14 15 public class InfJobLogExportReqVO {
15 16  
16   - @ApiModelProperty(value = "处理器的名字")
  17 + @ApiModelProperty(value = "任务编号", example = "10")
  18 + private Long jobId;
  19 +
  20 + @ApiModelProperty(value = "处理器的名字", notes = "模糊匹配")
17 21 private String handlerName;
18 22  
19 23 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
... ... @@ -24,7 +28,7 @@ public class InfJobLogExportReqVO {
24 28 @ApiModelProperty(value = "结束执行时间")
25 29 private Date endTime;
26 30  
27   - @ApiModelProperty(value = "任务状态")
  31 + @ApiModelProperty(value = "任务状态", notes = "参见 InfJobLogStatusEnum 枚举")
28 32 private Integer status;
29 33  
30 34 }
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogPageReqVO.java
... ... @@ -18,7 +18,10 @@ import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOU
18 18 @ToString(callSuper = true)
19 19 public class InfJobLogPageReqVO extends PageParam {
20 20  
21   - @ApiModelProperty(value = "处理器的名字")
  21 + @ApiModelProperty(value = "任务编号", example = "10")
  22 + private Long jobId;
  23 +
  24 + @ApiModelProperty(value = "处理器的名字", notes = "模糊匹配")
22 25 private String handlerName;
23 26  
24 27 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
... ... @@ -29,7 +32,7 @@ public class InfJobLogPageReqVO extends PageParam {
29 32 @ApiModelProperty(value = "结束执行时间")
30 33 private Date endTime;
31 34  
32   - @ApiModelProperty(value = "任务状态")
  35 + @ApiModelProperty(value = "任务状态", notes = "参见 InfJobLogStatusEnum 枚举")
33 36 private Integer status;
34 37  
35 38 }
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogRespVO.java
... ... @@ -14,7 +14,7 @@ import java.util.Date;
14 14 @ToString(callSuper = true)
15 15 public class InfJobLogRespVO extends InfJobLogBaseVO {
16 16  
17   - @ApiModelProperty(value = "日志编号", required = true)
  17 + @ApiModelProperty(value = "日志编号", required = true, example = "1024")
18 18 private Long id;
19 19  
20 20 @ApiModelProperty(value = "创建时间", required = true)
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/convert/job/InfJobLogConvert.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.convert.job;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogExcelVO;
  5 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogRespVO;
  6 +import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobLogDO;
  7 +import org.mapstruct.Mapper;
  8 +import org.mapstruct.factory.Mappers;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * 定时任务日志 Convert
  14 + *
  15 + * @author 芋艿
  16 + */
  17 +@Mapper
  18 +public interface InfJobLogConvert {
  19 +
  20 + InfJobLogConvert INSTANCE = Mappers.getMapper(InfJobLogConvert.class);
  21 +
  22 + InfJobLogRespVO convert(InfJobLogDO bean);
  23 +
  24 + List<InfJobLogRespVO> convertList(List<InfJobLogDO> list);
  25 +
  26 + PageResult<InfJobLogRespVO> convertPage(PageResult<InfJobLogDO> page);
  27 +
  28 + List<InfJobLogExcelVO> convertList02(List<InfJobLogDO> list);
  29 +
  30 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobDO.java
... ... @@ -6,8 +6,6 @@ import com.baomidou.mybatisplus.annotation.TableId;
6 6 import com.baomidou.mybatisplus.annotation.TableName;
7 7 import lombok.*;
8 8  
9   -import java.util.Date;
10   -
11 9 /**
12 10 * 定时任务 DO
13 11 *
... ... @@ -45,35 +43,10 @@ public class InfJobDO extends BaseDO {
45 43 * 处理器的参数
46 44 */
47 45 private String handlerParam;
48   -
49   - // ========== 时间相关字段 ==========
50   -
51 46 /**
52 47 * CRON 表达式
53 48 */
54 49 private String cronExpression;
55   - /**
56   - * 最后一次执行的开始时间
57   - *
58   - * 该字段在任务执行结束后,进行记录
59   - */
60   - private Date executeBeginTime;
61   - /**
62   - * 最后一次执行的结束时间
63   - *
64   - * 该字段在任务执行结束后,进行记录
65   - */
66   - private Date executeEndTime;
67   - /**
68   - * 上一次触发时间,来自 Quartz SCHE_TRIGGERS 表
69   - */
70   - private Date firePrevTime;
71   - /**
72   - * 下一次触发时间,来自 Quartz SCHE_TRIGGERS 表
73   - *
74   - * 在触发器状态从 `ACQUIRED` 变成 `BLOCKED` 时,就会更新 PREV_FIRE_TIME、NEXT_FIRE_TIME,然后定时任务才正式开始执行
75   - */
76   - private Date fireNextTime;
77 50  
78 51 // ========== 重试相关字段 ==========
79 52 /**
... ... @@ -96,8 +69,4 @@ public class InfJobDO extends BaseDO {
96 69 */
97 70 private Integer monitorTimeout;
98 71  
99   - // TODO misfirePolicy
100   - // TODO concurrent
101   - // TODO 失败重试
102   -
103 72 }
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/dal/mysql/job/InfJobLogMapper.java
1 1 package cn.iocoder.dashboard.modules.infra.dal.mysql.job;
2 2  
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
3 4 import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
  6 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogExportReqVO;
  7 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogPageReqVO;
4 8 import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobLogDO;
5 9 import org.apache.ibatis.annotations.Mapper;
6 10  
  11 +import java.util.List;
  12 +
7 13 /**
8 14 * 任务日志 Mapper
9 15 *
... ... @@ -11,4 +17,27 @@ import org.apache.ibatis.annotations.Mapper;
11 17 */
12 18 @Mapper
13 19 public interface InfJobLogMapper extends BaseMapperX<InfJobLogDO> {
  20 +
  21 + default PageResult<InfJobLogDO> selectPage(InfJobLogPageReqVO reqVO) {
  22 + return selectPage(reqVO, new QueryWrapperX<InfJobLogDO>()
  23 + .eqIfPresent("job_id", reqVO.getJobId())
  24 + .likeIfPresent("handler_name", reqVO.getHandlerName())
  25 + .geIfPresent("begin_time", reqVO.getBeginTime())
  26 + .leIfPresent("end_time", reqVO.getEndTime())
  27 + .eqIfPresent("status", reqVO.getStatus())
  28 + .orderByDesc("id") // ID 倒序
  29 + );
  30 + }
  31 +
  32 + default List<InfJobLogDO> selectList(InfJobLogExportReqVO reqVO) {
  33 + return selectList(new QueryWrapperX<InfJobLogDO>()
  34 + .eqIfPresent("job_id", reqVO.getJobId())
  35 + .likeIfPresent("handler_name", reqVO.getHandlerName())
  36 + .geIfPresent("begin_time", reqVO.getBeginTime())
  37 + .leIfPresent("end_time", reqVO.getEndTime())
  38 + .eqIfPresent("status", reqVO.getStatus())
  39 + .orderByDesc("id") // ID 倒序
  40 + );
  41 + }
  42 +
14 43 }
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/service/job/InfJobLogService.java
1 1 package cn.iocoder.dashboard.modules.infra.service.job;
2 2  
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
3 4 import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService;
  5 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogExportReqVO;
  6 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogPageReqVO;
  7 +import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobLogDO;
  8 +
  9 +import java.util.Collection;
  10 +import java.util.List;
4 11  
5 12 /**
6 13 * Job 日志 Service 接口
... ... @@ -8,4 +15,37 @@ import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService
8 15 * @author 芋道源码
9 16 */
10 17 public interface InfJobLogService extends JobLogFrameworkService {
  18 +
  19 + /**
  20 + * 获得定时任务
  21 + *
  22 + * @param id 编号
  23 + * @return 定时任务
  24 + */
  25 + InfJobLogDO getJobLog(Long id);
  26 +
  27 + /**
  28 + * 获得定时任务列表
  29 + *
  30 + * @param ids 编号
  31 + * @return 定时任务列表
  32 + */
  33 + List<InfJobLogDO> getJobLogList(Collection<Long> ids);
  34 +
  35 + /**
  36 + * 获得定时任务分页
  37 + *
  38 + * @param pageReqVO 分页查询
  39 + * @return 定时任务分页
  40 + */
  41 + PageResult<InfJobLogDO> getJobLogPage(InfJobLogPageReqVO pageReqVO);
  42 +
  43 + /**
  44 + * 获得定时任务列表, 用于 Excel 导出
  45 + *
  46 + * @param exportReqVO 查询条件
  47 + * @return 定时任务分页
  48 + */
  49 + List<InfJobLogDO> getJobLogList(InfJobLogExportReqVO exportReqVO);
  50 +
11 51 }
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/service/job/impl/InfJobLogServiceImpl.java
1 1 package cn.iocoder.dashboard.modules.infra.service.job.impl;
2 2  
  3 +import cn.iocoder.dashboard.common.pojo.PageResult;
  4 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogExportReqVO;
  5 +import cn.iocoder.dashboard.modules.infra.controller.job.vo.log.InfJobLogPageReqVO;
3 6 import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobLogDO;
4 7 import cn.iocoder.dashboard.modules.infra.dal.mysql.job.InfJobLogMapper;
5 8 import cn.iocoder.dashboard.modules.infra.enums.job.InfJobLogStatusEnum;
... ... @@ -10,7 +13,9 @@ import org.springframework.stereotype.Service;
10 13 import org.springframework.validation.annotation.Validated;
11 14  
12 15 import javax.annotation.Resource;
  16 +import java.util.Collection;
13 17 import java.util.Date;
  18 +import java.util.List;
14 19  
15 20 /**
16 21 * Job 日志 Service 实现类
... ... @@ -46,4 +51,24 @@ public class InfJobLogServiceImpl implements InfJobLogService {
46 51 }
47 52 }
48 53  
  54 + @Override
  55 + public InfJobLogDO getJobLog(Long id) {
  56 + return jobLogMapper.selectById(id);
  57 + }
  58 +
  59 + @Override
  60 + public List<InfJobLogDO> getJobLogList(Collection<Long> ids) {
  61 + return jobLogMapper.selectBatchIds(ids);
  62 + }
  63 +
  64 + @Override
  65 + public PageResult<InfJobLogDO> getJobLogPage(InfJobLogPageReqVO pageReqVO) {
  66 + return jobLogMapper.selectPage(pageReqVO);
  67 + }
  68 +
  69 + @Override
  70 + public List<InfJobLogDO> getJobLogList(InfJobLogExportReqVO exportReqVO) {
  71 + return jobLogMapper.selectList(exportReqVO);
  72 + }
  73 +
49 74 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dict/SysDictDataMapper.java
... ... @@ -15,8 +15,9 @@ import java.util.List;
15 15 @Mapper
16 16 public interface SysDictDataMapper extends BaseMapperX<SysDictDataDO> {
17 17  
18   - default SysDictDataDO selectByLabel(String label) {
19   - return selectOne(new QueryWrapper<SysDictDataDO>().eq("label", label));
  18 + default SysDictDataDO selectByDictTypeAndLabel(String dictType, String label) {
  19 + return selectOne(new QueryWrapper<SysDictDataDO>().eq("dict_type", dictType)
  20 + .eq("label", label));
20 21 }
21 22  
22 23 default int selectCountByDictType(String dictType) {
... ...
src/main/java/cn/iocoder/dashboard/modules/system/enums/dict/SysDictTypeEnum.java
... ... @@ -18,8 +18,9 @@ public enum SysDictTypeEnum {
18 18 SYS_BOOLEAN_STRING("sys_boolean_string"), // Boolean 是否类型
19 19  
20 20 INF_REDIS_TIMEOUT_TYPE("inf_redis_timeout_type"), // Redis 超时类型
21   - INF_JOB_STATUS("inf_job_status") // 任务状态的枚举
22   - ;
  21 + INF_JOB_STATUS("inf_job_status"), // 定时任务状态的枚举
  22 + INF_JOB_LOG_STATUS("inf_job_log_status") // 定时任务日志状态的枚举
  23 + ,;
23 24  
24 25  
25 26 /**
... ...
src/main/java/cn/iocoder/dashboard/modules/system/job/auth/SysUserSessionTimeoutJob.java
... ... @@ -15,9 +15,6 @@ public class SysUserSessionTimeoutJob implements JobHandler {
15 15  
16 16 @Override
17 17 public String execute(String param) throws Exception {
18   - if (true) {
19   - throw new RuntimeException("测试异常");
20   - }
21 18 // System.out.println("执行了一次任务");
22 19 log.info("[execute][执行任务:{}]", param);
23 20 return null;
... ...
src/main/java/cn/iocoder/dashboard/modules/system/service/dict/impl/SysDictDataServiceImpl.java
... ... @@ -195,13 +195,13 @@ public class SysDictDataServiceImpl implements SysDictDataService {
195 195 // 校验自己存在
196 196 checkDictDataExists(id);
197 197 // 校验字典数据的值的唯一性
198   - checkDictDataValueUnique(id, label);
  198 + checkDictDataValueUnique(id, dictType, label);
199 199 // 校验字典类型有效
200 200 checkDictTypeValid(dictType);
201 201 }
202 202  
203   - private void checkDictDataValueUnique(Long id, String label) {
204   - SysDictDataDO dictData = dictDataMapper.selectByLabel(label);
  203 + private void checkDictDataValueUnique(Long id, String dictType, String label) {
  204 + SysDictDataDO dictData = dictDataMapper.selectByDictTypeAndLabel(dictType, label);
205 205 if (dictData == null) {
206 206 return;
207 207 }
... ...
src/main/java/cn/iocoder/dashboard/modules/tool/controller/test/ToolTestDemoController.java
... ... @@ -51,7 +51,7 @@ public class ToolTestDemoController {
51 51  
52 52 @DeleteMapping("/delete")
53 53 @ApiOperation("删除测试示例")
54   - @ApiImplicitParam(name = "id", value = "编号", required = true)
  54 + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
55 55 @PreAuthorize("@ss.hasPermission('tool:test-demo:delete')")
56 56 public CommonResult<Boolean> deleteTestDemo(@RequestParam("id") Long id) {
57 57 testDemoService.deleteTestDemo(id);
... ...
src/main/resources/application.yaml
... ... @@ -50,11 +50,16 @@ spring:
50 50 properties: # 添加 Quartz Scheduler 附加属性,更多可以看 http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/configuration.html 文档
51 51 org:
52 52 quartz:
  53 + # Scheduler 相关配置
  54 + scheduler:
  55 + instanceName: schedulerName
  56 + instanceId: AUTO # 自动生成 instance ID
53 57 # JobStore 相关配置
54 58 jobStore:
55 59 class: org.quartz.impl.jdbcjobstore.JobStoreTX # JobStore 实现类
56 60 isClustered: true # 是集群模式
57   - clusterCheckinInterval: 1000
  61 + clusterCheckinInterval: 15000 # 集群检查频率,单位:毫秒。默认为 15000,即 15 秒
  62 + misfireThreshold: 60000 # misfire 阀值,单位:毫秒。
58 63 # 线程池相关配置
59 64 threadPool:
60 65 threadCount: 25 # 线程池大小。默认为 10 。
... ...