Commit 3959aadae2bec0eecaf4e31fe0c018d5cfe869db

Authored by YunaiV
1 parent a4a13efa

1. 优化 JobHandlerInvoker 的实现,增加重试机制

2. 去除作业异常,自动暂时作业的机制。
Showing 30 changed files with 1019 additions and 1017 deletions
ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java deleted
1   -package com.ruoyi.common.constant;
2   -
3   -/**
4   - * 任务调度通用常量
5   - *
6   - * @author ruoyi
7   - */
8   -public class ScheduleConstants {
9   - public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
10   -
11   - /**
12   - * 执行目标key
13   - */
14   - public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
15   -
16   - /**
17   - * 默认
18   - */
19   - public static final String MISFIRE_DEFAULT = "0";
20   -
21   - /**
22   - * 立即触发执行
23   - */
24   - public static final String MISFIRE_IGNORE_MISFIRES = "1";
25   -
26   - /**
27   - * 触发一次执行
28   - */
29   - public static final String MISFIRE_FIRE_AND_PROCEED = "2";
30   -
31   - /**
32   - * 不触发立即执行
33   - */
34   - public static final String MISFIRE_DO_NOTHING = "3";
35   -
36   - public enum Status {
37   - /**
38   - * 正常
39   - */
40   - NORMAL("0"),
41   - /**
42   - * 暂停
43   - */
44   - PAUSE("1");
45   -
46   - private String value;
47   -
48   - private Status(String value) {
49   - this.value = value;
50   - }
51   -
52   - public String getValue() {
53   - return value;
54   - }
55   - }
56   -}
ruoyi-common/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java deleted
1   -package com.ruoyi.quartz.service.impl;
2   -
3   -import java.util.List;
4   -
5   -import org.springframework.beans.factory.annotation.Autowired;
6   -import org.springframework.stereotype.Service;
7   -import com.ruoyi.quartz.domain.SysJobLog;
8   -import com.ruoyi.quartz.mapper.SysJobLogMapper;
9   -import com.ruoyi.quartz.service.ISysJobLogService;
10   -
11   -/**
12   - * 定时任务调度日志信息 服务层
13   - *
14   - * @author ruoyi
15   - */
16   -@Service
17   -public class SysJobLogServiceImpl implements ISysJobLogService {
18   -
19   - @Autowired
20   - private SysJobLogMapper jobLogMapper;
21   -
22   - /**
23   - * 获取quartz调度器日志的计划任务
24   - *
25   - * @param jobLog 调度日志信息
26   - * @return 调度任务日志集合
27   - */
28   - @Override
29   - public List<SysJobLog> selectJobLogList(SysJobLog jobLog) {
30   - return jobLogMapper.selectJobLogList(jobLog);
31   - }
32   -
33   - /**
34   - * 通过调度任务日志ID查询调度信息
35   - *
36   - * @param jobLogId 调度任务日志ID
37   - * @return 调度任务日志对象信息
38   - */
39   - @Override
40   - public SysJobLog selectJobLogById(Long jobLogId) {
41   - return jobLogMapper.selectJobLogById(jobLogId);
42   - }
43   -
44   - /**
45   - * 新增任务日志
46   - *
47   - * @param jobLog 调度日志信息
48   - */
49   - @Override
50   - public void addJobLog(SysJobLog jobLog) {
51   - jobLogMapper.insertJobLog(jobLog);
52   - }
53   -
54   -}
ruoyi-common/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java deleted
1   -package com.ruoyi.quartz.util;
2   -
3   -import java.util.Date;
4   -
5   -import org.quartz.Job;
6   -import org.quartz.JobExecutionContext;
7   -import org.quartz.JobExecutionException;
8   -import org.slf4j.Logger;
9   -import org.slf4j.LoggerFactory;
10   -import com.ruoyi.common.constant.Constants;
11   -import com.ruoyi.common.constant.ScheduleConstants;
12   -import com.ruoyi.common.utils.ExceptionUtil;
13   -import com.ruoyi.common.utils.StringUtils;
14   -import com.ruoyi.common.utils.bean.BeanUtils;
15   -import com.ruoyi.common.utils.spring.SpringUtils;
16   -import com.ruoyi.quartz.domain.SysJob;
17   -import com.ruoyi.quartz.domain.SysJobLog;
18   -import com.ruoyi.quartz.service.ISysJobLogService;
19   -
20   -/**
21   - * 抽象quartz调用
22   - *
23   - * @author ruoyi
24   - */
25   -public abstract class AbstractQuartzJob implements Job {
26   - private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
27   -
28   - /**
29   - * 线程本地变量
30   - */
31   - private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
32   -
33   - @Override
34   - public void execute(JobExecutionContext context) throws JobExecutionException {
35   - SysJob sysJob = new SysJob();
36   - BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
37   - try {
38   - before(context, sysJob);
39   - if (sysJob != null) {
40   - doExecute(context, sysJob);
41   - }
42   - after(context, sysJob, null);
43   - } catch (Exception e) {
44   - log.error("任务执行异常 - :", e);
45   - after(context, sysJob, e);
46   - }
47   - }
48   -
49   - /**
50   - * 执行前
51   - *
52   - * @param context 工作执行上下文对象
53   - * @param sysJob 系统计划任务
54   - */
55   - protected void before(JobExecutionContext context, SysJob sysJob) {
56   - threadLocal.set(new Date());
57   - }
58   -
59   - /**
60   - * 执行后
61   - *
62   - * @param context 工作执行上下文对象
63   - * @param sysJob 系统计划任务
64   - */
65   - protected void after(JobExecutionContext context, SysJob sysJob, Exception e) {
66   - Date startTime = threadLocal.get();
67   - threadLocal.remove();
68   -
69   - final SysJobLog sysJobLog = new SysJobLog();
70   - sysJobLog.setJobName(sysJob.getJobName());
71   - sysJobLog.setJobGroup(sysJob.getJobGroup());
72   - sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
73   - sysJobLog.setStartTime(startTime);
74   - sysJobLog.setStopTime(new Date());
75   - long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();
76   - sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
77   - if (e != null) {
78   - sysJobLog.setStatus(Constants.FAIL);
79   - String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
80   - sysJobLog.setExceptionInfo(errorMsg);
81   - } else {
82   - sysJobLog.setStatus(Constants.SUCCESS);
83   - }
84   -
85   - // 写入数据库当中
86   - SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);
87   - }
88   -
89   - /**
90   - * 执行方法,由子类重载
91   - *
92   - * @param context 工作执行上下文对象
93   - * @param sysJob 系统计划任务
94   - * @throws Exception 执行过程中的异常
95   - */
96   - protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
97   -}
ruoyi-common/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java deleted
1   -package com.ruoyi.quartz.util;
2   -
3   -import org.quartz.CronScheduleBuilder;
4   -import org.quartz.CronTrigger;
5   -import org.quartz.Job;
6   -import org.quartz.JobBuilder;
7   -import org.quartz.JobDetail;
8   -import org.quartz.JobKey;
9   -import org.quartz.Scheduler;
10   -import org.quartz.SchedulerException;
11   -import org.quartz.TriggerBuilder;
12   -import org.quartz.TriggerKey;
13   -import com.ruoyi.common.constant.ScheduleConstants;
14   -import com.ruoyi.common.exception.job.TaskException;
15   -import com.ruoyi.common.exception.job.TaskException.Code;
16   -import com.ruoyi.quartz.domain.SysJob;
17   -
18   -/**
19   - * 定时任务工具类
20   - *
21   - * @author ruoyi
22   - */
23   -public class ScheduleUtils {
24   -
25   - /**
26   - * 设置定时任务策略
27   - */
28   - public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)
29   - throws TaskException {
30   - switch (job.getMisfirePolicy()) {
31   - case ScheduleConstants.MISFIRE_DEFAULT:
32   - return cb;
33   - case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
34   - return cb.withMisfireHandlingInstructionIgnoreMisfires();
35   - case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
36   - return cb.withMisfireHandlingInstructionFireAndProceed();
37   - case ScheduleConstants.MISFIRE_DO_NOTHING:
38   - return cb.withMisfireHandlingInstructionDoNothing();
39   - default:
40   - throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
41   - + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
42   - }
43   - }
44   -}
ruoyi-ui/src/utils/constants.js
... ... @@ -54,7 +54,6 @@ export const ToolCodegenTemplateTypeEnum = {
54 54 */
55 55 export const InfJobStatusEnum = {
56 56 INIT: 0, // 初始化中
57   - NORMAL: 1, // 开启运行
58   - EXCEPTION: 2, // 异常运行
59   - STOP: 3, // 暂停运行
  57 + NORMAL: 1, // 运行中
  58 + STOP: 2, // 暂停运行
60 59 }
... ...
ruoyi-ui/src/views/index.vue
1   -<template>
2   - <div class="app-container home">
3   - <el-row :gutter="20">
4   - <el-col :sm="24" :lg="24">
5   - <blockquote class="text-warning" style="font-size: 14px">
6   - 领取阿里云通用云产品1888优惠券
7   - <br />
8   - <el-link
9   - href="https://www.aliyun.com/minisite/goods?userCode=brki8iof"
10   - type="primary"
11   - target="_blank"
12   - >https://www.aliyun.com/minisite/goods?userCode=brki8iof</el-link
13   - >
14   - <br />
15   - 领取腾讯云通用云产品2860优惠券
16   - <br />
17   - <el-link
18   - href="https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console"
19   - type="primary"
20   - target="_blank"
21   - >https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console</el-link
22   - >
23   - <br />
24   - 阿里云服务器折扣区
25   - <el-link href="http://aly.ruoyi.vip" type="primary" target="_blank"
26   - >>☛☛点我进入☚☚</el-link
27   - >
28   - &nbsp;&nbsp;&nbsp; 腾讯云服务器秒杀区
29   - <el-link href="http://txy.ruoyi.vip" type="primary" target="_blank"
30   - >>☛☛点我进入☚☚</el-link
31   - ><br />
32   - <h4 class="text-danger">
33   - 云产品通用红包,可叠加官网常规优惠使用。(仅限新用户)
34   - </h4>
35   - </blockquote>
36   -
37   - <hr />
38   - </el-col>
39   - </el-row>
40   - <el-row :gutter="20">
41   - <el-col :sm="24" :lg="12" style="padding-left: 20px">
42   - <h2>芋道后台管理框架</h2>
43   - <p>
44   - 一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了芋道管理系统。,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
45   - </p>
46   - <p>
47   - <b>当前版本:</b> <span>v{{ version }}</span>
48   - </p>
49   - <p>
50   - <el-tag type="danger">&yen;免费开源</el-tag>
51   - </p>
52   - <p>
53   - <el-button
54   - type="primary"
55   - size="mini"
56   - icon="el-icon-cloudy"
57   - plain
58   - @click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"
59   - >访问码云</el-button
60   - >
61   - <el-button
62   - size="mini"
63   - icon="el-icon-s-home"
64   - plain
65   - @click="goTarget('http://ruoyi.vip')"
66   - >访问主页</el-button
67   - >
68   - </p>
69   - </el-col>
70   -
71   - <el-col :sm="24" :lg="12" style="padding-left: 50px">
72   - <el-row>
73   - <el-col :span="12">
74   - <h2>技术选型</h2>
75   - </el-col>
76   - </el-row>
77   - <el-row>
78   - <el-col :span="6">
79   - <h4>后端技术</h4>
80   - <ul>
81   - <li>SpringBoot</li>
82   - <li>Spring Security</li>
83   - <li>JWT</li>
84   - <li>MyBatis</li>
85   - <li>Druid</li>
86   - <li>Fastjson</li>
87   - <li>...</li>
88   - </ul>
89   - </el-col>
90   - <el-col :span="6">
91   - <h4>前端技术</h4>
92   - <ul>
93   - <li>Vue</li>
94   - <li>Vuex</li>
95   - <li>Element-ui</li>
96   - <li>Axios</li>
97   - <li>Sass</li>
98   - <li>Quill</li>
99   - <li>...</li>
100   - </ul>
101   - </el-col>
102   - </el-row>
103   - </el-col>
104   - </el-row>
105   - <el-divider />
106   - <el-row :gutter="20">
107   - <el-col :xs="24" :sm="24" :md="12" :lg="8">
108   - <el-card class="update-log">
109   - <div slot="header" class="clearfix">
110   - <span>联系信息</span>
111   - </div>
112   - <div class="body">
113   - <p>
114   - <i class="el-icon-s-promotion"></i> 官网:<el-link
115   - href="http://www.ruoyi.vip"
116   - target="_blank"
117   - >http://www.ruoyi.vip</el-link
118   - >
119   - </p>
120   - <p>
121   - <i class="el-icon-user-solid"></i> QQ群:<s>满937441</s>
122   - <s>满887144332</s> <s>满180251782</s>
123   - <a href="https://jq.qq.com/?_wv=1027&k=4WWwqNxN" target="_blank"
124   - > 104180207</a
125   - >
126   - </p>
127   - <p>
128   - <i class="el-icon-chat-dot-round"></i> 微信:<a
129   - href="javascript:;"
130   - >/ *芋道</a
131   - >
132   - </p>
133   - <p>
134   - <i class="el-icon-money"></i> 支付宝:<a
135   - href="javascript:;"
136   - class="支付宝信息"
137   - >/ *芋道</a
138   - >
139   - </p>
140   - </div>
141   - </el-card>
142   - </el-col>
143   - <el-col :xs="24" :sm="24" :md="12" :lg="8">
144   - <el-card class="update-log">
145   - <div slot="header" class="clearfix">
146   - <span>更新日志</span>
147   - </div>
148   - <el-collapse accordion>
149   - <el-collapse-item title="v3.3.0 - 2020-12-14">
150   - <ol>
151   - <li>新增缓存监控功能</li>
152   - <li>支持主题风格配置</li>
153   - <li>修复多级菜单之间切换无法缓存的问题</li>
154   - <li>多级菜单自动配置组件</li>
155   - <li>代码生成预览支持高亮显示</li>
156   - <li>支持Get请求映射Params参数</li>
157   - <li>删除用户和角色解绑关联</li>
158   - <li>去除用户手机邮箱部门必填验证</li>
159   - <li>Excel支持注解align对齐方式</li>
160   - <li>Excel支持导入Boolean型数据</li>
161   - <li>优化头像样式,鼠标移入悬停遮罩</li>
162   - <li>代码生成预览提供滚动机制</li>
163   - <li>代码生成删除多余的数字float类型</li>
164   - <li>修正转换字符串的目标字符集属性</li>
165   - <li>回显数据字典防止空值报错</li>
166   - <li>日志记录增加过滤多文件场景</li>
167   - <li>修改缓存Set方法可能导致嵌套的问题</li>
168   - <li>移除前端一些多余的依赖</li>
169   - <li>防止安全扫描YUI出现的风险提示</li>
170   - <li>修改node-sass为dart-sass</li>
171   - <li>升级SpringBoot到最新版本2.1.18</li>
172   - <li>升级poi到最新版本4.1.2</li>
173   - <li>升级oshi到最新版本v5.3.6</li>
174   - <li>升级bitwalker到最新版本1.21</li>
175   - <li>升级axios到最新版本0.21.0</li>
176   - <li>升级element-ui到最新版本2.14.1</li>
177   - <li>升级vue到最新版本2.6.12</li>
178   - <li>升级vuex到最新版本3.6.0</li>
179   - <li>升级vue-cli到版本4.5.9</li>
180   - <li>升级vue-router到最新版本3.4.9</li>
181   - <li>升级vue-cli到最新版本4.4.6</li>
182   - <li>升级vue-cropper到最新版本0.5.5</li>
183   - <li>升级clipboard到最新版本2.0.6</li>
184   - <li>升级core-js到最新版本3.8.1</li>
185   - <li>升级echarts到最新版本4.9.0</li>
186   - <li>升级file-saver到最新版本2.0.4</li>
187   - <li>升级fuse.js到最新版本6.4.3</li>
188   - <li>升级js-beautify到最新版本1.13.0</li>
189   - <li>升级js-cookie到最新版本2.2.1</li>
190   - <li>升级path-to-regexp到最新版本6.2.0</li>
191   - <li>升级quill到最新版本1.3.7</li>
192   - <li>升级screenfull到最新版本5.0.2</li>
193   - <li>升级sortablejs到最新版本1.10.2</li>
194   - <li>升级vuedraggable到最新版本2.24.3</li>
195   - <li>升级chalk到最新版本4.1.0</li>
196   - <li>升级eslint到最新版本7.15.0</li>
197   - <li>升级eslint-plugin-vue到最新版本7.2.0</li>
198   - <li>升级lint-staged到最新版本10.5.3</li>
199   - <li>升级runjs到最新版本4.4.2</li>
200   - <li>升级sass-loader到最新版本10.1.0</li>
201   - <li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>
202   - <li>升级svg-sprite-loader到最新版本5.1.1</li>
203   - <li>升级vue-template-compiler到最新版本2.6.12</li>
204   - <li>其他细节优化</li>
205   - </ol>
206   - </el-collapse-item>
207   - <el-collapse-item title="v3.2.1 - 2020-11-18">
208   - <ol>
209   - <li>阻止任意文件下载漏洞</li>
210   - <li>代码生成支持上传控件</li>
211   - <li>新增图片上传组件</li>
212   - <li>调整默认首页</li>
213   - <li>升级druid到最新版本v1.2.2</li>
214   - <li>mapperLocations配置支持分隔符</li>
215   - <li>权限信息调整</li>
216   - <li>调整sql默认时间</li>
217   - <li>解决代码生成没有bit类型的问题</li>
218   - <li>升级pagehelper到最新版1.3.0</li>
219   - </ol>
220   - </el-collapse-item>
221   - <el-collapse-item title="v3.2.0 - 2020-10-10">
222   - <ol>
223   - <li>升级springboot版本到2.1.17 提升安全性</li>
224   - <li>升级oshi到最新版本v5.2.5</li>
225   - <li>升级druid到最新版本v1.2.1</li>
226   - <li>升级jjwt到版本0.9.1</li>
227   - <li>升级fastjson到最新版1.2.74</li>
228   - <li>修改sass为node-sass,避免el-icon图标乱码</li>
229   - <li>代码生成支持同步数据库</li>
230   - <li>代码生成支持富文本控件</li>
231   - <li>代码生成页面时不忽略remark属性</li>
232   - <li>代码生成添加select必填选项</li>
233   - <li>Excel导出类型NUMERIC支持精度浮点类型</li>
234   - <li>Excel导出targetAttr优化获取值,防止get方法不规范</li>
235   - <li>Excel注解支持自动统计数据总和</li>
236   - <li>Excel注解支持设置BigDecimal精度&舍入规则</li>
237   - <li>菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)</li>
238   - <li>允许用户分配到部门父节点</li>
239   - <li>菜单新增是否缓存keep-alive</li>
240   - <li>表格操作列间距调整</li>
241   - <li>限制系统内置参数不允许删除</li>
242   - <li>富文本组件优化,支持自定义高度&图片冲突问题</li>
243   - <li>富文本工具栏样式对齐</li>
244   - <li>导入excel整形值校验优化</li>
245   - <li>修复页签关闭所有时固定标签路由不刷新问题</li>
246   - <li>表单构建布局型组件新增按钮</li>
247   - <li>左侧菜单文字过长显示省略号</li>
248   - <li>修正根节点为子部门时,树状结构显示问题</li>
249   - <li>修正调用目标字符串最大长度</li>
250   - <li>修正菜单提示信息错误</li>
251   - <li>修正定时任务执行一次权限标识</li>
252   - <li>修正数据库字符串类型nvarchar</li>
253   - <li>优化递归子节点</li>
254   - <li>优化数据权限判断</li>
255   - <li>其他细节优化</li>
256   - </ol>
257   - </el-collapse-item>
258   -
259   - <el-collapse-item title="v3.1.0 - 2020-08-13">
260   - <ol>
261   - <li>表格工具栏右侧添加刷新&显隐查询组件</li>
262   - <li>后端支持CORS跨域请求</li>
263   - <li>代码生成支持选择上级菜单</li>
264   - <li>代码生成支持自定义路径</li>
265   - <li>代码生成支持复选框</li>
266   - <li>Excel导出导入支持dictType字典类型</li>
267   - <li>Excel支持分割字符串组内容</li>
268   - <li>验证码类型支持(数组计算、字符验证)</li>
269   - <li>升级vue-cli版本到4.4.4</li>
270   - <li>修改 node-sass 为 dart-sass</li>
271   - <li>表单类型为Integer/Long设置整形默认值</li>
272   - <li>代码生成器默认mapper路径与默认mapperScan路径不一致</li>
273   - <li>优化防重复提交拦截器</li>
274   - <li>优化上级菜单不能选择自己</li>
275   - <li>修复角色的权限分配后,未实时生效问题</li>
276   - <li>修复在线用户日志记录类型</li>
277   - <li>修复富文本空格和缩进保存后不生效问题</li>
278   - <li>修复在线用户判断逻辑</li>
279   - <li>唯一限制条件只返回单条数据</li>
280   - <li>添加获取当前的环境配置方法</li>
281   - <li>超时登录后页面跳转到首页</li>
282   - <li>全局异常状态汉化拦截处理</li>
283   - <li>HTML过滤器改为将html转义</li>
284   - <li>检查字符支持小数点&降级改成异常提醒</li>
285   - <li>其他细节优化</li>
286   - </ol>
287   - </el-collapse-item>
288   -
289   - <el-collapse-item title="v3.0.0 - 2020-07-20">
290   - <ol>
291   - <li>单应用调整为多模块项目</li>
292   - <li>升级element-ui版本到2.13.2</li>
293   - <li>删除babel,提高编译速度。</li>
294   - <li>新增菜单默认主类目</li>
295   - <li>编码文件名修改为uuid方式</li>
296   - <li>定时任务cron表达式验证</li>
297   - <li>角色权限修改时已有权限未自动勾选异常修复</li>
298   - <li>防止切换权限用户后登录出现404</li>
299   - <li>Excel支持sort导出排序</li>
300   - <li>创建用户不允许选择超级管理员角色</li>
301   - <li>修复代码生成导入表结构出现异常页面不提醒问题</li>
302   - <li>修复代码生成点击多次表修改数据不变化的问题</li>
303   - <li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li>
304   - <li>修复布局为small者mini用户表单显示错位问题</li>
305   - <li>修复热部署导致的强换异常问题</li>
306   - <li>修改用户管理复选框宽度,防止部分浏览器出现省略号</li>
307   - <li>IpUtils工具,清除Xss特殊字符,防止Xff注入攻击</li>
308   - <li>生成domain 如果是浮点型 统一用BigDecimal</li>
309   - <li>定时任务调整label-width,防止部署出现错位</li>
310   - <li>调整表头固定列默认样式</li>
311   - <li>代码生成模板调整,字段为String并且必填则加空串条件</li>
312   - <li>代码生成字典Integer/Long使用parseInt</li>
313   - <li>
314   - 修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序
315   - </li>
316   - <li>修正岗位导出权限注解</li>
317   - <li>禁止加密密文返回前端</li>
318   - <li>修复代码生成页面中的查询条件创建时间未生效的问题</li>
319   - <li>修复首页搜索菜单外链无法点击跳转问题</li>
320   - <li>修复菜单管理选择图标,backspace删除时不过滤数据</li>
321   - <li>用户管理部门分支节点不可检查&显示计数</li>
322   - <li>数据范围过滤属性调整</li>
323   - <li>其他细节优化</li>
324   - </ol>
325   - </el-collapse-item>
326   -
327   - <el-collapse-item title="v2.3.0 - 2020-06-01">
328   - <ol>
329   - <li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>
330   - <li>dev启动默认打开浏览器</li>
331   - <li>vue-cli使用默认source-map</li>
332   - <li>slidebar eslint报错优化</li>
333   - <li>当tags-view滚动关闭右键菜单</li>
334   - <li>字典管理添加缓存读取</li>
335   - <li>参数管理支持缓存操作</li>
336   - <li>支持一级菜单(和主页同级)在main区域显示</li>
337   - <li>限制外链地址必须以http(s)开头</li>
338   - <li>tagview & sidebar 主题颜色与element ui(全局)同步</li>
339   - <li>修改数据源类型优先级,先根据方法,再根据类</li>
340   - <li>支持是否需要设置token属性,自定义返回码消息。</li>
341   - <li>swagger请求前缀加入配置。</li>
342   - <li>登录地点设置内容过长则隐藏显示</li>
343   - <li>修复定时任务执行一次按钮后不提示消息问题</li>
344   - <li>修改上级部门(选择项排除本身和下级)</li>
345   - <li>通用http发送方法增加参数 contentType 编码类型</li>
346   - <li>更换IP地址查询接口</li>
347   - <li>修复页签变量undefined</li>
348   - <li>添加校验部门包含未停用的子部门</li>
349   - <li>修改定时任务详情下次执行时间日期显示错误</li>
350   - <li>角色管理查询设置默认排序字段</li>
351   - <li>swagger添加enable参数控制是否启用</li>
352   - <li>只对json类型请求构建可重复读取inputStream的request</li>
353   - <li>修改代码生成字典字段int类型没有自动选中问题</li>
354   - <li>vuex用户名取值修正</li>
355   - <li>表格树模板去掉多余的)</li>
356   - <li>代码生成序号修正</li>
357   - <li>全屏情况下不调整上外边距</li>
358   - <li>代码生成Date字段添加默认格式</li>
359   - <li>用户管理角色选择权限控制</li>
360   - <li>修复路由懒加载报错问题</li>
361   - <li>模板sql.vm添加菜单状态</li>
362   - <li>设置用户名称不能修改</li>
363   - <li>dialog添加append-to-body属性,防止ie遮罩</li>
364   - <li>菜单区分状态和显示隐藏功能</li>
365   - <li>升级fastjson到最新版1.2.68 修复安全加固</li>
366   - <li>修复代码生成如果选择字典类型缺失逗号问题</li>
367   - <li>登录请求params更换为data,防止暴露url</li>
368   - <li>日志返回时间格式处理</li>
369   - <li>添加handle控制允许拖动的元素</li>
370   - <li>布局设置点击扩大范围</li>
371   - <li>代码生成列属性排序查询</li>
372   - <li>代码生成列支持拖动排序</li>
373   - <li>修复时间格式不支持ios问题</li>
374   - <li>表单构建添加父级class,防止冲突</li>
375   - <li>定时任务并发属性修正</li>
376   - <li>角色禁用&菜单隐藏不查询权限</li>
377   - <li>其他细节优化</li>
378   - </ol>
379   - </el-collapse-item>
380   -
381   - <el-collapse-item title="v2.2.0 - 2020-03-18">
382   - <ol>
383   - <li>系统监控新增定时任务功能</li>
384   - <li>添加一个打包Web工程bat</li>
385   - <li>修复页签鼠标滚轮按下的时候,可以关闭不可关闭的tag</li>
386   - <li>修复点击退出登录有时会无提示问题</li>
387   - <li>修复防重复提交注解无效问题</li>
388   - <li>修复通知公告批量删除异常问题</li>
389   - <li>添加菜单时路由地址必填限制</li>
390   - <li>代码生成字段描述可编辑</li>
391   - <li>修复用户修改个人信息导致缓存不过期问题</li>
392   - <li>个人信息创建时间获取正确属性值</li>
393   - <li>操作日志详细显示正确类型</li>
394   - <li>导入表单击行数据时选中对应的复选框</li>
395   - <li>批量替换表前缀逻辑调整</li>
396   - <li>固定重定向路径表达式</li>
397   - <li>升级element-ui版本到2.13.0</li>
398   - <li>操作日志排序调整</li>
399   - <li>修复charts切换侧边栏或者缩放窗口显示bug</li>
400   - <li>其他细节优化</li>
401   - </ol>
402   - </el-collapse-item>
403   -
404   - <el-collapse-item title="v2.1.0 - 2020-02-24">
405   - <ol>
406   - <li>新增表单构建</li>
407   - <li>代码生成支持树表结构</li>
408   - <li>新增用户导入</li>
409   - <li>修复动态加载路由页面刷新问题</li>
410   - <li>修复地址开关无效问题</li>
411   - <li>汉化错误提示页面</li>
412   - <li>代码生成已知问题修改</li>
413   - <li>修复多数据源下配置关闭出现异常处理</li>
414   - <li>添加HTML过滤器,用于去除XSS漏洞隐患</li>
415   - <li>修复上传头像控制台出现异常</li>
416   - <li>修改用户管理分页不正确的问题</li>
417   - <li>修复验证码记录提示错误</li>
418   - <li>修复request.js缺少Message引用</li>
419   - <li>修复表格时间为空出现的异常</li>
420   - <li>添加Jackson日期反序列化时区配置</li>
421   - <li>调整根据用户权限加载菜单数据树形结构</li>
422   - <li>调整成功登陆不恢复按钮,防止多次点击</li>
423   - <li>修改用户个人资料同步缓存信息</li>
424   - <li>修复页面同时出现el-upload和Editor不显示处理</li>
425   - <li>修复在角色管理页修改菜单权限偶尔未选中问题</li>
426   - <li>配置文件新增redis密码属性</li>
427   - <li>设置mybatis全局的配置文件</li>
428   - <li>其他细节优化</li>
429   - </ol>
430   - </el-collapse-item>
431   -
432   - <el-collapse-item title="v2.0.0 - 2019-12-02">
433   - <ol>
434   - <li>新增代码生成</li>
435   - <li>新增@RepeatSubmit注解,防止重复提交</li>
436   - <li>新增菜单主目录添加/删除操作</li>
437   - <li>日志记录过滤特殊对象,防止转换异常</li>
438   - <li>修改代码生成路由脚本错误</li>
439   - <li>用户上传头像实时同步缓存,无需重新登录</li>
440   - <li>调整切换页签后不重新加载数据</li>
441   - <li>添加jsencrypt实现参数的前端加密</li>
442   - <li>系统退出删除用户缓存记录</li>
443   - <li>其他细节优化</li>
444   - </ol>
445   - </el-collapse-item>
446   - <el-collapse-item title="v1.1.0 - 2019-11-11">
447   - <ol>
448   - <li>新增在线用户管理</li>
449   - <li>新增按钮组功能实现(批量删除、导出、清空)</li>
450   - <li>新增查询条件重置按钮</li>
451   - <li>新增Swagger全局Token配置</li>
452   - <li>新增后端参数校验</li>
453   - <li>修复字典管理页面的日期查询异常</li>
454   - <li>修改时间函数命名防止冲突</li>
455   - <li>去除菜单上级校验,默认为顶级</li>
456   - <li>修复用户密码无法修改问题</li>
457   - <li>修复菜单类型为按钮时不显示权限标识</li>
458   - <li>其他细节优化</li>
459   - </ol>
460   - </el-collapse-item>
461   - <el-collapse-item title="v1.0.0 - 2019-10-08">
462   - <ol>
463   - <li>芋道前后端分离系统正式发布</li>
464   - </ol>
465   - </el-collapse-item>
466   - </el-collapse>
467   - </el-card>
468   - </el-col>
469   - <el-col :xs="24" :sm="24" :md="12" :lg="8">
470   - <el-card class="update-log">
471   - <div slot="header" class="clearfix">
472   - <span>捐赠支持</span>
473   - </div>
474   - <div class="body">
475   - <img
476   - src="https://oscimg.oschina.net/oscnet/up-d6695f82666e5018f715c41cb7ee60d3b73.png"
477   - alt="donate"
478   - width="100%"
479   - />
480   - <span style="display: inline-block; height: 30px; line-height: 30px"
481   - >你可以请作者喝杯咖啡表示鼓励</span
482   - >
483   - </div>
484   - </el-card>
485   - </el-col>
486   - </el-row>
487   - </div>
488   -</template>
489   -
490   -<script>
491   -export default {
492   - name: "index",
493   - data() {
494   - return {
495   - // 版本号
496   - version: "3.3.0",
497   - };
498   - },
499   - methods: {
500   - goTarget(href) {
501   - window.open(href, "_blank");
502   - },
503   - },
504   -};
505   -</script>
506   -
507   -<style scoped lang="scss">
508   -.home {
509   - blockquote {
510   - padding: 10px 20px;
511   - margin: 0 0 20px;
512   - font-size: 17.5px;
513   - border-left: 5px solid #eee;
514   - }
515   - hr {
516   - margin-top: 20px;
517   - margin-bottom: 20px;
518   - border: 0;
519   - border-top: 1px solid #eee;
520   - }
521   - .col-item {
522   - margin-bottom: 20px;
523   - }
524   -
525   - ul {
526   - padding: 0;
527   - margin: 0;
528   - }
529   -
530   - font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
531   - font-size: 13px;
532   - color: #676a6c;
533   - overflow-x: hidden;
534   -
535   - ul {
536   - list-style-type: none;
537   - }
538   -
539   - h4 {
540   - margin-top: 0px;
541   - }
542   -
543   - h2 {
544   - margin-top: 10px;
545   - font-size: 26px;
546   - font-weight: 100;
547   - }
548   -
549   - p {
550   - margin-top: 10px;
551   -
552   - b {
553   - font-weight: 700;
554   - }
555   - }
556   -
557   - .update-log {
558   - ol {
559   - display: block;
560   - list-style-type: decimal;
561   - margin-block-start: 1em;
562   - margin-block-end: 1em;
563   - margin-inline-start: 0;
564   - margin-inline-end: 0;
565   - padding-inline-start: 40px;
566   - }
567   - }
568   -}
569   -</style>
570   -
  1 +<template>
  2 + <div class="dashboard-editor-container">
  3 +
  4 + <panel-group @handleSetLineChartData="handleSetLineChartData" />
  5 +
  6 + <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
  7 + <line-chart :chart-data="lineChartData" />
  8 + </el-row>
  9 +
  10 + <el-row :gutter="32">
  11 + <el-col :xs="24" :sm="24" :lg="8">
  12 + <div class="chart-wrapper">
  13 + <raddar-chart />
  14 + </div>
  15 + </el-col>
  16 + <el-col :xs="24" :sm="24" :lg="8">
  17 + <div class="chart-wrapper">
  18 + <pie-chart />
  19 + </div>
  20 + </el-col>
  21 + <el-col :xs="24" :sm="24" :lg="8">
  22 + <div class="chart-wrapper">
  23 + <bar-chart />
  24 + </div>
  25 + </el-col>
  26 + </el-row>
  27 +
  28 +
  29 + </div>
  30 +</template>
  31 +
  32 +<script>
  33 +import PanelGroup from './dashboard/PanelGroup'
  34 +import LineChart from './dashboard/LineChart'
  35 +import RaddarChart from './dashboard/RaddarChart'
  36 +import PieChart from './dashboard/PieChart'
  37 +import BarChart from './dashboard/BarChart'
  38 +
  39 +const lineChartData = {
  40 + newVisitis: {
  41 + expectedData: [100, 120, 161, 134, 105, 160, 165],
  42 + actualData: [120, 82, 91, 154, 162, 140, 145]
  43 + },
  44 + messages: {
  45 + expectedData: [200, 192, 120, 144, 160, 130, 140],
  46 + actualData: [180, 160, 151, 106, 145, 150, 130]
  47 + },
  48 + purchases: {
  49 + expectedData: [80, 100, 121, 104, 105, 90, 100],
  50 + actualData: [120, 90, 100, 138, 142, 130, 130]
  51 + },
  52 + shoppings: {
  53 + expectedData: [130, 140, 141, 142, 145, 150, 160],
  54 + actualData: [120, 82, 91, 154, 162, 140, 130]
  55 + }
  56 +}
  57 +
  58 +export default {
  59 + name: 'Index',
  60 + components: {
  61 + PanelGroup,
  62 + LineChart,
  63 + RaddarChart,
  64 + PieChart,
  65 + BarChart
  66 + },
  67 + data() {
  68 + return {
  69 + lineChartData: lineChartData.newVisitis
  70 + }
  71 + },
  72 + methods: {
  73 + handleSetLineChartData(type) {
  74 + this.lineChartData = lineChartData[type]
  75 + }
  76 + }
  77 +}
  78 +</script>
  79 +
  80 +<style lang="scss" scoped>
  81 +.dashboard-editor-container {
  82 + padding: 32px;
  83 + background-color: rgb(240, 242, 245);
  84 + position: relative;
  85 +
  86 + .chart-wrapper {
  87 + background: #fff;
  88 + padding: 16px 16px 0;
  89 + margin-bottom: 32px;
  90 + }
  91 +}
  92 +
  93 +@media (max-width:1024px) {
  94 + .chart-wrapper {
  95 + padding: 8px;
  96 + }
  97 +}
  98 +</style>
