Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
RuoYi Vue
Commits
2cc14e5f
Commit
2cc14e5f
authored
Mar 18, 2020
by
RuoYi
Browse files
若依 2.2
parent
505ee1d6
Changes
42
Hide whitespace changes
Inline
Side-by-side
ruoyi-ui/package.json
View file @
2cc14e5f
{
"name"
:
"ruoyi"
,
"version"
:
"2.
1
.0"
,
"version"
:
"2.
2
.0"
,
"description"
:
"若依管理系统"
,
"author"
:
"若依"
,
"license"
:
"MIT"
,
...
...
ruoyi-ui/src/api/monitor/job.js
0 → 100644
View file @
2cc14e5f
import
request
from
'
@/utils/request
'
// 查询定时任务调度列表
export
function
listJob
(
query
)
{
return
request
({
url
:
'
/monitor/job/list
'
,
method
:
'
get
'
,
params
:
query
})
}
// 查询定时任务调度详细
export
function
getJob
(
jobId
)
{
return
request
({
url
:
'
/monitor/job/
'
+
jobId
,
method
:
'
get
'
})
}
// 新增定时任务调度
export
function
addJob
(
data
)
{
return
request
({
url
:
'
/monitor/job
'
,
method
:
'
post
'
,
data
:
data
})
}
// 修改定时任务调度
export
function
updateJob
(
data
)
{
return
request
({
url
:
'
/monitor/job
'
,
method
:
'
put
'
,
data
:
data
})
}
// 删除定时任务调度
export
function
delJob
(
jobId
)
{
return
request
({
url
:
'
/monitor/job/
'
+
jobId
,
method
:
'
delete
'
})
}
// 导出定时任务调度
export
function
exportJob
(
query
)
{
return
request
({
url
:
'
/monitor/job/export
'
,
method
:
'
get
'
,
params
:
query
})
}
// 任务状态修改
export
function
changeJobStatus
(
jobId
,
status
)
{
const
data
=
{
jobId
,
status
}
return
request
({
url
:
'
/monitor/job/changeStatus
'
,
method
:
'
put
'
,
data
:
data
})
}
// 定时任务立即执行一次
export
function
runJob
(
jobId
,
jobGroup
)
{
const
data
=
{
jobId
,
jobGroup
}
return
request
({
url
:
'
/monitor/job/run
'
,
method
:
'
put
'
,
data
:
data
})
}
\ No newline at end of file
ruoyi-ui/src/api/monitor/jobLog.js
0 → 100644
View file @
2cc14e5f
import
request
from
'
@/utils/request
'
// 查询调度日志列表
export
function
listJobLog
(
query
)
{
return
request
({
url
:
'
/monitor/jobLog/list
'
,
method
:
'
get
'
,
params
:
query
})
}
// 删除调度日志
export
function
delJobLog
(
jobLogId
)
{
return
request
({
url
:
'
/monitor/jobLog/
'
+
jobLogId
,
method
:
'
delete
'
})
}
// 清空调度日志
export
function
cleanJobLog
()
{
return
request
({
url
:
'
/monitor/jobLog/clean
'
,
method
:
'
delete
'
})
}
// 导出调度日志
export
function
exportJobLog
(
query
)
{
return
request
({
url
:
'
/monitor/jobLog/export
'
,
method
:
'
get
'
,
params
:
query
})
}
\ No newline at end of file
ruoyi-ui/src/components/SvgIcon/index.vue
View file @
2cc14e5f
<
template
>
<div
v-if=
"isExternal"
:style=
"styleExternalIcon"
class=
"svg-external-icon svg-icon"
v-on=
"$listeners"
/>
<svg
v-else
:class=
"svgClass"
aria-hidden=
"true"
v-on=
"$listeners"
>
<use
:xlink
:href=
"iconName"
/>
<use
:href=
"iconName"
/>
</svg>
</
template
>
...
...
ruoyi-ui/src/layout/components/TagsView/index.vue
View file @
2cc14e5f
...
...
@@ -158,7 +158,7 @@ export default {
toLastView
(
visitedViews
,
view
)
{
const
latestView
=
visitedViews
.
slice
(
-
1
)[
0
]
if
(
latestView
)
{
this
.
$router
.
push
(
latestView
)
this
.
$router
.
push
(
latestView
.
fullPath
)
}
else
{
// now the default is to redirect to the home page if there is no tags-view,
// you can adjust it according to your needs.
...
...
ruoyi-ui/src/router/index.js
View file @
2cc14e5f
...
...
@@ -92,6 +92,19 @@ export const constantRoutes = [
}
]
},
{
path
:
'
/job
'
,
component
:
Layout
,
hidden
:
true
,
children
:
[
{
path
:
'
log
'
,
component
:
()
=>
import
(
'
@/views/monitor/job/log
'
),
name
:
'
JobLog
'
,
meta
:
{
title
:
'
调度日志
'
}
}
]
},
{
path
:
'
/gen
'
,
component
:
Layout
,
...
...
ruoyi-ui/src/store/modules/tagsView.js
View file @
2cc14e5f
...
...
@@ -28,13 +28,8 @@ const mutations = {
}
},
DEL_CACHED_VIEW
:
(
state
,
view
)
=>
{
for
(
const
i
of
state
.
cachedViews
)
{
if
(
i
===
view
.
name
)
{
const
index
=
state
.
cachedViews
.
indexOf
(
i
)
state
.
cachedViews
.
splice
(
index
,
1
)
break
}
}
const
index
=
state
.
cachedViews
.
indexOf
(
view
.
name
)
index
>
-
1
&&
state
.
cachedViews
.
splice
(
index
,
1
)
},
DEL_OTHERS_VISITED_VIEWS
:
(
state
,
view
)
=>
{
...
...
@@ -43,12 +38,10 @@ const mutations = {
})
},
DEL_OTHERS_CACHED_VIEWS
:
(
state
,
view
)
=>
{
for
(
const
i
of
state
.
cachedViews
)
{
if
(
i
===
view
.
name
)
{
const
index
=
state
.
cachedViews
.
indexOf
(
i
)
state
.
cachedViews
=
state
.
cachedViews
.
slice
(
index
,
index
+
1
)
break
}
if
(
index
>
-
1
)
{
state
.
cachedViews
=
state
.
cachedViews
.
slice
(
index
,
index
+
1
)
}
else
{
state
.
cachedViews
=
[]
}
},
...
...
ruoyi-ui/src/views/monitor/job/index.vue
View file @
2cc14e5f
<
template
>
<div
class=
"app-container"
>
定时任务
<el-form
:model=
"queryParams"
ref=
"queryForm"
:inline=
"true"
label-width=
"68px"
>
<el-form-item
label=
"任务名称"
prop=
"jobName"
>
<el-input
v-model=
"queryParams.jobName"
placeholder=
"请输入任务名称"
clearable
size=
"small"
@
keyup.enter.native=
"handleQuery"
/>
</el-form-item>
<el-form-item
label=
"任务组名"
prop=
"jobGroup"
>
<el-select
v-model=
"queryParams.jobGroup"
placeholder=
"请选择任务组名"
clearable
size=
"small"
>
<el-option
v-for=
"dict in jobGroupOptions"
:key=
"dict.dictValue"
:label=
"dict.dictLabel"
:value=
"dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"任务状态"
prop=
"status"
>
<el-select
v-model=
"queryParams.status"
placeholder=
"请选择任务状态"
clearable
size=
"small"
>
<el-option
v-for=
"dict in statusOptions"
:key=
"dict.dictValue"
:label=
"dict.dictLabel"
:value=
"dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
icon=
"el-icon-search"
size=
"mini"
@
click=
"handleQuery"
>
搜索
</el-button>
<el-button
icon=
"el-icon-refresh"
size=
"mini"
@
click=
"resetQuery"
>
重置
</el-button>
</el-form-item>
</el-form>
<el-row
:gutter=
"10"
class=
"mb8"
>
<el-col
:span=
"1.5"
>
<el-button
type=
"primary"
icon=
"el-icon-plus"
size=
"mini"
@
click=
"handleAdd"
v-hasPermi=
"['monitor:job:add']"
>
新增
</el-button>
</el-col>
<el-col
:span=
"1.5"
>
<el-button
type=
"success"
icon=
"el-icon-edit"
size=
"mini"
:disabled=
"single"
@
click=
"handleUpdate"
v-hasPermi=
"['monitor:job:edit']"
>
修改
</el-button>
</el-col>
<el-col
:span=
"1.5"
>
<el-button
type=
"danger"
icon=
"el-icon-delete"
size=
"mini"
:disabled=
"multiple"
@
click=
"handleDelete"
v-hasPermi=
"['monitor:job:remove']"
>
删除
</el-button>
</el-col>
<el-col
:span=
"1.5"
>
<el-button
type=
"warning"
icon=
"el-icon-download"
size=
"mini"
@
click=
"handleExport"
v-hasPermi=
"['monitor:job:export']"
>
导出
</el-button>
</el-col>
<el-col
:span=
"1.5"
>
<el-button
type=
"info"
icon=
"el-icon-s-operation"
size=
"mini"
@
click=
"handleJobLog"
v-hasPermi=
"['monitor:job:query']"
>
日志
</el-button>
</el-col>
</el-row>
<el-table
v-loading=
"loading"
:data=
"jobList"
@
selection-change=
"handleSelectionChange"
>
<el-table-column
type=
"selection"
width=
"55"
align=
"center"
/>
<el-table-column
label=
"任务编号"
align=
"center"
prop=
"jobId"
/>
<el-table-column
label=
"任务名称"
align=
"center"
prop=
"jobName"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"任务组名"
align=
"center"
prop=
"jobGroup"
:formatter=
"jobGroupFormat"
/>
<el-table-column
label=
"调用目标字符串"
align=
"center"
prop=
"invokeTarget"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"cron执行表达式"
align=
"center"
prop=
"cronExpression"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"状态"
align=
"center"
>
<template
slot-scope=
"scope"
>
<el-switch
v-model=
"scope.row.status"
active-value=
"0"
inactive-value=
"1"
@
change=
"handleStatusChange(scope.row)"
></el-switch>
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
align=
"center"
class-name=
"small-padding fixed-width"
>
<
template
slot-scope=
"scope"
>
<el-button
size=
"mini"
type=
"text"
icon=
"el-icon-caret-right"
@
click=
"handleRun(scope.row)"
v-hasPermi=
"['monitor:job:edit']"
>
执行一次
</el-button>
<el-button
size=
"mini"
type=
"text"
icon=
"el-icon-view"
@
click=
"handleView(scope.row)"
v-hasPermi=
"['monitor:job:query']"
>
详细
</el-button>
</
template
>
</el-table-column>
</el-table>
<pagination
v-show=
"total>0"
:total=
"total"
:page.sync=
"queryParams.pageNum"
:limit.sync=
"queryParams.pageSize"
@
pagination=
"getList"
/>
<!-- 添加或修改定时任务对话框 -->
<el-dialog
:title=
"title"
:visible.sync=
"open"
width=
"700px"
>
<el-form
ref=
"form"
:model=
"form"
:rules=
"rules"
label-width=
"100px"
>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"任务名称"
prop=
"jobName"
>
<el-input
v-model=
"form.jobName"
placeholder=
"请输入任务名称"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"任务分组"
prop=
"jobGroup"
>
<el-select
v-model=
"form.jobGroup"
placeholder=
"请选择"
>
<el-option
v-for=
"dict in jobGroupOptions"
:key=
"dict.dictValue"
:label=
"dict.dictLabel"
:value=
"dict.dictValue"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col
:span=
"24"
>
<el-form-item
prop=
"invokeTarget"
>
<span
slot=
"label"
>
调用方法
<el-tooltip
placement=
"top"
>
<div
slot=
"content"
>
Bean调用示例:ryTask.ryParams('ry')
<br
/>
Class类调用示例:com.ruoyi.quartz.task.RyTask.ryParams('ry')
<br
/>
参数说明:支持字符串,布尔类型,长整型,浮点型,整型
</div>
<i
class=
"el-icon-question"
></i>
</el-tooltip>
</span>
<el-input
v-model=
"form.invokeTarget"
placeholder=
"请输入调用目标字符串"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"cron表达式"
prop=
"cronExpression"
>
<el-input
v-model=
"form.cronExpression"
placeholder=
"请输入cron执行表达式"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"是否并发"
prop=
"concurrent"
>
<el-radio-group
v-model=
"form.concurrent"
size=
"small"
>
<el-radio-button
label=
"0"
>
允许
</el-radio-button>
<el-radio-button
label=
"1"
>
禁止
</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-col
:span=
"24"
>
<el-form-item
label=
"错误策略"
prop=
"misfirePolicy"
>
<el-radio-group
v-model=
"form.misfirePolicy"
size=
"small"
>
<el-radio-button
label=
"1"
>
立即执行
</el-radio-button>
<el-radio-button
label=
"2"
>
执行一次
</el-radio-button>
<el-radio-button
label=
"3"
>
放弃执行
</el-radio-button>
</el-radio-group>
</el-form-item>
</el-col>
<el-col
:span=
"24"
>
<el-form-item
label=
"状态"
>
<el-radio-group
v-model=
"form.status"
>
<el-radio
v-for=
"dict in statusOptions"
:key=
"dict.dictValue"
:label=
"dict.dictValue"
>
{{dict.dictLabel}}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
type=
"primary"
@
click=
"submitForm"
>
确 定
</el-button>
<el-button
@
click=
"cancel"
>
取 消
</el-button>
</div>
</el-dialog>
<!-- 任务日志详细 -->
<el-dialog
title=
"任务详细"
:visible.sync=
"openView"
width=
"700px"
>
<el-form
ref=
"form"
:model=
"form"
label-width=
"120px"
size=
"mini"
>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"任务编号:"
>
{{ form.jobId }}
</el-form-item>
<el-form-item
label=
"任务名称:"
>
{{ form.jobName }}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"任务分组:"
>
{{ jobGroupFormat(form) }}
</el-form-item>
<el-form-item
label=
"创建时间:"
>
{{ form.createTime }}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"cron表达式:"
>
{{ form.cronExpression }}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"下次执行时间:"
>
{{ parseTime(form.nextValidTime) }}
</el-form-item>
</el-col>
<el-col
:span=
"24"
>
<el-form-item
label=
"调用目标方法:"
>
{{ form.invokeTarget }}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"任务状态:"
>
<div
v-if=
"form.status == 0"
>
正常
</div>
<div
v-else-if=
"form.status == 1"
>
失败
</div>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"是否并发:"
>
<div
v-if=
"form.status == 0"
>
允许
</div>
<div
v-else-if=
"form.status == 1"
>
禁止
</div>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"执行策略:"
>
<div
v-if=
"form.misfirePolicy == 0"
>
默认策略
</div>
<div
v-else-if=
"form.misfirePolicy == 1"
>
立即执行
</div>
<div
v-else-if=
"form.misfirePolicy == 2"
>
执行一次
</div>
<div
v-else-if=
"form.misfirePolicy == 3"
>
放弃执行
</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"openView = false"
>
关 闭
</el-button>
</div>
</el-dialog>
</div>
</
template
>
\ No newline at end of file
</template>
<
script
>
import
{
listJob
,
getJob
,
delJob
,
addJob
,
updateJob
,
exportJob
,
runJob
,
changeJobStatus
}
from
"
@/api/monitor/job
"
;
export
default
{
name
:
"
Job
"
,
data
()
{
return
{
// 遮罩层
loading
:
true
,
// 选中数组
ids
:
[],
// 非单个禁用
single
:
true
,
// 非多个禁用
multiple
:
true
,
// 总条数
total
:
0
,
// 定时任务表格数据
jobList
:
[],
// 弹出层标题
title
:
""
,
// 是否显示弹出层
open
:
false
,
// 是否显示详细弹出层
openView
:
false
,
// 任务组名字典
jobGroupOptions
:
[],
// 状态字典
statusOptions
:
[],
// 查询参数
queryParams
:
{
pageNum
:
1
,
pageSize
:
10
,
jobName
:
undefined
,
jobGroup
:
undefined
,
status
:
undefined
},
// 表单参数
form
:
{},
// 表单校验
rules
:
{
jobName
:
[
{
required
:
true
,
message
:
"
任务名称不能为空
"
,
trigger
:
"
blur
"
}
],
invokeTarget
:
[
{
required
:
true
,
message
:
"
调用目标字符串不能为空
"
,
trigger
:
"
blur
"
}
],
cronExpression
:
[
{
required
:
true
,
message
:
"
cron执行表达式不能为空
"
,
trigger
:
"
blur
"
}
]
}
};
},
created
()
{
this
.
getList
();
this
.
getDicts
(
"
sys_job_group
"
).
then
(
response
=>
{
this
.
jobGroupOptions
=
response
.
data
;
});
this
.
getDicts
(
"
sys_job_status
"
).
then
(
response
=>
{
this
.
statusOptions
=
response
.
data
;
});
},
methods
:
{
/** 查询定时任务列表 */
getList
()
{
this
.
loading
=
true
;
listJob
(
this
.
queryParams
).
then
(
response
=>
{
this
.
jobList
=
response
.
rows
;
this
.
total
=
response
.
total
;
this
.
loading
=
false
;
});
},
// 任务组名字典翻译
jobGroupFormat
(
row
,
column
)
{
return
this
.
selectDictLabel
(
this
.
jobGroupOptions
,
row
.
jobGroup
);
},
// 状态字典翻译
statusFormat
(
row
,
column
)
{
return
this
.
selectDictLabel
(
this
.
statusOptions
,
row
.
status
);
},
// 取消按钮
cancel
()
{
this
.
open
=
false
;
this
.
reset
();
},
// 表单重置
reset
()
{
this
.
form
=
{
jobId
:
undefined
,
jobName
:
undefined
,
jobGroup
:
undefined
,
invokeTarget
:
undefined
,
cronExpression
:
undefined
,
misfirePolicy
:
1
,
concurrent
:
1
,
status
:
"
0
"
};
this
.
resetForm
(
"
form
"
);
},
/** 搜索按钮操作 */
handleQuery
()
{
this
.
queryParams
.
pageNum
=
1
;
this
.
getList
();
},
/** 重置按钮操作 */
resetQuery
()
{
this
.
resetForm
(
"
queryForm
"
);
this
.
handleQuery
();
},
// 多选框选中数据
handleSelectionChange
(
selection
)
{
this
.
ids
=
selection
.
map
(
item
=>
item
.
jobId
);
this
.
single
=
selection
.
length
!=
1
;
this
.
multiple
=
!
selection
.
length
;
},
// 任务状态修改
handleStatusChange
(
row
)
{
let
text
=
row
.
status
===
"
0
"
?
"
启用
"
:
"
停用
"
;
this
.
$confirm
(
'
确认要"
'
+
text
+
'
""
'
+
row
.
jobName
+
'
"任务吗?
'
,
"
警告
"
,
{
confirmButtonText
:
"
确定
"
,
cancelButtonText
:
"
取消
"
,
type
:
"
warning
"
}).
then
(
function
()
{
return
changeJobStatus
(
row
.
jobId
,
row
.
status
);
}).
then
(()
=>
{
this
.
msgSuccess
(
text
+
"
成功
"
);
}).
catch
(
function
()
{
row
.
status
=
row
.
status
===
"
0
"
?
"
1
"
:
"
0
"
;
});
},
/* 立即执行一次 */
handleRun
(
row
)
{
this
.
$confirm
(
'
确认要立即执行一次"
'
+
row
.
jobName
+
'
"任务吗?
'
,
"
警告
"
,
{
confirmButtonText
:
"
确定
"
,
cancelButtonText
:
"
取消
"
,
type
:
"
warning
"
}).
then
(
function
()
{
return
runJob
(
row
.
jobId
,
row
.
jobGroup
);
}).
then
(
function
()
{
this
.
msgSuccess
(
"
执行成功
"
);
}).
catch
(
function
()
{});
},
/** 任务详细信息 */
handleView
(
row
)
{
getJob
(
row
.
jobId
).
then
(
response
=>
{
this
.
form
=
response
.
data
;
this
.
openView
=
true
;
});
},
/** 任务日志列表查询 */
handleJobLog
()
{
this
.
$router
.
push
(
"
/job/log
"
);
},
/** 新增按钮操作 */
handleAdd
()
{
this
.
reset
();
this
.
open
=
true
;
this
.
title
=
"
添加任务
"
;
},
/** 修改按钮操作 */
handleUpdate
(
row
)
{
this
.
reset
();
const
jobId
=
row
.
jobId
||
this
.
ids
;
getJob
(
jobId
).
then
(
response
=>
{
this
.
form
=
response
.
data
;
this
.
open
=
true
;
this
.
title
=
"
修改任务
"
;
});
},
/** 提交按钮 */
submitForm
:
function
()
{
this
.
$refs
[
"
form
"
].
validate
(
valid
=>
{
if
(
valid
)
{
if
(
this
.
form
.
jobId
!=
undefined
)
{
updateJob
(
this
.
form
).
then
(
response
=>
{
if
(
response
.
code
===
200
)
{
this
.
msgSuccess
(
"
修改成功
"
);
this
.
open
=
false
;
this
.
getList
();
}
else
{
this
.
msgError
(
response
.
msg
);
}
});
}
else
{
addJob
(
this
.
form
).
then
(
response
=>
{
if
(
response
.
code
===
200
)
{
this
.
msgSuccess
(
"
新增成功
"
);
this
.
open
=
false
;
this
.
getList
();
}
else
{
this
.
msgError
(
response
.
msg
);
}
});
}
}
});
},
/** 删除按钮操作 */
handleDelete
(
row
)
{
const
jobIds
=
row
.
jobId
||
this
.
ids
;
this
.
$confirm
(
'
是否确认删除定时任务编号为"
'
+
jobIds
+
'
"的数据项?
'
,
"
警告
"
,
{
confirmButtonText
:
"
确定
"
,
cancelButtonText
:
"
取消
"
,
type
:
"
warning
"
}).
then
(
function
()
{
return
delJob
(
jobIds
);
}).
then
(()
=>
{
this
.
getList
();
this
.
msgSuccess
(
"
删除成功
"
);
}).
catch
(
function
()
{});
},
/** 导出按钮操作 */
handleExport
()
{
const
queryParams
=
this
.
queryParams
;
this
.
$confirm
(
"
是否确认导出所有定时任务数据项?
"
,
"
警告
"
,
{
confirmButtonText
:
"
确定
"
,
cancelButtonText
:
"
取消
"
,
type
:
"
warning
"
}).
then
(
function
()
{
return
exportJob
(
queryParams
);
}).
then
(
response
=>
{
this
.
download
(
response
.
msg
);
}).
catch
(
function
()
{});
}
}
};
</
script
>
\ No newline at end of file
ruoyi-ui/src/views/monitor/job/log.vue
0 → 100644
View file @
2cc14e5f
<
template
>
<div
class=
"app-container"
>
<el-form
:model=
"queryParams"
ref=
"queryForm"
:inline=
"true"
label-width=
"68px"
>
<el-form-item
label=
"任务名称"
prop=
"jobName"
>
<el-input
v-model=
"queryParams.jobName"
placeholder=
"请输入任务名称"
clearable
size=
"small"
style=
"width: 240px"
@
keyup.enter.native=
"handleQuery"
/>
</el-form-item>
<el-form-item
label=
"任务组名"
prop=
"jobGroup"
>
<el-select
v-model=
"queryParams.jobGroup"
placeholder=
"请任务组名"
clearable
size=
"small"
style=
"width: 240px"
>
<el-option
v-for=
"dict in jobGroupOptions"
:key=
"dict.dictValue"
:label=
"dict.dictLabel"
:value=
"dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"执行状态"
prop=
"status"
>
<el-select
v-model=
"queryParams.status"
placeholder=
"请选择执行状态"
clearable
size=
"small"
style=
"width: 240px"
>
<el-option
v-for=
"dict in statusOptions"
:key=
"dict.dictValue"
:label=
"dict.dictLabel"
:value=
"dict.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item
label=
"执行时间"
>
<el-date-picker
v-model=
"dateRange"
size=
"small"
style=
"width: 240px"
value-format=
"yyyy-MM-dd"
type=
"daterange"
range-separator=
"-"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button
type=
"primary"
icon=
"el-icon-search"
size=
"mini"
@
click=
"handleQuery"
>
搜索
</el-button>
<el-button
icon=
"el-icon-refresh"
size=
"mini"
@
click=
"resetQuery"
>
重置
</el-button>
</el-form-item>
</el-form>
<el-row
:gutter=
"10"
class=
"mb8"
>
<el-col
:span=
"1.5"
>
<el-button
type=
"danger"
icon=
"el-icon-delete"
size=
"mini"
:disabled=
"multiple"
@
click=
"handleDelete"
v-hasPermi=
"['monitor:job:remove']"
>
删除
</el-button>
</el-col>
<el-col
:span=
"1.5"
>
<el-button
type=
"danger"
icon=
"el-icon-delete"
size=
"mini"
@
click=
"handleClean"
v-hasPermi=
"['monitor:job:remove']"
>
清空
</el-button>
</el-col>
<el-col
:span=
"1.5"
>
<el-button
type=
"warning"
icon=
"el-icon-download"
size=
"mini"
@
click=
"handleExport"
v-hasPermi=
"['monitor:jobLog:export']"
>
导出
</el-button>
</el-col>
</el-row>
<el-table
v-loading=
"loading"
:data=
"jobLogList"
@
selection-change=
"handleSelectionChange"
>
<el-table-column
type=
"selection"
width=
"55"
align=
"center"
/>
<el-table-column
label=
"日志编号"
width=
"80"
align=
"center"
prop=
"jobLogId"
/>
<el-table-column
label=
"任务名称"
align=
"center"
prop=
"jobName"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"任务组名"
align=
"center"
prop=
"jobGroup"
:formatter=
"jobGroupFormat"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"调用目标字符串"
align=
"center"
prop=
"invokeTarget"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"日志信息"
align=
"center"
prop=
"jobMessage"
:show-overflow-tooltip=
"true"
/>
<el-table-column
label=
"执行状态"
align=
"center"
prop=
"status"
:formatter=
"statusFormat"
/>
<el-table-column
label=
"执行时间"
align=
"center"
prop=
"createTime"
width=
"180"
>
<template
slot-scope=
"scope"
>
<span>
{{
parseTime
(
scope
.
row
.
createTime
)
}}
</span>
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
align=
"center"
class-name=
"small-padding fixed-width"
>
<
template
slot-scope=
"scope"
>
<el-button
size=
"mini"
type=
"text"
icon=
"el-icon-view"
@
click=
"handleView(scope.row)"
v-hasPermi=
"['monitor:job:query']"
>
详细
</el-button>
</
template
>
</el-table-column>
</el-table>
<pagination
v-show=
"total>0"
:total=
"total"
:page.sync=
"queryParams.pageNum"
:limit.sync=
"queryParams.pageSize"
@
pagination=
"getList"
/>
<!-- 调度日志详细 -->
<el-dialog
title=
"调度日志详细"
:visible.sync=
"open"
width=
"700px"
>
<el-form
ref=
"form"
:model=
"form"
label-width=
"100px"
size=
"mini"
>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
label=
"日志序号:"
>
{{ form.jobLogId }}
</el-form-item>
<el-form-item
label=
"任务名称:"
>
{{ form.jobName }}
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"任务分组:"
>
{{ form.jobGroup }}
</el-form-item>
<el-form-item
label=
"执行时间:"
>
{{ form.createTime }}
</el-form-item>
</el-col>
<el-col
:span=
"24"
>
<el-form-item
label=
"调用方法:"
>
{{ form.invokeTarget }}
</el-form-item>
</el-col>
<el-col
:span=
"24"
>
<el-form-item
label=
"日志信息:"
>
{{ form.jobMessage }}
</el-form-item>
</el-col>
<el-col
:span=
"24"
>
<el-form-item
label=
"执行状态:"
>
<div
v-if=
"form.status == 0"
>
正常
</div>
<div
v-else-if=
"form.status == 1"
>
失败
</div>
</el-form-item>
</el-col>
<el-col
:span=
"24"
>
<el-form-item
label=
"异常信息:"
v-if=
"form.status == 1"
>
{{ form.exceptionInfo }}
</el-form-item>
</el-col>
</el-row>
</el-form>
<div
slot=
"footer"
class=
"dialog-footer"
>
<el-button
@
click=
"open = false"
>
关 闭
</el-button>
</div>
</el-dialog>
</div>
</template>
<
script
>
import
{
listJobLog
,
delJobLog
,
exportJobLog
,
cleanJobLog
}
from
"
@/api/monitor/jobLog
"
;
export
default
{
name
:
"
JobLog
"
,
data
()
{
return
{
// 遮罩层
loading
:
true
,
// 选中数组
ids
:
[],
// 非多个禁用
multiple
:
true
,
// 总条数
total
:
0
,
// 调度日志表格数据
jobLogList
:
[],
// 是否显示弹出层
open
:
false
,
// 日期范围
dateRange
:
[],
// 表单参数
form
:
{},
// 执行状态字典
statusOptions
:
[],
// 任务组名字典
jobGroupOptions
:
[],
// 查询参数
queryParams
:
{
pageNum
:
1
,
pageSize
:
10
,
jobName
:
undefined
,
jobGroup
:
undefined
,
status
:
undefined
},
// 表单参数
form
:
{}
};
},
created
()
{
this
.
getList
();
this
.
getDicts
(
"
sys_job_status
"
).
then
(
response
=>
{
this
.
statusOptions
=
response
.
data
;
});
this
.
getDicts
(
"
sys_job_group
"
).
then
(
response
=>
{
this
.
jobGroupOptions
=
response
.
data
;
});
},
methods
:
{
/** 查询调度日志列表 */
getList
()
{
this
.
loading
=
true
;
listJobLog
(
this
.
addDateRange
(
this
.
queryParams
,
this
.
dateRange
)).
then
(
response
=>
{
this
.
jobLogList
=
response
.
rows
;
this
.
total
=
response
.
total
;
this
.
loading
=
false
;
}
);
},
// 执行状态字典翻译
statusFormat
(
row
,
column
)
{
return
this
.
selectDictLabel
(
this
.
statusOptions
,
row
.
status
);
},
// 任务组名字典翻译
jobGroupFormat
(
row
,
column
)
{
return
this
.
selectDictLabel
(
this
.
jobGroupOptions
,
row
.
jobGroup
);
},
/** 搜索按钮操作 */
handleQuery
()
{
this
.
queryParams
.
pageNum
=
1
;
this
.
getList
();
},
/** 重置按钮操作 */
resetQuery
()
{
this
.
dateRange
=
[];
this
.
resetForm
(
"
queryForm
"
);
this
.
handleQuery
();
},
// 多选框选中数据
handleSelectionChange
(
selection
)
{
this
.
ids
=
selection
.
map
(
item
=>
item
.
jobLogId
);
this
.
multiple
=
!
selection
.
length
;
},
/** 详细按钮操作 */
handleView
(
row
)
{
this
.
open
=
true
;
this
.
form
=
row
;
},
/** 删除按钮操作 */
handleDelete
(
row
)
{
const
jobLogIds
=
this
.
ids
;
this
.
$confirm
(
'
是否确认删除调度日志编号为"
'
+
jobLogIds
+
'
"的数据项?
'
,
"
警告
"
,
{
confirmButtonText
:
"
确定
"
,
cancelButtonText
:
"
取消
"
,
type
:
"
warning
"
}).
then
(
function
()
{
return
delJobLog
(
jobLogIds
);
}).
then
(()
=>
{
this
.
getList
();
this
.
msgSuccess
(
"
删除成功
"
);
}).
catch
(
function
()
{});
},
/** 清空按钮操作 */
handleClean
()
{
this
.
$confirm
(
"
是否确认清空所有调度日志数据项?
"
,
"
警告
"
,
{
confirmButtonText
:
"
确定
"
,
cancelButtonText
:
"
取消
"
,
type
:
"
warning
"
}).
then
(
function
()
{
return
cleanJobLog
();
}).
then
(()
=>
{
this
.
getList
();
this
.
msgSuccess
(
"
清空成功
"
);
}).
catch
(
function
()
{});
},
/** 导出按钮操作 */
handleExport
()
{
const
queryParams
=
this
.
queryParams
;
this
.
$confirm
(
"
是否确认导出所有调度日志数据项?
"
,
"
警告
"
,
{
confirmButtonText
:
"
确定
"
,
cancelButtonText
:
"
取消
"
,
type
:
"
warning
"
}).
then
(
function
()
{
return
exportJobLog
(
queryParams
);
}).
then
(
response
=>
{
this
.
download
(
response
.
msg
);
}).
catch
(
function
()
{});
}
}
};
</
script
>
\ No newline at end of file
ruoyi/pom.xml
View file @
2cc14e5f
...
...
@@ -5,7 +5,7 @@
<groupId>
com.ruoyi
</groupId>
<artifactId>
ruoyi
</artifactId>
<version>
2.
1
.0
</version>
<version>
2.
2
.0
</version>
<packaging>
jar
</packaging>
<name>
ruoyi
</name>
...
...
@@ -224,12 +224,25 @@
<artifactId>
poi-ooxml
</artifactId>
<version>
${poi.version}
</version>
</dependency>
<!--velocity代码生成使用模板 -->
<dependency>
<groupId>
org.apache.velocity
</groupId>
<artifactId>
velocity
</artifactId>
<version>
${velocity.version}
</version>
</dependency>
<!-- 定时任务 -->
<dependency>
<groupId>
org.quartz-scheduler
</groupId>
<artifactId>
quartz
</artifactId>
<exclusions>
<exclusion>
<groupId>
com.mchange
</groupId>
<artifactId>
c3p0
</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
...
...
ruoyi/sql/quartz.sql
0 → 100644
View file @
2cc14e5f
-- ----------------------------
-- 1、存储每一个已配置的 jobDetail 的详细信息
-- ----------------------------
drop
table
if
exists
QRTZ_JOB_DETAILS
;
create
table
QRTZ_JOB_DETAILS
(
sched_name
varchar
(
120
)
not
null
,
job_name
varchar
(
200
)
not
null
,
job_group
varchar
(
200
)
not
null
,
description
varchar
(
250
)
null
,
job_class_name
varchar
(
250
)
not
null
,
is_durable
varchar
(
1
)
not
null
,
is_nonconcurrent
varchar
(
1
)
not
null
,
is_update_data
varchar
(
1
)
not
null
,
requests_recovery
varchar
(
1
)
not
null
,
job_data
blob
null
,
primary
key
(
sched_name
,
job_name
,
job_group
)
)
engine
=
innodb
;
-- ----------------------------
-- 2、 存储已配置的 Trigger 的信息
-- ----------------------------
drop
table
if
exists
QRTZ_TRIGGERS
;
create
table
QRTZ_TRIGGERS
(
sched_name
varchar
(
120
)
not
null
,
trigger_name
varchar
(
200
)
not
null
,
trigger_group
varchar
(
200
)
not
null
,
job_name
varchar
(
200
)
not
null
,
job_group
varchar
(
200
)
not
null
,
description
varchar
(
250
)
null
,
next_fire_time
bigint
(
13
)
null
,
prev_fire_time
bigint
(
13
)
null
,
priority
integer
null
,
trigger_state
varchar
(
16
)
not
null
,
trigger_type
varchar
(
8
)
not
null
,
start_time
bigint
(
13
)
not
null
,
end_time
bigint
(
13
)
null
,
calendar_name
varchar
(
200
)
null
,
misfire_instr
smallint
(
2
)
null
,
job_data
blob
null
,
primary
key
(
sched_name
,
trigger_name
,
trigger_group
),
foreign
key
(
sched_name
,
job_name
,
job_group
)
references
QRTZ_JOB_DETAILS
(
sched_name
,
job_name
,
job_group
)
)
engine
=
innodb
;
-- ----------------------------
-- 3、 存储简单的 Trigger,包括重复次数,间隔,以及已触发的次数
-- ----------------------------
drop
table
if
exists
QRTZ_SIMPLE_TRIGGERS
;
create
table
QRTZ_SIMPLE_TRIGGERS
(
sched_name
varchar
(
120
)
not
null
,
trigger_name
varchar
(
200
)
not
null
,
trigger_group
varchar
(
200
)
not
null
,
repeat_count
bigint
(
7
)
not
null
,
repeat_interval
bigint
(
12
)
not
null
,
times_triggered
bigint
(
10
)
not
null
,
primary
key
(
sched_name
,
trigger_name
,
trigger_group
),
foreign
key
(
sched_name
,
trigger_name
,
trigger_group
)
references
QRTZ_TRIGGERS
(
sched_name
,
trigger_name
,
trigger_group
)
)
engine
=
innodb
;
-- ----------------------------
-- 4、 存储 Cron Trigger,包括 Cron 表达式和时区信息
-- ----------------------------
drop
table
if
exists
QRTZ_CRON_TRIGGERS
;
create
table
QRTZ_CRON_TRIGGERS
(
sched_name
varchar
(
120
)
not
null
,
trigger_name
varchar
(
200
)
not
null
,
trigger_group
varchar
(
200
)
not
null
,
cron_expression
varchar
(
200
)
not
null
,
time_zone_id
varchar
(
80
),
primary
key
(
sched_name
,
trigger_name
,
trigger_group
),
foreign
key
(
sched_name
,
trigger_name
,
trigger_group
)
references
QRTZ_TRIGGERS
(
sched_name
,
trigger_name
,
trigger_group
)
)
engine
=
innodb
;
-- ----------------------------
-- 5、 Trigger 作为 Blob 类型存储(用于 Quartz 用户用 JDBC 创建他们自己定制的 Trigger 类型,JobStore 并不知道如何存储实例的时候)
-- ----------------------------
drop
table
if
exists
QRTZ_BLOB_TRIGGERS
;
create
table
QRTZ_BLOB_TRIGGERS
(
sched_name
varchar
(
120
)
not
null
,
trigger_name
varchar
(
200
)
not
null
,
trigger_group
varchar
(
200
)
not
null
,
blob_data
blob
null
,
primary
key
(
sched_name
,
trigger_name
,
trigger_group
),
foreign
key
(
sched_name
,
trigger_name
,
trigger_group
)
references
QRTZ_TRIGGERS
(
sched_name
,
trigger_name
,
trigger_group
)
)
engine
=
innodb
;
-- ----------------------------
-- 6、 以 Blob 类型存储存放日历信息, quartz可配置一个日历来指定一个时间范围
-- ----------------------------
drop
table
if
exists
QRTZ_CALENDARS
;
create
table
QRTZ_CALENDARS
(
sched_name
varchar
(
120
)
not
null
,
calendar_name
varchar
(
200
)
not
null
,
calendar
blob
not
null
,
primary
key
(
sched_name
,
calendar_name
)
)
engine
=
innodb
;
-- ----------------------------
-- 7、 存储已暂停的 Trigger 组的信息
-- ----------------------------
drop
table
if
exists
QRTZ_PAUSED_TRIGGER_GRPS
;
create
table
QRTZ_PAUSED_TRIGGER_GRPS
(
sched_name
varchar
(
120
)
not
null
,
trigger_group
varchar
(
200
)
not
null
,
primary
key
(
sched_name
,
trigger_group
)
)
engine
=
innodb
;
-- ----------------------------
-- 8、 存储与已触发的 Trigger 相关的状态信息,以及相联 Job 的执行信息
-- ----------------------------
drop
table
if
exists
QRTZ_FIRED_TRIGGERS
;
create
table
QRTZ_FIRED_TRIGGERS
(
sched_name
varchar
(
120
)
not
null
,
entry_id
varchar
(
95
)
not
null
,
trigger_name
varchar
(
200
)
not
null
,
trigger_group
varchar
(
200
)
not
null
,
instance_name
varchar
(
200
)
not
null
,
fired_time
bigint
(
13
)
not
null
,
sched_time
bigint
(
13
)
not
null
,
priority
integer
not
null
,
state
varchar
(
16
)
not
null
,
job_name
varchar
(
200
)
null
,
job_group
varchar
(
200
)
null
,
is_nonconcurrent
varchar
(
1
)
null
,
requests_recovery
varchar
(
1
)
null
,
primary
key
(
sched_name
,
entry_id
)
)
engine
=
innodb
;
-- ----------------------------
-- 9、 存储少量的有关 Scheduler 的状态信息,假如是用于集群中,可以看到其他的 Scheduler 实例
-- ----------------------------
drop
table
if
exists
QRTZ_SCHEDULER_STATE
;
create
table
QRTZ_SCHEDULER_STATE
(
sched_name
varchar
(
120
)
not
null
,
instance_name
varchar
(
200
)
not
null
,
last_checkin_time
bigint
(
13
)
not
null
,
checkin_interval
bigint
(
13
)
not
null
,
primary
key
(
sched_name
,
instance_name
)
)
engine
=
innodb
;
-- ----------------------------
-- 10、 存储程序的悲观锁的信息(假如使用了悲观锁)
-- ----------------------------
drop
table
if
exists
QRTZ_LOCKS
;
create
table
QRTZ_LOCKS
(
sched_name
varchar
(
120
)
not
null
,
lock_name
varchar
(
40
)
not
null
,
primary
key
(
sched_name
,
lock_name
)
)
engine
=
innodb
;
drop
table
if
exists
QRTZ_SIMPROP_TRIGGERS
;
create
table
QRTZ_SIMPROP_TRIGGERS
(
sched_name
varchar
(
120
)
not
null
,
trigger_name
varchar
(
200
)
not
null
,
trigger_group
varchar
(
200
)
not
null
,
str_prop_1
varchar
(
512
)
null
,
str_prop_2
varchar
(
512
)
null
,
str_prop_3
varchar
(
512
)
null
,
int_prop_1
int
null
,
int_prop_2
int
null
,
long_prop_1
bigint
null
,
long_prop_2
bigint
null
,
dec_prop_1
numeric
(
13
,
4
)
null
,
dec_prop_2
numeric
(
13
,
4
)
null
,
bool_prop_1
varchar
(
1
)
null
,
bool_prop_2
varchar
(
1
)
null
,
primary
key
(
sched_name
,
trigger_name
,
trigger_group
),
foreign
key
(
sched_name
,
trigger_name
,
trigger_group
)
references
QRTZ_TRIGGERS
(
sched_name
,
trigger_name
,
trigger_group
)
)
engine
=
innodb
;
commit
;
\ No newline at end of file
ruoyi/src/main/java/com/ruoyi/RuoYiApplication.java
View file @
2cc14e5f
...
...
@@ -14,7 +14,7 @@ public class RuoYiApplication
{
public
static
void
main
(
String
[]
args
)
{
//
System.setProperty("spring.devtools.restart.enabled", "false");
System
.
setProperty
(
"spring.devtools.restart.enabled"
,
"false"
);
SpringApplication
.
run
(
RuoYiApplication
.
class
,
args
);
System
.
out
.
println
(
"(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n"
+
" .-------. ____ __ \n"
+
...
...
ruoyi/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
0 → 100644
View file @
2cc14e5f
package
com.ruoyi.common.constant
;
/**
* 任务调度通用常量
*
* @author ruoyi
*/
public
interface
ScheduleConstants
{
public
static
final
String
TASK_CLASS_NAME
=
"TASK_CLASS_NAME"
;
/** 执行目标key */
public
static
final
String
TASK_PROPERTIES
=
"TASK_PROPERTIES"
;
/** 默认 */
public
static
final
String
MISFIRE_DEFAULT
=
"0"
;
/** 立即触发执行 */
public
static
final
String
MISFIRE_IGNORE_MISFIRES
=
"1"
;
/** 触发一次执行 */
public
static
final
String
MISFIRE_FIRE_AND_PROCEED
=
"2"
;
/** 不触发立即执行 */
public
static
final
String
MISFIRE_DO_NOTHING
=
"3"
;
public
enum
Status
{
/**
* 正常
*/
NORMAL
(
"0"
),
/**
* 暂停
*/
PAUSE
(
"1"
);
private
String
value
;
private
Status
(
String
value
)
{
this
.
value
=
value
;
}
public
String
getValue
()
{
return
value
;
}
}
}
ruoyi/src/main/java/com/ruoyi/common/exception/job/TaskException.java
0 → 100644
View file @
2cc14e5f
package
com.ruoyi.common.exception.job
;
/**
* 计划策略异常
*
* @author ruoyi
*/
public
class
TaskException
extends
Exception
{
private
static
final
long
serialVersionUID
=
1L
;
private
Code
code
;
public
TaskException
(
String
msg
,
Code
code
)
{
this
(
msg
,
code
,
null
);
}
public
TaskException
(
String
msg
,
Code
code
,
Exception
nestedEx
)
{
super
(
msg
,
nestedEx
);
this
.
code
=
code
;
}
public
Code
getCode
()
{
return
code
;
}
public
enum
Code
{
TASK_EXISTS
,
NO_TASK_EXISTS
,
TASK_ALREADY_STARTED
,
UNKNOWN
,
CONFIG_ERROR
,
TASK_NODE_NOT_AVAILABLE
}
}
\ No newline at end of file
ruoyi/src/main/java/com/ruoyi/common/utils/ExceptionUtil.java
0 → 100644
View file @
2cc14e5f
package
com.ruoyi.common.utils
;
import
java.io.PrintWriter
;
import
java.io.StringWriter
;
import
org.apache.commons.lang3.exception.ExceptionUtils
;
/**
* 错误信息处理类。
*
* @author ruoyi
*/
public
class
ExceptionUtil
{
/**
* 获取exception的详细错误信息。
*/
public
static
String
getExceptionMessage
(
Throwable
e
)
{
StringWriter
sw
=
new
StringWriter
();
e
.
printStackTrace
(
new
PrintWriter
(
sw
,
true
));
String
str
=
sw
.
toString
();
return
str
;
}
public
static
String
getRootErrorMseeage
(
Exception
e
)
{
Throwable
root
=
ExceptionUtils
.
getRootCause
(
e
);
root
=
(
root
==
null
?
e
:
root
);
if
(
root
==
null
)
{
return
""
;
}
String
msg
=
root
.
getMessage
();
if
(
msg
==
null
)
{
return
"null"
;
}
return
StringUtils
.
defaultString
(
msg
);
}
}
ruoyi/src/main/java/com/ruoyi/common/utils/bean/BeanUtils.java
0 → 100644
View file @
2cc14e5f
package
com.ruoyi.common.utils.bean
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
/**
* Bean 工具类
*
* @author ruoyi
*/
public
class
BeanUtils
extends
org
.
springframework
.
beans
.
BeanUtils
{
/** Bean方法名中属性名开始的下标 */
private
static
final
int
BEAN_METHOD_PROP_INDEX
=
3
;
/** * 匹配getter方法的正则表达式 */
private
static
final
Pattern
GET_PATTERN
=
Pattern
.
compile
(
"get(\\p{javaUpperCase}\\w*)"
);
/** * 匹配setter方法的正则表达式 */
private
static
final
Pattern
SET_PATTERN
=
Pattern
.
compile
(
"set(\\p{javaUpperCase}\\w*)"
);
/**
* Bean属性复制工具方法。
*
* @param dest 目标对象
* @param src 源对象
*/
public
static
void
copyBeanProp
(
Object
dest
,
Object
src
)
{
try
{
copyProperties
(
src
,
dest
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
/**
* 获取对象的setter方法。
*
* @param obj 对象
* @return 对象的setter方法列表
*/
public
static
List
<
Method
>
getSetterMethods
(
Object
obj
)
{
// setter方法列表
List
<
Method
>
setterMethods
=
new
ArrayList
<
Method
>();
// 获取所有方法
Method
[]
methods
=
obj
.
getClass
().
getMethods
();
// 查找setter方法
for
(
Method
method
:
methods
)
{
Matcher
m
=
SET_PATTERN
.
matcher
(
method
.
getName
());
if
(
m
.
matches
()
&&
(
method
.
getParameterTypes
().
length
==
1
))
{
setterMethods
.
add
(
method
);
}
}
// 返回setter方法列表
return
setterMethods
;
}
/**
* 获取对象的getter方法。
*
* @param obj 对象
* @return 对象的getter方法列表
*/
public
static
List
<
Method
>
getGetterMethods
(
Object
obj
)
{
// getter方法列表
List
<
Method
>
getterMethods
=
new
ArrayList
<
Method
>();
// 获取所有方法
Method
[]
methods
=
obj
.
getClass
().
getMethods
();
// 查找getter方法
for
(
Method
method
:
methods
)
{
Matcher
m
=
GET_PATTERN
.
matcher
(
method
.
getName
());
if
(
m
.
matches
()
&&
(
method
.
getParameterTypes
().
length
==
0
))
{
getterMethods
.
add
(
method
);
}
}
// 返回getter方法列表
return
getterMethods
;
}
/**
* 检查Bean方法名中的属性名是否相等。<br>
* 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。
*
* @param m1 方法名1
* @param m2 方法名2
* @return 属性名一样返回true,否则返回false
*/
public
static
boolean
isMethodPropEquals
(
String
m1
,
String
m2
)
{
return
m1
.
substring
(
BEAN_METHOD_PROP_INDEX
).
equals
(
m2
.
substring
(
BEAN_METHOD_PROP_INDEX
));
}
}
ruoyi/src/main/java/com/ruoyi/common/utils/http/HttpHelper.java
View file @
2cc14e5f
...
...
@@ -21,7 +21,6 @@ public class HttpHelper
public
static
String
getBodyString
(
ServletRequest
request
)
{
StringBuilder
sb
=
new
StringBuilder
();
BufferedReader
reader
=
null
;
try
(
InputStream
inputStream
=
request
.
getInputStream
())
...
...
ruoyi/src/main/java/com/ruoyi/common/utils/job/AbstractQuartzJob.java
0 → 100644
View file @
2cc14e5f
package
com.ruoyi.common.utils.job
;
import
java.util.Date
;
import
org.quartz.Job
;
import
org.quartz.JobExecutionContext
;
import
org.quartz.JobExecutionException
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
com.ruoyi.common.constant.Constants
;
import
com.ruoyi.common.constant.ScheduleConstants
;
import
com.ruoyi.common.utils.ExceptionUtil
;
import
com.ruoyi.common.utils.StringUtils
;
import
com.ruoyi.common.utils.bean.BeanUtils
;
import
com.ruoyi.common.utils.spring.SpringUtils
;
import
com.ruoyi.project.monitor.domain.SysJob
;
import
com.ruoyi.project.monitor.domain.SysJobLog
;
import
com.ruoyi.project.monitor.service.ISysJobLogService
;
/**
* 抽象quartz调用
*
* @author ruoyi
*/
public
abstract
class
AbstractQuartzJob
implements
Job
{
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
AbstractQuartzJob
.
class
);
/**
* 线程本地变量
*/
private
static
ThreadLocal
<
Date
>
threadLocal
=
new
ThreadLocal
<>();
@Override
public
void
execute
(
JobExecutionContext
context
)
throws
JobExecutionException
{
SysJob
sysJob
=
new
SysJob
();
BeanUtils
.
copyBeanProp
(
sysJob
,
context
.
getMergedJobDataMap
().
get
(
ScheduleConstants
.
TASK_PROPERTIES
));
try
{
before
(
context
,
sysJob
);
if
(
sysJob
!=
null
)
{
doExecute
(
context
,
sysJob
);
}
after
(
context
,
sysJob
,
null
);
}
catch
(
Exception
e
)
{
log
.
error
(
"任务执行异常 - :"
,
e
);
after
(
context
,
sysJob
,
e
);
}
}
/**
* 执行前
*
* @param context 工作执行上下文对象
* @param sysJob 系统计划任务
*/
protected
void
before
(
JobExecutionContext
context
,
SysJob
sysJob
)
{
threadLocal
.
set
(
new
Date
());
}
/**
* 执行后
*
* @param context 工作执行上下文对象
* @param sysScheduleJob 系统计划任务
*/
protected
void
after
(
JobExecutionContext
context
,
SysJob
sysJob
,
Exception
e
)
{
Date
startTime
=
threadLocal
.
get
();
threadLocal
.
remove
();
final
SysJobLog
sysJobLog
=
new
SysJobLog
();
sysJobLog
.
setJobName
(
sysJob
.
getJobName
());
sysJobLog
.
setJobGroup
(
sysJob
.
getJobGroup
());
sysJobLog
.
setInvokeTarget
(
sysJob
.
getInvokeTarget
());
sysJobLog
.
setStartTime
(
startTime
);
sysJobLog
.
setStopTime
(
new
Date
());
long
runMs
=
sysJobLog
.
getStopTime
().
getTime
()
-
sysJobLog
.
getStartTime
().
getTime
();
sysJobLog
.
setJobMessage
(
sysJobLog
.
getJobName
()
+
" 总共耗时:"
+
runMs
+
"毫秒"
);
if
(
e
!=
null
)
{
sysJobLog
.
setStatus
(
Constants
.
FAIL
);
String
errorMsg
=
StringUtils
.
substring
(
ExceptionUtil
.
getExceptionMessage
(
e
),
0
,
2000
);
sysJobLog
.
setExceptionInfo
(
errorMsg
);
}
else
{
sysJobLog
.
setStatus
(
Constants
.
SUCCESS
);
}
// 写入数据库当中
SpringUtils
.
getBean
(
ISysJobLogService
.
class
).
addJobLog
(
sysJobLog
);
}
/**
* 执行方法,由子类重载
*
* @param context 工作执行上下文对象
* @param sysJob 系统计划任务
* @throws Exception 执行过程中的异常
*/
protected
abstract
void
doExecute
(
JobExecutionContext
context
,
SysJob
sysJob
)
throws
Exception
;
}
ruoyi/src/main/java/com/ruoyi/common/utils/job/CronUtils.java
0 → 100644
View file @
2cc14e5f
package
com.ruoyi.common.utils.job
;
import
java.text.ParseException
;
import
java.util.Date
;
import
org.quartz.CronExpression
;
/**
* cron表达式工具类
*
* @author ruoyi
*
*/
public
class
CronUtils
{
/**
* 返回一个布尔值代表一个给定的Cron表达式的有效性
*
* @param cronExpression Cron表达式
* @return boolean 表达式是否有效
*/
public
static
boolean
isValid
(
String
cronExpression
)
{
return
CronExpression
.
isValidExpression
(
cronExpression
);
}
/**
* 返回一个字符串值,表示该消息无效Cron表达式给出有效性
*
* @param cronExpression Cron表达式
* @return String 无效时返回表达式错误描述,如果有效返回null
*/
public
static
String
getInvalidMessage
(
String
cronExpression
)
{
try
{
new
CronExpression
(
cronExpression
);
return
null
;
}
catch
(
ParseException
pe
)
{
return
pe
.
getMessage
();
}
}
/**
* 返回下一个执行时间根据给定的Cron表达式
*
* @param cronExpression Cron表达式
* @return Date 下次Cron表达式执行时间
*/
public
static
Date
getNextExecution
(
String
cronExpression
)
{
try
{
CronExpression
cron
=
new
CronExpression
(
cronExpression
);
return
cron
.
getNextValidTimeAfter
(
new
Date
(
System
.
currentTimeMillis
()));
}
catch
(
ParseException
e
)
{
throw
new
IllegalArgumentException
(
e
.
getMessage
());
}
}
}
ruoyi/src/main/java/com/ruoyi/common/utils/job/JobInvokeUtil.java
0 → 100644
View file @
2cc14e5f
package
com.ruoyi.common.utils.job
;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.Method
;
import
java.util.LinkedList
;
import
java.util.List
;
import
com.ruoyi.common.utils.StringUtils
;
import
com.ruoyi.common.utils.spring.SpringUtils
;
import
com.ruoyi.project.monitor.domain.SysJob
;
/**
* 任务执行工具
*
* @author ruoyi
*/
public
class
JobInvokeUtil
{
/**
* 执行方法
*
* @param sysJob 系统任务
*/
public
static
void
invokeMethod
(
SysJob
sysJob
)
throws
Exception
{
String
invokeTarget
=
sysJob
.
getInvokeTarget
();
String
beanName
=
getBeanName
(
invokeTarget
);
String
methodName
=
getMethodName
(
invokeTarget
);
List
<
Object
[]>
methodParams
=
getMethodParams
(
invokeTarget
);
if
(!
isValidClassName
(
beanName
))
{
Object
bean
=
SpringUtils
.
getBean
(
beanName
);
invokeMethod
(
bean
,
methodName
,
methodParams
);
}
else
{
Object
bean
=
Class
.
forName
(
beanName
).
newInstance
();
invokeMethod
(
bean
,
methodName
,
methodParams
);
}
}
/**
* 调用任务方法
*
* @param bean 目标对象
* @param methodName 方法名称
* @param methodParams 方法参数
*/
private
static
void
invokeMethod
(
Object
bean
,
String
methodName
,
List
<
Object
[]>
methodParams
)
throws
NoSuchMethodException
,
SecurityException
,
IllegalAccessException
,
IllegalArgumentException
,
InvocationTargetException
{
if
(
StringUtils
.
isNotNull
(
methodParams
)
&&
methodParams
.
size
()
>
0
)
{
Method
method
=
bean
.
getClass
().
getDeclaredMethod
(
methodName
,
getMethodParamsType
(
methodParams
));
method
.
invoke
(
bean
,
getMethodParamsValue
(
methodParams
));
}
else
{
Method
method
=
bean
.
getClass
().
getDeclaredMethod
(
methodName
);
method
.
invoke
(
bean
);
}
}
/**
* 校验是否为为class包名
*
* @param str 名称
* @return true是 false否
*/
public
static
boolean
isValidClassName
(
String
invokeTarget
)
{
return
StringUtils
.
countMatches
(
invokeTarget
,
"."
)
>
1
;
}
/**
* 获取bean名称
*
* @param invokeTarget 目标字符串
* @return bean名称
*/
public
static
String
getBeanName
(
String
invokeTarget
)
{
String
beanName
=
StringUtils
.
substringBefore
(
invokeTarget
,
"("
);
return
StringUtils
.
substringBeforeLast
(
beanName
,
"."
);
}
/**
* 获取bean方法
*
* @param invokeTarget 目标字符串
* @return method方法
*/
public
static
String
getMethodName
(
String
invokeTarget
)
{
String
methodName
=
StringUtils
.
substringBefore
(
invokeTarget
,
"("
);
return
StringUtils
.
substringAfterLast
(
methodName
,
"."
);
}
/**
* 获取method方法参数相关列表
*
* @param invokeTarget 目标字符串
* @return method方法相关参数列表
*/
public
static
List
<
Object
[]>
getMethodParams
(
String
invokeTarget
)
{
String
methodStr
=
StringUtils
.
substringBetween
(
invokeTarget
,
"("
,
")"
);
if
(
StringUtils
.
isEmpty
(
methodStr
))
{
return
null
;
}
String
[]
methodParams
=
methodStr
.
split
(
","
);
List
<
Object
[]>
classs
=
new
LinkedList
<>();
for
(
int
i
=
0
;
i
<
methodParams
.
length
;
i
++)
{
String
str
=
StringUtils
.
trimToEmpty
(
methodParams
[
i
]);
// String字符串类型,包含'
if
(
StringUtils
.
contains
(
str
,
"'"
))
{
classs
.
add
(
new
Object
[]
{
StringUtils
.
replace
(
str
,
"'"
,
""
),
String
.
class
});
}
// boolean布尔类型,等于true或者false
else
if
(
StringUtils
.
equals
(
str
,
"true"
)
||
StringUtils
.
equalsIgnoreCase
(
str
,
"false"
))
{
classs
.
add
(
new
Object
[]
{
Boolean
.
valueOf
(
str
),
Boolean
.
class
});
}
// long长整形,包含L
else
if
(
StringUtils
.
containsIgnoreCase
(
str
,
"L"
))
{
classs
.
add
(
new
Object
[]
{
Long
.
valueOf
(
StringUtils
.
replaceIgnoreCase
(
str
,
"L"
,
""
)),
Long
.
class
});
}
// double浮点类型,包含D
else
if
(
StringUtils
.
containsIgnoreCase
(
str
,
"D"
))
{
classs
.
add
(
new
Object
[]
{
Double
.
valueOf
(
StringUtils
.
replaceIgnoreCase
(
str
,
"D"
,
""
)),
Double
.
class
});
}
// 其他类型归类为整形
else
{
classs
.
add
(
new
Object
[]
{
Integer
.
valueOf
(
str
),
Integer
.
class
});
}
}
return
classs
;
}
/**
* 获取参数类型
*
* @param methodParams 参数相关列表
* @return 参数类型列表
*/
public
static
Class
<?>[]
getMethodParamsType
(
List
<
Object
[]>
methodParams
)
{
Class
<?>[]
classs
=
new
Class
<?>[
methodParams
.
size
()];
int
index
=
0
;
for
(
Object
[]
os
:
methodParams
)
{
classs
[
index
]
=
(
Class
<?>)
os
[
1
];
index
++;
}
return
classs
;
}
/**
* 获取参数值
*
* @param methodParams 参数相关列表
* @return 参数值列表
*/
public
static
Object
[]
getMethodParamsValue
(
List
<
Object
[]>
methodParams
)
{
Object
[]
classs
=
new
Object
[
methodParams
.
size
()];
int
index
=
0
;
for
(
Object
[]
os
:
methodParams
)
{
classs
[
index
]
=
(
Object
)
os
[
0
];
index
++;
}
return
classs
;
}
}
Prev
1
2
3
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment