当前位置: 首页 > news >正文

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);}

相关文章:

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&qu…...

洛谷P1722 矩阵Ⅱ——卡特兰数

传送门&#xff1a; P1722 矩阵 II - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1722 用不需要除任何数的公式来求。 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstdio> #include<cmath> #includ…...

Unity | Shader基础知识(第六集:语法<如何加入外部颜色资源>)

目录 一、本节介绍 1 上集回顾 2 本节介绍 二、语法结构 1 复习 2 理论知识 3 Shader里声明的写法 4 Properties和SubShader毕竟不是一家人 三、 片元着色器中使用资源 四、代码实现 五、全部代码 六、下集介绍 相关阅读 Unity - Manual: Writing Surface Shaders…...

使用opencv的Laplacian算子实现图像边缘检测

1 边缘检测介绍 图像边缘检测技术是图像处理和计算机视觉等领域最基本的问题&#xff0c;也是经典的技术难题之一。如何快速、精确地提取图像边缘信息&#xff0c;一直是国内外的研究热点&#xff0c;同时边缘的检测也是图像处理中的一个难题。早期的经典算法包括边缘算子方法…...

5. PyTorch——数据处理模块

1.数据加载 在PyTorch中&#xff0c;数据加载可通过自定义的数据集对象。数据集对象被抽象为Dataset类&#xff0c;实现自定义的数据集需要继承Dataset&#xff0c;并实现两个Python魔法方法&#xff1a; __getitem__&#xff1a;返回一条数据&#xff0c;或一个样本。obj[in…...

Android 移动端编译 cityhash动态库

最近做项目&#xff0c; 硬件端 需要 用 cityhash 编译一个 动态库 提供给移动端使用&#xff0c;l 记录一下 编译过程 city .cpp // // Created by Administrator on 2023/12/12. // // Copyright (c) 2011 Google, Inc. // // Permission is hereby granted, free of charg…...

IO流学习