... ...
ruoyi-ui/src/views/index_old.vue 0 → 100644
  1 +<template>
  2 + <div class="app-container home">
  3 + <el-row :gutter="20">
  4 + <el-col :sm="24" :lg="24">
  5 + <blockquote class="text-warning" style="font-size: 14px">
  6 + 领取阿里云通用云产品1888优惠券
  7 + <br />
  8 + <el-link
  9 + href="https://www.aliyun.com/minisite/goods?userCode=brki8iof"
  10 + type="primary"
  11 + target="_blank"
  12 + >https://www.aliyun.com/minisite/goods?userCode=brki8iof</el-link
  13 + >
  14 + <br />
  15 + 领取腾讯云通用云产品2860优惠券
  16 + <br />
  17 + <el-link
  18 + href="https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console"
  19 + type="primary"
  20 + target="_blank"
  21 + >https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console</el-link
  22 + >
  23 + <br />
  24 + 阿里云服务器折扣区
  25 + <el-link href="http://aly.ruoyi.vip" type="primary" target="_blank"
  26 + >>☛☛点我进入☚☚</el-link
  27 + >
  28 + &nbsp;&nbsp;&nbsp; 腾讯云服务器秒杀区
  29 + <el-link href="http://txy.ruoyi.vip" type="primary" target="_blank"
  30 + >>☛☛点我进入☚☚</el-link
  31 + ><br />
  32 + <h4 class="text-danger">
  33 + 云产品通用红包,可叠加官网常规优惠使用。(仅限新用户)
  34 + </h4>
  35 + </blockquote>
  36 +
  37 + <hr />
  38 + </el-col>
  39 + </el-row>
  40 + <el-row :gutter="20">
  41 + <el-col :sm="24" :lg="12" style="padding-left: 20px">
  42 + <h2>芋道后台管理框架</h2>
  43 + <p>
  44 + 一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了芋道管理系统。,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
  45 + </p>
  46 + <p>
  47 + <b>当前版本:</b> <span>v{{ version }}</span>
  48 + </p>
  49 + <p>
  50 + <el-tag type="danger">&yen;免费开源</el-tag>
  51 + </p>
  52 + <p>
  53 + <el-button
  54 + type="primary"
  55 + size="mini"
  56 + icon="el-icon-cloudy"
  57 + plain
  58 + @click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"
  59 + >访问码云</el-button
  60 + >
  61 + <el-button
  62 + size="mini"
  63 + icon="el-icon-s-home"
  64 + plain
  65 + @click="goTarget('http://ruoyi.vip')"
  66 + >访问主页</el-button
  67 + >
  68 + </p>
  69 + </el-col>
  70 +
  71 + <el-col :sm="24" :lg="12" style="padding-left: 50px">
  72 + <el-row>
  73 + <el-col :span="12">
  74 + <h2>技术选型</h2>
  75 + </el-col>
  76 + </el-row>
  77 + <el-row>
  78 + <el-col :span="6">
  79 + <h4>后端技术</h4>
  80 + <ul>
  81 + <li>SpringBoot</li>
  82 + <li>Spring Security</li>
  83 + <li>JWT</li>
  84 + <li>MyBatis</li>
  85 + <li>Druid</li>
  86 + <li>Fastjson</li>
  87 + <li>...</li>
  88 + </ul>
  89 + </el-col>
  90 + <el-col :span="6">
  91 + <h4>前端技术</h4>
  92 + <ul>
  93 + <li>Vue</li>
  94 + <li>Vuex</li>
  95 + <li>Element-ui</li>
  96 + <li>Axios</li>
  97 + <li>Sass</li>
  98 + <li>Quill</li>
  99 + <li>...</li>
  100 + </ul>
  101 + </el-col>
  102 + </el-row>
  103 + </el-col>
  104 + </el-row>
  105 + <el-divider />
  106 + <el-row :gutter="20">
  107 + <el-col :xs="24" :sm="24" :md="12" :lg="8">
  108 + <el-card class="update-log">
  109 + <div slot="header" class="clearfix">
  110 + <span>联系信息</span>
  111 + </div>
  112 + <div class="body">
  113 + <p>
  114 + <i class="el-icon-s-promotion"></i> 官网:<el-link
  115 + href="http://www.ruoyi.vip"
  116 + target="_blank"
  117 + >http://www.ruoyi.vip</el-link
  118 + >
  119 + </p>
  120 + <p>
  121 + <i class="el-icon-user-solid"></i> QQ群:<s>满937441</s>
  122 + <s>满887144332</s> <s>满180251782</s>
  123 + <a href="https://jq.qq.com/?_wv=1027&k=4WWwqNxN" target="_blank"
  124 + > 104180207</a
  125 + >
  126 + </p>
  127 + <p>
  128 + <i class="el-icon-chat-dot-round"></i> 微信:<a
  129 + href="javascript:;"
  130 + >/ *芋道</a
  131 + >
  132 + </p>
  133 + <p>
  134 + <i class="el-icon-money"></i> 支付宝:<a
  135 + href="javascript:;"
  136 + class="支付宝信息"
  137 + >/ *芋道</a
  138 + >
  139 + </p>
  140 + </div>
  141 + </el-card>
  142 + </el-col>
  143 + <el-col :xs="24" :sm="24" :md="12" :lg="8">
  144 + <el-card class="update-log">
  145 + <div slot="header" class="clearfix">
  146 + <span>更新日志</span>
  147 + </div>
  148 + <el-collapse accordion>
  149 + <el-collapse-item title="v3.3.0 - 2020-12-14">
  150 + <ol>
  151 + <li>新增缓存监控功能</li>
  152 + <li>支持主题风格配置</li>
  153 + <li>修复多级菜单之间切换无法缓存的问题</li>
  154 + <li>多级菜单自动配置组件</li>
  155 + <li>代码生成预览支持高亮显示</li>
  156 + <li>支持Get请求映射Params参数</li>
  157 + <li>删除用户和角色解绑关联</li>
  158 + <li>去除用户手机邮箱部门必填验证</li>
  159 + <li>Excel支持注解align对齐方式</li>
  160 + <li>Excel支持导入Boolean型数据</li>
  161 + <li>优化头像样式,鼠标移入悬停遮罩</li>
  162 + <li>代码生成预览提供滚动机制</li>
  163 + <li>代码生成删除多余的数字float类型</li>
  164 + <li>修正转换字符串的目标字符集属性</li>
  165 + <li>回显数据字典防止空值报错</li>
  166 + <li>日志记录增加过滤多文件场景</li>
  167 + <li>修改缓存Set方法可能导致嵌套的问题</li>
  168 + <li>移除前端一些多余的依赖</li>
  169 + <li>防止安全扫描YUI出现的风险提示</li>
  170 + <li>修改node-sass为dart-sass</li>
  171 + <li>升级SpringBoot到最新版本2.1.18</li>
  172 + <li>升级poi到最新版本4.1.2</li>
  173 + <li>升级oshi到最新版本v5.3.6</li>
  174 + <li>升级bitwalker到最新版本1.21</li>
  175 + <li>升级axios到最新版本0.21.0</li>
  176 + <li>升级element-ui到最新版本2.14.1</li>
  177 + <li>升级vue到最新版本2.6.12</li>
  178 + <li>升级vuex到最新版本3.6.0</li>
  179 + <li>升级vue-cli到版本4.5.9</li>
  180 + <li>升级vue-router到最新版本3.4.9</li>
  181 + <li>升级vue-cli到最新版本4.4.6</li>
  182 + <li>升级vue-cropper到最新版本0.5.5</li>
  183 + <li>升级clipboard到最新版本2.0.6</li>
  184 + <li>升级core-js到最新版本3.8.1</li>
  185 + <li>升级echarts到最新版本4.9.0</li>
  186 + <li>升级file-saver到最新版本2.0.4</li>
  187 + <li>升级fuse.js到最新版本6.4.3</li>
  188 + <li>升级js-beautify到最新版本1.13.0</li>
  189 + <li>升级js-cookie到最新版本2.2.1</li>
  190 + <li>升级path-to-regexp到最新版本6.2.0</li>
  191 + <li>升级quill到最新版本1.3.7</li>
  192 + <li>升级screenfull到最新版本5.0.2</li>
  193 + <li>升级sortablejs到最新版本1.10.2</li>
  194 + <li>升级vuedraggable到最新版本2.24.3</li>
  195 + <li>升级chalk到最新版本4.1.0</li>
  196 + <li>升级eslint到最新版本7.15.0</li>
  197 + <li>升级eslint-plugin-vue到最新版本7.2.0</li>
  198 + <li>升级lint-staged到最新版本10.5.3</li>
  199 + <li>升级runjs到最新版本4.4.2</li>
  200 + <li>升级sass-loader到最新版本10.1.0</li>
  201 + <li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>
  202 + <li>升级svg-sprite-loader到最新版本5.1.1</li>
  203 + <li>升级vue-template-compiler到最新版本2.6.12</li>
  204 + <li>其他细节优化</li>
  205 + </ol>
  206 + </el-collapse-item>
  207 + <el-collapse-item title="v3.2.1 - 2020-11-18">
  208 + <ol>
  209 + <li>阻止任意文件下载漏洞</li>
  210 + <li>代码生成支持上传控件</li>
  211 + <li>新增图片上传组件</li>
  212 + <li>调整默认首页</li>
  213 + <li>升级druid到最新版本v1.2.2</li>
  214 + <li>mapperLocations配置支持分隔符</li>
  215 + <li>权限信息调整</li>
  216 + <li>调整sql默认时间</li>
  217 + <li>解决代码生成没有bit类型的问题</li>
  218 + <li>升级pagehelper到最新版1.3.0</li>
  219 + </ol>
  220 + </el-collapse-item>
  221 + <el-collapse-item title="v3.2.0 - 2020-10-10">
  222 + <ol>
  223 + <li>升级springboot版本到2.1.17 提升安全性</li>
  224 + <li>升级oshi到最新版本v5.2.5</li>
  225 + <li>升级druid到最新版本v1.2.1</li>
  226 + <li>升级jjwt到版本0.9.1</li>
  227 + <li>升级fastjson到最新版1.2.74</li>
  228 + <li>修改sass为node-sass,避免el-icon图标乱码</li>
  229 + <li>代码生成支持同步数据库</li>
  230 + <li>代码生成支持富文本控件</li>
  231 + <li>代码生成页面时不忽略remark属性</li>
  232 + <li>代码生成添加select必填选项</li>
  233 + <li>Excel导出类型NUMERIC支持精度浮点类型</li>
  234 + <li>Excel导出targetAttr优化获取值,防止get方法不规范</li>
  235 + <li>Excel注解支持自动统计数据总和</li>
  236 + <li>Excel注解支持设置BigDecimal精度&舍入规则</li>
  237 + <li>菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)</li>
  238 + <li>允许用户分配到部门父节点</li>
  239 + <li>菜单新增是否缓存keep-alive</li>
  240 + <li>表格操作列间距调整</li>
  241 + <li>限制系统内置参数不允许删除</li>
  242 + <li>富文本组件优化,支持自定义高度&图片冲突问题</li>
  243 + <li>富文本工具栏样式对齐</li>
  244 + <li>导入excel整形值校验优化</li>
  245 + <li>修复页签关闭所有时固定标签路由不刷新问题</li>
  246 + <li>表单构建布局型组件新增按钮</li>
  247 + <li>左侧菜单文字过长显示省略号</li>
  248 + <li>修正根节点为子部门时,树状结构显示问题</li>
  249 + <li>修正调用目标字符串最大长度</li>
  250 + <li>修正菜单提示信息错误</li>
  251 + <li>修正定时任务执行一次权限标识</li>
  252 + <li>修正数据库字符串类型nvarchar</li>
  253 + <li>优化递归子节点</li>
  254 + <li>优化数据权限判断</li>
  255 + <li>其他细节优化</li>
  256 + </ol>
  257 + </el-collapse-item>
  258 +
  259 + <el-collapse-item title="v3.1.0 - 2020-08-13">
  260 + <ol>
  261 + <li>表格工具栏右侧添加刷新&显隐查询组件</li>
  262 + <li>后端支持CORS跨域请求</li>
  263 + <li>代码生成支持选择上级菜单</li>
  264 + <li>代码生成支持自定义路径</li>
  265 + <li>代码生成支持复选框</li>
  266 + <li>Excel导出导入支持dictType字典类型</li>
  267 + <li>Excel支持分割字符串组内容</li>
  268 + <li>验证码类型支持(数组计算、字符验证)</li>
  269 + <li>升级vue-cli版本到4.4.4</li>
  270 + <li>修改 node-sass 为 dart-sass</li>
  271 + <li>表单类型为Integer/Long设置整形默认值</li>
  272 + <li>代码生成器默认mapper路径与默认mapperScan路径不一致</li>
  273 + <li>优化防重复提交拦截器</li>
  274 + <li>优化上级菜单不能选择自己</li>
  275 + <li>修复角色的权限分配后,未实时生效问题</li>
  276 + <li>修复在线用户日志记录类型</li>
  277 + <li>修复富文本空格和缩进保存后不生效问题</li>
  278 + <li>修复在线用户判断逻辑</li>
  279 + <li>唯一限制条件只返回单条数据</li>
  280 + <li>添加获取当前的环境配置方法</li>
  281 + <li>超时登录后页面跳转到首页</li>
  282 + <li>全局异常状态汉化拦截处理</li>
  283 + <li>HTML过滤器改为将html转义</li>
  284 + <li>检查字符支持小数点&降级改成异常提醒</li>
  285 + <li>其他细节优化</li>
  286 + </ol>
  287 + </el-collapse-item>
  288 +
  289 + <el-collapse-item title="v3.0.0 - 2020-07-20">
  290 + <ol>
  291 + <li>单应用调整为多模块项目</li>
  292 + <li>升级element-ui版本到2.13.2</li>
  293 + <li>删除babel,提高编译速度。</li>
  294 + <li>新增菜单默认主类目</li>
  295 + <li>编码文件名修改为uuid方式</li>
  296 + <li>定时任务cron表达式验证</li>
  297 + <li>角色权限修改时已有权限未自动勾选异常修复</li>
  298 + <li>防止切换权限用户后登录出现404</li>
  299 + <li>Excel支持sort导出排序</li>
  300 + <li>创建用户不允许选择超级管理员角色</li>
  301 + <li>修复代码生成导入表结构出现异常页面不提醒问题</li>
  302 + <li>修复代码生成点击多次表修改数据不变化的问题</li>
  303 + <li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li>
  304 + <li>修复布局为small者mini用户表单显示错位问题</li>
  305 + <li>修复热部署导致的强换异常问题</li>
  306 + <li>修改用户管理复选框宽度,防止部分浏览器出现省略号</li>
  307 + <li>IpUtils工具,清除Xss特殊字符,防止Xff注入攻击</li>
  308 + <li>生成domain 如果是浮点型 统一用BigDecimal</li>
  309 + <li>定时任务调整label-width,防止部署出现错位</li>
  310 + <li>调整表头固定列默认样式</li>
  311 + <li>代码生成模板调整,字段为String并且必填则加空串条件</li>
  312 + <li>代码生成字典Integer/Long使用parseInt</li>
  313 + <li>
  314 + 修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序
  315 + </li>
  316 + <li>修正岗位导出权限注解</li>
  317 + <li>禁止加密密文返回前端</li>
  318 + <li>修复代码生成页面中的查询条件创建时间未生效的问题</li>
  319 + <li>修复首页搜索菜单外链无法点击跳转问题</li>
  320 + <li>修复菜单管理选择图标,backspace删除时不过滤数据</li>
  321 + <li>用户管理部门分支节点不可检查&显示计数</li>
  322 + <li>数据范围过滤属性调整</li>
  323 + <li>其他细节优化</li>
  324 + </ol>
  325 + </el-collapse-item>
  326 +
  327 + <el-collapse-item title="v2.3.0 - 2020-06-01">
  328 + <ol>
  329 + <li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>
  330 + <li>dev启动默认打开浏览器</li>
  331 + <li>vue-cli使用默认source-map</li>
  332 + <li>slidebar eslint报错优化</li>
  333 + <li>当tags-view滚动关闭右键菜单</li>
  334 + <li>字典管理添加缓存读取</li>
  335 + <li>参数管理支持缓存操作</li>
  336 + <li>支持一级菜单(和主页同级)在main区域显示</li>
  337 + <li>限制外链地址必须以http(s)开头</li>
  338 + <li>tagview & sidebar 主题颜色与element ui(全局)同步</li>
  339 + <li>修改数据源类型优先级,先根据方法,再根据类</li>
  340 + <li>支持是否需要设置token属性,自定义返回码消息。</li>
  341 + <li>swagger请求前缀加入配置。</li>
  342 + <li>登录地点设置内容过长则隐藏显示</li>
  343 + <li>修复定时任务执行一次按钮后不提示消息问题</li>
  344 + <li>修改上级部门(选择项排除本身和下级)</li>
  345 + <li>通用http发送方法增加参数 contentType 编码类型</li>
  346 + <li>更换IP地址查询接口</li>
  347 + <li>修复页签变量undefined</li>
  348 + <li>添加校验部门包含未停用的子部门</li>
  349 + <li>修改定时任务详情下次执行时间日期显示错误</li>
  350 + <li>角色管理查询设置默认排序字段</li>
  351 + <li>swagger添加enable参数控制是否启用</li>
  352 + <li>只对json类型请求构建可重复读取inputStream的request</li>
  353 + <li>修改代码生成字典字段int类型没有自动选中问题</li>
  354 + <li>vuex用户名取值修正</li>
  355 + <li>表格树模板去掉多余的)</li>
  356 + <li>代码生成序号修正</li>
  357 + <li>全屏情况下不调整上外边距</li>
  358 + <li>代码生成Date字段添加默认格式</li>
  359 + <li>用户管理角色选择权限控制</li>
  360 + <li>修复路由懒加载报错问题</li>
  361 + <li>模板sql.vm添加菜单状态</li>
  362 + <li>设置用户名称不能修改</li>
  363 + <li>dialog添加append-to-body属性,防止ie遮罩</li>
  364 + <li>菜单区分状态和显示隐藏功能</li>
  365 + <li>升级fastjson到最新版1.2.68 修复安全加固</li>
  366 + <li>修复代码生成如果选择字典类型缺失逗号问题</li>
  367 + <li>登录请求params更换为data,防止暴露url</li>
  368 + <li>日志返回时间格式处理</li>
  369 + <li>添加handle控制允许拖动的元素</li>
  370 + <li>布局设置点击扩大范围</li>
  371 + <li>代码生成列属性排序查询</li>
  372 + <li>代码生成列支持拖动排序</li>
  373 + <li>修复时间格式不支持ios问题</li>
  374 + <li>表单构建添加父级class,防止冲突</li>
  375 + <li>定时任务并发属性修正</li>
  376 + <li>角色禁用&菜单隐藏不查询权限</li>
  377 + <li>其他细节优化</li>
  378 + </ol>
  379 + </el-collapse-item>
  380 +
  381 + <el-collapse-item title="v2.2.0 - 2020-03-18">
  382 + <ol>
  383 + <li>系统监控新增定时任务功能</li>
  384 + <li>添加一个打包Web工程bat</li>
  385 + <li>修复页签鼠标滚轮按下的时候,可以关闭不可关闭的tag</li>
  386 + <li>修复点击退出登录有时会无提示问题</li>
  387 + <li>修复防重复提交注解无效问题</li>
  388 + <li>修复通知公告批量删除异常问题</li>
  389 + <li>添加菜单时路由地址必填限制</li>
  390 + <li>代码生成字段描述可编辑</li>
  391 + <li>修复用户修改个人信息导致缓存不过期问题</li>
  392 + <li>个人信息创建时间获取正确属性值</li>
  393 + <li>操作日志详细显示正确类型</li>
  394 + <li>导入表单击行数据时选中对应的复选框</li>
  395 + <li>批量替换表前缀逻辑调整</li>
  396 + <li>固定重定向路径表达式</li>
  397 + <li>升级element-ui版本到2.13.0</li>
  398 + <li>操作日志排序调整</li>
  399 + <li>修复charts切换侧边栏或者缩放窗口显示bug</li>
  400 + <li>其他细节优化</li>
  401 + </ol>
  402 + </el-collapse-item>
  403 +
  404 + <el-collapse-item title="v2.1.0 - 2020-02-24">
  405 + <ol>
  406 + <li>新增表单构建</li>
  407 + <li>代码生成支持树表结构</li>
  408 + <li>新增用户导入</li>
  409 + <li>修复动态加载路由页面刷新问题</li>
  410 + <li>修复地址开关无效问题</li>
  411 + <li>汉化错误提示页面</li>
  412 + <li>代码生成已知问题修改</li>
  413 + <li>修复多数据源下配置关闭出现异常处理</li>
  414 + <li>添加HTML过滤器,用于去除XSS漏洞隐患</li>
  415 + <li>修复上传头像控制台出现异常</li>
  416 + <li>修改用户管理分页不正确的问题</li>
  417 + <li>修复验证码记录提示错误</li>
  418 + <li>修复request.js缺少Message引用</li>
  419 + <li>修复表格时间为空出现的异常</li>
  420 + <li>添加Jackson日期反序列化时区配置</li>
  421 + <li>调整根据用户权限加载菜单数据树形结构</li>
  422 + <li>调整成功登陆不恢复按钮,防止多次点击</li>
  423 + <li>修改用户个人资料同步缓存信息</li>
  424 + <li>修复页面同时出现el-upload和Editor不显示处理</li>
  425 + <li>修复在角色管理页修改菜单权限偶尔未选中问题</li>
  426 + <li>配置文件新增redis密码属性</li>
  427 + <li>设置mybatis全局的配置文件</li>
  428 + <li>其他细节优化</li>
  429 + </ol>
  430 + </el-collapse-item>
  431 +
  432 + <el-collapse-item title="v2.0.0 - 2019-12-02">
  433 + <ol>
  434 + <li>新增代码生成</li>
  435 + <li>新增@RepeatSubmit注解,防止重复提交</li>
  436 + <li>新增菜单主目录添加/删除操作</li>
  437 + <li>日志记录过滤特殊对象,防止转换异常</li>
  438 + <li>修改代码生成路由脚本错误</li>
  439 + <li>用户上传头像实时同步缓存,无需重新登录</li>
  440 + <li>调整切换页签后不重新加载数据</li>
  441 + <li>添加jsencrypt实现参数的前端加密</li>
  442 + <li>系统退出删除用户缓存记录</li>
  443 + <li>其他细节优化</li>
  444 + </ol>
  445 + </el-collapse-item>
  446 + <el-collapse-item title="v1.1.0 - 2019-11-11">
  447 + <ol>
  448 + <li>新增在线用户管理</li>
  449 + <li>新增按钮组功能实现(批量删除、导出、清空)</li>
  450 + <li>新增查询条件重置按钮</li>
  451 + <li>新增Swagger全局Token配置</li>
  452 + <li>新增后端参数校验</li>
  453 + <li>修复字典管理页面的日期查询异常</li>
  454 + <li>修改时间函数命名防止冲突</li>
  455 + <li>去除菜单上级校验,默认为顶级</li>
  456 + <li>修复用户密码无法修改问题</li>
  457 + <li>修复菜单类型为按钮时不显示权限标识</li>
  458 + <li>其他细节优化</li>
  459 + </ol>
  460 + </el-collapse-item>
  461 + <el-collapse-item title="v1.0.0 - 2019-10-08">
  462 + <ol>
  463 + <li>芋道前后端分离系统正式发布</li>
  464 + </ol>
  465 + </el-collapse-item>
  466 + </el-collapse>
  467 + </el-card>
  468 + </el-col>
  469 + <el-col :xs="24" :sm="24" :md="12" :lg="8">
  470 + <el-card class="update-log">
  471 + <div slot="header" class="clearfix">
  472 + <span>捐赠支持</span>
  473 + </div>
  474 + <div class="body">
  475 + <img
  476 + src="https://oscimg.oschina.net/oscnet/up-d6695f82666e5018f715c41cb7ee60d3b73.png"
  477 + alt="donate"
  478 + width="100%"
  479 + />
  480 + <span style="display: inline-block; height: 30px; line-height: 30px"
  481 + >你可以请作者喝杯咖啡表示鼓励</span
  482 + >
  483 + </div>
  484 + </el-card>
  485 + </el-col>
  486 + </el-row>
  487 + </div>
  488 +</template>
  489 +
  490 +<script>
  491 +export default {
  492 + name: "index",
  493 + data() {
  494 + return {
  495 + // 版本号
  496 + version: "3.3.0",
  497 + };
  498 + },
  499 + methods: {
  500 + goTarget(href) {
  501 + window.open(href, "_blank");
  502 + },
  503 + },
  504 +};
  505 +</script>
  506 +
  507 +<style scoped lang="scss">
  508 +.home {
  509 + blockquote {
  510 + padding: 10px 20px;
  511 + margin: 0 0 20px;
  512 + font-size: 17.5px;
  513 + border-left: 5px solid #eee;
  514 + }
  515 + hr {
  516 + margin-top: 20px;
  517 + margin-bottom: 20px;
  518 + border: 0;
  519 + border-top: 1px solid #eee;
  520 + }
  521 + .col-item {
  522 + margin-bottom: 20px;
  523 + }
  524 +
  525 + ul {
  526 + padding: 0;
  527 + margin: 0;
  528 + }
  529 +
  530 + font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  531 + font-size: 13px;
  532 + color: #676a6c;
  533 + overflow-x: hidden;
  534 +
  535 + ul {
  536 + list-style-type: none;
  537 + }
  538 +
  539 + h4 {
  540 + margin-top: 0px;
  541 + }
  542 +
  543 + h2 {
  544 + margin-top: 10px;
  545 + font-size: 26px;
  546 + font-weight: 100;
  547 + }
  548 +
  549 + p {
  550 + margin-top: 10px;
  551 +
  552 + b {
  553 + font-weight: 700;
  554 + }
  555 + }
  556 +
  557 + .update-log {
  558 + ol {
  559 + display: block;
  560 + list-style-type: decimal;
  561 + margin-block-start: 1em;
  562 + margin-block-end: 1em;
  563 + margin-inline-start: 0;
  564 + margin-inline-end: 0;
  565 + padding-inline-start: 40px;
  566 + }
  567 + }
  568 +}
  569 +</style>
  570 +
