vue3 添加编辑页使用 cron 表达式生成

示例效果图
在这里插入图片描述

1、添加组件

<template><div class="v3c"><ul class="v3c-tab"><li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 1 }" @click="onHandleTab(1)"></li><li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 2 }" @click="onHandleTab(2)"></li><li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 3 }" @click="onHandleTab(3)"></li><li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 4 }" @click="onHandleTab(4)"></li><li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 5 }" @click="onHandleTab(5)"></li><li class="v3c-tab-item" :class="{ 'v3c-active': tabActive == 6 }" @click="onHandleTab(6)"></li></ul><!-- 秒 --><div class="v3c-content" v-show="tabActive == 1"><!-- 每一秒 --><div><el-radio label="1" v-model="state.second.cronEvery">每一秒钟</el-radio></div><!-- 每隔多久 --><div class="mt-15"><el-radio label="2" v-model="state.second.cronEvery">每隔</el-radio><el-input-number v-model="state.second.incrementIncrement" :min="1" :max="60" controls-position="right"/><span class="ml-5 mr-5">秒执行, 从</span><el-input-number v-model="state.second.incrementStart" :min="0" :max="59" controls-position="right"/><span>秒开始</span></div><!-- 具体秒数 --><div class="mt-15"><el-radio label="3" v-model="state.second.cronEvery">具体秒数(可多选)</el-radio><el-select v-model="state.second.specificSpecific" multiple clearable style="width: 140px"><el-option v-for="(item, index) in 60" :key="index" :label="index" :value="index"/></el-select></div><!-- 周期从 --><div class="mt-15"><el-radio label="4" v-model="state.second.cronEvery">周期从</el-radio><el-input-number v-model="state.second.rangeStart" :min="0" :max="59" controls-position="right"/><sapn></sapn><span class="ml-10 mr-5"></span><el-input-number v-model="state.second.rangeEnd" :min="0" :max="59" controls-position="right"/><sapn></sapn></div></div><!-- 分钟 --><div class="v3c-content" v-show="tabActive == 2"><!-- 每一分钟 --><div><el-radio label="1" v-model="state.minute.cronEvery">每一分钟</el-radio></div><!-- 每隔多久 --><div class="mt-15"><el-radio label="2" v-model="state.minute.cronEvery">每隔</el-radio><el-input-number v-model="state.minute.incrementIncrement" :min="1" :max="60" controls-position="right"/><span class="ml-5 mr-5">分执行,从</span><el-input-number v-model="state.minute.incrementStart" :min="0" :max="59" controls-position="right"/><span>分开始</span></div><!-- 具体分钟数 --><div class="mt-15"><el-radio label="3" v-model="state.minute.cronEvery">具体分钟数(可多选)</el-radio><el-select v-model="state.minute.specificSpecific" multiple clearable style="width: 140px"><el-option v-for="(item, index) in 60" :key="index" :label="index" :value="index"/></el-select></div><!-- 周期从 --><div class="mt-15"><el-radio label="4" v-model="state.minute.cronEvery">周期从</el-radio><el-input-number v-model="state.minute.rangeStart" :min="0" :max="59" controls-position="right"/><span></span><span class="ml-10 mr-5"></span><el-input-number v-model="state.minute.rangeEnd" :min="0" :max="59" controls-position="right"/><span></span></div></div><!-- 小时 --><div class="v3c-content" v-show="tabActive == 3"><!-- 每一小时 --><div><el-radio label="1" v-model="state.hour.cronEvery">每一小时</el-radio></div><!-- 每隔多久 --><div class="mt-15"><el-radio label="2" v-model="state.hour.cronEvery">每隔</el-radio><el-input-number v-model="state.hour.incrementIncrement" :min="1" :max="24" controls-position="right"/><span class="ml-5 mr-5">小时执行,从</span><el-input-number v-model="state.hour.incrementStart" :min="0" :max="23" controls-position="right"/><span>小时开始</span></div><!-- 具体小时数 --><div class="mt-15"><el-radio label="3" v-model="state.hour.cronEvery">具体小时数(可多选)</el-radio><el-select v-model="state.hour.specificSpecific" multiple clearable style="width: 140px"><el-option v-for="(item, index) in 24" :key="index" :label="index" :value="index"/></el-select></div><!-- 周期从 --><div class="mt-15"><el-radio label="4" v-model="state.hour.cronEvery">周期从</el-radio><el-input-number v-model="state.hour.rangeStart" :min="0" :max="23" controls-position="right"/><span></span><span class="ml-10 mr-5"></span><el-input-number v-model="state.hour.rangeEnd" :min="0" :max="23" controls-position="right"/><span></span></div></div><!-- 天 --><div class="v3c-content" v-show="tabActive == 4"><!-- 1 --><div><el-radio label="1" v-model="state.day.cronEvery">每一天</el-radio></div><!-- 2 -->
<!--            <div class="mt-15">-->
<!--                <el-radio label="2" v-model="state.day.cronEvery">每隔</el-radio>-->
<!--                <el-input-number v-model="state.week.incrementIncrement" :min="1" :max="60" controls-position="right"/>-->
<!--                <span class="ml-5 mr-5">周执行,从</span>-->
<!--                <el-input-number v-model="state.week.incrementStart" :min="1" :max="52" controls-position="right"/>-->
<!--                <span>周开始</span>-->
<!--            </div>--><!-- 3 --><div class="mt-15"><el-radio label="3" v-model="state.day.cronEvery">每隔</el-radio><el-input-number v-model="state.day.incrementIncrement" :min="1" :max="30" controls-position="right"/><span class="ml-5 mr-5">天执行,从</span><el-input-number v-model="state.day.incrementStart" :min="1" :max="30" controls-position="right"/><span>天开始</span></div><!-- 4 --><div class="mt-15"><el-radio label="4" v-model="state.day.cronEvery">具体星期几(可多选)</el-radio><el-select v-model="state.week.specificSpecific" multiple clearable style="width: 140px"><el-option v-for="(item, index) in weekList" :key="index" :label="item.name" :value="item.value"/></el-select></div><!-- 5 --><div class="mt-15"><el-radio label="5" v-model="state.day.cronEvery">具体天数(可多选)</el-radio><el-select v-model="state.day.specificSpecific" multiple clearable style="width: 140px"><el-option v-for="(item, index) in 31" :key="index" :label="item" :value="item"/></el-select></div><!-- 6 --><!-- <div class="mt-15"><el-radio label="6" v-model="state.day.cronEvery">在这个月的最后一天</el-radio></div> --><!-- 7 --><!-- <div class="mt-15"><el-radio label="7" v-model="state.day.cronEvery">在这个月的最后一个工作日</el-radio></div> --><!-- 8 --><!-- <div class="mt-15"><el-radio label="8" v-model="state.day.cronEvery">在这个月的最后一个</el-radio><el-select v-model="state.day.cronLastSpecificDomDay" style="width: 140px"><el-option v-for="(item, index) in weekList" :key="index" :label="item.name" :value="item.val" /></el-select></div> --><!-- 9 --><!-- <div class="mt-15"><el-radio label="9" v-model="state.day.cronEvery">{{ }}</el-radio><el-input-number v-model="state.day.cronDaysBeforeEomMinus" :min="1" :max="31" controls-position="right" /><span>在本月底前</span></div> --><!-- 10 --><!-- <div class="mt-15"><el-radio label="10" v-model="state.day.cronEvery">最近的工作日(周一至周五)至本月</el-radio><el-input-number v-model="state.day.cronDaysNearestWeekday" :min="1" :max="31" controls-position="right" /><span>日</span></div> --><!-- 11 --><!-- <div class="mt-15"><el-radio label="11" v-model="state.day.cronEvery">在这个月的第</el-radio><el-input-number v-model="state.week.cronNthDayNth" :min="1" :max="5" controls-position="right" /><span>个</span><el-select v-model="state.week.cronNthDayDay" style="width: 140px"><el-option v-for="(item, index) in weekList" :key="index" :label="item.name" :value="item.val" /></el-select></div> --></div><!-- 月 --><div class="v3c-content" v-show="tabActive == 5"><!-- 1 --><div><el-radio label="1" v-model="state.month.cronEvery">每一月</el-radio></div><!-- 2 --><div class="mt-15"><el-radio label="2" v-model="state.month.cronEvery">每隔</el-radio><el-input-number v-model="state.month.incrementIncrement" :min="1" :max="12" controls-position="right"/><span class="ml-5 mr-5">月执行,从</span><el-input-number v-model="state.month.incrementStart" :min="1" :max="12" controls-position="right"/><span>月开始</span></div><!-- 3 --><div class="mt-15"><el-radio label="3" v-model="state.month.cronEvery">具体月数(可多选)</el-radio><el-select multiple clearable v-model="state.month.specificSpecific" style="width: 140px"><el-option v-for="(item, index) in 12" :key="index" :label="item" :value="item"/></el-select></div><!-- 4 --><div class="mt-15"><el-radio label="4" v-model="state.month.cronEvery">周期从</el-radio><el-input-number v-model="state.month.rangeStart" :min="1" :max="12" controls-position="right"/><span></span><span class="ml-10 mr-5"></span><el-input-number v-model="state.month.rangeEnd" :min="1" :max="12" controls-position="right"/><span></span></div></div><!-- 年 --><div class="v3c-content" v-show="tabActive == 6"><!-- 1 --><div><el-radio label="1" v-model="state.year.cronEvery">每一年</el-radio></div><!-- 2 --><div class="mt-15"><el-radio label="2" v-model="state.year.cronEvery">每隔</el-radio><el-input-number v-model="state.year.incrementIncrement" :min="1" :max="99" controls-position="right"/><span class="ml-5 mr-5">年执行,从</span><el-input-number v-model="state.year.incrementStart" :min="currYear" :max="currYear + 10"controls-position="right" style="width:100px;"/><span>年开始</span></div><!-- 3 -->
<!--            <div class="mt-15">-->
<!--                <el-radio label="3" v-model="state.year.cronEvery">具体年份(可多选)</el-radio>-->
<!--                <el-select multiple clearable v-model="state.year.specificSpecific" style="width: 140px">-->
<!--                    <el-option v-for="(item, index) in 100" :key="index" :label="currYear + item" :value="currYear + item"/>-->
<!--                </el-select>-->
<!--            </div>-->
<!--            &lt;!&ndash; 4 &ndash;&gt;-->
<!--            <div class="mt-15">-->
<!--                <el-radio label="4" v-model="state.year.cronEvery">周期从</el-radio>-->
<!--                <el-input-number v-model="state.year.rangeStart" :min="currYear" :max="currYear + 10" controls-position="right"-->
<!--                                 style="width:100px;"/>-->
<!--                <span>年</span><span class="ml-10 mr-5">到</span>-->
<!--                <el-input-number v-model="state.year.rangeEnd" :min="currYear" :max="currYear + 10" controls-position="right"-->
<!--                                 style="width:100px;"/>-->
<!--                <span>年</span>-->
<!--            </div>--></div><div class="mt-15"><el-input v-model="value"/></div></div>
</template><script>
import {reactive, computed, toRefs, defineComponent, ref, watch} from "vue";
// (默认是每一分钟一次)
export default defineComponent({name: "Vue3Cron",props: {maxHeight: String,change: Function,value: String,},setup(props, {emit}) {const weekList = ref([{name: '星期日', val: 'SUN', value: 1,},{name: '星期一', val: 'MON', value: 2,},{name: '星期二', val: 'TUE', value: 3,},{name: '星期三', val: 'WED', value: 4,},{name: '星期四', val: 'THU', value: 5,},{name: '星期五', val: 'FRI', value: 6,},{name: '星期六', val: 'SAT', value: 7,},])const tabActive = ref(1);const currYear = ref(new Date().getFullYear());const onHandleTab = (index) => {tabActive.value = index;};// (默认是每一分钟一次)const state = reactive({second: {cronEvery: "1",incrementStart: 0,incrementIncrement: 1,rangeStart: 0,rangeEnd: 0,specificSpecific: [],},minute: {cronEvery: "1",incrementStart: 0,incrementIncrement: 1,rangeStart: 0,rangeEnd: 0,specificSpecific: [],},hour: {cronEvery: "1",incrementStart: 1,incrementIncrement: 1,rangeStart: 0,rangeEnd: 0,specificSpecific: [],},day: {cronEvery: "1",incrementStart: 1,incrementIncrement: 1,rangeStart: 0,rangeEnd: 0,specificSpecific: [],cronLastSpecificDomDay: 1,cronDaysBeforeEomMinus: 0,cronDaysNearestWeekday: 1,},week: {cronEvery: "1",incrementStart: 1,incrementIncrement: 1,specificSpecific: [],cronNthDayDay: 1,cronNthDayNth: 1,},month: {cronEvery: "1",incrementStart: 1,incrementIncrement: 1,rangeStart: 1,rangeEnd: 1,specificSpecific: [],},year: {cronEvery: "1",incrementStart: new Date().getFullYear(),incrementIncrement: 1,rangeStart: new Date().getFullYear(),rangeEnd: new Date().getFullYear(),specificSpecific: [],},output: {second: "",minute: "",hour: "",day: "",month: "",Week: "",year: "",},secondsText: computed(() => {let seconds = "";let cronEvery = state.second.cronEvery;switch (cronEvery?.toString()) {case "1":seconds = "*";break;case "2":seconds = state.second.incrementStart + "/" + state.second.incrementIncrement;break;case "3":state.second.specificSpecific.map((val) => {seconds += val + ",";});seconds = seconds.slice(0, -1);break;case "4":seconds = state.second.rangeStart + "-" + state.second.rangeEnd;break;}return seconds;}),minutesText: computed(() => {let minutes = "";let cronEvery = state.minute.cronEvery;switch (cronEvery?.toString()) {case "1":minutes = "*";break;case "2":minutes = state.minute.incrementStart + "/" + state.minute.incrementIncrement;break;case "3":state.minute.specificSpecific.map((val) => {minutes += val + ",";});minutes = minutes.slice(0, -1);break;case "4":minutes = state.minute.rangeStart + "-" + state.minute.rangeEnd;break;}return minutes;}),hoursText: computed(() => {let hours = "";let cronEvery = state.hour.cronEvery;switch (cronEvery?.toString()) {case "1":hours = "*";break;case "2":hours = state.hour.incrementStart + "/" + state.hour.incrementIncrement;break;case "3":state.hour.specificSpecific.map((val) => {hours += val + ",";});hours = hours.slice(0, -1);break;case "4":hours = state.hour.rangeStart + "-" + state.hour.rangeEnd;break;}return hours;}),daysText: computed(() => {let days = "";let cronEvery = state.day.cronEvery;switch (cronEvery?.toString()) {case "1":break;case "2":case "4":case "11":days = "?";break;case "3":days = state.day.incrementStart + "/" + state.day.incrementIncrement;break;case "5":state.day.specificSpecific.map((val) => {days += val + ",";});days = days.slice(0, -1);break;case "6":days = "L";break;case "7":days = "LW";break;case "8":days = state.day.cronLastSpecificDomDay + "L";break;case "9":days = "L-" + state.day.cronDaysBeforeEomMinus;break;case "10":days = state.day.cronDaysNearestWeekday + "W";break;}return days;}),weeksText: computed(() => {console.log("------------")let weeks = "";let cronEvery = state.day.cronEvery;switch (cronEvery?.toString()) {case "2":weeks = state.week.incrementStart + "/" + state.week.incrementIncrement;break;case "4":state.week.specificSpecific.map((val) => {weeks += val + ",";});weeks = weeks.slice(0, -1);break;case "5":weeks = "?";break;case "10":weeks = "?";break;case "11":weeks = state.week.cronNthDayDay + "#" + state.week.cronNthDayNth;break;}return weeks;}),monthsText: computed(() => {let months = "";let cronEvery = state.month.cronEvery;switch (cronEvery?.toString()) {case "1":months = "*";break;case "2":months = state.month.incrementStart + "/" + state.month.incrementIncrement;break;case "3":state.month.specificSpecific.map((val) => {months += val + ",";});months = months.slice(0, -1);break;case "4":months = state.month.rangeStart + "-" + state.month.rangeEnd;break;}return months;}),yearsText: computed(() => {let years = "";// TODO,目前先不指定年份,注释以下代码let cronEvery = state.year.cronEvery;switch (cronEvery?.toString()) {case "1":years = "*";break;case "2":years = state.year.incrementStart + "/" + state.year.incrementIncrement;break;case "3":state.year.specificSpecific.map((val) => {years += val + ",";});years = years.slice(0, -1);break;case "4":years = state.year.rangeStart + "-" + state.year.rangeEnd;break;}return years;}),cron: computed(() => {let secondsText = `${state.secondsText || "*"}`let minutesText = `${state.minutesText || "*"}`let hoursText = `${state.hoursText || "*"}`let daysText = `${state.daysText || "*"}`let monthsText = `${state.monthsText || "*"}`let weeksText = `${state.weeksText || "?"}`let yearsText = `${state.yearsText || "*"}`if (minutesText !== '*') {secondsText = secondsText === '*' ? '0' : secondsText;}if (hoursText !== '*') {secondsText = secondsText === '*' ? '0' : secondsText;minutesText = minutesText === '*' ? '0' : minutesText;}if (daysText !== '*') {secondsText = secondsText === '*' ? '0' : secondsText;minutesText = minutesText === '*' ? '0' : minutesText;hoursText = hoursText === '*' ? '0' : hoursText;}if (weeksText !== '?') {secondsText = secondsText === '*' ? '0' : secondsText;minutesText = minutesText === '*' ? '0' : minutesText;hoursText = hoursText === '*' ? '0' : hoursText;}if (monthsText !== '*') {secondsText = secondsText === '*' ? '0' : secondsText;minutesText = minutesText === '*' ? '0' : minutesText;hoursText = hoursText === '*' ? '0' : hoursText;daysText = daysText === '*' ? '1' : daysText;}if (yearsText !== '*') {secondsText = secondsText === '*' ? '0' : secondsText;minutesText = minutesText === '*' ? '0' : minutesText;hoursText = hoursText === '*' ? '0' : hoursText;// daysText = daysText === '*' ? '1' : daysText;// monthsText = monthsText === '*' ? '1' : monthsText;}return secondsText + " " + minutesText + " " + hoursText + " " + daysText + " " + monthsText + " " + weeksText + " " + yearsText;}),});const rest = (data) => {for (let i in data) {if (data[i] instanceof Object) {this.rest(data[i]);} else {switch (typeof data[i]) {case "object":data[i] = [];break;case "string":data[i] = "";break;}}}};// 点击变更调用方数据const handleChange = () => {if (typeof state.cron !== "string") return false;emit("change", state.cron);};// 数据变化时变更调用方数据watch(() => state.cron,(value) => {if (typeof state.cron !== "string") return;emit("update:value", value);});return {weekList,state,handleChange,rest,tabActive,onHandleTab,currYear,};},
});
</script><style lang="css" scoped>
:deep(.el-input-number) {width: 80px;margin-right: 5px;
}:deep(.el-radio) {margin-right: 10px;
}.v3c {width: auto;border: 1px solid #f5f7fa;
}.v3c-tab {padding: 0;list-style: none;margin: 0;background-color: #f5f7fa;display: flex;
}.v3c-tab-item {flex: 1;text-align: center;cursor: pointer;padding: 6px;
}.v3c-tab-item.v3c-active {background-color: #409eff;color: #ffffff;
}.v3c-content > div {line-height: 50px;
}.v3c-content {padding: 20px;max-height: v-bind(maxHeight);overflow: hidden;overflow-y: auto;
}.v3c input[type="text"] {width: 80px;
}.v3c input[type="number"] {width: 80px;height: 28px;border: 1px solid #d9d9d9;
}.v3c select {width: 80px;height: 32px;border: 1px solid #d9d9d9;
}.v3c select[multiple] {width: 80px;height: 100px;border: 1px solid #d9d9d9;
}
</style>

2、使用组件

2.1、定义相关前置参数

import {defineAsyncComponent} from "vue";
export default {components: {Vue3Cron: defineAsyncComponent(() => import('@/components/vue3-cron/cron.vue')),},data() {return {// 表单参数obj: {},// 定义弹窗开关字段cronDialogVisible: false,cronTimes: [],uri: {// 定义预览 uri 的接口地址temporalPrediction: "/api/admin/dispatch/dispatchTask/temporalPrediction",}}},methods: {// 获取调度的预计执行时间temporalPrediction(cron, startTime, endTime) {this.crud.get(this.uri.temporalPrediction, {cron: cron, startTime: startTime, endTime: endTime}).then(res => {this.cronTimes = res.data.data;})}, }   

2.2、 添加插槽 (添加/编辑页中)

<!-- cron 表达式插槽 -->
<template #cron="{size,row,index}"><!-- 展示当前cron 表达式--><el-input v-model="this.obj.cron" placeholder=""/><!-- 打开 cron 生成弹窗,详见定义弹窗中的内容  --><el-button type="primary" style="margin-top: 10px;margin-bottom: 10px" @click="cronDialogVisible=true">cron 生成</el-button><!-- 时间预测-- 与预览 (当前页面中)   --><el-button type="primary" style="margin-top: 10px;margin-bottom: 10px" @click="temporalPrediction(this.obj.cron,this.obj.startTime,this.obj.endTime) ">时间预测</el-button><div v-for="(item,index) in cronTimes">{{ item }}</div>
</template>

2.3、定义弹窗 (添加/编辑页中)

 <!--  cron 是弹窗 --><el-dialog title="cron 生成" v-if="cronDialogVisible" v-model="cronDialogVisible"><!--  选择 --><Vue3Cron  v-model:value="this.obj.cron"/><!-- 时间预测-- 与预览 (弹窗中)   --><el-button type="primary" style="margin-top: 10px;margin-bottom: 10px" @click="temporalPrediction(this.obj.cron) ">获取最近运行时间</el-button><div v-for="(item,index) in cronTimes">{{ item }}</div></el-dialog>

后端部分 ( java)

pom.xml

  <!-- quartz --><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.1</version></dependency><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId><version>2.2.1</version></dependency><dependency><groupId>com.cronutils</groupId><artifactId>cron-utils</artifactId><version>9.1.0</version></dependency>

接口 controller

  @GetMapping(value = "/temporalPrediction")@ApiOperation(value = "时间预测")public Result<List<String>> temporalPrediction(@RequestParam String cron,String startTime,String endTime) {return Result.success(baseService.temporalPrediction( cron, startTime, endTime));}

接口 service

   /*** 时间预测** @param cron cron* @param startTime 开始时间* @param endTime 结束时间* @return {@link List}<{@link String}>*/List<String> temporalPrediction(String cron, String startTime, String endTime);@Overridepublic List<String> temporalPrediction(String cron, String startTime, String endTime) {List<String> nextExecuteTimes = null;try {if (StringUtils.isBlank(startTime) && StringUtils.isBlank(endTime)) {nextExecuteTimes = QuartzUtil.getNextExecuteTimes(cron, 10);} else {nextExecuteTimes = QuartzUtil.getNextExecuteTimesByTimeRange(cron, startTime, endTime, 10);}} catch (Exception e) {throw new ErrorException("cron 表达式解析失败");}return nextExecuteTimes;}

QuartzUtil 工具

 /*** 根据时间范围获取新的cron表达式** @param cronExpression 现有的 cron 表达式* @param startTimeStr 开始时间* @param startTimeStr 结束时间* @return {@link String} 时间范围*/public static String getNewCronByTimeRange(String cronExpression, String startTimeStr, String endTimeStr) {LocalDateTime startTime = LocalDateTimeUtil.parse("2021-01-01 " + startTimeStr);LocalDateTime endTime = LocalDateTimeUtil.parse("2021-01-01 " + endTimeStr);if (LocalDateTimeUtil.isAfter(startTime, endTime)) {throw new ErrorException("开始时间不能小于结束时间");}long minutes = LocalDateTimeUtil.betweenTwoTime(startTime, endTime, ChronoUnit.MINUTES);if (minutes == 0) {// 差值为0, cron 表达式结果不变return cronExpression;}// 随机分钟数long randomLong = RandomUtil.randomLong(minutes);// 随机秒数long second = RandomUtil.randomLong(59);LocalDateTime time = LocalDateTimeUtil.plus(startTime, randomLong, ChronoUnit.MINUTES);// System.out.println("随机数:" + randomLong+ " 随机时间:" + time.getHour() +":" + time.getMinute()  +":"+ second);String[] cronExpressionArray = cronExpression.split(" ");cronExpressionArray[0] = second + "";cronExpressionArray[1] = time.getMinute() + "";cronExpressionArray[2] = time.getHour() + "";return String.join(" ", cronExpressionArray);}/*** 列出接下来的 n次 执行时间 (根据 cron 表达式)** @param cronExpression cron表达式* @param num 预测次数* @throws ParseException 解析异常 (cron 表达式不规范需返回异常,调用方需主动处理该错误)*/public static List<String> getNextExecuteTimes(String cronExpression, int num) {List<String> dates = new ArrayList<>();CronExpression cron = null;try {cron = new CronExpression(cronExpression);} catch (ParseException e) {throw new RuntimeException(e);}Date currentDate = new Date();for (int i = 0; i < num; i++) {Date nextFireTime = cron.getNextValidTimeAfter(currentDate);currentDate = nextFireTime;dates.add(formatDate(nextFireTime));}return dates;}/*** 列出接下来的 n次 执行时间 (根据 cron 表达式+ 时间范围)** @param cronExpression cron表达式* @param num 预测次数* @throws ParseException 解析异常 (cron 表达式不规范需返回异常,调用方需主动处理该错误)*/public static List<String> getNextExecuteTimesByTimeRange(String cronExpression, String startTimeStr, String endTimeStr, int num) {List<String> dates = new ArrayList<>();for (int i = 0; i < num; i++) {String newCron = getNewCronByTimeRange(cronExpression, startTimeStr, endTimeStr);CronExpression cron = null;try {// 每次获取为 i 的最后一次的执行来保证 年月日 单位的执行日期, 时分秒日期每次 i 循环时修改获得cron = new CronExpression(newCron);} catch (ParseException e) {throw new RuntimeException(e);}Date currentDate = new Date();for (int j = 0; j <= i; j++) {Date nextFireTime = cron.getNextValidTimeAfter(currentDate);currentDate = nextFireTime;if (j == i) {dates.add(formatDate(nextFireTime));}}}return dates;}/*** 格式化时间日期** @param date 日期* @return {@link String}*/private static String formatDate(Date date) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return sdf.format(date);}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/218705.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小航助学2023年9月电子学会Scratch三级真题(含题库答题软件账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09; 单选题2.00分 删除编辑附件图文 答案:C 第1题运行下面程序后&#xff0c;角色的x坐标值是&#xff1f;&#xff08; &#xff09; A、100B、90C、110D、120 答…

【前端学习记录】记一次分片上传逻辑的调试过程

前言 在项目开发的过程中&#xff0c;经常会遇到上传和下载&#xff0c;对于上传来说&#xff0c;如果是小文件的话&#xff0c;接口响应会比较快&#xff0c;但是对于大文件&#xff0c;则需要对其分片以减少请求体的大小和上传时间。 小文件上传 以Vue框架使用<el-uplo…

官宣 鸿雁成为2023汇丰世界羽联世界巡回赛总决赛官方供应商

全屋智能和羽毛球运动能擦出怎样的火花&#xff1f; 鸿雁给你答案&#xff01; 12月13日&#xff0c;2023汇丰世界羽联世界巡回赛总决赛将在杭州举行。 鸿雁签约成为2023汇丰世界羽联世界巡回赛总决赛官方供应商&#xff0c;将携手世界羽联&#xff0c;为广大羽毛球爱好者们…

Yolov5双目测距-双目相机计数及测距教程(附代码)

引言 在计算机视觉领域&#xff0c;Yolov5-Binocular相机距离计数及测距是一个引人注目的研究方向。本教程将为小白用户提供一个简明扼要的学习指南&#xff0c;涵盖了关键步骤&#xff0c;包括标定、公示推倒以及重要的代码片段。 第一步&#xff1a;环境搭建 首先&#x…

【Geoserver】将geoserver迁移到jetty的发行包中

之前讲了在Geosever的二进制发行包中升级jetty的内容&#xff0c;我测试之后发现有些问题&#xff0c;本地运行可能没有问题&#xff0c;但是在linux上运行报错了。 于是我想着换个思路好了&#xff0c;总是想着将Geosever中的jetty包替换掉&#xff0c;干脆反过来&#xff0c;…

2023_Spark_实验二十六:编写Shell模拟生成点击实时数据

引言&#xff1a;流式数据处理主要处理实时数据&#xff0c;由于实验教学过程中&#xff0c;每个同学无法拿到实时数据&#xff0c;因此我们开发shell脚本模拟实时数据生成&#xff0c;支持后续实验。 实验目的&#xff1a;通过开发模拟实时点击流shell脚本&#xff0c;模拟实时…

【Database】什么是数据库?常见的数据库类型有哪些?

什么是数据库&#xff1f;常见的数据库类型有哪些&#xff1f; 首先&#xff0c;什么是数据库&#xff1f;把它想象成一个数字游乐场&#xff0c;我们以结构化的方式组织和存储大量信息。现在&#xff0c;让我们来谈谈数据库的主要类型。 关系型数据库&#xff1a; 想象一下…

深度学习的目标检测算法综述

信息记录材料 2022年10月 第23卷第10期 【摘要】目标检测是深度学习的一个重要应用&#xff0c;目前在智能驾驶、工业检测相关领域都获得应用&#xff0c;具有重要的现实意义。本文对基于深度学习目标检测算法原理和应用情况进行简述&#xff0c;首先介绍结合区域提取和卷积神经…

Spring上IOC之@EnableAspectJAutoProxy

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

3分钟,掌握“曲面屏显示屏”

在3分钟内掌握“曲面屏显示屏”的概念和特点&#xff0c;可以按照以下步骤进行&#xff1a; 一、了解曲面屏显示屏的基本概念 曲面屏显示屏是一种采用柔性塑料的显示屏&#xff0c;主要通过OLED面板来实现。相比直面屏幕&#xff0c;曲面屏幕弹性更好&#xff0c;不易破碎。此外…

扫描电镜(SEM)样品在进行扫描电镜观察前需要进行哪些处理

对于扫描电镜&#xff08;Scanning Electron Microscope&#xff0c;SEM&#xff09;样品的制备&#xff0c;需要经过一系列处理步骤以确保样品表面的干净、导电性好&#xff0c;并且能够提供高质量的显微图像。以下是一些常见的处理步骤&#xff1a; 1. 固定样品&#xff08;…

锂电3V升12V1A升压芯片WT3209

锂电3V升12V1A升压芯片WT3209 WT3209是一款高功率密度全集成BOOST升压转换器&#xff0c;具备高效能解决方案。3V升12V1A,5V升12V1A WT3209内部集成的功率MOSFET管导通电阻为上管13mΩ和下管11mΩ&#xff0c;具备2A开关电流能力&#xff0c;并且能够提供高达12.6V的输出电压。…

算法:只出现一次的数字(位运算:异或运算)

异或运算 时间复杂度 O(n) 空间复杂度 O(1) /*** param {number[]} nums* return {number}*/ var singleNumber function (nums) {let item nums[0]if (nums.length > 1) {for (let i 1; i < nums.length; i) {// 将10进制转成2进制进行异或运算&#xff08;相同得0&…

CB400X即将停产?NX400上线,本田最新的外观设计直接就国产了?

NX500 之前米兰车展的时候给大家分享过本田对于500系列的升级&#xff0c;并且宣布NX500代替CB500X&#xff0c;采用了全新的外观设计&#xff0c;没有看过的小伙伴可以查阅下之前的文章内容&#xff0c;不过最新的工信部的信息&#xff0c;可以看到NX500的外观设计应用到了CB…

光栅化渲染:光栅化算法实现

光栅化是将图元转换为二维图像的过程。 该图像的每个点都包含颜色和深度等信息。 因此&#xff0c;对图元进行光栅化由两部分组成。 第一个是确定窗口坐标中整数网格的哪些方格被图元占据。 第二个是为每个这样的方块分配颜色和深度值。 &#xff08;OpenGL 规范&#xff09; N…

CTD测试流程

连接 连接17Plus&#xff0c;用usb转232线&#xff0c;db9公针2、3分别接Data I/O的2、3。DB9的5接Data I/O的1。尼龙塞子打开状态。不用闭合。 软件连接 打开SeaTermAF V2&#xff0c;注意打开前先把串口插上&#xff0c;否则软件读不到串口。如果读不到&#xff0c;就在插…

C/C++ 快乐数: 编写一个算法来判断一个数n是不是快乐数

题目&#xff1a; 编写一个算法来判断一个数n是不是快乐数。 快乐数的定义&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1&#xff0c;也可能是 无限循环 但始终变不到 1。 如果这个过…

使用不同的颜色映射绘制热力图Seaborn

使用不同的颜色映射绘制热力图 一、使用 Seaborn 库创建热力图二、cmap关于其他颜色的设置三、自己设置颜色映射 一、使用 Seaborn 库创建热力图 选择Seaborn颜色官网 使用 Seaborn 库创建热力图&#xff0c;你可以使用 seaborn.heatmap() 函数。下面是一个示例代码&#xf…

网络基础(七):传输层协议介绍

目录 一、TCP协议&#xff08;传输控制协议&#xff09; 1、TCP协议介绍 2、TCP协议特性 3、TCP报文格式 4、TCP的三次握手 4.1TCP三次握手的概念 4.2TCP三次握手流程图 4.3 TCP三次握手阐释说明 5、TCP的四次挥手 5.1TCP四次挥手的概念 5.2TCP四次挥手的流程图 5.…

【C语言】RDMACM、Verbs API与epoll一起使用的示例

一、epoll介绍 epoll是Linux内核为处理大批量文件描述符而作了改进的poll&#xff0c;是Linux下多路复用IO接口select/poll的增强版本&#xff0c;它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。 以下是epoll的主要使用方法和优点&#xff1a; epo…