IO流:存储和读取数据的解决方案 import java.io.FileOutputStream; import java.io.IOException;public class Test {public static void main(String[] args) throws IOException {//1.创建对象//写出 输入流 OutputStream//本地文件fileFileOutputStream fos new FileOutputS…...

新手HTML和CSS的常见知识点

​​​​ 目录 1.HTML标题标签&#xff08;到&#xff09;用于定义网页中的标题&#xff0c;并按照重要性递减排列。例如&#xff1a; 2.HTML段落标签&#xff08;&#xff09;用于定义网页中的段落。例如&#xff1a; 3.HTML链接标签&#xff08;&#xff09;用于创建链接…...

RocketMQ系统性学习-RocketMQ领域模型及Linux下单机安装

MQ 之间的对比 三种常用的 MQ 对比&#xff0c;ActiveMQ、Kafka、RocketMQ 性能方面&#xff1a; 三种 MQ 吞吐量级别为&#xff1a;万&#xff0c;百万&#xff0c;十万消息发送时延&#xff1a;毫秒&#xff0c;毫秒&#xff0c;微秒可用性&#xff1a;主从&#xff0c;分…...

微服务架构之争:Quarkus VS Spring Boot

在容器时代&#xff08;“Docker时代”&#xff09;&#xff0c;无论如何&#xff0c;Java仍然活着。Java在性能方面一直很有名&#xff0c;主要是因为代码和真实机器之间的抽象层&#xff0c;多平台的成本&#xff08;一次编写&#xff0c;随处运行——还记得吗&#xff1f;&a…...

如何使用ArcGIS Pro拼接影像

为了方便数据的存储和传输&#xff0c;我们在网上获取到的影像一般都是分块的&#xff0c;正式使用之前需要对这些影像进行拼接&#xff0c;这里为大家介绍一下ArcGIS Pro中拼接影像的方法&#xff0c;希望能对你有所帮助。 数据来源 本教程所使用的数据是从水经微图中下载的…...

[论文笔记] chatgpt系列 SparseMOE—GPT4的MOE结构

SparseMOE: 稀疏激活的MOE Swtich MOE,所有token要在K个专家网络中,选择一个专家网络。 显存增加。 Experts Choice:路由MOE:​​​​​​​ 由专家选择token。这样不同的专家都选择到某个token,也可以不选择该token。 由于FFN层的时间复杂度和attention层不同,FFN层的时…...

C# WPF上位机开发(键盘绘图控制)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 在软件开发中&#xff0c;如果存在canvas图像的话&#xff0c;一般有几种控制方法。一种是鼠标控制&#xff1b;一种是键盘控制&#xff1b;还有一…...

《地理信息系统原理》笔记/期末复习资料(10. 空间数据挖掘与空间决策支持系统)

目录 10. 空间数据挖掘与空间决策支持系统 10.1. 空间数据挖掘 10.1.1. 空间数据挖掘的概念 10.1.2. 空间数据挖掘的方法与过程 10.1.3. 空间数据挖掘的应用 10.2. 空间决策支持系统 10.2.1. 空间决策支持系统的概念 10.2.2. 空间决策支持系统的结构 10.2.3. 空间决策…...

uniapp播放 m3u8格式视频 兼容pc和移动端

支持全自动播放、设置参数 自己摸索出来的,花了一天时间,给点订阅支持下,订阅后,不懂的地方可以私聊我。 代码实现 代码实现 1.安装dplayer组件 npm i dplayer2. static/index.html下引入 hls 引入hls.min.js 可以存放在static项目hls下面<script src="/static…...

产品经理之Axure的元件库使用详细案例

⭐⭐ 产品经理专栏&#xff1a;产品专栏 ⭐⭐ 个人主页&#xff1a;个人主页 ​ 目录 前言 一.Axure的元件库的使用 1.1 元件介绍 1.2 基本元件的使用 1.2.1 矩形、按钮、标题的使用 1.2.2 图片及热区的使用 1.3 表单元件及表格元件的使用 1.3.1表单元件的使用 1.3.…...

数字化转型对企业有什么好处?

引言 数字化转型已经成为当今商业领域中的一股强大力量&#xff0c;它不仅仅是简单的技术更新&#xff0c;更是企业发展的重要战略转变。随着科技的迅猛发展和全球化竞争的加剧&#xff0c;企业们正在积极探索如何将数字化的力量融入到他们的运营和战略中。 数字化转型不仅是传…...

微信小程序:按钮禁用,避免按钮重复提交

wxml <view class"modal-buttons"><view class"one_btn" bindtap"submit">确认</view><view class"two_btn" bindtap"cancel">取消</view> </view> wxss /* 按钮 */ .modal-buttons…...

JAVA 异常分类及处理

JAVA 异常分类及处理 概念 如果某个方法不能按照正常的途径完成任务&#xff0c;就可以通过另一种路径退出方法。在这种情况下会抛出一个封装了错误信息的对象。此时&#xff0c;这个方法会立刻退出同时不返回任何值。另外&#xff0c;调用这个方法的其他代码也无法继续执行&…...

C语言--求数组的最大值和最小值【两种方法】

&#x1f357;方法一&#xff1a;用for循环遍历数组&#xff0c;找出最大值与最小值 &#x1f357;方法二&#xff1a;用qsort排序&#xff0c;让数组成为升序的有序数组&#xff0c;第一个值就是最小值&#xff0c;最后一个是最大值 完整代码&#xff1a; 方法一&#xff1a; …...

ES-组合与聚合

ES组合查询 1 must 满足两个match才会被命中 GET /mergeindex/_search {"query": {"bool": {"must": [{"match": {"name": "liyong"}},{"match_phrase": {"desc": "liyong"}}]}}…...

在 Spring Boot 中发送邮件简单实现

Spring Boot 对于发送邮件这种常用功能也提供了开箱即用的 Starter&#xff1a;spring-boot-starter-mail。 通过这个 starter&#xff0c;只需要简单的几行配置就可以在 Spring Boot 中实现邮件发送&#xff0c;可用于发送验证码、账户激活等等业务场景。 本文将通过实际的案…...

深入理解网络 I/O:单 Selector 多线程|单线程模型

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…...

Kafka Avro序列化之三:使用Schema Register实现

为什么需要Schema Register 注册表 无论是使用传统的Avro API自定义序列化类和反序列化类 还是 使用Twitter的Bijection类库实现Avro的序列化与反序列化,这两种方法都有一个缺点:在每条Kafka记录里都嵌入了schema,这会让记录的大小成倍地增加。但是不管怎样,在读取记录时…...

EasyExcel

概述 GitHub - alibaba/easyexcel: 快速、简洁、解决大文件内存溢出的java处理Excel工具 EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。 他能让你在不用考虑性能、内存的等因素的…...

java 探针两种模式实战

分为两种 程序运行前的agent&#xff1a;premain 程序运行中的agent&#xff1a;agentmain 在程序运行前的agent javaagent是java命令的一个参数&#xff0c;所以需要通过-javaagent 来指定一个jar包&#xff08;就是我们要做的代理包&#xff09;能够实现在主程序运行前来执行…...

uniGUI之MASK遮罩

在页面进行后台数据库操作的时候&#xff0c;不想 用户再进行 页面上的 其他操作&#xff0c;这时候就要 将页面 遮罩。例如UniDBGrid有LoadMask属性。 1]使用ScreenMask函数 2]JS调用 3]一个控件控制遮罩另一个控件(如Button遮罩UniDBGrid) //很简单&#xff0c;本例子就是告…...

DevOps云原生创建devops流水线(微服务项目上传git,打包镜像,部署k8s)

开发和运维人员的解决方案 一、中间件的部署&#xff08;Sentinel/MongoDB/MySQL&#xff09; 二、创建DevOps工程 邀请成员 三、创建流水线 四、编辑流水线 ①、拉取代码&#xff08;若失败&#xff0c;则将制定容器改为maven&#xff09; 若失败&#xff0c;则将命令改…...

【vim 学习系列文章 13.1 -- 自动命令autocmd 根据文件类型设置vim参数】

文章目录 autocmd 根据文件类型配置vim参数vim 文本类型 autocmd 根据文件类型配置vim参数 在 Vim 中&#xff0c;你可以使用 autocmd &#xff08;自动命令&#xff09;来根据文件类型自动执行特定的函数。首先&#xff0c;你需要定义这些函数&#xff0c;然后使用 autocmd 与…...

算法基础概念之数据结构

邻接表 每个点作为头节点接一条链表 链表中元素均为该头节点指向的点 优先队列 参数: ①储存元素类型 ②底层使用的存储结构(一般为vector) ③比较方式(默认小于)...

网站建设wang1314/长沙竞价优化

*Java程序的运行包括两个非常重要的阶段 -编译阶段 -运行阶段 *编译阶段 -编译阶段主要的任务是检查Java源程序是否符合Java语法&#xff0c;符合Java语法则能够生成正常的字节码文件&#xff08;xxx.class&#xff09;&#xff0c;不符合规则则无法生成字节码文件。 -字节码文…...

专业做网站费用/北京网站优化步骤

docker pull centos:centos7 想要拉取其他版本的镜像&#xff0c;参考网址&#xff1a; https://hub.docker.com/_/centos?tabtags&page1...

小企业如何优化网站建设/网络推广工作好干吗

用户对象类&#xff08;User Object Class&#xff09;这个是在 LDAP 用户对象中对用户分类的名字。例如&#xff1a;user用户对象过滤器&#xff08;User Object Filter&#xff09;当对用户对象进行搜索的时候使用的过滤器。例如&#xff1a;(&(objectCategoryPerson)(s…...

西安市政府网站建设/被代运营骗了去哪投诉

对绝大年夜部分高考生来说&#xff0c;都是以高考成绩能否婚配来抉择黉舍的。这三所黉舍的打算机专业录取分数高低差别&#xff0c;其中北京航空航天大年夜学打算机专业的录取分数最高&#xff0c;其次是哈尔滨产业大年夜学(深圳)&#xff0c;再次是哈尔滨产业大年夜学本部。抉…...

衡水网站制作/营销推广方案模板

MySQL 索引 数据库创建索引的几种方法 数据库建表添加索引&#xff08;一&#xff09; mysql创建索引三种方式 数据库索引的创建和使用 Mysql哪些字段适合建立索引 MySQL索引的创建与使用 MySQL索引是如何提高查询效率的呢&#xff1f; mysql 查询速度_为什么 MySQL 添…...

有没有做机械加工的网站/网站策划方案案例

copy过来有些图没了&#xff0c;见这里第二章 - 系统模型分3大块physical mode&#xff08;只考虑物理连接方面的模型&#xff09;&#xff1b;architechture mode&#xff08;主要是“计算”方面的体系结构模型&#xff0c;例如peer to peer、client to server&#xff09;fun…...