Commit 014f91533c049bf2445ba6107f11e87cb3197004
1 parent
3959aada
1. 完成 quartz 的封装
Showing
33 changed files
with
440 additions
and
552 deletions
bin/clean.bat deleted
bin/package.bat deleted
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 | \ No newline at end of file | 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,3 +73,11 @@ export function runJob(jobId) { | ||
| 73 | method: 'put' | 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 | \ No newline at end of file | 0 | \ No newline at end of file |
ruoyi-ui/src/utils/dict.js
| @@ -18,6 +18,7 @@ export const DICT_TYPE = { | @@ -18,6 +18,7 @@ export const DICT_TYPE = { | ||
| 18 | 18 | ||
| 19 | INF_REDIS_TIMEOUT_TYPE: 'inf_redis_timeout_type', | 19 | INF_REDIS_TIMEOUT_TYPE: 'inf_redis_timeout_type', |
| 20 | INF_JOB_STATUS: 'inf_job_status', | 20 | INF_JOB_STATUS: 'inf_job_status', |
| 21 | + INF_JOB_LOG_STATUS: 'inf_job_log_status', | ||
| 21 | 22 | ||
| 22 | TOOL_CODEGEN_TEMPLATE_TYPE: 'tool_codegen_template_type', | 23 | TOOL_CODEGEN_TEMPLATE_TYPE: 'tool_codegen_template_type', |
| 23 | } | 24 | } |
ruoyi-ui/src/views/infra/job/index.vue
| @@ -30,7 +30,7 @@ | @@ -30,7 +30,7 @@ | ||
| 30 | </el-col> | 30 | </el-col> |
| 31 | <el-col :span="1.5"> | 31 | <el-col :span="1.5"> |
| 32 | <el-button type="info" icon="el-icon-s-operation" size="mini" @click="handleJobLog" | 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 | </el-col> | 34 | </el-col> |
| 35 | <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | 35 | <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> |
| 36 | </el-row> | 36 | </el-row> |
| @@ -50,6 +50,8 @@ | @@ -50,6 +50,8 @@ | ||
| 50 | <template slot-scope="scope"> | 50 | <template slot-scope="scope"> |
| 51 | <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)" | 51 | <el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)" |
| 52 | v-hasPermi="['infra:job:query']">详细</el-button> | 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 | <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" | 55 | <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" |
| 54 | v-hasPermi="['infra:job:update']">修改</el-button> | 56 | v-hasPermi="['infra:job:update']">修改</el-button> |
| 55 | <el-button size="mini" type="text" icon="el-icon-check" @click="handleChangeStatus(scope.row, true)" | 57 | <el-button size="mini" type="text" icon="el-icon-check" @click="handleChangeStatus(scope.row, true)" |
| @@ -109,13 +111,10 @@ | @@ -109,13 +111,10 @@ | ||
| 109 | <el-form-item label="处理器的名字:">{{ form.handlerName }}</el-form-item> | 111 | <el-form-item label="处理器的名字:">{{ form.handlerName }}</el-form-item> |
| 110 | <el-form-item label="处理器的参数:">{{ form.handlerParam }}</el-form-item> | 112 | <el-form-item label="处理器的参数:">{{ form.handlerParam }}</el-form-item> |
| 111 | <el-form-item label="cron表达式:">{{ form.cronExpression }}</el-form-item> | 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 | <el-form-item label="重试次数:">{{ form.retryCount }}</el-form-item> | 114 | <el-form-item label="重试次数:">{{ form.retryCount }}</el-form-item> |
| 117 | <el-form-item label="重试间隔:">{{ form.retryInterval + " 毫秒" }}</el-form-item> | 115 | <el-form-item label="重试间隔:">{{ form.retryInterval + " 毫秒" }}</el-form-item> |
| 118 | <el-form-item label="监控超时时间:">{{ form.monitorTimeout > 0 ? form.monitorTimeout + " 毫秒" : "未开启" }}</el-form-item> | 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 | </el-col> | 118 | </el-col> |
| 120 | </el-row> | 119 | </el-row> |
| 121 | </el-form> | 120 | </el-form> |
| @@ -128,7 +127,7 @@ | @@ -128,7 +127,7 @@ | ||
| 128 | </template> | 127 | </template> |
| 129 | 128 | ||
| 130 | <script> | 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 | import { InfJobStatusEnum } from "@/utils/constants"; | 131 | import { InfJobStatusEnum } from "@/utils/constants"; |
| 133 | 132 | ||
| 134 | export default { | 133 | export default { |
| @@ -169,6 +168,7 @@ export default { | @@ -169,6 +168,7 @@ export default { | ||
| 169 | retryCount: [{ required: true, message: "重试次数不能为空", trigger: "blur" }], | 168 | retryCount: [{ required: true, message: "重试次数不能为空", trigger: "blur" }], |
| 170 | retryInterval: [{ required: true, message: "重试间隔不能为空", trigger: "blur" }], | 169 | retryInterval: [{ required: true, message: "重试间隔不能为空", trigger: "blur" }], |
| 171 | }, | 170 | }, |
| 171 | + nextTimes: [], // 后续执行时间 | ||
| 172 | 172 | ||
| 173 | // 枚举 | 173 | // 枚举 |
| 174 | InfJobStatusEnum: InfJobStatusEnum | 174 | InfJobStatusEnum: InfJobStatusEnum |
| @@ -204,6 +204,7 @@ export default { | @@ -204,6 +204,7 @@ export default { | ||
| 204 | retryInterval: undefined, | 204 | retryInterval: undefined, |
| 205 | monitorTimeout: undefined, | 205 | monitorTimeout: undefined, |
| 206 | }; | 206 | }; |
| 207 | + this.nextTimes = []; | ||
| 207 | this.resetForm("form"); | 208 | this.resetForm("form"); |
| 208 | }, | 209 | }, |
| 209 | /** 搜索按钮操作 */ | 210 | /** 搜索按钮操作 */ |
| @@ -234,10 +235,23 @@ export default { | @@ -234,10 +235,23 @@ export default { | ||
| 234 | this.form = response.data; | 235 | this.form = response.data; |
| 235 | this.openView = true; | 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 | handleAdd() { | 257 | handleAdd() { |
ruoyi-ui/src/views/infra/job/log.vue
| 1 | <template> | 1 | <template> |
| 2 | <div class="app-container"> | 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 | </el-form-item> | 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 | </el-form-item> | 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 | </el-form-item> | 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 | </el-form-item> | 19 | </el-form-item> |
| 58 | <el-form-item> | 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 | <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> | 22 | <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> |
| 61 | </el-form-item> | 23 | </el-form-item> |
| 62 | </el-form> | 24 | </el-form> |
| 63 | 25 | ||
| 64 | <el-row :gutter="10" class="mb8"> | 26 | <el-row :gutter="10" class="mb8"> |
| 65 | <el-col :span="1.5"> | 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 | </el-col> | 30 | </el-col> |
| 93 | <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> | 31 | <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> |
| 94 | </el-row> | 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 | <template slot-scope="scope"> | 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 | </template> | 53 | </template> |
| 108 | </el-table-column> | 54 | </el-table-column> |
| 109 | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | 55 | <el-table-column label="操作" align="center" class-name="small-padding fixed-width"> |
| 110 | <template slot-scope="scope"> | 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 | </template> | 59 | </template> |
| 119 | </el-table-column> | 60 | </el-table-column> |
| 120 | </el-table> | 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 | <el-dialog title="调度日志详细" :visible.sync="open" width="700px" append-to-body> | 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 | <el-row> | 69 | <el-row> |
| 134 | <el-col :span="12"> | 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 | </el-col> | 80 | </el-col> |
| 157 | </el-row> | 81 | </el-row> |
| 158 | </el-form> | 82 | </el-form> |
| @@ -164,7 +88,7 @@ | @@ -164,7 +88,7 @@ | ||
| 164 | </template> | 88 | </template> |
| 165 | 89 | ||
| 166 | <script> | 90 | <script> |
| 167 | -import { listJobLog, delJobLog, exportJobLog, cleanJobLog } from "@/api/monitor/jobLog"; | 91 | +import { getJobLogPage, exportJobLogExcel } from "@/api/infra/jobLog"; |
| 168 | 92 | ||
| 169 | export default { | 93 | export default { |
| 170 | name: "JobLog", | 94 | name: "JobLog", |
| @@ -172,125 +96,81 @@ export default { | @@ -172,125 +96,81 @@ export default { | ||
| 172 | return { | 96 | return { |
| 173 | // 遮罩层 | 97 | // 遮罩层 |
| 174 | loading: true, | 98 | loading: true, |
| 175 | - // 选中数组 | ||
| 176 | - ids: [], | ||
| 177 | - // 非多个禁用 | ||
| 178 | - multiple: true, | ||
| 179 | // 显示搜索条件 | 99 | // 显示搜索条件 |
| 180 | showSearch: true, | 100 | showSearch: true, |
| 181 | // 总条数 | 101 | // 总条数 |
| 182 | total: 0, | 102 | total: 0, |
| 183 | // 调度日志表格数据 | 103 | // 调度日志表格数据 |
| 184 | - jobLogList: [], | 104 | + list: [], |
| 185 | // 是否显示弹出层 | 105 | // 是否显示弹出层 |
| 186 | open: false, | 106 | open: false, |
| 187 | - // 日期范围 | ||
| 188 | - dateRange: [], | ||
| 189 | // 表单参数 | 107 | // 表单参数 |
| 190 | form: {}, | 108 | form: {}, |
| 191 | - // 执行状态字典 | ||
| 192 | - statusOptions: [], | ||
| 193 | - // 任务组名字典 | ||
| 194 | - jobGroupOptions: [], | ||
| 195 | // 查询参数 | 109 | // 查询参数 |
| 196 | queryParams: { | 110 | queryParams: { |
| 197 | - pageNum: 1, | 111 | + pageNo: 1, |
| 198 | pageSize: 10, | 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 | created() { | 120 | created() { |
| 121 | + this.queryParams.jobId = this.$route.query && this.$route.query.jobId; | ||
| 206 | this.getList(); | 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 | methods: { | 124 | methods: { |
| 215 | /** 查询调度日志列表 */ | 125 | /** 查询调度日志列表 */ |
| 216 | getList() { | 126 | getList() { |
| 217 | this.loading = true; | 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 | this.loading = false; | 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 | handleQuery() { | 140 | handleQuery() { |
| 235 | - this.queryParams.pageNum = 1; | 141 | + this.queryParams.pageNo = 1; |
| 236 | this.getList(); | 142 | this.getList(); |
| 237 | }, | 143 | }, |
| 238 | /** 重置按钮操作 */ | 144 | /** 重置按钮操作 */ |
| 239 | resetQuery() { | 145 | resetQuery() { |
| 240 | - this.dateRange = []; | ||
| 241 | this.resetForm("queryForm"); | 146 | this.resetForm("queryForm"); |
| 242 | this.handleQuery(); | 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 | handleView(row) { | 150 | handleView(row) { |
| 251 | this.open = true; | 151 | this.open = true; |
| 252 | this.form = row; | 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 | handleExport() { | 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 | \ No newline at end of file | 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,6 +2,11 @@ package cn.iocoder.dashboard.framework.quartz.core.util; | ||
| 2 | 2 | ||
| 3 | import org.quartz.CronExpression; | 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 | * Quartz Cron 表达式的工具类 | 11 | * Quartz Cron 表达式的工具类 |
| 7 | * | 12 | * |
| @@ -19,4 +24,31 @@ public class CronUtils { | @@ -19,4 +24,31 @@ public class CronUtils { | ||
| 19 | return CronExpression.isValidExpression(cronExpression); | 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,6 +4,7 @@ import cn.iocoder.dashboard.common.pojo.CommonResult; | ||
| 4 | import cn.iocoder.dashboard.common.pojo.PageResult; | 4 | import cn.iocoder.dashboard.common.pojo.PageResult; |
| 5 | import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils; | 5 | import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils; |
| 6 | import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog; | 6 | import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog; |
| 7 | +import cn.iocoder.dashboard.framework.quartz.core.util.CronUtils; | ||
| 7 | import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.*; | 8 | import cn.iocoder.dashboard.modules.infra.controller.job.vo.job.*; |
| 8 | import cn.iocoder.dashboard.modules.infra.convert.job.InfJobConvert; | 9 | import cn.iocoder.dashboard.modules.infra.convert.job.InfJobConvert; |
| 9 | import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobDO; | 10 | import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobDO; |
| @@ -22,6 +23,8 @@ import javax.servlet.http.HttpServletResponse; | @@ -22,6 +23,8 @@ import javax.servlet.http.HttpServletResponse; | ||
| 22 | import javax.validation.Valid; | 23 | import javax.validation.Valid; |
| 23 | import java.io.IOException; | 24 | import java.io.IOException; |
| 24 | import java.util.Collection; | 25 | import java.util.Collection; |
| 26 | +import java.util.Collections; | ||
| 27 | +import java.util.Date; | ||
| 25 | import java.util.List; | 28 | import java.util.List; |
| 26 | 29 | ||
| 27 | import static cn.iocoder.dashboard.common.pojo.CommonResult.success; | 30 | import static cn.iocoder.dashboard.common.pojo.CommonResult.success; |
| @@ -123,4 +126,20 @@ public class InfJobController { | @@ -123,4 +126,20 @@ public class InfJobController { | ||
| 123 | ExcelUtils.write(response, "定时任务.xls", "数据", InfJobExcelVO.class, datas); | 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,14 +23,14 @@ public class InfJobBaseVO { | ||
| 23 | @NotNull(message = "CRON 表达式不能为空") | 23 | @NotNull(message = "CRON 表达式不能为空") |
| 24 | private String cronExpression; | 24 | private String cronExpression; |
| 25 | 25 | ||
| 26 | - @ApiModelProperty(value = "重试次数", required = true) | 26 | + @ApiModelProperty(value = "重试次数", required = true, example = "3") |
| 27 | @NotNull(message = "重试次数不能为空") | 27 | @NotNull(message = "重试次数不能为空") |
| 28 | private Integer retryCount; | 28 | private Integer retryCount; |
| 29 | 29 | ||
| 30 | - @ApiModelProperty(value = "重试间隔", required = true) | 30 | + @ApiModelProperty(value = "重试间隔", required = true, example = "1000") |
| 31 | @NotNull(message = "重试间隔不能为空") | 31 | @NotNull(message = "重试间隔不能为空") |
| 32 | private Integer retryInterval; | 32 | private Integer retryInterval; |
| 33 | - | 33 | + |
| 34 | @ApiModelProperty(value = "监控超时时间", example = "1000") | 34 | @ApiModelProperty(value = "监控超时时间", example = "1000") |
| 35 | private Integer monitorTimeout; | 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,18 +25,6 @@ public class InfJobRespVO extends InfJobBaseVO { | ||
| 25 | @NotNull(message = "处理器的名字不能为空") | 25 | @NotNull(message = "处理器的名字不能为空") |
| 26 | private String handlerName; | 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 | @ApiModelProperty(value = "创建时间", required = true) | 28 | @ApiModelProperty(value = "创建时间", required = true) |
| 41 | private Date createTime; | 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,18 +16,18 @@ import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOU | ||
| 16 | @Data | 16 | @Data |
| 17 | public class InfJobLogBaseVO { | 17 | public class InfJobLogBaseVO { |
| 18 | 18 | ||
| 19 | - @ApiModelProperty(value = "任务编号", required = true) | 19 | + @ApiModelProperty(value = "任务编号", required = true, example = "1024") |
| 20 | @NotNull(message = "任务编号不能为空") | 20 | @NotNull(message = "任务编号不能为空") |
| 21 | private Long jobId; | 21 | private Long jobId; |
| 22 | 22 | ||
| 23 | - @ApiModelProperty(value = "处理器的名字", required = true) | 23 | + @ApiModelProperty(value = "处理器的名字", required = true, example = "sysUserSessionTimeoutJob") |
| 24 | @NotNull(message = "处理器的名字不能为空") | 24 | @NotNull(message = "处理器的名字不能为空") |
| 25 | private String handlerName; | 25 | private String handlerName; |
| 26 | 26 | ||
| 27 | - @ApiModelProperty(value = "处理器的参数") | 27 | + @ApiModelProperty(value = "处理器的参数", example = "yudao") |
| 28 | private String handlerParam; | 28 | private String handlerParam; |
| 29 | 29 | ||
| 30 | - @ApiModelProperty(value = "第几次执行", required = true) | 30 | + @ApiModelProperty(value = "第几次执行", required = true, example = "1") |
| 31 | @NotNull(message = "第几次执行不能为空") | 31 | @NotNull(message = "第几次执行不能为空") |
| 32 | private Integer executeIndex; | 32 | private Integer executeIndex; |
| 33 | 33 | ||
| @@ -40,14 +40,14 @@ public class InfJobLogBaseVO { | @@ -40,14 +40,14 @@ public class InfJobLogBaseVO { | ||
| 40 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | 40 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| 41 | private Date endTime; | 41 | private Date endTime; |
| 42 | 42 | ||
| 43 | - @ApiModelProperty(value = "执行时长") | 43 | + @ApiModelProperty(value = "执行时长", example = "123") |
| 44 | private Integer duration; | 44 | private Integer duration; |
| 45 | 45 | ||
| 46 | - @ApiModelProperty(value = "任务状态", required = true) | 46 | + @ApiModelProperty(value = "任务状态", required = true, example = "1", notes = "参见 InfJobLogStatusEnum 枚举") |
| 47 | @NotNull(message = "任务状态不能为空") | 47 | @NotNull(message = "任务状态不能为空") |
| 48 | private Integer status; | 48 | private Integer status; |
| 49 | 49 | ||
| 50 | - @ApiModelProperty(value = "结果数据") | 50 | + @ApiModelProperty(value = "结果数据", example = "执行成功") |
| 51 | private String result; | 51 | private String result; |
| 52 | 52 | ||
| 53 | } | 53 | } |
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogExcelVO.java
| 1 | package cn.iocoder.dashboard.modules.infra.controller.job.vo.log; | 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 | import com.alibaba.excel.annotation.ExcelProperty; | 6 | import com.alibaba.excel.annotation.ExcelProperty; |
| 4 | import lombok.Data; | 7 | import lombok.Data; |
| 5 | 8 | ||
| @@ -37,7 +40,8 @@ public class InfJobLogExcelVO { | @@ -37,7 +40,8 @@ public class InfJobLogExcelVO { | ||
| 37 | @ExcelProperty("执行时长") | 40 | @ExcelProperty("执行时长") |
| 38 | private Integer duration; | 41 | private Integer duration; |
| 39 | 42 | ||
| 40 | - @ExcelProperty("任务状态") | 43 | + @ExcelProperty(value = "任务状态", converter = DictConvert.class) |
| 44 | + @DictFormat(SysDictTypeEnum.INF_JOB_STATUS) | ||
| 41 | private Integer status; | 45 | private Integer status; |
| 42 | 46 | ||
| 43 | @ExcelProperty("结果数据") | 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,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty; | ||
| 5 | import lombok.Data; | 5 | import lombok.Data; |
| 6 | import org.springframework.format.annotation.DateTimeFormat; | 6 | import org.springframework.format.annotation.DateTimeFormat; |
| 7 | 7 | ||
| 8 | +import javax.validation.constraints.NotNull; | ||
| 8 | import java.util.Date; | 9 | import java.util.Date; |
| 9 | 10 | ||
| 10 | import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | 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,7 +14,10 @@ import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOU | ||
| 13 | @Data | 14 | @Data |
| 14 | public class InfJobLogExportReqVO { | 15 | public class InfJobLogExportReqVO { |
| 15 | 16 | ||
| 16 | - @ApiModelProperty(value = "处理器的名字") | 17 | + @ApiModelProperty(value = "任务编号", example = "10") |
| 18 | + private Long jobId; | ||
| 19 | + | ||
| 20 | + @ApiModelProperty(value = "处理器的名字", notes = "模糊匹配") | ||
| 17 | private String handlerName; | 21 | private String handlerName; |
| 18 | 22 | ||
| 19 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | 23 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| @@ -24,7 +28,7 @@ public class InfJobLogExportReqVO { | @@ -24,7 +28,7 @@ public class InfJobLogExportReqVO { | ||
| 24 | @ApiModelProperty(value = "结束执行时间") | 28 | @ApiModelProperty(value = "结束执行时间") |
| 25 | private Date endTime; | 29 | private Date endTime; |
| 26 | 30 | ||
| 27 | - @ApiModelProperty(value = "任务状态") | 31 | + @ApiModelProperty(value = "任务状态", notes = "参见 InfJobLogStatusEnum 枚举") |
| 28 | private Integer status; | 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,7 +18,10 @@ import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOU | ||
| 18 | @ToString(callSuper = true) | 18 | @ToString(callSuper = true) |
| 19 | public class InfJobLogPageReqVO extends PageParam { | 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 | private String handlerName; | 25 | private String handlerName; |
| 23 | 26 | ||
| 24 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | 27 | @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) |
| @@ -29,7 +32,7 @@ public class InfJobLogPageReqVO extends PageParam { | @@ -29,7 +32,7 @@ public class InfJobLogPageReqVO extends PageParam { | ||
| 29 | @ApiModelProperty(value = "结束执行时间") | 32 | @ApiModelProperty(value = "结束执行时间") |
| 30 | private Date endTime; | 33 | private Date endTime; |
| 31 | 34 | ||
| 32 | - @ApiModelProperty(value = "任务状态") | 35 | + @ApiModelProperty(value = "任务状态", notes = "参见 InfJobLogStatusEnum 枚举") |
| 33 | private Integer status; | 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,7 +14,7 @@ import java.util.Date; | ||
| 14 | @ToString(callSuper = true) | 14 | @ToString(callSuper = true) |
| 15 | public class InfJobLogRespVO extends InfJobLogBaseVO { | 15 | public class InfJobLogRespVO extends InfJobLogBaseVO { |
| 16 | 16 | ||
| 17 | - @ApiModelProperty(value = "日志编号", required = true) | 17 | + @ApiModelProperty(value = "日志编号", required = true, example = "1024") |
| 18 | private Long id; | 18 | private Long id; |
| 19 | 19 | ||
| 20 | @ApiModelProperty(value = "创建时间", required = true) | 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,8 +6,6 @@ import com.baomidou.mybatisplus.annotation.TableId; | ||
| 6 | import com.baomidou.mybatisplus.annotation.TableName; | 6 | import com.baomidou.mybatisplus.annotation.TableName; |
| 7 | import lombok.*; | 7 | import lombok.*; |
| 8 | 8 | ||
| 9 | -import java.util.Date; | ||
| 10 | - | ||
| 11 | /** | 9 | /** |
| 12 | * 定时任务 DO | 10 | * 定时任务 DO |
| 13 | * | 11 | * |
| @@ -45,35 +43,10 @@ public class InfJobDO extends BaseDO { | @@ -45,35 +43,10 @@ public class InfJobDO extends BaseDO { | ||
| 45 | * 处理器的参数 | 43 | * 处理器的参数 |
| 46 | */ | 44 | */ |
| 47 | private String handlerParam; | 45 | private String handlerParam; |
| 48 | - | ||
| 49 | - // ========== 时间相关字段 ========== | ||
| 50 | - | ||
| 51 | /** | 46 | /** |
| 52 | * CRON 表达式 | 47 | * CRON 表达式 |
| 53 | */ | 48 | */ |
| 54 | private String cronExpression; | 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,8 +69,4 @@ public class InfJobDO extends BaseDO { | ||
| 96 | */ | 69 | */ |
| 97 | private Integer monitorTimeout; | 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 | package cn.iocoder.dashboard.modules.infra.dal.mysql.job; | 1 | package cn.iocoder.dashboard.modules.infra.dal.mysql.job; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.dashboard.common.pojo.PageResult; | ||
| 3 | import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; | 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 | import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobLogDO; | 8 | import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobLogDO; |
| 5 | import org.apache.ibatis.annotations.Mapper; | 9 | import org.apache.ibatis.annotations.Mapper; |
| 6 | 10 | ||
| 11 | +import java.util.List; | ||
| 12 | + | ||
| 7 | /** | 13 | /** |
| 8 | * 任务日志 Mapper | 14 | * 任务日志 Mapper |
| 9 | * | 15 | * |
| @@ -11,4 +17,27 @@ import org.apache.ibatis.annotations.Mapper; | @@ -11,4 +17,27 @@ import org.apache.ibatis.annotations.Mapper; | ||
| 11 | */ | 17 | */ |
| 12 | @Mapper | 18 | @Mapper |
| 13 | public interface InfJobLogMapper extends BaseMapperX<InfJobLogDO> { | 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 | package cn.iocoder.dashboard.modules.infra.service.job; | 1 | package cn.iocoder.dashboard.modules.infra.service.job; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.dashboard.common.pojo.PageResult; | ||
| 3 | import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService; | 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 | * Job 日志 Service 接口 | 13 | * Job 日志 Service 接口 |
| @@ -8,4 +15,37 @@ import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService | @@ -8,4 +15,37 @@ import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService | ||
| 8 | * @author 芋道源码 | 15 | * @author 芋道源码 |
| 9 | */ | 16 | */ |
| 10 | public interface InfJobLogService extends JobLogFrameworkService { | 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 | package cn.iocoder.dashboard.modules.infra.service.job.impl; | 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 | import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobLogDO; | 6 | import cn.iocoder.dashboard.modules.infra.dal.dataobject.job.InfJobLogDO; |
| 4 | import cn.iocoder.dashboard.modules.infra.dal.mysql.job.InfJobLogMapper; | 7 | import cn.iocoder.dashboard.modules.infra.dal.mysql.job.InfJobLogMapper; |
| 5 | import cn.iocoder.dashboard.modules.infra.enums.job.InfJobLogStatusEnum; | 8 | import cn.iocoder.dashboard.modules.infra.enums.job.InfJobLogStatusEnum; |
| @@ -10,7 +13,9 @@ import org.springframework.stereotype.Service; | @@ -10,7 +13,9 @@ import org.springframework.stereotype.Service; | ||
| 10 | import org.springframework.validation.annotation.Validated; | 13 | import org.springframework.validation.annotation.Validated; |
| 11 | 14 | ||
| 12 | import javax.annotation.Resource; | 15 | import javax.annotation.Resource; |
| 16 | +import java.util.Collection; | ||
| 13 | import java.util.Date; | 17 | import java.util.Date; |
| 18 | +import java.util.List; | ||
| 14 | 19 | ||
| 15 | /** | 20 | /** |
| 16 | * Job 日志 Service 实现类 | 21 | * Job 日志 Service 实现类 |
| @@ -46,4 +51,24 @@ public class InfJobLogServiceImpl implements InfJobLogService { | @@ -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,8 +15,9 @@ import java.util.List; | ||
| 15 | @Mapper | 15 | @Mapper |
| 16 | public interface SysDictDataMapper extends BaseMapperX<SysDictDataDO> { | 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 | default int selectCountByDictType(String dictType) { | 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,8 +18,9 @@ public enum SysDictTypeEnum { | ||
| 18 | SYS_BOOLEAN_STRING("sys_boolean_string"), // Boolean 是否类型 | 18 | SYS_BOOLEAN_STRING("sys_boolean_string"), // Boolean 是否类型 |
| 19 | 19 | ||
| 20 | INF_REDIS_TIMEOUT_TYPE("inf_redis_timeout_type"), // Redis 超时类型 | 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,9 +15,6 @@ public class SysUserSessionTimeoutJob implements JobHandler { | ||
| 15 | 15 | ||
| 16 | @Override | 16 | @Override |
| 17 | public String execute(String param) throws Exception { | 17 | public String execute(String param) throws Exception { |
| 18 | - if (true) { | ||
| 19 | - throw new RuntimeException("测试异常"); | ||
| 20 | - } | ||
| 21 | // System.out.println("执行了一次任务"); | 18 | // System.out.println("执行了一次任务"); |
| 22 | log.info("[execute][执行任务:{}]", param); | 19 | log.info("[execute][执行任务:{}]", param); |
| 23 | return null; | 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,13 +195,13 @@ public class SysDictDataServiceImpl implements SysDictDataService { | ||
| 195 | // 校验自己存在 | 195 | // 校验自己存在 |
| 196 | checkDictDataExists(id); | 196 | checkDictDataExists(id); |
| 197 | // 校验字典数据的值的唯一性 | 197 | // 校验字典数据的值的唯一性 |
| 198 | - checkDictDataValueUnique(id, label); | 198 | + checkDictDataValueUnique(id, dictType, label); |
| 199 | // 校验字典类型有效 | 199 | // 校验字典类型有效 |
| 200 | checkDictTypeValid(dictType); | 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 | if (dictData == null) { | 205 | if (dictData == null) { |
| 206 | return; | 206 | return; |
| 207 | } | 207 | } |
src/main/java/cn/iocoder/dashboard/modules/tool/controller/test/ToolTestDemoController.java
| @@ -51,7 +51,7 @@ public class ToolTestDemoController { | @@ -51,7 +51,7 @@ public class ToolTestDemoController { | ||
| 51 | 51 | ||
| 52 | @DeleteMapping("/delete") | 52 | @DeleteMapping("/delete") |
| 53 | @ApiOperation("删除测试示例") | 53 | @ApiOperation("删除测试示例") |
| 54 | - @ApiImplicitParam(name = "id", value = "编号", required = true) | 54 | + @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class) |
| 55 | @PreAuthorize("@ss.hasPermission('tool:test-demo:delete')") | 55 | @PreAuthorize("@ss.hasPermission('tool:test-demo:delete')") |
| 56 | public CommonResult<Boolean> deleteTestDemo(@RequestParam("id") Long id) { | 56 | public CommonResult<Boolean> deleteTestDemo(@RequestParam("id") Long id) { |
| 57 | testDemoService.deleteTestDemo(id); | 57 | testDemoService.deleteTestDemo(id); |
src/main/resources/application.yaml
| @@ -50,11 +50,16 @@ spring: | @@ -50,11 +50,16 @@ spring: | ||
| 50 | properties: # 添加 Quartz Scheduler 附加属性,更多可以看 http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/configuration.html 文档 | 50 | properties: # 添加 Quartz Scheduler 附加属性,更多可以看 http://www.quartz-scheduler.org/documentation/2.4.0-SNAPSHOT/configuration.html 文档 |
| 51 | org: | 51 | org: |
| 52 | quartz: | 52 | quartz: |
| 53 | + # Scheduler 相关配置 | ||
| 54 | + scheduler: | ||
| 55 | + instanceName: schedulerName | ||
| 56 | + instanceId: AUTO # 自动生成 instance ID | ||
| 53 | # JobStore 相关配置 | 57 | # JobStore 相关配置 |
| 54 | jobStore: | 58 | jobStore: |
| 55 | class: org.quartz.impl.jdbcjobstore.JobStoreTX # JobStore 实现类 | 59 | class: org.quartz.impl.jdbcjobstore.JobStoreTX # JobStore 实现类 |
| 56 | isClustered: true # 是集群模式 | 60 | isClustered: true # 是集群模式 |
| 57 | - clusterCheckinInterval: 1000 | 61 | + clusterCheckinInterval: 15000 # 集群检查频率,单位:毫秒。默认为 15000,即 15 秒 |
| 62 | + misfireThreshold: 60000 # misfire 阀值,单位:毫秒。 | ||
| 58 | # 线程池相关配置 | 63 | # 线程池相关配置 |
| 59 | threadPool: | 64 | threadPool: |
| 60 | threadCount: 25 # 线程池大小。默认为 10 。 | 65 | threadCount: 25 # 线程池大小。默认为 10 。 |