... ...
ruoyi-ui/src/views/index_v1.vue deleted
1   -<template>
2   - <div class="dashboard-editor-container">
3   -
4   - <panel-group @handleSetLineChartData="handleSetLineChartData" />
5   -
6   - <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
7   - <line-chart :chart-data="lineChartData" />
8   - </el-row>
9   -
10   - <el-row :gutter="32">
11   - <el-col :xs="24" :sm="24" :lg="8">
12   - <div class="chart-wrapper">
13   - <raddar-chart />
14   - </div>
15   - </el-col>
16   - <el-col :xs="24" :sm="24" :lg="8">
17   - <div class="chart-wrapper">
18   - <pie-chart />
19   - </div>
20   - </el-col>
21   - <el-col :xs="24" :sm="24" :lg="8">
22   - <div class="chart-wrapper">
23   - <bar-chart />
24   - </div>
25   - </el-col>
26   - </el-row>
27   -
28   -
29   - </div>
30   -</template>
31   -
32   -<script>
33   -import PanelGroup from './dashboard/PanelGroup'
34   -import LineChart from './dashboard/LineChart'
35   -import RaddarChart from './dashboard/RaddarChart'
36   -import PieChart from './dashboard/PieChart'
37   -import BarChart from './dashboard/BarChart'
38   -
39   -const lineChartData = {
40   - newVisitis: {
41   - expectedData: [100, 120, 161, 134, 105, 160, 165],
42   - actualData: [120, 82, 91, 154, 162, 140, 145]
43   - },
44   - messages: {
45   - expectedData: [200, 192, 120, 144, 160, 130, 140],
46   - actualData: [180, 160, 151, 106, 145, 150, 130]
47   - },
48   - purchases: {
49   - expectedData: [80, 100, 121, 104, 105, 90, 100],
50   - actualData: [120, 90, 100, 138, 142, 130, 130]
51   - },
52   - shoppings: {
53   - expectedData: [130, 140, 141, 142, 145, 150, 160],
54   - actualData: [120, 82, 91, 154, 162, 140, 130]
55   - }
56   -}
57   -
58   -export default {
59   - name: 'Index',
60   - components: {
61   - PanelGroup,
62   - LineChart,
63   - RaddarChart,
64   - PieChart,
65   - BarChart
66   - },
67   - data() {
68   - return {
69   - lineChartData: lineChartData.newVisitis
70   - }
71   - },
72   - methods: {
73   - handleSetLineChartData(type) {
74   - this.lineChartData = lineChartData[type]
75   - }
76   - }
77   -}
78   -</script>
79   -
80   -<style lang="scss" scoped>
81   -.dashboard-editor-container {
82   - padding: 32px;
83   - background-color: rgb(240, 242, 245);
84   - position: relative;
85   -
86   - .chart-wrapper {
87   - background: #fff;
88   - padding: 16px 16px 0;
89   - margin-bottom: 32px;
90   - }
91   -}
92   -
93   -@media (max-width:1024px) {
94   - .chart-wrapper {
95   - padding: 8px;
96   - }
97   -}
98   -</style>
ruoyi-ui/src/views/infra/job/index.vue
... ... @@ -30,7 +30,7 @@
30 30 </el-col>
31 31 <el-col :span="1.5">
32 32 <el-button type="info" icon="el-icon-s-operation" size="mini" @click="handleJobLog"
33   - v-hasPermi="['monitor:job:query']">日志</el-button>
  33 + v-hasPermi="['infra:job:query']">日志</el-button>
34 34 </el-col>
35 35 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
36 36 </el-row>
... ... @@ -53,9 +53,9 @@
53 53 <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
54 54 v-hasPermi="['infra:job:update']">修改</el-button>
55 55 <el-button size="mini" type="text" icon="el-icon-check" @click="handleChangeStatus(scope.row, true)"
56   - v-hasPermi="['infra:job:update']">开启</el-button>
  56 + v-if="scope.row.status === InfJobStatusEnum.STOP" v-hasPermi="['infra:job:update']">开启</el-button>
57 57 <el-button size="mini" type="text" icon="el-icon-close" @click="handleChangeStatus(scope.row, false)"
58   - v-hasPermi="['infra:job:update']">暂停</el-button>
  58 + v-if="scope.row.status === InfJobStatusEnum.NORMAL" v-hasPermi="['infra:job:update']">暂停</el-button>
59 59 <el-button size="mini" type="text" icon="el-icon-caret-right" @click="handleRun(scope.row)"
60 60 v-hasPermi="['infra:job:trigger']">执行一次</el-button>
61 61 <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
... ... @@ -82,6 +82,12 @@
82 82 <el-form-item label="CRON 表达式" prop="cronExpression">
83 83 <el-input v-model="form.cronExpression" placeholder="请输入CRON 表达式" />
84 84 </el-form-item>
  85 + <el-form-item label="重试次数" prop="retryCount">
  86 + <el-input v-model="form.retryCount" placeholder="请输入重试次数。设置为 0 时,不进行重试" />
  87 + </el-form-item>
  88 + <el-form-item label="重试间隔" prop="retryInterval">
  89 + <el-input v-model="form.retryInterval" placeholder="请输入重试间隔,单位:毫秒。设置为 0 时,无需间隔" />
  90 + </el-form-item>
85 91 <el-form-item label="监控超时时间" prop="monitorTimeout">
86 92 <el-input v-model="form.monitorTimeout" placeholder="请输入监控超时时间,单位:毫秒" />
87 93 </el-form-item>
... ... @@ -107,6 +113,8 @@
107 113 <el-form-item label="最后一次执行的开始时间:">{{ parseTime(form.executeEndTime) }}</el-form-item>
108 114 <el-form-item label="上一次触发时间:">{{ parseTime(form.firePrevTime) }}</el-form-item>
109 115 <el-form-item label="下一次触发时间:">{{ parseTime(form.fireNextTime) }}</el-form-item>
  116 + <el-form-item label="重试次数:">{{ form.retryCount }}</el-form-item>
  117 + <el-form-item label="重试间隔:">{{ form.retryInterval + " 毫秒" }}</el-form-item>
110 118 <el-form-item label="监控超时时间:">{{ form.monitorTimeout > 0 ? form.monitorTimeout + " 毫秒" : "未开启" }}</el-form-item>
111 119 </el-col>
112 120 </el-row>
... ... @@ -158,7 +166,12 @@ export default {
158 166 name: [{ required: true, message: "任务名称不能为空", trigger: "blur" }],
159 167 handlerName: [{ required: true, message: "处理器的名字不能为空", trigger: "blur" }],
160 168 cronExpression: [{ required: true, message: "CRON 表达式不能为空", trigger: "blur" }],
161   - }
  169 + retryCount: [{ required: true, message: "重试次数不能为空", trigger: "blur" }],
  170 + retryInterval: [{ required: true, message: "重试间隔不能为空", trigger: "blur" }],
  171 + },
  172 +
  173 + // 枚举
  174 + InfJobStatusEnum: InfJobStatusEnum
162 175 };
163 176 },
164 177 created() {
... ... @@ -187,6 +200,8 @@ export default {
187 200 handlerName: undefined,
188 201 handlerParam: undefined,
189 202 cronExpression: undefined,
  203 + retryCount: undefined,
  204 + retryInterval: undefined,
190 205 monitorTimeout: undefined,
191 206 };
192 207 this.resetForm("form");
... ...
src/main/java/cn/iocoder/dashboard/framework/mybatis/core/query/QueryWrapperX.java
... ... @@ -65,6 +65,20 @@ public class QueryWrapperX&lt;T&gt; extends QueryWrapper&lt;T&gt; {
65 65 return this;
66 66 }
67 67  
  68 + public QueryWrapperX<T> ltIfPresent(String column, Object val) {
  69 + if (val != null) {
  70 + return (QueryWrapperX<T>) super.lt(column, val);
  71 + }
  72 + return this;
  73 + }
  74 +
  75 + public QueryWrapperX<T> leIfPresent(String column, Object val) {
  76 + if (val != null) {
  77 + return (QueryWrapperX<T>) super.le(column, val);
  78 + }
  79 + return this;
  80 + }
  81 +
68 82 public QueryWrapperX<T> betweenIfPresent(String column, Object val1, Object val2) {
69 83 if (val1 != null && val2 != null) {
70 84 return (QueryWrapperX<T>) super.between(column, val1, val2);
... ...
src/main/java/cn/iocoder/dashboard/framework/quartz/core/enums/JobDataKeyEnum.java
... ... @@ -7,6 +7,8 @@ public enum JobDataKeyEnum {
7 7  
8 8 JOB_ID,
9 9 JOB_HANDLER_NAME,
10   - JOB_HANDLER_PARAM
  10 + JOB_HANDLER_PARAM,
  11 + JOB_RETRY_COUNT, // 最大重试次数
  12 + JOB_RETRY_INTERVAL, // 每次重试间隔
11 13  
12 14 }
... ...
src/main/java/cn/iocoder/dashboard/framework/quartz/core/handler/JobHandlerInvoker.java
1 1 package cn.iocoder.dashboard.framework.quartz.core.handler;
2 2  
3 3 import cn.hutool.core.lang.Assert;
4   -import cn.hutool.core.util.StrUtil;
  4 +import cn.hutool.core.thread.ThreadUtil;
5 5 import cn.iocoder.dashboard.framework.quartz.core.enums.JobDataKeyEnum;
6 6 import cn.iocoder.dashboard.framework.quartz.core.service.JobLogFrameworkService;
7 7 import lombok.extern.slf4j.Slf4j;
... ... @@ -38,8 +38,11 @@ public class JobHandlerInvoker extends QuartzJobBean {
38 38 protected void executeInternal(JobExecutionContext executionContext) throws JobExecutionException {
39 39 // 第一步,获得 Job 数据
40 40 Long jobId = executionContext.getMergedJobDataMap().getLong(JobDataKeyEnum.JOB_ID.name());
41   - String jobHandlerName = getJobHandlerName(executionContext);
  41 + String jobHandlerName = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_NAME.name());
42 42 String jobHandlerParam = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_PARAM.name());
  43 + int refireCount = executionContext.getRefireCount();
  44 + int retryCount = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_COUNT.name(), 0);
  45 + int retryInterval = (Integer) executionContext.getMergedJobDataMap().getOrDefault(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), 0);
43 46  
44 47 // 第二步,执行任务
45 48 Long jobLogId = null;
... ... @@ -48,7 +51,7 @@ public class JobHandlerInvoker extends QuartzJobBean {
48 51 Throwable exception = null;
49 52 try {
50 53 // 记录 Job 日志(初始)
51   - jobLogId = jobLogFrameworkService.createJobLog(jobId, startTime, jobHandlerName, jobHandlerParam);
  54 + jobLogId = jobLogFrameworkService.createJobLog(jobId, startTime, jobHandlerName, jobHandlerParam, refireCount + 1);
52 55 // 执行任务
53 56 data = this.executeInternal(jobHandlerName, jobHandlerParam);
54 57 } catch (Throwable ex) {
... ... @@ -58,21 +61,8 @@ public class JobHandlerInvoker extends QuartzJobBean {
58 61 // 第三步,记录执行日志
59 62 this.updateJobLogResultAsync(jobLogId, startTime, data, exception, executionContext);
60 63  
61   - // 最终还是抛出异常,用于停止任务
62   - if (exception != null) {
63   - throw new JobExecutionException(exception);
64   - }
65   - }
66   -
67   - private static String getJobHandlerName(JobExecutionContext executionContext) {
68   - String jobHandlerName = executionContext.getMergedJobDataMap().getString(JobDataKeyEnum.JOB_HANDLER_NAME.name());
69   - if (StrUtil.isEmpty(jobHandlerName)) {
70   - log.error("[executeInternal][Job({}) 获取不到正确的 jobHandlerName({})]",
71   - executionContext.getJobDetail().getKey(), jobHandlerName);
72   - throw new IllegalStateException(StrUtil.format("Job({}) 获取不到正确的 jobHandlerName({})",
73   - executionContext.getJobDetail().getKey(), jobHandlerName));
74   - }
75   - return jobHandlerName;
  64 + // 第四步,处理有异常的情况
  65 + handleException(exception, refireCount, retryCount, retryInterval);
76 66 }
77 67  
78 68 private String executeInternal(String jobHandlerName, String jobHandlerParam) throws Exception {
... ... @@ -86,18 +76,38 @@ public class JobHandlerInvoker extends QuartzJobBean {
86 76 private void updateJobLogResultAsync(Long jobLogId, Date startTime, String data, Throwable exception,
87 77 JobExecutionContext executionContext) {
88 78 Date endTime = new Date();
  79 + // 处理是否成功
  80 + boolean success = exception == null;
  81 + if (!success) {
  82 + data = getRootCauseMessage(exception);
  83 + }
  84 + // 更新日志
89 85 try {
90   - if (data != null) { // 成功
91   - jobLogFrameworkService.updateJobLogSuccessAsync(jobLogId, endTime, (int) diff(endTime, startTime), data);
92   - } else { // 失败
93   - jobLogFrameworkService.updateJobLogErrorAsync(jobLogId, endTime, (int) diff(endTime, startTime),
94   - getRootCauseMessage(exception));
95   - }
  86 + jobLogFrameworkService.updateJobLogResultAsync(jobLogId, endTime, (int) diff(endTime, startTime), success, data);
96 87 } catch (Exception ex) {
97   - log.error("[executeInternal][Job({}) logId({}) 记录执行日志失败({})]",
98   - executionContext.getJobDetail().getKey(), jobLogId,
99   - data != null ? data : getRootCauseMessage(exception));
  88 + log.error("[executeInternal][Job({}) logId({}) 记录执行日志失败({}/{})]",
  89 + executionContext.getJobDetail().getKey(), jobLogId, success, data);
  90 + }
  91 + }
  92 +
  93 + private void handleException(Throwable exception,
  94 + int refireCount, int retryCount, int retryInterval) throws JobExecutionException {
  95 + // 如果有异常,则进行重试
  96 + if (exception == null) {
  97 + return;
  98 + }
  99 + // 情况一:如果到达重试上限,则直接抛出异常即可
  100 + if (refireCount >= retryCount) {
  101 + throw new JobExecutionException(exception);
  102 + }
  103 +
  104 + // 情况二:如果未到达重试上限,则 sleep 一定间隔时间,然后重试
  105 + // 这里使用 sleep 来实现,主要还是希望实现比较简单。因为,同一时间,不会存在大量失败的 Job。
  106 + if (retryInterval > 0) {
  107 + ThreadUtil.sleep(retryInterval);
100 108 }
  109 + // 第二个参数,refireImmediately = true,表示立即重试
  110 + throw new JobExecutionException(exception, true);
101 111 }
102 112  
103 113 }
... ...
src/main/java/cn/iocoder/dashboard/framework/quartz/core/scheduler/SchedulerManager.java
... ... @@ -30,9 +30,12 @@ public class SchedulerManager {
30 30 * @param jobHandlerName 任务处理器的名字
31 31 * @param jobHandlerParam 任务处理器的参数
32 32 * @param cronExpression CRON 表达式
  33 + * @param retryCount 重试次数
  34 + * @param retryInterval 重试间隔
33 35 * @throws SchedulerException 添加异常
34 36 */
35   - public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression)
  37 + public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression,
  38 + Integer retryCount, Integer retryInterval)
36 39 throws SchedulerException {
37 40 // 创建 JobDetail 对象
38 41 JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class)
... ... @@ -40,7 +43,7 @@ public class SchedulerManager {
40 43 .usingJobData(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName)
41 44 .withIdentity(jobHandlerName).build();
42 45 // 创建 Trigger 对象
43   - Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression);
  46 + Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval);
44 47 // 新增调度
45 48 scheduler.scheduleJob(jobDetail, trigger);
46 49 }
... ... @@ -51,12 +54,15 @@ public class SchedulerManager {
51 54 * @param jobHandlerName 任务处理器的名字
52 55 * @param jobHandlerParam 任务处理器的参数
53 56 * @param cronExpression CRON 表达式
  57 + * @param retryCount 重试次数
  58 + * @param retryInterval 重试间隔
54 59 * @throws SchedulerException 更新异常
55 60 */
56   - public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression)
  61 + public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression,
  62 + Integer retryCount, Integer retryInterval)
57 63 throws SchedulerException {
58 64 // 创建新 Trigger 对象
59   - Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression);
  65 + Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval);
60 66 // 修改调度
61 67 scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger);
62 68 }
... ... @@ -102,7 +108,7 @@ public class SchedulerManager {
102 108 */
103 109 public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam)
104 110 throws SchedulerException {
105   - JobDataMap data = new JobDataMap();
  111 + JobDataMap data = new JobDataMap(); // 无需重试,所以不设置 retryCount 和 retryInterval
106 112 data.put(JobDataKeyEnum.JOB_ID.name(), jobId);
107 113 data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName);
108 114 data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam);
... ... @@ -110,11 +116,14 @@ public class SchedulerManager {
110 116 scheduler.triggerJob(new JobKey(jobHandlerName), data);
111 117 }
112 118  
113   - private Trigger buildTrigger(String jobHandlerName, String jobHandlerParam, String cronExpression) {
  119 + private Trigger buildTrigger(String jobHandlerName, String jobHandlerParam, String cronExpression,
  120 + Integer retryCount, Integer retryInterval) {
114 121 return TriggerBuilder.newTrigger()
115 122 .withIdentity(jobHandlerName)
116   - .usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam)
117 123 .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
  124 + .usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam)
  125 + .usingJobData(JobDataKeyEnum.JOB_RETRY_COUNT.name(), retryCount)
  126 + .usingJobData(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), retryInterval)
118 127 .build();
119 128 }
120 129  
... ...
src/main/java/cn/iocoder/dashboard/framework/quartz/core/service/JobLogFrameworkService.java
... ... @@ -14,41 +14,31 @@ public interface JobLogFrameworkService {
14 14 /**
15 15 * 创建 Job 日志
16 16 *
17   - * @param jobId 任务编号
18   - * @param beginTime 开始时间
19   - * @param jobHandlerName Job 处理器的名字
  17 + * @param jobId 任务编号
  18 + * @param beginTime 开始时间
  19 + * @param jobHandlerName Job 处理器的名字
20 20 * @param jobHandlerParam Job 处理器的参数
  21 + * @param executeIndex 第几次执行
21 22 * @return Job 日志的编号
22 23 */
23 24 Long createJobLog(@NotNull(message = "任务编号不能为空") Long jobId,
24 25 @NotNull(message = "开始时间") Date beginTime,
25 26 @NotEmpty(message = "Job 处理器的名字不能为空") String jobHandlerName,
26   - String jobHandlerParam);
  27 + String jobHandlerParam,
  28 + @NotNull(message = "第几次执行不能为空") Integer executeIndex);
27 29  
28 30 /**
29   - * 更新 Job 日志成功
  31 + * 更新 Job 日志的执行结果
30 32 *
31   - * @param logId 日志编号
32   - * @param endTime 结束时间。因为是异步,避免记录时间不准去
  33 + * @param logId 日志编号
  34 + * @param endTime 结束时间。因为是异步,避免记录时间不准去
33 35 * @param duration 运行时长,单位:毫秒
34   - * @param result 成功数据
  36 + * @param success 是否成功
  37 + * @param result 成功数据
35 38 */
36   - void updateJobLogSuccessAsync(@NotNull(message = "日志编号不能为空") Long logId,
37   - @NotNull(message = "结束时间不能为空") Date endTime,
38   - @NotNull(message = "运行时长不能为空") Integer duration,
39   - String result);
40   -
41   - /**
42   - * 更新 Job 日志失败
43   - *
44   - * @param logId 日志编号
45   - * @param endTime 结束时间。因为是异步,避免记录时间不准去
46   - * @param duration 运行时长,单位:毫秒
47   - * @param result 异常提示
48   - */
49   - void updateJobLogErrorAsync(@NotNull(message = "日志编号不能为空") Long logId,
50   - @NotNull(message = "结束时间不能为空") Date endTime,
51   - @NotNull(message = "运行时长不能为空") Integer duration,
52   - String result);
  39 + void updateJobLogResultAsync(@NotNull(message = "日志编号不能为空") Long logId,
  40 + @NotNull(message = "结束时间不能为空") Date endTime,
  41 + @NotNull(message = "运行时长不能为空") Integer duration,
  42 + boolean success, String result);
53 43  
54 44 }
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/dbdoc/InfDbDocController.java renamed to src/main/java/cn/iocoder/dashboard/modules/infra/controller/doc/InfDbDocController.java
1   -package cn.iocoder.dashboard.modules.infra.controller.dbdoc;
  1 +package cn.iocoder.dashboard.modules.infra.controller.doc;
2 2  
3 3 import cn.hutool.extra.servlet.ServletUtil;
4 4 import cn.smallbun.screw.core.Configuration;
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/job/InfJobBaseVO.java
... ... @@ -23,6 +23,14 @@ public class InfJobBaseVO {
23 23 @NotNull(message = "CRON 表达式不能为空")
24 24 private String cronExpression;
25 25  
  26 + @ApiModelProperty(value = "重试次数", required = true)
  27 + @NotNull(message = "重试次数不能为空")
  28 + private Integer retryCount;
  29 +
  30 + @ApiModelProperty(value = "重试间隔", required = true)
  31 + @NotNull(message = "重试间隔不能为空")
  32 + private Integer retryInterval;
  33 +
26 34 @ApiModelProperty(value = "监控超时时间", example = "1000")
27 35 private Integer monitorTimeout;
28 36  
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogBaseVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
  2 +
  3 +import io.swagger.annotations.ApiModelProperty;
  4 +import lombok.Data;
  5 +import org.springframework.format.annotation.DateTimeFormat;
  6 +
  7 +import javax.validation.constraints.NotNull;
  8 +import java.util.Date;
  9 +
  10 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +/**
  13 +* 定时任务日志 Base VO,提供给添加、修改、详细的子 VO 使用
  14 +* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
  15 +*/
  16 +@Data
  17 +public class InfJobLogBaseVO {
  18 +
  19 + @ApiModelProperty(value = "任务编号", required = true)
  20 + @NotNull(message = "任务编号不能为空")
  21 + private Long jobId;
  22 +
  23 + @ApiModelProperty(value = "处理器的名字", required = true)
  24 + @NotNull(message = "处理器的名字不能为空")
  25 + private String handlerName;
  26 +
  27 + @ApiModelProperty(value = "处理器的参数")
  28 + private String handlerParam;
  29 +
  30 + @ApiModelProperty(value = "第几次执行", required = true)
  31 + @NotNull(message = "第几次执行不能为空")
  32 + private Integer executeIndex;
  33 +
  34 + @ApiModelProperty(value = "开始执行时间", required = true)
  35 + @NotNull(message = "开始执行时间不能为空")
  36 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  37 + private Date beginTime;
  38 +
  39 + @ApiModelProperty(value = "结束执行时间")
  40 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  41 + private Date endTime;
  42 +
  43 + @ApiModelProperty(value = "执行时长")
  44 + private Integer duration;
  45 +
  46 + @ApiModelProperty(value = "任务状态", required = true)
  47 + @NotNull(message = "任务状态不能为空")
  48 + private Integer status;
  49 +
  50 + @ApiModelProperty(value = "结果数据")
  51 + private String result;
  52 +
  53 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogExcelVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelProperty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Date;
  7 +
  8 +/**
  9 + * 定时任务 Excel VO
  10 + *
  11 + * @author 芋艿
  12 + */
  13 +@Data
  14 +public class InfJobLogExcelVO {
  15 +
  16 + @ExcelProperty("日志编号")
  17 + private Long id;
  18 +
  19 + @ExcelProperty("任务编号")
  20 + private Long jobId;
  21 +
  22 + @ExcelProperty("处理器的名字")
  23 + private String handlerName;
  24 +
  25 + @ExcelProperty("处理器的参数")
  26 + private String handlerParam;
  27 +
  28 + @ExcelProperty("第几次执行")
  29 + private Integer executeIndex;
  30 +
  31 + @ExcelProperty("开始执行时间")
  32 + private Date beginTime;
  33 +
  34 + @ExcelProperty("结束执行时间")
  35 + private Date endTime;
  36 +
  37 + @ExcelProperty("执行时长")
  38 + private Integer duration;
  39 +
  40 + @ExcelProperty("任务状态")
  41 + private Integer status;
  42 +
  43 + @ExcelProperty("结果数据")
  44 + private String result;
  45 +
  46 + @ExcelProperty("创建时间")
  47 + private Date createTime;
  48 +
  49 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogExportReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +
  8 +import java.util.Date;
  9 +
  10 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  11 +
  12 +@ApiModel(value = "定时任务 Excel 导出 Request VO", description = "参数和 InfJobLogPageReqVO 是一致的")
  13 +@Data
  14 +public class InfJobLogExportReqVO {
  15 +
  16 + @ApiModelProperty(value = "处理器的名字")
  17 + private String handlerName;
  18 +
  19 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  20 + @ApiModelProperty(value = "开始执行时间")
  21 + private Date beginTime;
  22 +
  23 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  24 + @ApiModelProperty(value = "结束执行时间")
  25 + private Date endTime;
  26 +
  27 + @ApiModelProperty(value = "任务状态")
  28 + private Integer status;
  29 +
  30 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogPageReqVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
  2 +
  3 +import cn.iocoder.dashboard.common.pojo.PageParam;
  4 +import io.swagger.annotations.ApiModel;
  5 +import io.swagger.annotations.ApiModelProperty;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.util.Date;
  12 +
  13 +import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@ApiModel("定时任务日志分页 Request VO")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +public class InfJobLogPageReqVO extends PageParam {
  20 +
  21 + @ApiModelProperty(value = "处理器的名字")
  22 + private String handlerName;
  23 +
  24 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  25 + @ApiModelProperty(value = "开始执行时间")
  26 + private Date beginTime;
  27 +
  28 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  29 + @ApiModelProperty(value = "结束执行时间")
  30 + private Date endTime;
  31 +
  32 + @ApiModelProperty(value = "任务状态")
  33 + private Integer status;
  34 +
  35 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/controller/job/vo/log/InfJobLogRespVO.java 0 → 100644
  1 +package cn.iocoder.dashboard.modules.infra.controller.job.vo.log;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +
  9 +import java.util.Date;
  10 +
  11 +@ApiModel("定时任务日志 Response VO")
  12 +@Data
  13 +@EqualsAndHashCode(callSuper = true)
  14 +@ToString(callSuper = true)
  15 +public class InfJobLogRespVO extends InfJobLogBaseVO {
  16 +
  17 + @ApiModelProperty(value = "日志编号", required = true)
  18 + private Long id;
  19 +
  20 + @ApiModelProperty(value = "创建时间", required = true)
  21 + private Date createTime;
  22 +
  23 +}
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobDO.java
... ... @@ -75,6 +75,18 @@ public class InfJobDO extends BaseDO {
75 75 */
76 76 private Date fireNextTime;
77 77  
  78 + // ========== 重试相关字段 ==========
  79 + /**
  80 + * 重试次数
  81 + * 如果不重试,则设置为 0
  82 + */
  83 + private Integer retryCount;
  84 + /**
  85 + * 重试间隔,单位:毫秒
  86 + * 如果没有间隔,则设置为 0
  87 + */
  88 + private Integer retryInterval;
  89 +
78 90 // ========== 监控相关字段 ==========
79 91 /**
80 92 * 监控超时时间,单位:毫秒
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/dal/dataobject/job/InfJobLogDO.java
... ... @@ -44,6 +44,12 @@ public class InfJobLogDO extends BaseDO {
44 44 * 冗余字段 {@link InfJobDO#getHandlerParam()}
45 45 */
46 46 private String handlerParam;
  47 + /**
  48 + * 第几次执行
  49 + *
  50 + * 用于区分是不是重试执行。如果是重试执行,则 index 大于 1
  51 + */
  52 + private Integer executeIndex;
47 53  
48 54 /**
49 55 * 开始执行时间
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/enums/job/InfJobStatusEnum.java
... ... @@ -23,17 +23,13 @@ public enum InfJobStatusEnum {
23 23 */
24 24 INIT(0, Collections.emptySet()),
25 25 /**
26   - * 开启运行
  26 + * 开启
27 27 */
28 28 NORMAL(1, Sets.newHashSet(STATE_WAITING, STATE_ACQUIRED, STATE_BLOCKED)),
29 29 /**
30   - * 异常运行
  30 + * 暂停
31 31 */
32   - EXCEPTION(2, Sets.newHashSet(STATE_COMPLETE)),
33   - /**
34   - * 暂停运行
35   - */
36   - STOP(3, Sets.newHashSet(STATE_PAUSED, STATE_PAUSED_BLOCKED));
  32 + STOP(2, Sets.newHashSet(STATE_PAUSED, STATE_PAUSED_BLOCKED));
37 33  
38 34 /**
39 35 * 状态
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/service/job/impl/InfJobLogServiceImpl.java
... ... @@ -26,8 +26,8 @@ public class InfJobLogServiceImpl implements InfJobLogService {
26 26 private InfJobLogMapper jobLogMapper;
27 27  
28 28 @Override
29   - public Long createJobLog(Long jobId, Date beginTime, String jobHandlerName, String jobHandlerParam) {
30   - InfJobLogDO log = InfJobLogDO.builder().jobId(jobId).handlerName(jobHandlerName).handlerParam(jobHandlerParam)
  29 + public Long createJobLog(Long jobId, Date beginTime, String jobHandlerName, String jobHandlerParam, Integer executeIndex) {
  30 + InfJobLogDO log = InfJobLogDO.builder().jobId(jobId).handlerName(jobHandlerName).handlerParam(jobHandlerParam).executeIndex(executeIndex)
31 31 .beginTime(beginTime).status(InfJobLogStatusEnum.RUNNING.getStatus()).build();
32 32 jobLogMapper.insert(log);
33 33 return log.getId();
... ... @@ -35,24 +35,14 @@ public class InfJobLogServiceImpl implements InfJobLogService {
35 35  
36 36 @Override
37 37 @Async
38   - public void updateJobLogSuccessAsync(Long logId, Date endTime, Integer duration, String result) {
39   - updateJobLogResult(logId, endTime, duration, result, InfJobLogStatusEnum.SUCCESS);
40   - }
41   -
42   - @Override
43   - @Async
44   - public void updateJobLogErrorAsync(Long logId, Date endTime, Integer duration, String result) {
45   - updateJobLogResult(logId, endTime, duration, result, InfJobLogStatusEnum.FAILURE);
46   - }
47   -
48   - private void updateJobLogResult(Long logId, Date endTime, Integer duration, String result, InfJobLogStatusEnum status) {
  38 + public void updateJobLogResultAsync(Long logId, Date endTime, Integer duration, boolean success, String result) {
49 39 try {
50 40 InfJobLogDO updateObj = InfJobLogDO.builder().id(logId).endTime(endTime).duration(duration)
51   - .status(status.getStatus()).result(result).build();
  41 + .status(success ? InfJobLogStatusEnum.SUCCESS.getStatus() : InfJobLogStatusEnum.FAILURE.getStatus()).result(result).build();
52 42 jobLogMapper.updateById(updateObj);
53 43 } catch (Exception ex) {
54   - log.error("[updateJobLogResult][logId({}) endTime({}) duration({}) result({}) status({})]",
55   - logId, endTime, duration, result, status);
  44 + log.error("[updateJobLogResultAsync][logId({}) endTime({}) duration({}) success({}) result({})]",
  45 + logId, endTime, duration, success, result);
56 46 }
57 47 }
58 48  
... ...
src/main/java/cn/iocoder/dashboard/modules/infra/service/job/impl/InfJobServiceImpl.java
... ... @@ -55,7 +55,8 @@ public class InfJobServiceImpl implements InfJobService {
55 55 jobMapper.insert(job);
56 56  
57 57 // 添加 Job 到 Quartz 中
58   - schedulerManager.addJob(job.getId(), job.getHandlerName(), job.getHandlerParam(), job.getCronExpression());
  58 + schedulerManager.addJob(job.getId(), job.getHandlerName(), job.getHandlerParam(), job.getCronExpression(),
  59 + createReqVO.getRetryCount(), createReqVO.getRetryInterval());
59 60 // 更新
60 61 InfJobDO updateObj = InfJobDO.builder().id(job.getId()).status(InfJobStatusEnum.NORMAL.getStatus()).build();
61 62 jobMapper.updateById(updateObj);
... ... @@ -80,7 +81,8 @@ public class InfJobServiceImpl implements InfJobService {
80 81 jobMapper.updateById(updateObj);
81 82  
82 83 // 更新 Job 到 Quartz 中
83   - schedulerManager.updateJob(job.getHandlerName(), updateReqVO.getHandlerParam(), updateReqVO.getCronExpression());
  84 + schedulerManager.updateJob(job.getHandlerName(), updateReqVO.getHandlerParam(), updateReqVO.getCronExpression(),
  85 + updateReqVO.getRetryCount(), updateReqVO.getRetryInterval());
84 86 }
85 87  
86 88 @Override
... ... @@ -138,7 +140,7 @@ public class InfJobServiceImpl implements InfJobService {
138 140 }
139 141  
140 142 private void validateCronExpression(String cronExpression) {
141   - if (CronUtils.isValid(cronExpression)) {
  143 + if (!CronUtils.isValid(cronExpression)) {
142 144 throw exception(JOB_CRON_EXPRESSION_VALID);
143 145 }
144 146 }
... ...
src/main/java/cn/iocoder/dashboard/modules/system/job/auth/SysUserSessionTimeoutJob.java
... ... @@ -15,6 +15,9 @@ public class SysUserSessionTimeoutJob implements JobHandler {
15 15  
16 16 @Override
17 17 public String execute(String param) throws Exception {
  18 + if (true) {
  19 + throw new RuntimeException("测试异常");
  20 + }
18 21 // System.out.println("执行了一次任务");
19 22 log.info("[execute][执行任务:{}]", param);
20 23 return null;
... ...
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImpl.java
... ... @@ -134,6 +134,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
134 134 }
135 135  
136 136 @Override
  137 + @Transactional
137 138 public void syncCodegenFromDB(Long tableId) {
138 139 // 校验是否已经存在
139 140 ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
... ... @@ -148,6 +149,7 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
148 149 }
149 150  
150 151 @Override
  152 + @Transactional
151 153 public void syncCodegenFromSQL(Long tableId, String sql) {
152 154 // 校验是否已经存在
153 155 ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
... ... @@ -193,7 +195,9 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
193 195 codegenColumnMapper.insert(column); // TODO 批量插入
194 196 });
195 197 // 删除不存在的字段
196   - codegenColumnMapper.deleteBatchIds(deleteColumnIds);
  198 + if (CollUtil.isNotEmpty(deleteColumnIds)) {
  199 + codegenColumnMapper.deleteBatchIds(deleteColumnIds);
  200 + }
197 201 }
198 202  
199 203 @Override
... ...
src/main/resources/codegen/java/dal/mapper.vm
... ... @@ -27,7 +27,10 @@ import ${basePackage}.${table.moduleName}.controller.${table.businessName}.vo.*;
27 27 .geIfPresent("${column.columnName}", reqVO.get${JavaField}())
28 28 #end
29 29 #if (${column.listOperationCondition} == "<")##情况五,< 的时候
30   - .gtIfPresent("${column.columnName}", reqVO.get${JavaField}())
  30 + .ltIfPresent("${column.columnName}", reqVO.get${JavaField}())
  31 +#end
  32 +#if (${column.listOperationCondition} == "<=")##情况五,<= 的时候
  33 + .leIfPresent("${column.columnName}", reqVO.get${JavaField}())
31 34 #end
32 35 #if (${column.listOperationCondition} == "LIKE")##情况七,Like 的时候
33 36 .likeIfPresent("${column.columnName}", reqVO.get${JavaField}())
... ...
src/test/java/cn/iocoder/dashboard/framework/quartz/core/scheduler/SchedulerManagerTest.java
... ... @@ -20,13 +20,13 @@ class SchedulerManagerTest {
20 20 @Test
21 21 public void testAddJob() throws SchedulerException {
22 22 String jobHandlerName = StrUtil.lowerFirst(SysUserSessionTimeoutJob.class.getSimpleName());
23   - schedulerManager.addJob(1L, jobHandlerName, "test", "0/10 * * * * ? *");
  23 + schedulerManager.addJob(1L, jobHandlerName, "test", "0/10 * * * * ? *", 0, 0);
24 24 }
25 25  
26 26 @Test
27 27 public void testUpdateJob() throws SchedulerException {
28 28 String jobHandlerName = StrUtil.lowerFirst(SysUserSessionTimeoutJob.class.getSimpleName());
29   - schedulerManager.updateJob(jobHandlerName, "hahaha", "0/20 * * * * ? *");
  29 + schedulerManager.updateJob(jobHandlerName, "hahaha", "0/20 * * * * ? *", 0, 0);
30 30 }
31 31  
32 32 @Test
... ...