feat: 添加优化后的运维管理
This commit is contained in:
parent
e4977dced5
commit
80cbd417f5
13
README.md
13
README.md
@ -17,11 +17,10 @@
|
||||
|
||||
#### VPS推荐
|
||||
<a href="https://bwh81.net/aff.php?aff=70876" target="_blank">
|
||||
<img src="https://eladmin.vip/images/banner/side.jpeg" style="width: 435px;border-radius: 2px;">
|
||||
<img src="https://eladmin.vip/images/banner/side.jpeg" style="width: 435px;border-radius: 2px;" alt="帮瓦工">
|
||||
</a>
|
||||
|
||||
使用优惠码: `BWHNCXNVXV`,可获得 6.81% 的折扣, [查看介绍](https://eladmin.vip/pages/040101/)
|
||||
|
||||
#### 主要特性
|
||||
- 使用最新技术栈,社区资源丰富。
|
||||
- 高效率开发,代码生成器可一键生成前后端代码
|
||||
@ -32,8 +31,9 @@
|
||||
- 对一些常用地前端组件封装:表格数据请求、数据字典等
|
||||
- 前后端统一异常拦截处理,统一输出异常,避免繁琐的判断
|
||||
- 支持在线用户管理与服务器性能监控,支持限制单用户登录
|
||||
- 支持运维管理,可方便地对远程服务器的应用进行部署与管理
|
||||
|
||||
#### 系统功能
|
||||
#### 系统功能
|
||||
- 用户管理:提供用户的相关配置,新增用户后,默认密码为123456
|
||||
- 角色管理:对权限与菜单进行分配,可根据部门设置角色的数据权限
|
||||
- 菜单管理:已实现菜单动态路由,后端可配置化,支持多级菜单
|
||||
@ -48,6 +48,7 @@
|
||||
- 七牛云存储:可同步七牛云存储的数据到系统,无需登录七牛云直接操作云数据
|
||||
- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试
|
||||
- 服务监控:监控服务器的负载情况
|
||||
- 运维管理:一键部署你的应用
|
||||
|
||||
#### 项目结构
|
||||
项目采用按功能分模块的开发方式,结构如下
|
||||
@ -62,7 +63,7 @@
|
||||
|
||||
- `eladmin-generator` 为系统的代码生成模块,支持生成前后端CRUD代码
|
||||
|
||||
#### 后端详细结构
|
||||
#### 详细结构
|
||||
|
||||
```
|
||||
- eladmin-common 公共模块
|
||||
@ -86,7 +87,7 @@
|
||||
- FileUtil 文件工具类
|
||||
- eladmin-system 系统核心模块(系统启动入口)
|
||||
- sysrunner 程序启动后处理数据
|
||||
- modules 系统相关模块(登录授权、系统监控、定时任务、系统模块)
|
||||
- modules 系统相关模块(登录授权、系统监控、定时任务、系统模块、运维模块)
|
||||
- eladmin-logging 系统日志模块
|
||||
- eladmin-tools 系统第三方工具模块
|
||||
- email 邮件工具
|
||||
@ -102,6 +103,8 @@
|
||||
|
||||
- 感谢 [Moxun](https://github.com/moxun1639) 大佬提供的前端 Curd 通用组件
|
||||
|
||||
- 感谢 [zhy6599](https://gitee.com/zhy6599) 大佬提供的后端运维管理相关功能
|
||||
|
||||
- 感谢 [j.yao.SUSE](https://github.com/everhopingandwaiting) 大佬提供的匿名接口与Redis限流等功能
|
||||
|
||||
#### 项目捐赠
|
||||
|
27
eladmin-web/src/api/maint/app.js
Normal file
27
eladmin-web/src/api/maint/app.js
Normal file
@ -0,0 +1,27 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/app',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(ids) {
|
||||
return request({
|
||||
url: 'api/app',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/app',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export default { add, edit, del }
|
17
eladmin-web/src/api/maint/connect.js
Normal file
17
eladmin-web/src/api/maint/connect.js
Normal file
@ -0,0 +1,17 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function testDbConnect(data) {
|
||||
return request({
|
||||
url: 'api/database/testConnect',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function testServerConnect(data) {
|
||||
return request({
|
||||
url: 'api/serverDeploy/testConnect',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
35
eladmin-web/src/api/maint/database.js
Normal file
35
eladmin-web/src/api/maint/database.js
Normal file
@ -0,0 +1,35 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/database',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(ids) {
|
||||
return request({
|
||||
url: 'api/database',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/database',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function testDbConnection(data) {
|
||||
return request({
|
||||
url: 'api/database/testConnect',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export default { add, edit, del, testDbConnection }
|
77
eladmin-web/src/api/maint/deploy.js
Normal file
77
eladmin-web/src/api/maint/deploy.js
Normal file
@ -0,0 +1,77 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/deploy',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(ids) {
|
||||
return request({
|
||||
url: 'api/deploy',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/deploy',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getApps() {
|
||||
return request({
|
||||
url: 'api/app',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getServers() {
|
||||
return request({
|
||||
url: 'api/serverDeploy',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动服务
|
||||
* @param data 选中行
|
||||
*/
|
||||
export function startServer(data) {
|
||||
return request({
|
||||
url: 'api/deploy/startServer',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止服务
|
||||
* @param data 选中行
|
||||
*/
|
||||
export function stopServer(data) {
|
||||
return request({
|
||||
url: 'api/deploy/stopServer',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止服务
|
||||
* @param data 选中行
|
||||
*/
|
||||
export function serverStatus(data) {
|
||||
return request({
|
||||
url: 'api/deploy/serverStatus',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export default { add, edit, del, stopServer, serverStatus, startServer, getServers, getApps }
|
21
eladmin-web/src/api/maint/deployHistory.js
Normal file
21
eladmin-web/src/api/maint/deployHistory.js
Normal file
@ -0,0 +1,21 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function del(ids) {
|
||||
return request({
|
||||
url: 'api/deployHistory',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 版本回退
|
||||
* @param data 选中行
|
||||
*/
|
||||
export function reducte(data) {
|
||||
return request({
|
||||
url: 'api/deploy/serverReduction',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
27
eladmin-web/src/api/maint/serverDeploy.js
Normal file
27
eladmin-web/src/api/maint/serverDeploy.js
Normal file
@ -0,0 +1,27 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/serverDeploy',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(ids) {
|
||||
return request({
|
||||
url: 'api/serverDeploy',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/serverDeploy',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export default { add, edit, del }
|
144
eladmin-web/src/views/maint/app/index.vue
Normal file
144
eladmin-web/src/views/maint/app/index.vue
Normal file
@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!--工具栏-->
|
||||
<div class="head-container">
|
||||
<div v-if="crud.props.searchToggle">
|
||||
<!-- 搜索 -->
|
||||
<el-input v-model="query.name" clearable placeholder="输入名称搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" />
|
||||
<date-range-picker v-model="query.createTime" class="date-item" />
|
||||
<rrOperation />
|
||||
</div>
|
||||
<crudOperation :permission="permission">
|
||||
<el-button
|
||||
slot="left"
|
||||
v-permission="['admin','app:add']"
|
||||
:disabled="!currentRow"
|
||||
class="filter-item"
|
||||
size="mini"
|
||||
type="primary"
|
||||
icon="el-icon-plus"
|
||||
@click="copy"
|
||||
>复制</el-button>
|
||||
</crudOperation>
|
||||
</div>
|
||||
<!--表单组件-->
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="800px">
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px">
|
||||
<el-form-item label="应用名称" prop="name">
|
||||
<el-input v-model="form.name" style="width: 670px" placeholder="部署后的文件或者目录名称,用于备份" />
|
||||
</el-form-item>
|
||||
<el-form-item label="应用端口" prop="port">
|
||||
<el-input-number v-model.number="form.port" placeholder="例如:8080" />
|
||||
</el-form-item>
|
||||
<el-form-item label="上传目录" prop="uploadPath">
|
||||
<el-input v-model="form.uploadPath" style="width: 670px" placeholder="例如: /opt/upload" />
|
||||
</el-form-item>
|
||||
<el-form-item label="部署目录" prop="deployPath">
|
||||
<el-input v-model="form.deployPath" style="width: 670px" placeholder="例如: /opt/app" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备份目录" prop="backupPath">
|
||||
<el-input v-model="form.backupPath" style="width: 670px" placeholder="例如: /opt/backup" />
|
||||
</el-form-item>
|
||||
<el-form-item label="部署脚本" prop="deployScript">
|
||||
<el-input v-model="form.deployScript" :rows="3" type="textarea" autosize style="width: 670px" placeholder="" />
|
||||
</el-form-item>
|
||||
<el-form-item label="启动脚本" prop="startScript">
|
||||
<el-input v-model="form.startScript" :rows="3" type="textarea" autosize style="width: 670px" placeholder="" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button>
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--表格渲染-->
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row style="width: 100%" @selection-change="crud.selectionChangeHandler" @current-change="handleCurrentChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="name" label="应用名称" />
|
||||
<el-table-column prop="port" label="端口号" />
|
||||
<el-table-column prop="uploadPath" label="上传目录" />
|
||||
<el-table-column prop="deployPath" label="部署目录" />
|
||||
<el-table-column prop="backupPath" label="备份目录" />
|
||||
<el-table-column prop="createTime" label="创建日期" />
|
||||
<el-table-column v-if="checkPer(['admin','app:edit','app:del'])" label="操作" width="150px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<udOperation
|
||||
:data="scope.row"
|
||||
:permission="permission"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--分页组件-->
|
||||
<pagination />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import crudApp from '@/api/maint/app'
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud'
|
||||
import rrOperation from '@crud/RR.operation'
|
||||
import crudOperation from '@crud/CRUD.operation'
|
||||
import udOperation from '@crud/UD.operation'
|
||||
import pagination from '@crud/Pagination'
|
||||
import DateRangePicker from '@/components/DateRangePicker'
|
||||
|
||||
const defaultForm = { id: null, name: null, port: 8080, uploadPath: '/opt/upload', deployPath: '/opt/app', backupPath: '/opt/backup', startScript: null, deployScript: null }
|
||||
export default {
|
||||
name: 'App',
|
||||
components: { pagination, crudOperation, rrOperation, udOperation, DateRangePicker },
|
||||
cruds() {
|
||||
return CRUD({ title: '应用', url: 'api/app', crudMethod: { ...crudApp }})
|
||||
},
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()],
|
||||
data() {
|
||||
return {
|
||||
currentRow: null,
|
||||
permission: {
|
||||
add: ['admin', 'app:add'],
|
||||
edit: ['admin', 'app:edit'],
|
||||
del: ['admin', 'app:del']
|
||||
},
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '请输入应用名称', trigger: 'blur' }
|
||||
],
|
||||
port: [
|
||||
{ required: true, message: '请输入应用端口', trigger: 'blur', type: 'number' }
|
||||
],
|
||||
uploadPath: [
|
||||
{ required: true, message: '请输入上传目录', trigger: 'blur' }
|
||||
],
|
||||
deployPath: [
|
||||
{ required: true, message: '请输入部署目录', trigger: 'blur' }
|
||||
],
|
||||
backupPath: [
|
||||
{ required: true, message: '请输入备份目录', trigger: 'blur' }
|
||||
],
|
||||
startScript: [
|
||||
{ required: true, message: '请输入启动脚本', trigger: 'blur' }
|
||||
],
|
||||
deployScript: [
|
||||
{ required: true, message: '请输入部署脚本', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
copy() {
|
||||
for (const key in this.currentRow) {
|
||||
this.form[key] = this.currentRow[key]
|
||||
}
|
||||
this.form.id = null
|
||||
this.form.createTime = null
|
||||
this.crud.toAdd()
|
||||
},
|
||||
handleCurrentChange(row) {
|
||||
this.currentRow = JSON.parse(JSON.stringify(row))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
86
eladmin-web/src/views/maint/database/execute.vue
Normal file
86
eladmin-web/src/views/maint/database/execute.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="执行脚本" width="400px">
|
||||
<el-form ref="form" :rules="rules" size="small">
|
||||
<el-upload
|
||||
:action="databaseUploadApi"
|
||||
:data="databaseInfo"
|
||||
:headers="headers"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
class="upload-demo"
|
||||
drag
|
||||
>
|
||||
<i class="el-icon-upload" />
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或
|
||||
<em>点击上传</em>
|
||||
</div>
|
||||
<div slot="tip" class="el-upload__tip">上传后,系统会自动执行SQL脚本</div>
|
||||
</el-upload>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="cancel">关闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { getToken } from '@/utils/auth'
|
||||
export default {
|
||||
props: {
|
||||
databaseInfo: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
dialog: false,
|
||||
headers: {
|
||||
Authorization: getToken()
|
||||
},
|
||||
rules: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['databaseUploadApi'])
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
cancel() {
|
||||
this.dialog = false
|
||||
},
|
||||
handleSuccess(response, file, fileList) {
|
||||
if (response === 'success') {
|
||||
this.$notify({
|
||||
title: '执行成功',
|
||||
type: 'success',
|
||||
duration: 2500
|
||||
})
|
||||
} else {
|
||||
this.$notify({
|
||||
title: response,
|
||||
type: 'error',
|
||||
duration: 0
|
||||
})
|
||||
}
|
||||
},
|
||||
handleError(e, file, fileList) {
|
||||
const msg = JSON.parse(e.message)
|
||||
this.$notify({
|
||||
title: msg.message,
|
||||
type: 'error',
|
||||
duration: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
148
eladmin-web/src/views/maint/database/index.vue
Normal file
148
eladmin-web/src/views/maint/database/index.vue
Normal file
@ -0,0 +1,148 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!--工具栏-->
|
||||
<div class="head-container">
|
||||
<div v-if="crud.props.searchToggle">
|
||||
<!-- 搜索 -->
|
||||
<el-input v-model="query.blurry" clearable placeholder="模糊搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" />
|
||||
<date-range-picker v-model="query.createTime" class="date-item" />
|
||||
<rrOperation />
|
||||
</div>
|
||||
<crudOperation :permission="permission">
|
||||
<el-button
|
||||
slot="right"
|
||||
v-permission="['admin','database:add']"
|
||||
:disabled="!selectIndex"
|
||||
class="filter-item"
|
||||
size="mini"
|
||||
type="warning"
|
||||
icon="el-icon-upload"
|
||||
@click="execute"
|
||||
>执行脚本
|
||||
</el-button>
|
||||
</crudOperation>
|
||||
</div>
|
||||
<!--表单组件-->
|
||||
<eForm ref="execute" :database-info="currentRow" />
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="530px">
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="100px">
|
||||
<el-form-item label="连接名称" prop="name">
|
||||
<el-input v-model="form.name" style="width: 370px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="JDBC地址" prop="jdbcUrl">
|
||||
<el-input v-model="form.jdbcUrl" style="width: 300px" />
|
||||
<el-button :loading="loading" type="success" @click="testConnectDatabase">测试</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item label="用户" prop="userName">
|
||||
<el-input v-model="form.userName" style="width: 370px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="pwd">
|
||||
<el-input v-model="form.pwd" type="password" style="width: 370px" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button>
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--表格渲染-->
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row stripe style="width: 100%" @selection-change="handleCurrentChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="name" width="130px" label="数据库名称" />
|
||||
<el-table-column prop="jdbcUrl" label="连接地址" />
|
||||
<el-table-column prop="userName" width="200px" label="用户名" />
|
||||
<el-table-column prop="createTime" width="200px" label="创建日期" />
|
||||
<el-table-column v-if="checkPer(['admin','database:edit','database:del'])" label="操作" width="150px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<udOperation
|
||||
:data="scope.row"
|
||||
:permission="permission"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--分页组件-->
|
||||
<pagination />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import crudDatabase from '@/api/maint/database'
|
||||
import { testDbConnect } from '@/api/maint/connect'
|
||||
import eForm from './execute'
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud'
|
||||
import rrOperation from '@crud/RR.operation'
|
||||
import crudOperation from '@crud/CRUD.operation'
|
||||
import udOperation from '@crud/UD.operation'
|
||||
import pagination from '@crud/Pagination'
|
||||
import DateRangePicker from '@/components/DateRangePicker'
|
||||
|
||||
const defaultForm = { id: null, name: null, jdbcUrl: 'jdbc:mysql://', userName: null, pwd: null }
|
||||
export default {
|
||||
name: 'DataBase',
|
||||
components: { eForm, pagination, crudOperation, rrOperation, udOperation, DateRangePicker },
|
||||
cruds() {
|
||||
return CRUD({ title: '数据库', url: 'api/database', crudMethod: { ...crudDatabase }})
|
||||
},
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()],
|
||||
data() {
|
||||
return {
|
||||
currentRow: {},
|
||||
selectIndex: '',
|
||||
databaseInfo: '',
|
||||
loading: false,
|
||||
permission: {
|
||||
add: ['admin', 'database:add'],
|
||||
edit: ['admin', 'database:edit'],
|
||||
del: ['admin', 'database:del']
|
||||
},
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '请输入数据库名称', trigger: 'blur' }
|
||||
],
|
||||
jdbcUrl: [
|
||||
{ required: true, message: '请输入数据库连接地址', trigger: 'blur' }
|
||||
],
|
||||
userName: [
|
||||
{ required: true, message: '请输入用户名', trigger: 'blur' }
|
||||
],
|
||||
pwd: [
|
||||
{ required: true, message: '请输入数据库密码', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
testConnectDatabase() {
|
||||
this.$refs['form'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
testDbConnect(this.form).then((res) => {
|
||||
this.loading = false
|
||||
this.crud.notify(res ? '连接成功' : '连接失败', res ? 'success' : 'error')
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
execute() {
|
||||
this.$refs.execute.dialog = true
|
||||
},
|
||||
handleCurrentChange(selection) {
|
||||
this.crud.selections = selection
|
||||
if (selection.length === 1) {
|
||||
const row = selection[0]
|
||||
this.selectIndex = row.id
|
||||
this.currentRow = row
|
||||
} else {
|
||||
this.currentRow = {}
|
||||
this.selectIndex = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
190
eladmin-web/src/views/maint/deploy/deploy.vue
Normal file
190
eladmin-web/src/views/maint/deploy/deploy.vue
Normal file
@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="应用部署" width="400px">
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small">
|
||||
<el-upload
|
||||
:action="deployUploadApi"
|
||||
:data="deployInfo"
|
||||
:headers="headers"
|
||||
:on-success="handleSuccess"
|
||||
:on-error="handleError"
|
||||
class="upload-demo"
|
||||
drag
|
||||
>
|
||||
<i class="el-icon-upload" />
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或
|
||||
<em>点击上传</em>
|
||||
</div>
|
||||
<div slot="tip" class="el-upload__tip">多个应用上传文件名称为all.zip,数据库更新脚本扩展名为.sql,上传成功后系统自动部署系统。</div>
|
||||
</el-upload>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="cancel">关闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { add, edit, getApps, getServers } from '@/api/maint/deploy'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { getToken } from '@/utils/auth'
|
||||
|
||||
export default {
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
dialog: false,
|
||||
apps: [],
|
||||
servers: [],
|
||||
headers: {
|
||||
Authorization: getToken()
|
||||
},
|
||||
deployInfo: {},
|
||||
form: {
|
||||
id: '',
|
||||
appId: '',
|
||||
ip: '',
|
||||
selectIp: []
|
||||
},
|
||||
rules: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['deployUploadApi'])
|
||||
},
|
||||
created() {
|
||||
this.initWebSocket()
|
||||
},
|
||||
mounted() {
|
||||
this.initSelect()
|
||||
},
|
||||
methods: {
|
||||
cancel() {
|
||||
this.resetForm()
|
||||
},
|
||||
doSubmit() {
|
||||
this.loading = true
|
||||
if (this.isAdd) {
|
||||
this.doAdd()
|
||||
} else {
|
||||
this.doEdit()
|
||||
}
|
||||
},
|
||||
joinIp() {
|
||||
this.form.ip = ''
|
||||
this.form.selectIp.forEach(ip => {
|
||||
if (this.form.ip !== '') {
|
||||
this.form.ip += ','
|
||||
}
|
||||
this.form.ip += ip
|
||||
})
|
||||
},
|
||||
doAdd() {
|
||||
this.joinIp()
|
||||
add(this.form)
|
||||
.then(res => {
|
||||
this.resetForm()
|
||||
this.$notify({
|
||||
title: '添加成功',
|
||||
type: 'success',
|
||||
duration: 2500
|
||||
})
|
||||
this.loading = false
|
||||
this.$parent.init()
|
||||
})
|
||||
.catch(err => {
|
||||
this.loading = false
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
},
|
||||
doEdit() {
|
||||
this.joinIp()
|
||||
edit(this.form)
|
||||
.then(res => {
|
||||
this.resetForm()
|
||||
this.$notify({
|
||||
title: '修改成功',
|
||||
type: 'success',
|
||||
duration: 2500
|
||||
})
|
||||
this.loading = false
|
||||
this.$parent.init()
|
||||
})
|
||||
.catch(err => {
|
||||
this.loading = false
|
||||
console.log(err.response.data.message)
|
||||
})
|
||||
},
|
||||
resetForm() {
|
||||
this.dialog = false
|
||||
this.$refs['form'].resetFields()
|
||||
this.form = {
|
||||
id: '',
|
||||
appId: '',
|
||||
ip: '',
|
||||
selectIp: []
|
||||
}
|
||||
},
|
||||
initSelect() {
|
||||
getApps().then(res => {
|
||||
this.apps = res.content
|
||||
})
|
||||
getServers().then(res => {
|
||||
this.servers = res.content
|
||||
})
|
||||
},
|
||||
handleSuccess(response, file, fileList) {
|
||||
this.cancel()
|
||||
},
|
||||
// 监听上传失败
|
||||
handleError(e, file, fileList) {
|
||||
const msg = JSON.parse(e.message)
|
||||
this.$notify({
|
||||
title: msg.message,
|
||||
type: 'error',
|
||||
duration: 2500
|
||||
})
|
||||
},
|
||||
initWebSocket() {
|
||||
const wsUri = (process.env.VUE_APP_WS_API === '/' ? '/' : (process.env.VUE_APP_WS_API + '/')) + 'webSocket/deploy'
|
||||
this.websock = new WebSocket(wsUri)
|
||||
this.websock.onerror = this.webSocketOnError
|
||||
this.websock.onmessage = this.webSocketOnMessage
|
||||
},
|
||||
webSocketOnError(e) {
|
||||
this.$notify({
|
||||
title: 'WebSocket连接发生错误',
|
||||
type: 'error',
|
||||
duration: 0
|
||||
})
|
||||
},
|
||||
webSocketOnMessage(e) {
|
||||
const data = JSON.parse(e.data)
|
||||
if (data.msgType === 'INFO') {
|
||||
this.$notify({
|
||||
title: '',
|
||||
message: data.msg,
|
||||
type: 'success',
|
||||
dangerouslyUseHTMLString: true,
|
||||
duration: 5500
|
||||
})
|
||||
} else if (data.msgType === 'ERROR') {
|
||||
this.$notify({
|
||||
title: '',
|
||||
message: data.msg,
|
||||
dangerouslyUseHTMLString: true,
|
||||
type: 'error',
|
||||
duration: 0
|
||||
})
|
||||
}
|
||||
},
|
||||
webSocketSend(agentData) {
|
||||
this.websock.send(agentData)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
229
eladmin-web/src/views/maint/deploy/index.vue
Normal file
229
eladmin-web/src/views/maint/deploy/index.vue
Normal file
@ -0,0 +1,229 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!--工具栏-->
|
||||
<div class="head-container">
|
||||
<div v-if="crud.props.searchToggle">
|
||||
<!-- 搜索 -->
|
||||
<el-input v-model="query.appName" clearable placeholder="输入应用名称查询" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" />
|
||||
<date-range-picker v-model="query.createTime" class="date-item" />
|
||||
<rrOperation />
|
||||
</div>
|
||||
<crudOperation :permission="permission">
|
||||
<template slot="right">
|
||||
<el-button
|
||||
v-permission="['admin','deploy:add']"
|
||||
:disabled="!selectIndex"
|
||||
class="filter-item"
|
||||
size="mini"
|
||||
type="primary"
|
||||
icon="el-icon-upload"
|
||||
@click="sysRestore"
|
||||
>系统还原
|
||||
</el-button>
|
||||
<el-button
|
||||
v-permission="['admin','deploy:add']"
|
||||
:disabled="!selectIndex"
|
||||
class="filter-item"
|
||||
size="mini"
|
||||
type="primary"
|
||||
icon="el-icon-upload"
|
||||
@click="serverStatus"
|
||||
>状态查询
|
||||
</el-button>
|
||||
<el-button
|
||||
v-permission="['admin','deploy:add']"
|
||||
:disabled="!selectIndex"
|
||||
class="filter-item"
|
||||
size="mini"
|
||||
type="success"
|
||||
icon="el-icon-upload"
|
||||
@click="startServer"
|
||||
>启动
|
||||
</el-button>
|
||||
<el-button
|
||||
v-permission="['admin','deploy:add']"
|
||||
:disabled="!selectIndex"
|
||||
class="filter-item"
|
||||
size="mini"
|
||||
type="danger"
|
||||
icon="el-icon-upload"
|
||||
@click="stopServer"
|
||||
>停止
|
||||
</el-button>
|
||||
<el-button
|
||||
v-permission="['admin','deploy:add']"
|
||||
:disabled="!selectIndex"
|
||||
class="filter-item"
|
||||
size="mini"
|
||||
type="warning"
|
||||
icon="el-icon-upload"
|
||||
@click="deploy"
|
||||
>一键部署
|
||||
</el-button>
|
||||
</template>
|
||||
</crudOperation>
|
||||
</div>
|
||||
<!--表单组件-->
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="500px">
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px">
|
||||
<el-form-item label="应用" prop="app.id">
|
||||
<el-select v-model.number="form.app.id" placeholder="请选择" style="width: 370px">
|
||||
<el-option v-for="item in apps" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="服务器" prop="deploys">
|
||||
<el-select v-model="form.deploys" multiple placeholder="请选择" style="width: 370px">
|
||||
<el-option v-for="item in servers" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button>
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--统还原组件-->
|
||||
<fForm ref="sysRestore" :key="times" :app-name="appName" />
|
||||
<dForm ref="deploy" />
|
||||
<!--表格渲染-->
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" highlight-current-row stripe style="width: 100%" @selection-change="handleCurrentChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="app.name" label="应用名称" />
|
||||
<el-table-column prop="servers" label="服务器列表" />
|
||||
<el-table-column prop="createTime" label="部署日期" />
|
||||
<el-table-column v-if="checkPer(['admin','deploy:edit','deploy:del'])" label="操作" width="150px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<udOperation
|
||||
:data="scope.row"
|
||||
:permission="permission"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--分页组件-->
|
||||
<pagination />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import crudDeploy from '@/api/maint/deploy'
|
||||
import dForm from './deploy'
|
||||
import fForm from './sysRestore'
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud'
|
||||
import rrOperation from '@crud/RR.operation'
|
||||
import crudOperation from '@crud/CRUD.operation'
|
||||
import udOperation from '@crud/UD.operation'
|
||||
import pagination from '@crud/Pagination'
|
||||
import DateRangePicker from '@/components/DateRangePicker'
|
||||
|
||||
const defaultForm = { id: null, app: { id: null }, deploys: [] }
|
||||
export default {
|
||||
name: 'Deploy',
|
||||
components: { dForm, fForm, pagination, crudOperation, rrOperation, udOperation, DateRangePicker },
|
||||
cruds() {
|
||||
return CRUD({ title: '部署', url: 'api/deploy', crudMethod: { ...crudDeploy }})
|
||||
},
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()],
|
||||
data() {
|
||||
return {
|
||||
currentRow: {}, selectIndex: '', appName: '', urlHistory: '',
|
||||
times: 0, appId: '', deployId: '', apps: [], servers: [],
|
||||
permission: {
|
||||
add: ['admin', 'deploy:add'],
|
||||
edit: ['admin', 'deploy:edit'],
|
||||
del: ['admin', 'deploy:del']
|
||||
},
|
||||
rules: {
|
||||
'app.id': [
|
||||
{ required: true, message: '应用不能为空', trigger: 'blur', type: 'number' }
|
||||
],
|
||||
deploys: [
|
||||
{ required: true, message: '服务器不能为空', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
[CRUD.HOOK.beforeRefresh]() {
|
||||
this.selectIndex = ''
|
||||
return true
|
||||
},
|
||||
// 新增编辑前做的操作
|
||||
[CRUD.HOOK.beforeToCU](crud, form) {
|
||||
this.initSelect()
|
||||
const deploys = []
|
||||
form.deploys.forEach(function(deploy, index) {
|
||||
deploys.push(deploy.id)
|
||||
})
|
||||
this.form.deploys = deploys
|
||||
},
|
||||
// 提交前
|
||||
[CRUD.HOOK.beforeSubmit]() {
|
||||
const deploys = []
|
||||
this.form.deploys.forEach(function(data, index) {
|
||||
const deploy = { id: data }
|
||||
deploys.push(deploy)
|
||||
})
|
||||
this.form.deploys = deploys
|
||||
return true
|
||||
},
|
||||
deploy() {
|
||||
this.$refs.deploy.dialog = true
|
||||
this.$refs.deploy.deployInfo = this.currentRow
|
||||
},
|
||||
sysRestore() {
|
||||
this.$refs.sysRestore.dialog = true
|
||||
},
|
||||
handleCurrentChange(selection) {
|
||||
this.crud.selections = selection
|
||||
if (selection.length === 1) {
|
||||
const row = selection[0]
|
||||
this.selectIndex = row.id
|
||||
this.currentRow = row
|
||||
this.appName = row.app.name
|
||||
this.times = this.times + 1
|
||||
this.appId = row.appId
|
||||
this.deployId = row.id
|
||||
} else {
|
||||
this.currentRow = {}
|
||||
this.selectIndex = ''
|
||||
}
|
||||
},
|
||||
startServer() {
|
||||
crudDeploy.startServer(JSON.stringify(this.currentRow))
|
||||
.then(res => {
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('error:' + err.response.data.message)
|
||||
})
|
||||
},
|
||||
stopServer() {
|
||||
crudDeploy.stopServer(JSON.stringify(this.currentRow))
|
||||
.then(res => {
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('error:' + err.response.data.message)
|
||||
})
|
||||
},
|
||||
serverStatus() {
|
||||
crudDeploy.serverStatus(JSON.stringify(this.currentRow))
|
||||
.then(res => {
|
||||
})
|
||||
.catch(err => {
|
||||
console.log('error:' + err.response.data.message)
|
||||
})
|
||||
},
|
||||
initSelect() {
|
||||
crudDeploy.getApps().then(res => {
|
||||
this.apps = res.content
|
||||
})
|
||||
crudDeploy.getServers().then(res => {
|
||||
this.servers = res.content
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
107
eladmin-web/src/views/maint/deploy/sysRestore.vue
Normal file
107
eladmin-web/src/views/maint/deploy/sysRestore.vue
Normal file
@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :visible.sync="dialog" title="系统还原" width="800px">
|
||||
<!--工具栏-->
|
||||
<div class="head-container">
|
||||
<date-range-picker v-model="query.createTime" class="date-item" />
|
||||
<el-button class="filter-item" size="mini" type="success" icon="el-icon-search" @click="toQuery">搜索</el-button>
|
||||
</div>
|
||||
<el-form size="small" label-width="80px">
|
||||
<!--表格渲染-->
|
||||
<el-table v-loading="loading" :data="data" style="width: 100%" @row-click="showRow">
|
||||
<el-table-column width="30px">
|
||||
<template slot-scope="scope">
|
||||
<el-radio v-model="radio" :label="scope.$index" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="appName" label="应用名称" />
|
||||
<el-table-column prop="ip" label="部署IP" />
|
||||
<el-table-column prop="deployDate" label="部署时间" />
|
||||
<el-table-column prop="deployUser" label="部署人员" />
|
||||
</el-table>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="cancel">取消</el-button>
|
||||
<el-button v-permission="['admin','deploy:add']" :loading="submitLoading" type="primary" @click="doSubmit">确认</el-button>
|
||||
</div>
|
||||
<!--分页组件-->
|
||||
<el-pagination
|
||||
:total="total"
|
||||
:current-page="page"
|
||||
style="margin-top: 8px"
|
||||
layout="total, prev, pager, next, sizes"
|
||||
@size-change="sizeChange"
|
||||
@current-change="pageChange"
|
||||
/>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import crud from '@/mixins/crud'
|
||||
import { reducte } from '@/api/maint/deployHistory'
|
||||
import DateRangePicker from '@/components/DateRangePicker'
|
||||
export default {
|
||||
components: { DateRangePicker },
|
||||
mixins: [crud],
|
||||
props: {
|
||||
appName: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
submitLoading: false,
|
||||
dialog: false,
|
||||
history: [],
|
||||
radio: '',
|
||||
appNames: '',
|
||||
selectIndex: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$nextTick(() => {
|
||||
this.init()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
beforeInit() {
|
||||
this.url = 'api/deployHistory'
|
||||
this.deployId = this.$parent.deployId
|
||||
if (this.deployId === '') {
|
||||
return false
|
||||
}
|
||||
this.params['deployId'] = this.deployId
|
||||
return true
|
||||
},
|
||||
showRow(row) {
|
||||
this.radio = this.data.indexOf(row)
|
||||
this.selectIndex = row.id
|
||||
},
|
||||
cancel() {
|
||||
this.dialog = false
|
||||
this.submitLoading = false
|
||||
},
|
||||
doSubmit() {
|
||||
if (this.selectIndex === '') {
|
||||
this.$message.error('请选择要还原的备份')
|
||||
} else {
|
||||
this.submitLoading = true
|
||||
reducte(JSON.stringify(this.data[this.radio]))
|
||||
.then(res => {
|
||||
this.dialog = false
|
||||
this.submitLoading = false
|
||||
this.appNames = ''
|
||||
this.$parent.crud.toQuery()
|
||||
})
|
||||
.catch(err => {
|
||||
this.submitLoading = false
|
||||
console.log('error:' + err.response.data.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
93
eladmin-web/src/views/maint/deployHistory/index.vue
Normal file
93
eladmin-web/src/views/maint/deployHistory/index.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!--工具栏-->
|
||||
<div class="head-container">
|
||||
<div v-if="crud.props.searchToggle">
|
||||
<!-- 搜索 -->
|
||||
<el-input v-model="query.blurry" clearable placeholder="输入搜索内容" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" />
|
||||
<date-range-picker v-model="query.deployDate" class="date-item" />
|
||||
<rrOperation />
|
||||
</div>
|
||||
<crudOperation :permission="permission" />
|
||||
</div>
|
||||
<!--表格渲染-->
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%" @selection-change="crud.selectionChangeHandler">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="appName" label="应用名称" />
|
||||
<el-table-column prop="ip" label="部署IP" />
|
||||
<el-table-column prop="deployUser" label="部署人员" />
|
||||
<el-table-column prop="deployDate" label="部署时间" />
|
||||
<el-table-column v-if="checkPer(['admin','deployHistory:del'])" label="操作" width="100px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-popover
|
||||
:ref="scope.row.id"
|
||||
v-permission="['admin','deployHistory:del']"
|
||||
placement="top"
|
||||
width="180"
|
||||
>
|
||||
<p>确定删除本条数据吗?</p>
|
||||
<div style="text-align: right; margin: 0">
|
||||
<el-button size="mini" type="text" @click="$refs[scope.row.id].doClose()">取消</el-button>
|
||||
<el-button :loading="delLoading" type="primary" size="mini" @click="delMethod(scope.row.id)">确定</el-button>
|
||||
</div>
|
||||
<el-button slot="reference" type="danger" icon="el-icon-delete" size="mini" />
|
||||
</el-popover>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--分页组件-->
|
||||
<pagination />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { del } from '@/api/maint/deployHistory'
|
||||
import CRUD, { presenter, header } from '@crud/crud'
|
||||
import rrOperation from '@crud/RR.operation'
|
||||
import crudOperation from '@crud/CRUD.operation'
|
||||
import pagination from '@crud/Pagination'
|
||||
import DateRangePicker from '@/components/DateRangePicker'
|
||||
|
||||
export default {
|
||||
name: 'DeployHistory',
|
||||
components: { pagination, crudOperation, rrOperation, DateRangePicker },
|
||||
cruds() {
|
||||
return CRUD({ title: '部署历史', url: 'api/deployHistory', crudMethod: { del }})
|
||||
},
|
||||
mixins: [presenter(), header()],
|
||||
data() {
|
||||
return {
|
||||
delLoading: false,
|
||||
permission: {
|
||||
del: ['admin', 'deployHistory:del']
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.crud.optShow = {
|
||||
add: false,
|
||||
edit: false,
|
||||
del: true,
|
||||
download: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
delMethod(id) {
|
||||
this.delLoading = true
|
||||
del([id]).then(() => {
|
||||
this.delLoading = false
|
||||
this.$refs[id].doClose()
|
||||
this.crud.dleChangePage(1)
|
||||
this.crud.delSuccessNotify()
|
||||
this.crud.toQuery()
|
||||
}).catch(() => {
|
||||
this.delLoading = false
|
||||
this.$refs[id].doClose()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
136
eladmin-web/src/views/maint/server/index.vue
Normal file
136
eladmin-web/src/views/maint/server/index.vue
Normal file
@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!--工具栏-->
|
||||
<div class="head-container">
|
||||
<div v-if="crud.props.searchToggle">
|
||||
<!-- 搜索 -->
|
||||
<el-input v-model="query.blurry" clearable placeholder="输入名称或IP搜索" style="width: 200px" class="filter-item" @keyup.enter.native="crud.toQuery" />
|
||||
<date-range-picker v-model="query.createTime" class="date-item" />
|
||||
<rrOperation />
|
||||
</div>
|
||||
<crudOperation :permission="permission" />
|
||||
</div>
|
||||
<!--表单组件-->
|
||||
<el-dialog append-to-body :close-on-click-modal="false" :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0" :title="crud.status.title" width="470px">
|
||||
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="55px">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="form.name" style="width: 370px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="IP" prop="ip">
|
||||
<el-input v-model="form.ip" style="width: 370px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="端口" prop="port">
|
||||
<el-input-number v-model.number="form.port" controls-position="right" style="width: 370px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="账号" prop="account">
|
||||
<el-input v-model="form.account" style="width: 370px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码" prop="password">
|
||||
<el-input v-model="form.password" type="password" style="width: 200px" />
|
||||
<el-button :loading="loading" type="success" style="align: right;" @click="testConnectServer">测试连接</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="text" @click="crud.cancelCU">取消</el-button>
|
||||
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!--表格渲染-->
|
||||
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%" @selection-change="crud.selectionChangeHandler">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="name" label="名称" />
|
||||
<el-table-column prop="ip" label="IP" />
|
||||
<el-table-column prop="port" label="端口" />
|
||||
<el-table-column prop="account" label="账号" />
|
||||
<el-table-column prop="createTime" label="创建日期" />
|
||||
<el-table-column v-if="checkPer(['admin','serverDeploy:edit','serverDeploy:del'])" label="操作" width="150px" align="center">
|
||||
<template slot-scope="scope">
|
||||
<udOperation
|
||||
:data="scope.row"
|
||||
:permission="permission"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!--分页组件-->
|
||||
<pagination />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import crudServer from '@/api/maint/serverDeploy'
|
||||
import { testServerConnect } from '@/api/maint/connect'
|
||||
import { validateIP } from '@/utils/validate'
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud'
|
||||
import rrOperation from '@crud/RR.operation'
|
||||
import crudOperation from '@crud/CRUD.operation'
|
||||
import udOperation from '@crud/UD.operation'
|
||||
import pagination from '@crud/Pagination'
|
||||
import DateRangePicker from '@/components/DateRangePicker'
|
||||
|
||||
const defaultForm = { id: null, name: null, ip: null, port: 22, account: 'root', password: null }
|
||||
export default {
|
||||
name: 'Server',
|
||||
components: { pagination, crudOperation, rrOperation, udOperation, DateRangePicker },
|
||||
cruds() {
|
||||
return CRUD({ title: '服务器', url: 'api/serverDeploy', crudMethod: { ...crudServer }})
|
||||
},
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()],
|
||||
data() {
|
||||
return {
|
||||
accountList: [],
|
||||
accountMap: {},
|
||||
loading: false,
|
||||
permission: {
|
||||
add: ['admin', 'serverDeploy:add'],
|
||||
edit: ['admin', 'serverDeploy:edit'],
|
||||
del: ['admin', 'serverDeploy:del']
|
||||
},
|
||||
rules: {
|
||||
name: [
|
||||
{ required: true, message: '请输入名称', trigger: 'blur' }
|
||||
],
|
||||
ip: [
|
||||
{ required: true, message: '请输入IP', trigger: 'blur' },
|
||||
{ validator: validateIP, trigger: 'change' }
|
||||
],
|
||||
port: [
|
||||
{ required: true, message: '请输入端口', trigger: 'blur', type: 'number' }
|
||||
],
|
||||
account: [
|
||||
{ required: true, message: '请输入账号', trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: true, message: '请输入密码', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
testConnectServer() {
|
||||
this.$refs['form'].validate((valid) => {
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
testServerConnect(this.form).then((res) => {
|
||||
this.loading = false
|
||||
this.$notify({
|
||||
title: res ? '连接成功' : '连接失败',
|
||||
type: res ? 'success' : 'error',
|
||||
duration: 2500
|
||||
})
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
::v-deep .el-input-number .el-input__inner {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
@ -17,7 +17,7 @@
|
||||
|
||||
#### VPS推荐
|
||||
<a href="https://bwh81.net/aff.php?aff=70876" target="_blank">
|
||||
<img src="https://eladmin.vip/images/banner/side.jpeg" style="width: 435px;border-radius: 2px;">
|
||||
<img src="https://eladmin.vip/images/banner/side.jpeg" style="width: 435px;border-radius: 2px;" alt="帮瓦工">
|
||||
</a>
|
||||
|
||||
使用优惠码: `BWHNCXNVXV`,可获得 6.81% 的折扣, [查看介绍](https://eladmin.vip/pages/040101/)
|
||||
@ -31,6 +31,7 @@
|
||||
- 对一些常用地前端组件封装:表格数据请求、数据字典等
|
||||
- 前后端统一异常拦截处理,统一输出异常,避免繁琐的判断
|
||||
- 支持在线用户管理与服务器性能监控,支持限制单用户登录
|
||||
- 支持运维管理,可方便地对远程服务器的应用进行部署与管理
|
||||
|
||||
#### 系统功能
|
||||
- 用户管理:提供用户的相关配置,新增用户后,默认密码为123456
|
||||
@ -47,6 +48,7 @@
|
||||
- 七牛云存储:可同步七牛云存储的数据到系统,无需登录七牛云直接操作云数据
|
||||
- 支付宝支付:整合了支付宝支付并且提供了测试账号,可自行测试
|
||||
- 服务监控:监控服务器的负载情况
|
||||
- 运维管理:一键部署你的应用
|
||||
|
||||
#### 项目结构
|
||||
项目采用按功能分模块的开发方式,结构如下
|
||||
@ -85,7 +87,7 @@
|
||||
- FileUtil 文件工具类
|
||||
- eladmin-system 系统核心模块(系统启动入口)
|
||||
- sysrunner 程序启动后处理数据
|
||||
- modules 系统相关模块(登录授权、系统监控、定时任务、系统模块)
|
||||
- modules 系统相关模块(登录授权、系统监控、定时任务、系统模块、运维模块)
|
||||
- eladmin-logging 系统日志模块
|
||||
- eladmin-tools 系统第三方工具模块
|
||||
- email 邮件工具
|
||||
@ -101,6 +103,8 @@
|
||||
|
||||
- 感谢 [Moxun](https://github.com/moxun1639) 大佬提供的前端 Curd 通用组件
|
||||
|
||||
- 感谢 [zhy6599](https://gitee.com/zhy6599) 大佬提供的后端运维管理相关功能
|
||||
|
||||
- 感谢 [j.yao.SUSE](https://github.com/everhopingandwaiting) 大佬提供的匿名接口与Redis限流等功能
|
||||
|
||||
#### 项目捐赠
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.config.webConfig;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
/**
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-24 15:44
|
||||
*/
|
||||
@Configuration
|
||||
public class WebSocketConfig {
|
||||
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter() {
|
||||
return new ServerEndpointExporter();
|
||||
}
|
||||
}
|
@ -62,6 +62,18 @@
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- linux的管理 -->
|
||||
<dependency>
|
||||
<groupId>ch.ethz.ganymed</groupId>
|
||||
<artifactId>ganymed-ssh2</artifactId>
|
||||
<version>build210</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jcraft</groupId>
|
||||
<artifactId>jsch</artifactId>
|
||||
<version>0.1.55</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 获取系统信息 -->
|
||||
<dependency>
|
||||
<groupId>com.github.oshi</groupId>
|
||||
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.zhengjie.base.BaseEntity;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("mnt_app")
|
||||
public class App extends BaseEntity implements Serializable {
|
||||
|
||||
|
||||
@TableId(value = "app_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "端口")
|
||||
private int port;
|
||||
|
||||
@ApiModelProperty(value = "上传路径")
|
||||
private String uploadPath;
|
||||
|
||||
@ApiModelProperty(value = "部署路径")
|
||||
private String deployPath;
|
||||
|
||||
@ApiModelProperty(value = "备份路径")
|
||||
private String backupPath;
|
||||
|
||||
@ApiModelProperty(value = "启动脚本")
|
||||
private String startScript;
|
||||
|
||||
@ApiModelProperty(value = "部署脚本")
|
||||
private String deployScript;
|
||||
|
||||
public void copy(App source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.zhengjie.base.BaseEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("mnt_database")
|
||||
public class Database extends BaseEntity implements Serializable {
|
||||
|
||||
@TableId(value = "db_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(value = "数据库名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "数据库连接地址")
|
||||
private String jdbcUrl;
|
||||
|
||||
@ApiModelProperty(value = "数据库密码")
|
||||
private String pwd;
|
||||
|
||||
@ApiModelProperty(value = "用户名")
|
||||
private String userName;
|
||||
|
||||
public void copy(Database source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.zhengjie.base.BaseEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("mnt_deploy")
|
||||
public class Deploy extends BaseEntity implements Serializable {
|
||||
|
||||
@TableId(value = "deploy_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "应用编号")
|
||||
private Long appId;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(name = "服务器", hidden = true)
|
||||
private Set<Server> deploys;
|
||||
|
||||
@TableField(exist = false)
|
||||
@ApiModelProperty(value = "应用")
|
||||
private App app;
|
||||
|
||||
public void copy(Deploy source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
|
||||
public String getServers() {
|
||||
if(CollectionUtil.isNotEmpty(deploys)){
|
||||
return deploys.stream().map(Server::getName).collect(Collectors.joining(","));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("mnt_deploy_history")
|
||||
public class DeployHistory implements Serializable {
|
||||
|
||||
@TableId(value = "history_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(value = "应用名称")
|
||||
private String appName;
|
||||
|
||||
@ApiModelProperty(value = "IP")
|
||||
private String ip;
|
||||
|
||||
@ApiModelProperty(value = "部署时间")
|
||||
private Timestamp deployDate;
|
||||
|
||||
@ApiModelProperty(value = "部署者")
|
||||
private String deployUser;
|
||||
|
||||
@ApiModelProperty(value = "部署ID")
|
||||
private Long deployId;
|
||||
|
||||
public void copy(DeployHistory source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.bean.copier.CopyOptions;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.zhengjie.base.BaseEntity;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("mnt_server")
|
||||
public class Server extends BaseEntity implements Serializable {
|
||||
|
||||
@TableId(value = "server_id", type = IdType.AUTO)
|
||||
@ApiModelProperty(value = "ID", hidden = true)
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty(value = "服务器名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "IP")
|
||||
private String ip;
|
||||
|
||||
@ApiModelProperty(value = "端口")
|
||||
private Integer port;
|
||||
|
||||
@ApiModelProperty(value = "账号")
|
||||
private String account;
|
||||
|
||||
@ApiModelProperty(value = "密码")
|
||||
private String password;
|
||||
|
||||
public void copy(Server source){
|
||||
BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Server that = (Server) o;
|
||||
return Objects.equals(id, that.id) &&
|
||||
Objects.equals(name, that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Data
|
||||
public class AppQueryCriteria{
|
||||
|
||||
@ApiModelProperty(value = "名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Data
|
||||
public class DatabaseQueryCriteria{
|
||||
|
||||
@ApiModelProperty(value = "名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "数据源")
|
||||
private String jdbcUrl;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Data
|
||||
public class DeployHistoryQueryCriteria{
|
||||
|
||||
@ApiModelProperty(value = "模糊查询")
|
||||
private String blurry;
|
||||
|
||||
@ApiModelProperty(value = "部署ID")
|
||||
private Long deployId;
|
||||
|
||||
@ApiModelProperty(value = "部署时间")
|
||||
private List<Timestamp> deployDate;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Data
|
||||
public class DeployQueryCriteria{
|
||||
|
||||
@ApiModelProperty(value = "应用名称")
|
||||
private String appName;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
|
||||
@ApiModelProperty(value = "查询分页偏移量", hidden = true)
|
||||
private Long offset;
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Data
|
||||
public class ServerQueryCriteria {
|
||||
|
||||
@ApiModelProperty(value = "模糊查询")
|
||||
private String blurry;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
private List<Timestamp> createTime;
|
||||
|
||||
@ApiModelProperty(value = "页码", example = "1")
|
||||
private Integer page = 1;
|
||||
|
||||
@ApiModelProperty(value = "每页数据量", example = "10")
|
||||
private Integer size = 10;
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* <<
|
||||
* Davinci
|
||||
* ==
|
||||
* Copyright (C) 2016 - 2019 EDP
|
||||
* ==
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* >>
|
||||
*
|
||||
*/
|
||||
|
||||
package me.zhengjie.modules.maint.domain.enums;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@Slf4j
|
||||
@SuppressWarnings({"unchecked","all"})
|
||||
public enum DataTypeEnum {
|
||||
|
||||
/** mysql */
|
||||
MYSQL("mysql", "mysql", "com.mysql.jdbc.Driver", "`", "`", "'", "'"),
|
||||
|
||||
/** oracle */
|
||||
ORACLE("oracle", "oracle", "oracle.jdbc.driver.OracleDriver", "\"", "\"", "\"", "\""),
|
||||
|
||||
/** sql server */
|
||||
SQLSERVER("sqlserver", "sqlserver", "com.microsoft.sqlserver.jdbc.SQLServerDriver", "\"", "\"", "\"", "\""),
|
||||
|
||||
/** h2 */
|
||||
H2("h2", "h2", "org.h2.Driver", "`", "`", "\"", "\""),
|
||||
|
||||
/** phoenix */
|
||||
PHOENIX("phoenix", "hbase phoenix", "org.apache.phoenix.jdbc.PhoenixDriver", "", "", "\"", "\""),
|
||||
|
||||
/** mongo */
|
||||
MONGODB("mongo", "mongodb", "mongodb.jdbc.MongoDriver", "`", "`", "\"", "\""),
|
||||
|
||||
/** sql4es */
|
||||
ELASTICSEARCH("sql4es", "elasticsearch", "nl.anchormen.sql4es.jdbc.ESDriver", "", "", "'", "'"),
|
||||
|
||||
/** presto */
|
||||
PRESTO("presto", "presto", "com.facebook.presto.jdbc.PrestoDriver", "", "", "\"", "\""),
|
||||
|
||||
/** moonbox */
|
||||
MOONBOX("moonbox", "moonbox", "moonbox.jdbc.MbDriver", "`", "`", "`", "`"),
|
||||
|
||||
/** cassandra */
|
||||
CASSANDRA("cassandra", "cassandra", "com.github.adejanovski.cassandra.jdbc.CassandraDriver", "", "", "'", "'"),
|
||||
|
||||
/** click house */
|
||||
CLICKHOUSE("clickhouse", "clickhouse", "ru.yandex.clickhouse.ClickHouseDriver", "", "", "\"", "\""),
|
||||
|
||||
/** kylin */
|
||||
KYLIN("kylin", "kylin", "org.apache.kylin.jdbc.Driver", "\"", "\"", "\"", "\""),
|
||||
|
||||
/** vertica */
|
||||
VERTICA("vertica", "vertica", "com.vertica.jdbc.Driver", "", "", "'", "'"),
|
||||
|
||||
/** sap */
|
||||
HANA("sap", "sap hana", "com.sap.db.jdbc.Driver", "", "", "'", "'"),
|
||||
|
||||
/** impala */
|
||||
IMPALA("impala", "impala", "com.cloudera.impala.jdbc41.Driver", "", "", "'", "'");
|
||||
|
||||
private String feature;
|
||||
private String desc;
|
||||
private String driver;
|
||||
private String keywordPrefix;
|
||||
private String keywordSuffix;
|
||||
private String aliasPrefix;
|
||||
private String aliasSuffix;
|
||||
|
||||
private static final String JDBC_URL_PREFIX = "jdbc:";
|
||||
|
||||
DataTypeEnum(String feature, String desc, String driver, String keywordPrefix, String keywordSuffix, String aliasPrefix, String aliasSuffix) {
|
||||
this.feature = feature;
|
||||
this.desc = desc;
|
||||
this.driver = driver;
|
||||
this.keywordPrefix = keywordPrefix;
|
||||
this.keywordSuffix = keywordSuffix;
|
||||
this.aliasPrefix = aliasPrefix;
|
||||
this.aliasSuffix = aliasSuffix;
|
||||
}
|
||||
|
||||
public static DataTypeEnum urlOf(String jdbcUrl) {
|
||||
String url = jdbcUrl.toLowerCase().trim();
|
||||
for (DataTypeEnum dataTypeEnum : values()) {
|
||||
if (url.startsWith(JDBC_URL_PREFIX + dataTypeEnum.feature)) {
|
||||
try {
|
||||
Class<?> aClass = Class.forName(dataTypeEnum.getDriver());
|
||||
if (null == aClass) {
|
||||
throw new RuntimeException("Unable to get driver instance for jdbcUrl: " + jdbcUrl);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Unable to get driver instance: " + jdbcUrl);
|
||||
}
|
||||
return dataTypeEnum;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getFeature() {
|
||||
return feature;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public String getDriver() {
|
||||
return driver;
|
||||
}
|
||||
|
||||
public String getKeywordPrefix() {
|
||||
return keywordPrefix;
|
||||
}
|
||||
|
||||
public String getKeywordSuffix() {
|
||||
return keywordSuffix;
|
||||
}
|
||||
|
||||
public String getAliasPrefix() {
|
||||
return aliasPrefix;
|
||||
}
|
||||
|
||||
public String getAliasSuffix() {
|
||||
return aliasSuffix;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.domain.enums;
|
||||
|
||||
/**
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-10 9:56
|
||||
*/
|
||||
public enum MsgType {
|
||||
/** 连接 */
|
||||
CONNECT,
|
||||
/** 关闭 */
|
||||
CLOSE,
|
||||
/** 信息 */
|
||||
INFO,
|
||||
/** 错误 */
|
||||
ERROR
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import me.zhengjie.modules.maint.domain.App;
|
||||
import me.zhengjie.modules.maint.domain.dto.AppQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface AppMapper extends BaseMapper<App> {
|
||||
|
||||
IPage<App> queryAll(@Param("criteria") AppQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
List<App> queryAll(@Param("criteria") AppQueryCriteria criteria);
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import me.zhengjie.modules.maint.domain.Database;
|
||||
import me.zhengjie.modules.maint.domain.dto.DatabaseQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface DatabaseMapper extends BaseMapper<Database> {
|
||||
|
||||
IPage<Database> findAll(@Param("criteria") DatabaseQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
List<Database> findAll(@Param("criteria") DatabaseQueryCriteria criteria);
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import me.zhengjie.modules.maint.domain.DeployHistory;
|
||||
import me.zhengjie.modules.maint.domain.dto.DeployHistoryQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface DeployHistoryMapper extends BaseMapper<DeployHistory> {
|
||||
|
||||
IPage<DeployHistory> findAll(@Param("criteria") DeployHistoryQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
List<DeployHistory> findAll(@Param("criteria") DeployHistoryQueryCriteria criteria);
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import me.zhengjie.modules.maint.domain.Deploy;
|
||||
import me.zhengjie.modules.maint.domain.dto.DeployQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface DeployMapper extends BaseMapper<Deploy> {
|
||||
|
||||
Long countAll(@Param("criteria") DeployQueryCriteria criteria);
|
||||
|
||||
List<Deploy> findAll(@Param("criteria") DeployQueryCriteria criteria);
|
||||
|
||||
Set<Long> getIdByAppIds(@Param("appIds") Set<Long> appIds);
|
||||
|
||||
Deploy getDeployById(@Param("deployId") Long deployId);
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.mapper;
|
||||
|
||||
import me.zhengjie.modules.maint.domain.Server;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface DeployServerMapper {
|
||||
|
||||
void insertData(@Param("deployId") Long deployId, @Param("servers") Set<Server> servers);
|
||||
|
||||
void deleteByDeployId(@Param("deployId") Long deployId);
|
||||
|
||||
void deleteByDeployIds(@Param("deployIds") Set<Long> deployIds);
|
||||
|
||||
void deleteByServerIds(@Param("serverIds") Set<Long> serverIds);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2019-2023 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import me.zhengjie.modules.maint.domain.Server;
|
||||
import me.zhengjie.modules.maint.domain.dto.ServerQueryCriteria;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zheng Jie
|
||||
* @description
|
||||
* @date 2023-06-12
|
||||
**/
|
||||
@Mapper
|
||||
public interface ServerMapper extends BaseMapper<Server> {
|
||||
Server findByIp(@Param("ip") String ip);
|
||||
|
||||
IPage<Server> findAll(@Param("criteria") ServerQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
List<Server> findAll(@Param("criteria") ServerQueryCriteria criteria);
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.annotation.Log;
|
||||
import me.zhengjie.modules.maint.domain.App;
|
||||
import me.zhengjie.modules.maint.domain.dto.AppQueryCriteria;
|
||||
import me.zhengjie.modules.maint.service.AppService;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Api(tags = "运维:应用管理")
|
||||
@RequestMapping("/api/app")
|
||||
public class AppController {
|
||||
|
||||
private final AppService appService;
|
||||
|
||||
@ApiOperation("导出应用数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('app:list')")
|
||||
public void exportApp(HttpServletResponse response, AppQueryCriteria criteria) throws IOException {
|
||||
appService.download(appService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查询应用")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('app:list')")
|
||||
public ResponseEntity<PageResult<App>> queryApp(AppQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(appService.queryAll(criteria, page),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("新增应用")
|
||||
@ApiOperation(value = "新增应用")
|
||||
@PostMapping
|
||||
@PreAuthorize("@el.check('app:add')")
|
||||
public ResponseEntity<Object> createApp(@Validated @RequestBody App resources){
|
||||
appService.create(resources);
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("修改应用")
|
||||
@ApiOperation(value = "修改应用")
|
||||
@PutMapping
|
||||
@PreAuthorize("@el.check('app:edit')")
|
||||
public ResponseEntity<Object> updateApp(@Validated @RequestBody App resources){
|
||||
appService.update(resources);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("删除应用")
|
||||
@ApiOperation(value = "删除应用")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('app:del')")
|
||||
public ResponseEntity<Object> deleteApp(@RequestBody Set<Long> ids){
|
||||
appService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.annotation.Log;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.modules.maint.domain.Database;
|
||||
import me.zhengjie.modules.maint.domain.dto.DatabaseQueryCriteria;
|
||||
import me.zhengjie.modules.maint.service.DatabaseService;
|
||||
import me.zhengjie.modules.maint.util.SqlUtils;
|
||||
import me.zhengjie.utils.FileUtil;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Api(tags = "运维:数据库管理")
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/database")
|
||||
public class DatabaseController {
|
||||
|
||||
private final String fileSavePath = FileUtil.getTmpDirPath()+"/";
|
||||
private final DatabaseService databaseService;
|
||||
|
||||
@ApiOperation("导出数据库数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('database:list')")
|
||||
public void exportDatabase(HttpServletResponse response, DatabaseQueryCriteria criteria) throws IOException {
|
||||
databaseService.download(databaseService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查询数据库")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('database:list')")
|
||||
public ResponseEntity<PageResult<Database>> queryDatabase(DatabaseQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(databaseService.queryAll(criteria, page),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("新增数据库")
|
||||
@ApiOperation(value = "新增数据库")
|
||||
@PostMapping
|
||||
@PreAuthorize("@el.check('database:add')")
|
||||
public ResponseEntity<Object> createDatabase(@Validated @RequestBody Database resources){
|
||||
databaseService.create(resources);
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("修改数据库")
|
||||
@ApiOperation(value = "修改数据库")
|
||||
@PutMapping
|
||||
@PreAuthorize("@el.check('database:edit')")
|
||||
public ResponseEntity<Object> updateDatabase(@Validated @RequestBody Database resources){
|
||||
databaseService.update(resources);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("删除数据库")
|
||||
@ApiOperation(value = "删除数据库")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('database:del')")
|
||||
public ResponseEntity<Object> deleteDatabase(@RequestBody Set<String> ids){
|
||||
databaseService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("测试数据库链接")
|
||||
@ApiOperation(value = "测试数据库链接")
|
||||
@PostMapping("/testConnect")
|
||||
@PreAuthorize("@el.check('database:testConnect')")
|
||||
public ResponseEntity<Object> testConnect(@Validated @RequestBody Database resources){
|
||||
return new ResponseEntity<>(databaseService.testConnection(resources),HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("执行SQL脚本")
|
||||
@ApiOperation(value = "执行SQL脚本")
|
||||
@PostMapping(value = "/upload")
|
||||
@PreAuthorize("@el.check('database:add')")
|
||||
public ResponseEntity<Object> uploadDatabase(@RequestBody MultipartFile file, HttpServletRequest request)throws Exception{
|
||||
String id = request.getParameter("id");
|
||||
Database database = databaseService.getById(id);
|
||||
String fileName;
|
||||
if(database != null){
|
||||
fileName = FileUtil.verifyFilename(file.getOriginalFilename());
|
||||
File executeFile = new File(fileSavePath+fileName);
|
||||
FileUtil.del(executeFile);
|
||||
file.transferTo(executeFile);
|
||||
String result = SqlUtils.executeFile(database.getJdbcUrl(), database.getUserName(), database.getPwd(), executeFile);
|
||||
return new ResponseEntity<>(result,HttpStatus.OK);
|
||||
}else{
|
||||
throw new BadRequestException("Database not exist");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.annotation.Log;
|
||||
import me.zhengjie.modules.maint.domain.Deploy;
|
||||
import me.zhengjie.modules.maint.domain.DeployHistory;
|
||||
import me.zhengjie.modules.maint.domain.dto.DeployQueryCriteria;
|
||||
import me.zhengjie.modules.maint.service.DeployService;
|
||||
import me.zhengjie.utils.FileUtil;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@RestController
|
||||
@Api(tags = "运维:部署管理")
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/deploy")
|
||||
public class DeployController {
|
||||
|
||||
private final String fileSavePath = FileUtil.getTmpDirPath()+"/";
|
||||
private final DeployService deployService;
|
||||
|
||||
@ApiOperation("导出部署数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('database:list')")
|
||||
public void exportDeployData(HttpServletResponse response, DeployQueryCriteria criteria) throws IOException {
|
||||
deployService.download(deployService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查询部署")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('deploy:list')")
|
||||
public ResponseEntity<PageResult<Deploy>> queryDeployData(DeployQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(deployService.queryAll(criteria, page),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("新增部署")
|
||||
@ApiOperation(value = "新增部署")
|
||||
@PostMapping
|
||||
@PreAuthorize("@el.check('deploy:add')")
|
||||
public ResponseEntity<Object> createDeploy(@Validated @RequestBody Deploy resources){
|
||||
deployService.create(resources);
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("修改部署")
|
||||
@ApiOperation(value = "修改部署")
|
||||
@PutMapping
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<Object> updateDeploy(@Validated @RequestBody Deploy resources){
|
||||
deployService.update(resources);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("删除部署")
|
||||
@ApiOperation(value = "删除部署")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('deploy:del')")
|
||||
public ResponseEntity<Object> deleteDeploy(@RequestBody Set<Long> ids){
|
||||
deployService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("上传文件部署")
|
||||
@ApiOperation(value = "上传文件部署")
|
||||
@PostMapping(value = "/upload")
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<Object> uploadDeploy(@RequestBody MultipartFile file, HttpServletRequest request)throws Exception{
|
||||
Long id = Long.valueOf(request.getParameter("id"));
|
||||
String fileName = "";
|
||||
if(file != null){
|
||||
fileName = FileUtil.verifyFilename(file.getOriginalFilename());
|
||||
File deployFile = new File(fileSavePath+fileName);
|
||||
FileUtil.del(deployFile);
|
||||
file.transferTo(deployFile);
|
||||
//文件下一步要根据文件名字来
|
||||
deployService.deploy(fileSavePath+fileName ,id);
|
||||
}else{
|
||||
System.out.println("没有找到相对应的文件");
|
||||
}
|
||||
System.out.println("文件上传的原名称为:"+ Objects.requireNonNull(file).getOriginalFilename());
|
||||
Map<String,Object> map = new HashMap<>(2);
|
||||
map.put("errno",0);
|
||||
map.put("id",fileName);
|
||||
return new ResponseEntity<>(map,HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("系统还原")
|
||||
@ApiOperation(value = "系统还原")
|
||||
@PostMapping(value = "/serverReduction")
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<String> serverReduction(@Validated @RequestBody DeployHistory resources){
|
||||
String result = deployService.serverReduction(resources);
|
||||
return new ResponseEntity<>(result,HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("服务运行状态")
|
||||
@ApiOperation(value = "服务运行状态")
|
||||
@PostMapping(value = "/serverStatus")
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<String> serverStatus(@Validated @RequestBody Deploy resources){
|
||||
String result = deployService.serverStatus(resources);
|
||||
return new ResponseEntity<>(result,HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("启动服务")
|
||||
@ApiOperation(value = "启动服务")
|
||||
@PostMapping(value = "/startServer")
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<String> startServer(@Validated @RequestBody Deploy resources){
|
||||
String result = deployService.startServer(resources);
|
||||
return new ResponseEntity<>(result,HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("停止服务")
|
||||
@ApiOperation(value = "停止服务")
|
||||
@PostMapping(value = "/stopServer")
|
||||
@PreAuthorize("@el.check('deploy:edit')")
|
||||
public ResponseEntity<String> stopServer(@Validated @RequestBody Deploy resources){
|
||||
String result = deployService.stopServer(resources);
|
||||
return new ResponseEntity<>(result,HttpStatus.OK);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.annotation.Log;
|
||||
import me.zhengjie.modules.maint.domain.DeployHistory;
|
||||
import me.zhengjie.modules.maint.domain.dto.DeployHistoryQueryCriteria;
|
||||
import me.zhengjie.modules.maint.service.DeployHistoryService;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Api(tags = "运维:部署历史管理")
|
||||
@RequestMapping("/api/deployHistory")
|
||||
public class DeployHistoryController {
|
||||
|
||||
private final DeployHistoryService deployhistoryService;
|
||||
|
||||
@ApiOperation("导出部署历史数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('deployHistory:list')")
|
||||
public void exportDeployHistory(HttpServletResponse response, DeployHistoryQueryCriteria criteria) throws IOException {
|
||||
deployhistoryService.download(deployhistoryService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查询部署历史")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('deployHistory:list')")
|
||||
public ResponseEntity<PageResult<DeployHistory>> queryDeployHistory(DeployHistoryQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(deployhistoryService.queryAll(criteria, page),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("删除DeployHistory")
|
||||
@ApiOperation(value = "删除部署历史")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('deployHistory:del')")
|
||||
public ResponseEntity<Object> deleteDeployHistory(@RequestBody Set<String> ids){
|
||||
deployhistoryService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.rest;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.annotation.Log;
|
||||
import me.zhengjie.modules.maint.domain.Server;
|
||||
import me.zhengjie.modules.maint.domain.dto.ServerQueryCriteria;
|
||||
import me.zhengjie.modules.maint.service.ServerService;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@RestController
|
||||
@Api(tags = "运维:服务器管理")
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/serverDeploy")
|
||||
public class ServerController {
|
||||
|
||||
private final ServerService serverService;
|
||||
|
||||
@ApiOperation("导出服务器数据")
|
||||
@GetMapping(value = "/download")
|
||||
@PreAuthorize("@el.check('serverDeploy:list')")
|
||||
public void exportServerDeploy(HttpServletResponse response, ServerQueryCriteria criteria) throws IOException {
|
||||
serverService.download(serverService.queryAll(criteria), response);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "查询服务器")
|
||||
@GetMapping
|
||||
@PreAuthorize("@el.check('serverDeploy:list')")
|
||||
public ResponseEntity<PageResult<Server>> queryServerDeploy(ServerQueryCriteria criteria){
|
||||
Page<Object> page = new Page<>(criteria.getPage(), criteria.getSize());
|
||||
return new ResponseEntity<>(serverService.queryAll(criteria, page),HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("新增服务器")
|
||||
@ApiOperation(value = "新增服务器")
|
||||
@PostMapping
|
||||
@PreAuthorize("@el.check('serverDeploy:add')")
|
||||
public ResponseEntity<Object> createServerDeploy(@Validated @RequestBody Server resources){
|
||||
serverService.create(resources);
|
||||
return new ResponseEntity<>(HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log("修改服务器")
|
||||
@ApiOperation(value = "修改服务器")
|
||||
@PutMapping
|
||||
@PreAuthorize("@el.check('serverDeploy:edit')")
|
||||
public ResponseEntity<Object> updateServerDeploy(@Validated @RequestBody Server resources){
|
||||
serverService.update(resources);
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log("删除服务器")
|
||||
@ApiOperation(value = "删除Server")
|
||||
@DeleteMapping
|
||||
@PreAuthorize("@el.check('serverDeploy:del')")
|
||||
public ResponseEntity<Object> deleteServerDeploy(@RequestBody Set<Long> ids){
|
||||
serverService.delete(ids);
|
||||
return new ResponseEntity<>(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log("测试连接服务器")
|
||||
@ApiOperation(value = "测试连接服务器")
|
||||
@PostMapping("/testConnect")
|
||||
@PreAuthorize("@el.check('serverDeploy:add')")
|
||||
public ResponseEntity<Object> testConnectServerDeploy(@Validated @RequestBody Server resources){
|
||||
return new ResponseEntity<>(serverService.testConnect(resources),HttpStatus.CREATED);
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import me.zhengjie.modules.maint.domain.App;
|
||||
import me.zhengjie.modules.maint.domain.dto.AppQueryCriteria;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
public interface AppService extends IService<App> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<App> queryAll(AppQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部数据
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<App> queryAll(AppQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(App resources);
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param resources /
|
||||
*/
|
||||
void update(App resources);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<Long> ids);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
* @param apps /
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void download(List<App> apps, HttpServletResponse response) throws IOException;
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import me.zhengjie.modules.maint.domain.Database;
|
||||
import me.zhengjie.modules.maint.domain.dto.DatabaseQueryCriteria;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
public interface DatabaseService extends IService<Database> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<Database> queryAll(DatabaseQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<Database> queryAll(DatabaseQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(Database resources);
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param resources /
|
||||
*/
|
||||
void update(Database resources);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<String> ids);
|
||||
|
||||
/**
|
||||
* 测试连接
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
boolean testConnection(Database resources);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
* @param queryAll /
|
||||
* @param response /
|
||||
* @throws IOException e
|
||||
*/
|
||||
void download(List<Database> queryAll, HttpServletResponse response) throws IOException;
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import me.zhengjie.modules.maint.domain.DeployHistory;
|
||||
import me.zhengjie.modules.maint.domain.dto.DeployHistoryQueryCriteria;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
*/
|
||||
public interface DeployHistoryService extends IService<DeployHistory> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<DeployHistory> queryAll(DeployHistoryQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<DeployHistory> queryAll(DeployHistoryQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(DeployHistory resources);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<String> ids);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
* @param queryAll /
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void download(List<DeployHistory> queryAll, HttpServletResponse response) throws IOException;
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import me.zhengjie.modules.maint.domain.Deploy;
|
||||
import me.zhengjie.modules.maint.domain.DeployHistory;
|
||||
import me.zhengjie.modules.maint.domain.dto.DeployQueryCriteria;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
public interface DeployService extends IService<Deploy> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<Deploy> queryAll(DeployQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部数据
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<Deploy> queryAll(DeployQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(Deploy resources);
|
||||
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param resources /
|
||||
*/
|
||||
void update(Deploy resources);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<Long> ids);
|
||||
|
||||
/**
|
||||
* 部署服务
|
||||
* @param fileSavePath /
|
||||
* @param appId /
|
||||
*/
|
||||
void deploy(String fileSavePath, Long appId);
|
||||
|
||||
/**
|
||||
* 查询部署状态
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
String serverStatus(Deploy resources);
|
||||
/**
|
||||
* 启动服务
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
String startServer(Deploy resources);
|
||||
/**
|
||||
* 停止服务
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
String stopServer(Deploy resources);
|
||||
|
||||
/**
|
||||
* 停止服务
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
String serverReduction(DeployHistory resources);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
* @param queryAll /
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void download(List<Deploy> queryAll, HttpServletResponse response) throws IOException;
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import me.zhengjie.modules.maint.domain.Server;
|
||||
import me.zhengjie.modules.maint.domain.dto.ServerQueryCriteria;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
public interface ServerService extends IService<Server> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param criteria 条件
|
||||
* @param page 分页参数
|
||||
* @return /
|
||||
*/
|
||||
PageResult<Server> queryAll(ServerQueryCriteria criteria, Page<Object> page);
|
||||
|
||||
/**
|
||||
* 查询全部数据
|
||||
* @param criteria 条件
|
||||
* @return /
|
||||
*/
|
||||
List<Server> queryAll(ServerQueryCriteria criteria);
|
||||
|
||||
/**
|
||||
* 创建
|
||||
* @param resources /
|
||||
*/
|
||||
void create(Server resources);
|
||||
|
||||
/**
|
||||
* 编辑
|
||||
* @param resources /
|
||||
*/
|
||||
void update(Server resources);
|
||||
|
||||
/**
|
||||
* 删除
|
||||
* @param ids /
|
||||
*/
|
||||
void delete(Set<Long> ids);
|
||||
|
||||
/**
|
||||
* 根据IP查询
|
||||
*
|
||||
* @param ip /
|
||||
* @return /
|
||||
*/
|
||||
Server findByIp(String ip);
|
||||
|
||||
/**
|
||||
* 测试连接
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
Boolean testConnect(Server resources);
|
||||
|
||||
/**
|
||||
* 导出数据
|
||||
* @param queryAll /
|
||||
* @param response /
|
||||
* @throws IOException /
|
||||
*/
|
||||
void download(List<Server> queryAll, HttpServletResponse response) throws IOException;
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.modules.maint.domain.App;
|
||||
import me.zhengjie.modules.maint.domain.dto.AppQueryCriteria;
|
||||
import me.zhengjie.modules.maint.mapper.AppMapper;
|
||||
import me.zhengjie.modules.maint.mapper.DeployMapper;
|
||||
import me.zhengjie.modules.maint.mapper.DeployServerMapper;
|
||||
import me.zhengjie.modules.maint.service.AppService;
|
||||
import me.zhengjie.utils.FileUtil;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
import me.zhengjie.utils.PageUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class AppServiceImpl extends ServiceImpl<AppMapper, App> implements AppService {
|
||||
|
||||
private final AppMapper appMapper;
|
||||
private final DeployMapper deployMapper;
|
||||
private final DeployServerMapper deployServerMapper;
|
||||
|
||||
@Override
|
||||
public PageResult<App> queryAll(AppQueryCriteria criteria, Page<Object> page){
|
||||
return PageUtil.toPage(appMapper.queryAll(criteria, page));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<App> queryAll(AppQueryCriteria criteria){
|
||||
return appMapper.queryAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(App resources) {
|
||||
verification(resources);
|
||||
save(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(App resources) {
|
||||
verification(resources);
|
||||
App app = getById(resources.getId());
|
||||
app.copy(resources);
|
||||
saveOrUpdate(app);
|
||||
}
|
||||
|
||||
private void verification(App resources){
|
||||
String opt = "/opt";
|
||||
String home = "/home";
|
||||
if (!(resources.getUploadPath().startsWith(opt) || resources.getUploadPath().startsWith(home))) {
|
||||
throw new BadRequestException("文件只能上传在opt目录或者home目录 ");
|
||||
}
|
||||
if (!(resources.getDeployPath().startsWith(opt) || resources.getDeployPath().startsWith(home))) {
|
||||
throw new BadRequestException("文件只能部署在opt目录或者home目录 ");
|
||||
}
|
||||
if (!(resources.getBackupPath().startsWith(opt) || resources.getBackupPath().startsWith(home))) {
|
||||
throw new BadRequestException("文件只能备份在opt目录或者home目录 ");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<Long> ids) {
|
||||
// 删除应用
|
||||
removeBatchByIds(ids);
|
||||
// 删除部署
|
||||
Set<Long> deployIds = deployMapper.getIdByAppIds(ids);
|
||||
if(CollUtil.isNotEmpty(deployIds)){
|
||||
deployServerMapper.deleteByDeployIds(deployIds);
|
||||
deployMapper.deleteBatchIds(deployIds);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<App> apps, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (App app : apps) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("应用名称", app.getName());
|
||||
map.put("端口", app.getPort());
|
||||
map.put("上传目录", app.getUploadPath());
|
||||
map.put("部署目录", app.getDeployPath());
|
||||
map.put("备份目录", app.getBackupPath());
|
||||
map.put("启动脚本", app.getStartScript());
|
||||
map.put("部署脚本", app.getDeployScript());
|
||||
map.put("创建日期", app.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.modules.maint.domain.Database;
|
||||
import me.zhengjie.modules.maint.domain.dto.DatabaseQueryCriteria;
|
||||
import me.zhengjie.modules.maint.mapper.DatabaseMapper;
|
||||
import me.zhengjie.modules.maint.service.DatabaseService;
|
||||
import me.zhengjie.modules.maint.util.SqlUtils;
|
||||
import me.zhengjie.utils.FileUtil;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
import me.zhengjie.utils.PageUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DatabaseServiceImpl extends ServiceImpl<DatabaseMapper, Database> implements DatabaseService {
|
||||
|
||||
private final DatabaseMapper databaseMapper;
|
||||
|
||||
@Override
|
||||
public PageResult<Database> queryAll(DatabaseQueryCriteria criteria, Page<Object> page){
|
||||
return PageUtil.toPage(databaseMapper.findAll(criteria, page));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Database> queryAll(DatabaseQueryCriteria criteria){
|
||||
return databaseMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(Database resources) {
|
||||
resources.setId(IdUtil.simpleUUID());
|
||||
save(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(Database resources) {
|
||||
Database database = getById(resources.getId());
|
||||
database.copy(resources);
|
||||
saveOrUpdate(database);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<String> ids) {
|
||||
removeBatchByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testConnection(Database resources) {
|
||||
try {
|
||||
return SqlUtils.testConnection(resources.getJdbcUrl(), resources.getUserName(), resources.getPwd());
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<Database> databases, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (Database database : databases) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("数据库名称", database.getName());
|
||||
map.put("数据库连接地址", database.getJdbcUrl());
|
||||
map.put("用户名", database.getUserName());
|
||||
map.put("创建日期", database.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.modules.maint.domain.DeployHistory;
|
||||
import me.zhengjie.modules.maint.domain.dto.DeployHistoryQueryCriteria;
|
||||
import me.zhengjie.modules.maint.mapper.DeployHistoryMapper;
|
||||
import me.zhengjie.modules.maint.service.DeployHistoryService;
|
||||
import me.zhengjie.utils.DateUtil;
|
||||
import me.zhengjie.utils.FileUtil;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
import me.zhengjie.utils.PageUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DeployHistoryServiceImpl extends ServiceImpl<DeployHistoryMapper, DeployHistory> implements DeployHistoryService {
|
||||
|
||||
private final DeployHistoryMapper deployhistoryMapper;
|
||||
|
||||
@Override
|
||||
public PageResult<DeployHistory> queryAll(DeployHistoryQueryCriteria criteria, Page<Object> page){
|
||||
return PageUtil.toPage(deployhistoryMapper.findAll(criteria, page));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeployHistory> queryAll(DeployHistoryQueryCriteria criteria){
|
||||
return deployhistoryMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(DeployHistory resources) {
|
||||
resources.setId(IdUtil.simpleUUID());
|
||||
resources.setDeployDate(DateUtil.getTimeStamp());
|
||||
save(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<String> ids) {
|
||||
removeBatchByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<DeployHistory> deployHistories, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (DeployHistory deployHistory : deployHistories) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("部署编号", deployHistory.getDeployId());
|
||||
map.put("应用名称", deployHistory.getAppName());
|
||||
map.put("部署IP", deployHistory.getIp());
|
||||
map.put("部署时间", deployHistory.getDeployDate());
|
||||
map.put("部署人员", deployHistory.getDeployUser());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
@ -0,0 +1,429 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service.impl;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.exception.BadRequestException;
|
||||
import me.zhengjie.modules.maint.domain.App;
|
||||
import me.zhengjie.modules.maint.domain.Deploy;
|
||||
import me.zhengjie.modules.maint.domain.DeployHistory;
|
||||
import me.zhengjie.modules.maint.domain.Server;
|
||||
import me.zhengjie.modules.maint.domain.dto.DeployQueryCriteria;
|
||||
import me.zhengjie.modules.maint.mapper.DeployMapper;
|
||||
import me.zhengjie.modules.maint.mapper.DeployServerMapper;
|
||||
import me.zhengjie.modules.maint.service.DeployHistoryService;
|
||||
import me.zhengjie.modules.maint.service.DeployService;
|
||||
import me.zhengjie.modules.maint.service.ServerService;
|
||||
import me.zhengjie.modules.maint.util.ExecuteShellUtil;
|
||||
import me.zhengjie.modules.maint.util.ScpClientUtil;
|
||||
import me.zhengjie.modules.maint.domain.enums.MsgType;
|
||||
import me.zhengjie.modules.maint.service.websocket.SocketMsg;
|
||||
import me.zhengjie.modules.maint.service.websocket.WebSocketServer;
|
||||
import me.zhengjie.utils.FileUtil;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
import me.zhengjie.utils.PageUtil;
|
||||
import me.zhengjie.utils.SecurityUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class DeployServiceImpl extends ServiceImpl<DeployMapper, Deploy> implements DeployService {
|
||||
|
||||
private final String FILE_SEPARATOR = "/";
|
||||
private final DeployMapper deployMapper;
|
||||
private final DeployServerMapper deployServerMapper;
|
||||
private final ServerService serverService;
|
||||
private final DeployHistoryService deployHistoryService;
|
||||
/**
|
||||
* 循环次数
|
||||
*/
|
||||
private final Integer count = 30;
|
||||
|
||||
@Override
|
||||
public PageResult<Deploy> queryAll(DeployQueryCriteria criteria, Page<Object> page) {
|
||||
criteria.setOffset(page.offset());
|
||||
List<Deploy> deploys = deployMapper.findAll(criteria);
|
||||
Long total = deployMapper.countAll(criteria);
|
||||
return PageUtil.toPage(deploys, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Deploy> queryAll(DeployQueryCriteria criteria) {
|
||||
return deployMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(Deploy resources) {
|
||||
resources.setAppId(resources.getApp().getId());
|
||||
save(resources);
|
||||
// 保存关联关系
|
||||
deployServerMapper.insertData(resources.getId(), resources.getDeploys());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(Deploy resources) {
|
||||
Deploy deploy = getById(resources.getId());
|
||||
deploy.copy(resources);
|
||||
saveOrUpdate(deploy);
|
||||
// 更新关联关系
|
||||
deployServerMapper.deleteByDeployId(resources.getId());
|
||||
deployServerMapper.insertData(resources.getId(), resources.getDeploys());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<Long> ids) {
|
||||
removeBatchByIds(ids);
|
||||
// 删除关联
|
||||
deployServerMapper.deleteByDeployIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deploy(String fileSavePath, Long id) {
|
||||
deployApp(fileSavePath, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileSavePath 本机路径
|
||||
* @param id ID
|
||||
*/
|
||||
private void deployApp(String fileSavePath, Long id) {
|
||||
Deploy deploy = deployMapper.getDeployById(id);
|
||||
if (deploy == null) {
|
||||
sendMsg("部署信息不存在", MsgType.ERROR);
|
||||
throw new BadRequestException("部署信息不存在");
|
||||
}
|
||||
App app = deploy.getApp();
|
||||
if (app == null) {
|
||||
sendMsg("包对应应用信息不存在", MsgType.ERROR);
|
||||
throw new BadRequestException("包对应应用信息不存在");
|
||||
}
|
||||
int port = app.getPort();
|
||||
//这个是服务器部署路径
|
||||
String uploadPath = app.getUploadPath();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String msg;
|
||||
Set<Server> deploys = deploy.getDeploys();
|
||||
for (Server server : deploys) {
|
||||
String ip = server.getIp();
|
||||
ExecuteShellUtil executeShellUtil = getExecuteShellUtil(ip);
|
||||
//判断是否第一次部署
|
||||
boolean flag = checkFile(executeShellUtil, app);
|
||||
//第一步要确认服务器上有这个目录
|
||||
executeShellUtil.execute("mkdir -p " + app.getUploadPath());
|
||||
executeShellUtil.execute("mkdir -p " + app.getBackupPath());
|
||||
executeShellUtil.execute("mkdir -p " + app.getDeployPath());
|
||||
//上传文件
|
||||
msg = String.format("登陆到服务器:%s", ip);
|
||||
ScpClientUtil scpClientUtil = getScpClientUtil(ip);
|
||||
log.info(msg);
|
||||
sendMsg(msg, MsgType.INFO);
|
||||
msg = String.format("上传文件到服务器:%s<br>目录:%s下,请稍等...", ip, uploadPath);
|
||||
sendMsg(msg, MsgType.INFO);
|
||||
scpClientUtil.putFile(fileSavePath, uploadPath);
|
||||
if (flag) {
|
||||
sendMsg("停止原来应用", MsgType.INFO);
|
||||
//停止应用
|
||||
stopApp(port, executeShellUtil);
|
||||
sendMsg("备份原来应用", MsgType.INFO);
|
||||
//备份应用
|
||||
backupApp(executeShellUtil, ip, app.getDeployPath()+FILE_SEPARATOR, app.getName(), app.getBackupPath()+FILE_SEPARATOR, id);
|
||||
}
|
||||
sendMsg("部署应用", MsgType.INFO);
|
||||
//部署文件,并启动应用
|
||||
String deployScript = app.getDeployScript();
|
||||
executeShellUtil.execute(deployScript);
|
||||
sleep(3);
|
||||
sendMsg("应用部署中,请耐心等待部署结果,或者稍后手动查看部署状态", MsgType.INFO);
|
||||
int i = 0;
|
||||
boolean result = false;
|
||||
// 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败
|
||||
while (i++ < count){
|
||||
result = checkIsRunningStatus(port, executeShellUtil);
|
||||
if(result){
|
||||
break;
|
||||
}
|
||||
// 休眠6秒
|
||||
sleep(6);
|
||||
}
|
||||
sb.append("服务器:").append(server.getName()).append("<br>应用:").append(app.getName());
|
||||
sendResultMsg(result, sb);
|
||||
executeShellUtil.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void sleep(int second) {
|
||||
try {
|
||||
Thread.sleep(second * 1000L);
|
||||
} catch (InterruptedException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
private void backupApp(ExecuteShellUtil executeShellUtil, String ip, String fileSavePath, String appName, String backupPath, Long id) {
|
||||
String deployDate = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
backupPath += appName + FILE_SEPARATOR + deployDate + "\n";
|
||||
sb.append("mkdir -p ").append(backupPath);
|
||||
sb.append("mv -f ").append(fileSavePath);
|
||||
sb.append(appName).append(" ").append(backupPath);
|
||||
log.info("备份应用脚本:" + sb.toString());
|
||||
executeShellUtil.execute(sb.toString());
|
||||
//还原信息入库
|
||||
DeployHistory deployHistory = new DeployHistory();
|
||||
deployHistory.setAppName(appName);
|
||||
deployHistory.setDeployUser(SecurityUtils.getCurrentUsername());
|
||||
deployHistory.setIp(ip);
|
||||
deployHistory.setDeployId(id);
|
||||
deployHistoryService.create(deployHistory);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停App
|
||||
*
|
||||
* @param port 端口
|
||||
* @param executeShellUtil /
|
||||
*/
|
||||
private void stopApp(int port, ExecuteShellUtil executeShellUtil) {
|
||||
//发送停止命令
|
||||
executeShellUtil.execute(String.format("lsof -i :%d|grep -v \"PID\"|awk '{print \"kill -9\",$2}'|sh", port));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定端口程序是否在运行
|
||||
*
|
||||
* @param port 端口
|
||||
* @param executeShellUtil /
|
||||
* @return true 正在运行 false 已经停止
|
||||
*/
|
||||
private boolean checkIsRunningStatus(int port, ExecuteShellUtil executeShellUtil) {
|
||||
String result = executeShellUtil.executeForResult(String.format("fuser -n tcp %d", port));
|
||||
return result.indexOf("/tcp:")>0;
|
||||
}
|
||||
|
||||
private void sendMsg(String msg, MsgType msgType) {
|
||||
try {
|
||||
WebSocketServer.sendInfo(new SocketMsg(msg, msgType), "deploy");
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serverStatus(Deploy resources) {
|
||||
Set<Server> servers = resources.getDeploys();
|
||||
App app = resources.getApp();
|
||||
for (Server server : servers) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ExecuteShellUtil executeShellUtil = getExecuteShellUtil(server.getIp());
|
||||
sb.append("服务器:").append(server.getName()).append("<br>应用:").append(app.getName());
|
||||
boolean result = checkIsRunningStatus(app.getPort(), executeShellUtil);
|
||||
if (result) {
|
||||
sb.append("<br>正在运行");
|
||||
sendMsg(sb.toString(), MsgType.INFO);
|
||||
} else {
|
||||
sb.append("<br>已停止!");
|
||||
sendMsg(sb.toString(), MsgType.ERROR);
|
||||
}
|
||||
log.info(sb.toString());
|
||||
executeShellUtil.close();
|
||||
}
|
||||
return "执行完毕";
|
||||
}
|
||||
|
||||
private boolean checkFile(ExecuteShellUtil executeShellUtil, App app) {
|
||||
String result = executeShellUtil.executeForResult("find " + app.getDeployPath() + " -name " + app.getName());
|
||||
return result.indexOf(app.getName())>0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动服务
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
@Override
|
||||
public String startServer(Deploy resources) {
|
||||
Set<Server> deploys = resources.getDeploys();
|
||||
App app = resources.getApp();
|
||||
for (Server deploy : deploys) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ExecuteShellUtil executeShellUtil = getExecuteShellUtil(deploy.getIp());
|
||||
//为了防止重复启动,这里先停止应用
|
||||
stopApp(app.getPort(), executeShellUtil);
|
||||
sb.append("服务器:").append(deploy.getName()).append("<br>应用:").append(app.getName());
|
||||
sendMsg("下发启动命令", MsgType.INFO);
|
||||
executeShellUtil.execute(app.getStartScript());
|
||||
sleep(3);
|
||||
sendMsg("应用启动中,请耐心等待启动结果,或者稍后手动查看运行状态", MsgType.INFO);
|
||||
int i = 0;
|
||||
boolean result = false;
|
||||
// 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败
|
||||
while (i++ < count){
|
||||
result = checkIsRunningStatus(app.getPort(), executeShellUtil);
|
||||
if(result){
|
||||
break;
|
||||
}
|
||||
// 休眠6秒
|
||||
sleep(6);
|
||||
}
|
||||
sendResultMsg(result, sb);
|
||||
log.info(sb.toString());
|
||||
executeShellUtil.close();
|
||||
}
|
||||
return "执行完毕";
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止服务
|
||||
* @param resources /
|
||||
* @return /
|
||||
*/
|
||||
@Override
|
||||
public String stopServer(Deploy resources) {
|
||||
Set<Server> deploys = resources.getDeploys();
|
||||
App app = resources.getApp();
|
||||
for (Server deploy : deploys) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ExecuteShellUtil executeShellUtil = getExecuteShellUtil(deploy.getIp());
|
||||
sb.append("服务器:").append(deploy.getName()).append("<br>应用:").append(app.getName());
|
||||
sendMsg("下发停止命令", MsgType.INFO);
|
||||
//停止应用
|
||||
stopApp(app.getPort(), executeShellUtil);
|
||||
sleep(1);
|
||||
boolean result = checkIsRunningStatus(app.getPort(), executeShellUtil);
|
||||
if (result) {
|
||||
sb.append("<br>关闭失败!");
|
||||
sendMsg(sb.toString(), MsgType.ERROR);
|
||||
} else {
|
||||
sb.append("<br>关闭成功!");
|
||||
sendMsg(sb.toString(), MsgType.INFO);
|
||||
}
|
||||
log.info(sb.toString());
|
||||
executeShellUtil.close();
|
||||
}
|
||||
return "执行完毕";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serverReduction(DeployHistory resources) {
|
||||
Long deployId = resources.getDeployId();
|
||||
Deploy deployInfo = getById(deployId);
|
||||
String deployDate = DateUtil.format(resources.getDeployDate(), DatePattern.PURE_DATETIME_PATTERN);
|
||||
App app = deployInfo.getApp();
|
||||
if (app == null) {
|
||||
sendMsg("应用信息不存在:" + resources.getAppName(), MsgType.ERROR);
|
||||
throw new BadRequestException("应用信息不存在:" + resources.getAppName());
|
||||
}
|
||||
String backupPath = app.getBackupPath()+FILE_SEPARATOR;
|
||||
backupPath += resources.getAppName() + FILE_SEPARATOR + deployDate;
|
||||
//这个是服务器部署路径
|
||||
String deployPath = app.getDeployPath();
|
||||
String ip = resources.getIp();
|
||||
ExecuteShellUtil executeShellUtil = getExecuteShellUtil(ip);
|
||||
String msg;
|
||||
|
||||
msg = String.format("登陆到服务器:%s", ip);
|
||||
log.info(msg);
|
||||
sendMsg(msg, MsgType.INFO);
|
||||
sendMsg("停止原来应用", MsgType.INFO);
|
||||
//停止应用
|
||||
stopApp(app.getPort(), executeShellUtil);
|
||||
//删除原来应用
|
||||
sendMsg("删除应用", MsgType.INFO);
|
||||
executeShellUtil.execute("rm -rf " + deployPath + FILE_SEPARATOR + resources.getAppName());
|
||||
//还原应用
|
||||
sendMsg("还原应用", MsgType.INFO);
|
||||
executeShellUtil.execute("cp -r " + backupPath + "/. " + deployPath);
|
||||
sendMsg("启动应用", MsgType.INFO);
|
||||
executeShellUtil.execute(app.getStartScript());
|
||||
sendMsg("应用启动中,请耐心等待启动结果,或者稍后手动查看启动状态", MsgType.INFO);
|
||||
int i = 0;
|
||||
boolean result = false;
|
||||
// 由于启动应用需要时间,所以需要循环获取状态,如果超过30次,则认为是启动失败
|
||||
while (i++ < count){
|
||||
result = checkIsRunningStatus(app.getPort(), executeShellUtil);
|
||||
if(result){
|
||||
break;
|
||||
}
|
||||
// 休眠6秒
|
||||
sleep(6);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("服务器:").append(ip).append("<br>应用:").append(resources.getAppName());
|
||||
sendResultMsg(result, sb);
|
||||
executeShellUtil.close();
|
||||
return "";
|
||||
}
|
||||
|
||||
private ExecuteShellUtil getExecuteShellUtil(String ip) {
|
||||
Server server = serverService.findByIp(ip);
|
||||
if (server == null) {
|
||||
sendMsg("IP对应服务器信息不存在:" + ip, MsgType.ERROR);
|
||||
throw new BadRequestException("IP对应服务器信息不存在:" + ip);
|
||||
}
|
||||
return new ExecuteShellUtil(ip, server.getAccount(), server.getPassword(), server.getPort());
|
||||
}
|
||||
|
||||
private ScpClientUtil getScpClientUtil(String ip) {
|
||||
Server server = serverService.findByIp(ip);
|
||||
if (server == null) {
|
||||
sendMsg("IP对应服务器信息不存在:" + ip, MsgType.ERROR);
|
||||
throw new BadRequestException("IP对应服务器信息不存在:" + ip);
|
||||
}
|
||||
return ScpClientUtil.getInstance(ip, server.getPort(), server.getAccount(), server.getPassword());
|
||||
}
|
||||
|
||||
private void sendResultMsg(boolean result, StringBuilder sb) {
|
||||
if (result) {
|
||||
sb.append("<br>启动成功!");
|
||||
sendMsg(sb.toString(), MsgType.INFO);
|
||||
} else {
|
||||
sb.append("<br>启动失败!");
|
||||
sendMsg(sb.toString(), MsgType.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<Deploy> deploys, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (Deploy deploy : deploys) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("应用名称", deploy.getApp().getName());
|
||||
map.put("服务器", deploy.getServers());
|
||||
map.put("部署日期", deploy.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.zhengjie.modules.maint.domain.Server;
|
||||
import me.zhengjie.modules.maint.domain.dto.ServerQueryCriteria;
|
||||
import me.zhengjie.modules.maint.mapper.DeployServerMapper;
|
||||
import me.zhengjie.modules.maint.mapper.ServerMapper;
|
||||
import me.zhengjie.modules.maint.service.ServerService;
|
||||
import me.zhengjie.modules.maint.util.ExecuteShellUtil;
|
||||
import me.zhengjie.utils.FileUtil;
|
||||
import me.zhengjie.utils.PageResult;
|
||||
import me.zhengjie.utils.PageUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author zhanghouying
|
||||
* @date 2019-08-24
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ServerServiceImpl extends ServiceImpl<ServerMapper, Server> implements ServerService {
|
||||
|
||||
private final ServerMapper serverMapper;
|
||||
private final DeployServerMapper deployServerMapper;
|
||||
|
||||
@Override
|
||||
public PageResult<Server> queryAll(ServerQueryCriteria criteria, Page<Object> page){
|
||||
return PageUtil.toPage(serverMapper.findAll(criteria, page));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Server> queryAll(ServerQueryCriteria criteria){
|
||||
return serverMapper.findAll(criteria);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Server findByIp(String ip) {
|
||||
return serverMapper.findByIp(ip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean testConnect(Server resources) {
|
||||
ExecuteShellUtil executeShellUtil = null;
|
||||
try {
|
||||
executeShellUtil = new ExecuteShellUtil(resources.getIp(), resources.getAccount(), resources.getPassword(),resources.getPort());
|
||||
return executeShellUtil.execute("ls")==0;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}finally {
|
||||
if (executeShellUtil != null) {
|
||||
executeShellUtil.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void create(Server resources) {
|
||||
save(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(Server resources) {
|
||||
Server server = getById(resources.getId());
|
||||
server.copy(resources);
|
||||
saveOrUpdate(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Set<Long> ids) {
|
||||
removeBatchByIds(ids);
|
||||
// 删除与之关联的服务
|
||||
deployServerMapper.deleteByServerIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(List<Server> servers, HttpServletResponse response) throws IOException {
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (Server deploy : servers) {
|
||||
Map<String,Object> map = new LinkedHashMap<>();
|
||||
map.put("服务器名称", deploy.getName());
|
||||
map.put("服务器IP", deploy.getIp());
|
||||
map.put("端口", deploy.getPort());
|
||||
map.put("账号", deploy.getAccount());
|
||||
map.put("创建日期", deploy.getCreateTime());
|
||||
list.add(map);
|
||||
}
|
||||
FileUtil.downloadExcel(list, response);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service.websocket;
|
||||
|
||||
import lombok.Data;
|
||||
import me.zhengjie.modules.maint.domain.enums.MsgType;
|
||||
|
||||
/**
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-10 9:55
|
||||
*/
|
||||
@Data
|
||||
public class SocketMsg {
|
||||
private String msg;
|
||||
private MsgType msgType;
|
||||
|
||||
public SocketMsg(String msg, MsgType msgType) {
|
||||
this.msg = msg;
|
||||
this.msgType = msgType;
|
||||
}
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.service.websocket;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.websocket.*;
|
||||
import javax.websocket.server.PathParam;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-10 15:46
|
||||
*/
|
||||
@ServerEndpoint("/webSocket/{sid}")
|
||||
@Slf4j
|
||||
@Component
|
||||
public class WebSocketServer {
|
||||
|
||||
/**
|
||||
* concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
|
||||
*/
|
||||
private static final CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
|
||||
|
||||
/**
|
||||
* 与某个客户端的连接会话,需要通过它来给客户端发送数据
|
||||
*/
|
||||
private Session session;
|
||||
|
||||
/**
|
||||
* 接收sid
|
||||
*/
|
||||
private String sid="";
|
||||
/**
|
||||
* 连接建立成功调用的方法
|
||||
* */
|
||||
@OnOpen
|
||||
public void onOpen(Session session,@PathParam("sid") String sid) {
|
||||
this.session = session;
|
||||
//如果存在就先删除一个,防止重复推送消息
|
||||
webSocketSet.removeIf(webSocket -> webSocket.sid.equals(sid));
|
||||
webSocketSet.add(this);
|
||||
this.sid=sid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接关闭调用的方法
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose() {
|
||||
webSocketSet.remove(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 收到客户端消息后调用的方法
|
||||
* @param message 客户端发送过来的消息*/
|
||||
@OnMessage
|
||||
public void onMessage(String message, Session session) {
|
||||
log.info("收到来"+sid+"的信息:"+message);
|
||||
//群发消息
|
||||
for (WebSocketServer item : webSocketSet) {
|
||||
try {
|
||||
item.sendMessage(message);
|
||||
} catch (IOException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Session session, Throwable error) {
|
||||
log.error("发生错误", error);
|
||||
}
|
||||
/**
|
||||
* 实现服务器主动推送
|
||||
*/
|
||||
private void sendMessage(String message) throws IOException {
|
||||
this.session.getBasicRemote().sendText(message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 群发自定义消息
|
||||
* */
|
||||
public static void sendInfo(SocketMsg socketMsg,@PathParam("sid") String sid) throws IOException {
|
||||
String message = JSON.toJSONString(socketMsg);
|
||||
log.info("推送消息到"+sid+",推送内容:"+message);
|
||||
for (WebSocketServer item : webSocketSet) {
|
||||
try {
|
||||
//这里可以设定只推送给这个sid的,为null则全部推送
|
||||
if(sid==null) {
|
||||
item.sendMessage(message);
|
||||
}else if(item.sid.equals(sid)){
|
||||
item.sendMessage(message);
|
||||
}
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
WebSocketServer that = (WebSocketServer) o;
|
||||
return Objects.equals(session, that.session) &&
|
||||
Objects.equals(sid, that.sid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(session, sid);
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.util;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.jcraft.jsch.ChannelShell;
|
||||
import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.Session;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* 执行shell命令
|
||||
*
|
||||
* @author ZhangHouYing
|
||||
* @date 2019/8/10
|
||||
*/
|
||||
@Slf4j
|
||||
public class ExecuteShellUtil {
|
||||
|
||||
private Vector<String> stdout;
|
||||
|
||||
Session session;
|
||||
|
||||
public ExecuteShellUtil(final String ipAddress, final String username, final String password,int port) {
|
||||
try {
|
||||
JSch jsch = new JSch();
|
||||
session = jsch.getSession(username, ipAddress, port);
|
||||
session.setPassword(password);
|
||||
session.setConfig("StrictHostKeyChecking", "no");
|
||||
session.connect(3000);
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public int execute(final String command) {
|
||||
int returnCode = 0;
|
||||
ChannelShell channel = null;
|
||||
PrintWriter printWriter = null;
|
||||
BufferedReader input = null;
|
||||
stdout = new Vector<>();
|
||||
try {
|
||||
channel = (ChannelShell) session.openChannel("shell");
|
||||
channel.connect();
|
||||
input = new BufferedReader(new InputStreamReader(channel.getInputStream()));
|
||||
printWriter = new PrintWriter(channel.getOutputStream());
|
||||
printWriter.println(command);
|
||||
printWriter.println("exit");
|
||||
printWriter.flush();
|
||||
log.info("The remote command is: ");
|
||||
String line;
|
||||
while ((line = input.readLine()) != null) {
|
||||
stdout.add(line);
|
||||
System.out.println(line);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(),e);
|
||||
return -1;
|
||||
}finally {
|
||||
IoUtil.close(printWriter);
|
||||
IoUtil.close(input);
|
||||
if (channel != null) {
|
||||
channel.disconnect();
|
||||
}
|
||||
}
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
public void close(){
|
||||
if (session != null) {
|
||||
session.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public String executeForResult(String command) {
|
||||
execute(command);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String str : stdout) {
|
||||
sb.append(str);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.util;
|
||||
|
||||
import ch.ethz.ssh2.Connection;
|
||||
import ch.ethz.ssh2.SCPClient;
|
||||
import com.google.common.collect.Maps;
|
||||
import me.zhengjie.utils.StringUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 远程执行linux命令
|
||||
* @author ZhangHouYing
|
||||
* @date 2019-08-10 10:06
|
||||
*/
|
||||
public class ScpClientUtil {
|
||||
|
||||
private final String ip;
|
||||
private final int port;
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
static private final Map<String,ScpClientUtil> instance = Maps.newHashMap();
|
||||
|
||||
static synchronized public ScpClientUtil getInstance(String ip, int port, String username, String password) {
|
||||
instance.computeIfAbsent(ip, i -> new ScpClientUtil(i, port, username, password));
|
||||
return instance.get(ip);
|
||||
}
|
||||
|
||||
public ScpClientUtil(String ip, int port, String username, String password) {
|
||||
this.ip = ip;
|
||||
this.port = port;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public void getFile(String remoteFile, String localTargetDirectory) {
|
||||
Connection conn = new Connection(ip, port);
|
||||
try {
|
||||
conn.connect();
|
||||
boolean isAuthenticated = conn.authenticateWithPassword(username, password);
|
||||
if (!isAuthenticated) {
|
||||
System.err.println("authentication failed");
|
||||
}
|
||||
SCPClient client = new SCPClient(conn);
|
||||
client.get(remoteFile, localTargetDirectory);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(SCPClient.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}finally{
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void putFile(String localFile, String remoteTargetDirectory) {
|
||||
putFile(localFile, null, remoteTargetDirectory);
|
||||
}
|
||||
|
||||
public void putFile(String localFile, String remoteFileName, String remoteTargetDirectory) {
|
||||
putFile(localFile, remoteFileName, remoteTargetDirectory,null);
|
||||
}
|
||||
|
||||
public void putFile(String localFile, String remoteFileName, String remoteTargetDirectory, String mode) {
|
||||
Connection conn = new Connection(ip, port);
|
||||
try {
|
||||
conn.connect();
|
||||
boolean isAuthenticated = conn.authenticateWithPassword(username, password);
|
||||
if (!isAuthenticated) {
|
||||
System.err.println("authentication failed");
|
||||
}
|
||||
SCPClient client = new SCPClient(conn);
|
||||
if (StringUtils.isBlank(mode)) {
|
||||
mode = "0600";
|
||||
}
|
||||
if (remoteFileName == null) {
|
||||
client.put(localFile, remoteTargetDirectory);
|
||||
} else {
|
||||
client.put(localFile, remoteFileName, remoteTargetDirectory, mode);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ScpClientUtil.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}finally{
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Zheng Jie
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package me.zhengjie.modules.maint.util;
|
||||
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.util.StringUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.modules.maint.domain.enums.DataTypeEnum;
|
||||
import me.zhengjie.utils.CloseUtil;
|
||||
import javax.sql.DataSource;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author /
|
||||
*/
|
||||
@Slf4j
|
||||
public class SqlUtils {
|
||||
|
||||
/**
|
||||
* 获取数据源
|
||||
*
|
||||
* @param jdbcUrl /
|
||||
* @param userName /
|
||||
* @param password /
|
||||
* @return DataSource
|
||||
*/
|
||||
private static DataSource getDataSource(String jdbcUrl, String userName, String password) {
|
||||
DruidDataSource druidDataSource = new DruidDataSource();
|
||||
String className;
|
||||
try {
|
||||
className = DriverManager.getDriver(jdbcUrl.trim()).getClass().getName();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException("Get class name error: =" + jdbcUrl);
|
||||
}
|
||||
if (StringUtils.isEmpty(className)) {
|
||||
DataTypeEnum dataTypeEnum = DataTypeEnum.urlOf(jdbcUrl);
|
||||
if (null == dataTypeEnum) {
|
||||
throw new RuntimeException("Not supported data type: jdbcUrl=" + jdbcUrl);
|
||||
}
|
||||
druidDataSource.setDriverClassName(dataTypeEnum.getDriver());
|
||||
} else {
|
||||
druidDataSource.setDriverClassName(className);
|
||||
}
|
||||
|
||||
// 去掉不安全的参数
|
||||
jdbcUrl = sanitizeJdbcUrl(jdbcUrl);
|
||||
|
||||
druidDataSource.setUrl(jdbcUrl);
|
||||
druidDataSource.setUsername(userName);
|
||||
druidDataSource.setPassword(password);
|
||||
// 配置获取连接等待超时的时间
|
||||
druidDataSource.setMaxWait(3000);
|
||||
// 配置初始化大小、最小、最大
|
||||
druidDataSource.setInitialSize(1);
|
||||
druidDataSource.setMinIdle(1);
|
||||
druidDataSource.setMaxActive(1);
|
||||
|
||||
// 如果链接出现异常则直接判定为失败而不是一直重试
|
||||
druidDataSource.setBreakAfterAcquireFailure(true);
|
||||
try {
|
||||
druidDataSource.init();
|
||||
} catch (SQLException e) {
|
||||
log.error("Exception during pool initialization", e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
|
||||
return druidDataSource;
|
||||
}
|
||||
|
||||
private static Connection getConnection(String jdbcUrl, String userName, String password) {
|
||||
DataSource dataSource = getDataSource(jdbcUrl, userName, password);
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
} catch (Exception ignored) {}
|
||||
try {
|
||||
int timeOut = 5;
|
||||
if (null == connection || connection.isClosed() || !connection.isValid(timeOut)) {
|
||||
log.info("connection is closed or invalid, retry get connection!");
|
||||
connection = dataSource.getConnection();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("create connection error, jdbcUrl: {}", jdbcUrl);
|
||||
throw new RuntimeException("create connection error, jdbcUrl: " + jdbcUrl);
|
||||
} finally {
|
||||
CloseUtil.close(connection);
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
private static void releaseConnection(Connection connection) {
|
||||
if (null != connection) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean testConnection(String jdbcUrl, String userName, String password) {
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = getConnection(jdbcUrl, userName, password);
|
||||
if (null != connection) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Get connection failed:{}", e.getMessage());
|
||||
} finally {
|
||||
releaseConnection(connection);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String executeFile(String jdbcUrl, String userName, String password, File sqlFile) {
|
||||
Connection connection = getConnection(jdbcUrl, userName, password);
|
||||
try {
|
||||
batchExecute(connection, readSqlList(sqlFile));
|
||||
} catch (Exception e) {
|
||||
log.error("sql脚本执行发生异常:{}",e.getMessage());
|
||||
return e.getMessage();
|
||||
}finally {
|
||||
releaseConnection(connection);
|
||||
}
|
||||
return "success";
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量执行sql
|
||||
* @param connection /
|
||||
* @param sqlList /
|
||||
*/
|
||||
public static void batchExecute(Connection connection, List<String> sqlList) {
|
||||
try (Statement st = connection.createStatement()) {
|
||||
for (String sql : sqlList) {
|
||||
// 去除末尾的分号
|
||||
if (sql.endsWith(";")) {
|
||||
sql = sql.substring(0, sql.length() - 1);
|
||||
}
|
||||
// 检查 SQL 语句是否为空
|
||||
if (!sql.trim().isEmpty()) {
|
||||
st.addBatch(sql);
|
||||
}
|
||||
}
|
||||
st.executeBatch();
|
||||
} catch (SQLException e) {
|
||||
log.error("SQL脚本批量执行发生异常: {},错误代码: {}", e.getMessage(), e.getErrorCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将文件中的sql语句以;为单位读取到列表中
|
||||
* @param sqlFile /
|
||||
* @return /
|
||||
*/
|
||||
private static List<String> readSqlList(File sqlFile) {
|
||||
List<String> sqlList = new ArrayList<>();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
try (BufferedReader reader = Files.newBufferedReader(sqlFile.toPath(), StandardCharsets.UTF_8)) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
log.info("line: {}", line);
|
||||
sb.append(line.trim());
|
||||
|
||||
if (line.trim().endsWith(";")) {
|
||||
sqlList.add(sb.toString());
|
||||
// 清空 StringBuilder
|
||||
sb.setLength(0);
|
||||
} else {
|
||||
// 在行之间加一个空格
|
||||
sb.append(" ");
|
||||
}
|
||||
}
|
||||
if (sb.length() > 0) {
|
||||
sqlList.add(sb.toString().trim());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("读取SQL文件时发生异常: {}", e.getMessage());
|
||||
}
|
||||
return sqlList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除不安全的参数
|
||||
* @param jdbcUrl /
|
||||
* @return /
|
||||
*/
|
||||
private static String sanitizeJdbcUrl(String jdbcUrl) {
|
||||
// 定义不安全参数和其安全替代值
|
||||
String[][] unsafeParams = {
|
||||
// allowLoadLocalInfile:允许使用 LOAD DATA LOCAL INFILE,可能导致文件泄露
|
||||
{"allowLoadLocalInfile", "false"},
|
||||
// allowUrlInLocalInfile:允许在 LOAD DATA LOCAL INFILE 中使用 URL,可能导致未经授权的文件访问
|
||||
{"allowUrlInLocalInfile", "false"},
|
||||
// autoDeserialize:允许自动反序列化对象,可能导致反序列化漏洞
|
||||
{"autoDeserialize", "false"},
|
||||
// allowNanAndInf:允许使用 NaN 和 Infinity 作为数字值,可能导致不一致的数据处理
|
||||
{"allowNanAndInf", "false"},
|
||||
// allowMultiQueries:允许在一个语句中执行多个查询,可能导致 SQL 注入攻击
|
||||
{"allowMultiQueries", "false"},
|
||||
// allowPublicKeyRetrieval:允许从服务器检索公钥,可能导致中间人攻击
|
||||
{"allowPublicKeyRetrieval", "false"}
|
||||
};
|
||||
|
||||
// 替换不安全的参数
|
||||
for (String[] param : unsafeParams) {
|
||||
jdbcUrl = jdbcUrl.replaceAll("(?i)" + param[0] + "=true", param[0] + "=" + param[1]);
|
||||
}
|
||||
return jdbcUrl;
|
||||
}
|
||||
}
|
@ -18,5 +18,6 @@
|
||||
</root>
|
||||
|
||||
<!--部分日志调整为ERROR-->
|
||||
<logger name="io.undertow.websockets.jsr" level="ERROR"/>
|
||||
<logger name="io.netty.resolver.dns.DnsServerAddressStreamProviders" level="ERROR"/>
|
||||
</configuration>
|
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="me.zhengjie.modules.maint.mapper.AppMapper">
|
||||
<resultMap id="BaseResultMap" type="me.zhengjie.modules.maint.domain.App">
|
||||
<id column="app_id" property="id"/>
|
||||
<result column="name" property="name"/>
|
||||
<result column="port" property="port"/>
|
||||
<result column="upload_path" property="uploadPath"/>
|
||||
<result column="deploy_path" property="deployPath"/>
|
||||
<result column="backup_path" property="backupPath"/>
|
||||
<result column="start_script" property="startScript"/>
|
||||
<result column="deploy_script" property="deployScript"/>
|
||||
<result column="create_by" property="createBy"/>
|
||||
<result column="update_by" property="updateBy"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
app_id,name,port,upload_path,deploy_path,backup_path,start_script,deploy_script,create_by,update_by,create_time,update_time
|
||||
</sql>
|
||||
|
||||
<select id="queryAll" resultMap="BaseResultMap">
|
||||
select
|
||||
<include refid="Base_Column_List"/>
|
||||
from mnt_app
|
||||
<where>
|
||||
<if test="criteria.name != null and criteria.name != ''">
|
||||
and name like concat('%',#{criteria.name},'%')
|
||||
</if>
|
||||
<if test="criteria.createTime != null and criteria.createTime.size() > 0">
|
||||
and create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
|
||||
</if>
|
||||
</where>
|
||||
order by app_id desc
|
||||
</select>
|
||||
</mapper>
|
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="me.zhengjie.modules.maint.mapper.DatabaseMapper">
|
||||
<resultMap id="BaseResultMap" type="me.zhengjie.modules.maint.domain.Database">
|
||||
<id column="db_id" property="id"/>
|
||||
<result column="name" property="name"/>
|
||||
<result column="jdbc_url" property="jdbcUrl"/>
|
||||
<result column="pwd" property="pwd"/>
|
||||
<result column="user_name" property="userName"/>
|
||||
<result column="create_by" property="createBy"/>
|
||||
<result column="update_by" property="updateBy"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
db_id, name, jdbc_url, pwd, user_name, create_by, update_by, create_time, update_time
|
||||
</sql>
|
||||
|
||||
<select id="findAll" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List"/>
|
||||
FROM mnt_database
|
||||
<where>
|
||||
<if test="criteria.name != null and criteria.name != ''">
|
||||
AND name LIKE CONCAT('%',#{criteria.name},'%')
|
||||
</if>
|
||||
<if test="criteria.jdbcUrl != null and criteria.jdbcUrl != ''">
|
||||
AND jdbc_url = #{criteria.jdbcUrl}
|
||||
</if>
|
||||
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
|
||||
AND create_time BETWEEN #{criteria.createTime[0]} AND #{criteria.createTime[1]}
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
</mapper>
|
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="me.zhengjie.modules.maint.mapper.DeployHistoryMapper">
|
||||
<resultMap id="BaseResultMap" type="me.zhengjie.modules.maint.domain.DeployHistory">
|
||||
<id column="history_id" property="id"/>
|
||||
<result column="app_name" property="appName"/>
|
||||
<result column="ip" property="ip"/>
|
||||
<result column="deploy_date" property="deployDate"/>
|
||||
<result column="deploy_user" property="deployUser"/>
|
||||
<result column="deploy_id" property="deployId"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
history_id, app_name, ip, deploy_date, deploy_user, deploy_id
|
||||
</sql>
|
||||
|
||||
<select id="findAll" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List"/>
|
||||
FROM mnt_deploy_history
|
||||
<where>
|
||||
<if test="criteria.blurry != null and criteria.blurry != ''">
|
||||
AND (
|
||||
app_name LIKE CONCAT('%',#{criteria.blurry},'%')
|
||||
or ip LIKE CONCAT('%',#{criteria.blurry},'%')
|
||||
or deploy_user LIKE CONCAT('%',#{criteria.blurry},'%')
|
||||
)
|
||||
</if>
|
||||
<if test="criteria.deployId != null">
|
||||
AND deploy_id = #{criteria.deployId}
|
||||
</if>
|
||||
<if test="criteria.deployDate != null and criteria.deployDate.size() != 0">
|
||||
AND deploy_date BETWEEN #{criteria.deployDate[0]} AND #{criteria.deployDate[1]}
|
||||
</if>
|
||||
</where>
|
||||
order by deploy_date desc
|
||||
</select>
|
||||
|
||||
</mapper>
|
@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis_deploy.org//DTD Mapper 3.0//EN" "http://mybatis_deploy.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="me.zhengjie.modules.maint.mapper.DeployMapper">
|
||||
<resultMap id="BaseResultMap" type="me.zhengjie.modules.maint.domain.Deploy">
|
||||
<id column="d_deploy_id" property="id"/>
|
||||
<result column="d_app_id" property="appId"/>
|
||||
<result column="d_create_by" property="createBy"/>
|
||||
<result column="d_update_by" property="updateBy"/>
|
||||
<result column="d_create_time" property="createTime"/>
|
||||
<result column="d_update_time" property="updateTime"/>
|
||||
<association property="app" javaType="me.zhengjie.modules.maint.domain.App">
|
||||
<id column="a_app_id" property="id"/>
|
||||
<result column="a_name" property="name"/>
|
||||
<result column="a_port" property="port"/>
|
||||
<result column="a_upload_path" property="uploadPath"/>
|
||||
<result column="a_deploy_path" property="deployPath"/>
|
||||
<result column="a_backup_path" property="backupPath"/>
|
||||
<result column="a_start_script" property="startScript"/>
|
||||
<result column="a_deploy_script" property="deployScript"/>
|
||||
</association>
|
||||
<collection property="deploys" ofType="me.zhengjie.modules.maint.domain.Server">
|
||||
<id column="s_server_id" property="id"/>
|
||||
<result column="s_name" property="name"/>
|
||||
<result column="s_ip" property="ip"/>
|
||||
<result column="s_port" property="port"/>
|
||||
<result column="s_account" property="account"/>
|
||||
<result column="s_password" property="password"/>
|
||||
</collection>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
deploy.deploy_id as d_deploy_id, deploy.app_id as d_app_id,deploy.create_by as d_create_by,deploy.update_by as d_update_by,deploy.create_time as d_create_time,deploy.update_time as d_update_time,
|
||||
app.app_id as a_app_id,app.name as a_name,app.port as a_port,app.upload_path as a_upload_path,app.deploy_path as a_deploy_path,app.backup_path as a_backup_path,app.start_script as a_start_script,app.deploy_script as a_deploy_script
|
||||
</sql>
|
||||
|
||||
<sql id="Server_Column_List">
|
||||
server.server_id as s_server_id,server.name as s_name,server.ip as s_ip,server.port as s_port,server.account as s_account,server.password as s_password
|
||||
</sql>
|
||||
|
||||
<sql id="Where_sql">
|
||||
<where>
|
||||
<if test="criteria.appName != null and criteria.appName != ''">
|
||||
and app.name like concat('%',#{criteria.appName},'%')
|
||||
</if>
|
||||
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
|
||||
and deploy.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<select id="findAll" resultMap="BaseResultMap">
|
||||
select t.*,
|
||||
<include refid="Server_Column_List"/>
|
||||
from (
|
||||
select <include refid="Base_Column_List"/>
|
||||
from mnt_deploy deploy
|
||||
left join mnt_app app on deploy.app_id = app.app_id
|
||||
<include refid="Where_sql"/>
|
||||
order by deploy.deploy_id desc
|
||||
<if test="criteria.offset != null">
|
||||
limit #{criteria.offset}, #{criteria.size}
|
||||
</if>
|
||||
) t
|
||||
left join mnt_deploy_server mds on t.d_deploy_id = mds.deploy_id
|
||||
left join mnt_server server on server.server_id = mds.server_id
|
||||
order by t.d_deploy_id desc
|
||||
</select>
|
||||
|
||||
<select id="countAll" resultType="java.lang.Long">
|
||||
select count(*)
|
||||
from mnt_deploy deploy
|
||||
left join mnt_app app on deploy.app_id = app.app_id
|
||||
<include refid="Where_sql"/>
|
||||
</select>
|
||||
|
||||
<select id="getIdByAppIds" resultType="java.lang.Long">
|
||||
select deploy.deploy_id
|
||||
from mnt_deploy deploy
|
||||
where deploy.app_id in
|
||||
<foreach collection="appIds" item="appId" open="(" separator="," close=")">
|
||||
#{appId}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<select id="getDeployById" resultMap="BaseResultMap">
|
||||
select
|
||||
<include refid="Base_Column_List"/>,
|
||||
<include refid="Server_Column_List"/>
|
||||
from mnt_deploy deploy
|
||||
left join mnt_app app on deploy.app_id = app.app_id
|
||||
left join mnt_deploy_server mds on deploy.deploy_id = mds.deploy_id
|
||||
left join mnt_server server on server.server_id = mds.server_id
|
||||
where deploy.deploy_id = #{deployId}
|
||||
</select>
|
||||
</mapper>
|
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="me.zhengjie.modules.maint.mapper.DeployServerMapper">
|
||||
|
||||
<insert id="insertData">
|
||||
insert into mnt_deploy_server (deploy_id, server_id)
|
||||
values
|
||||
<foreach collection="servers" item="item" open="(" separator="),(" close=")">
|
||||
#{deployId}, #{item.id}
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<delete id="deleteByDeployId">
|
||||
delete from mnt_deploy_server
|
||||
where deploy_id = #{deployId}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteByDeployIds">
|
||||
delete from mnt_deploy_server
|
||||
where deploy_id in
|
||||
<foreach collection="deployIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<delete id="deleteByServerIds">
|
||||
delete from mnt_deploy_server
|
||||
where server_id in
|
||||
<foreach collection="serverIds" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
</mapper>
|
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatiorg//DTD Mapper 3.0//EN" "http://mybatiorg/dtd/mybatis-3-mapper.dtd" >
|
||||
<mapper namespace="me.zhengjie.modules.maint.mapper.ServerMapper">
|
||||
<resultMap id="BaseResultMap" type="me.zhengjie.modules.maint.domain.Server">
|
||||
<id column="server_id" property="id"/>
|
||||
<result column="name" property="name"/>
|
||||
<result column="ip" property="ip"/>
|
||||
<result column="port" property="port"/>
|
||||
<result column="account" property="account"/>
|
||||
<result column="password" property="password"/>
|
||||
<result column="create_by" property="createBy"/>
|
||||
<result column="update_by" property="updateBy"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
server_id, name, ip, port, account, password, create_by, update_by, create_time, update_time
|
||||
</sql>
|
||||
|
||||
<select id="findByIp" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List"/>
|
||||
FROM mnt_server
|
||||
<where>
|
||||
ip = #{ip}
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<select id="findAll" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List"/>
|
||||
FROM mnt_server
|
||||
<where>
|
||||
<if test="criteria.blurry != null and criteria.blurry != ''">
|
||||
AND (
|
||||
name LIKE CONCAT('%',#{criteria.blurry},'%')
|
||||
or ip LIKE CONCAT('%',#{criteria.blurry},'%')
|
||||
)
|
||||
</if>
|
||||
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
|
||||
AND create_time BETWEEN #{criteria.createTime[0]} AND #{criteria.createTime[1]}
|
||||
</if>
|
||||
</where>
|
||||
order by server_id desc
|
||||
</select>
|
||||
</mapper>
|
@ -55,13 +55,6 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
<exclusions>
|
||||
<!-- 排除 undertow-websockets-jsr 依赖,如果需要用到websockets,就移除这个 -->
|
||||
<exclusion>
|
||||
<groupId>io.undertow</groupId>
|
||||
<artifactId>undertow-websockets-jsr</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!--Spring boot 测试-->
|
||||
|
173
sql/eladmin.sql
173
sql/eladmin.sql
@ -71,6 +71,139 @@ BEGIN;
|
||||
INSERT INTO `code_config` (`config_id`, `table_name`, `author`, `cover`, `module_name`, `pack`, `path`, `api_path`, `prefix`, `api_alias`) VALUES (7, 'sys_role', 'test', b'0', 'test', 'test', 'test', 'test/', NULL, 'test');
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for mnt_app
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `mnt_app`;
|
||||
CREATE TABLE `mnt_app` (
|
||||
`app_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`name` varchar(255) DEFAULT NULL COMMENT '应用名称',
|
||||
`upload_path` varchar(255) DEFAULT NULL COMMENT '上传目录',
|
||||
`deploy_path` varchar(255) DEFAULT NULL COMMENT '部署路径',
|
||||
`backup_path` varchar(255) DEFAULT NULL COMMENT '备份路径',
|
||||
`port` int(255) DEFAULT NULL COMMENT '应用端口',
|
||||
`start_script` varchar(4000) DEFAULT NULL COMMENT '启动脚本',
|
||||
`deploy_script` varchar(4000) DEFAULT NULL COMMENT '部署脚本',
|
||||
`create_by` varchar(255) DEFAULT NULL COMMENT '创建者',
|
||||
`update_by` varchar(255) DEFAULT NULL COMMENT '更新者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建日期',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`app_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='应用管理';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of mnt_app
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for mnt_database
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `mnt_database`;
|
||||
CREATE TABLE `mnt_database` (
|
||||
`db_id` varchar(50) NOT NULL COMMENT 'ID',
|
||||
`name` varchar(255) NOT NULL COMMENT '名称',
|
||||
`jdbc_url` varchar(255) NOT NULL COMMENT 'jdbc连接',
|
||||
`user_name` varchar(255) NOT NULL COMMENT '账号',
|
||||
`pwd` varchar(255) NOT NULL COMMENT '密码',
|
||||
`create_by` varchar(255) DEFAULT NULL COMMENT '创建者',
|
||||
`update_by` varchar(255) DEFAULT NULL COMMENT '更新者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`db_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='数据库管理';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of mnt_database
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for mnt_deploy
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `mnt_deploy`;
|
||||
CREATE TABLE `mnt_deploy` (
|
||||
`deploy_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`app_id` bigint(20) DEFAULT NULL COMMENT '应用编号',
|
||||
`create_by` varchar(255) DEFAULT NULL COMMENT '创建者',
|
||||
`update_by` varchar(255) DEFAULT NULL COMMENT '更新者',
|
||||
`create_time` datetime DEFAULT NULL,
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`deploy_id`) USING BTREE,
|
||||
KEY `idx_app_id` (`app_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='部署管理';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of mnt_deploy
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for mnt_deploy_history
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `mnt_deploy_history`;
|
||||
CREATE TABLE `mnt_deploy_history` (
|
||||
`history_id` varchar(50) NOT NULL COMMENT 'ID',
|
||||
`app_name` varchar(255) NOT NULL COMMENT '应用名称',
|
||||
`deploy_date` datetime NOT NULL COMMENT '部署日期',
|
||||
`deploy_user` varchar(50) NOT NULL COMMENT '部署用户',
|
||||
`ip` varchar(20) NOT NULL COMMENT '服务器IP',
|
||||
`deploy_id` bigint(20) DEFAULT NULL COMMENT '部署编号',
|
||||
PRIMARY KEY (`history_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='部署历史管理';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of mnt_deploy_history
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for mnt_deploy_server
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `mnt_deploy_server`;
|
||||
CREATE TABLE `mnt_deploy_server` (
|
||||
`deploy_id` bigint(20) NOT NULL COMMENT '部署ID',
|
||||
`server_id` bigint(20) NOT NULL COMMENT '服务ID',
|
||||
PRIMARY KEY (`deploy_id`,`server_id`) USING BTREE,
|
||||
KEY `idx_deploy_id` (`deploy_id`),
|
||||
KEY `idx_server_id` (`server_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='应用与服务器关联';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of mnt_deploy_server
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for mnt_server
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `mnt_server`;
|
||||
CREATE TABLE `mnt_server` (
|
||||
`server_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`account` varchar(50) DEFAULT NULL COMMENT '账号',
|
||||
`ip` varchar(20) DEFAULT NULL COMMENT 'IP地址',
|
||||
`name` varchar(100) DEFAULT NULL COMMENT '名称',
|
||||
`password` varchar(100) DEFAULT NULL COMMENT '密码',
|
||||
`port` int(11) DEFAULT NULL COMMENT '端口',
|
||||
`create_by` varchar(255) DEFAULT NULL COMMENT '创建者',
|
||||
`update_by` varchar(255) DEFAULT NULL COMMENT '更新者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`server_id`) USING BTREE,
|
||||
KEY `idx_ip` (`ip`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='服务器管理';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of mnt_server
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
COMMIT;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for sys_dept
|
||||
-- ----------------------------
|
||||
@ -238,16 +371,16 @@ CREATE TABLE `sys_menu` (
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建日期',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`menu_id`) USING BTREE,
|
||||
UNIQUE KEY `uniq_title` (`title`),
|
||||
UNIQUE KEY `uniq_name` (`name`),
|
||||
UNIQUE KEY `uniq_title` (`title`),
|
||||
KEY `idx_pid` (`pid`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=118 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='系统菜单';
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=117 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='系统菜单';
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of sys_menu
|
||||
-- ----------------------------
|
||||
BEGIN;
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (1, NULL, 7, 0, '系统管理', NULL, NULL, 1, 'system', 'system', b'0', b'0', b'0', NULL, NULL, NULL, '2018-12-18 15:11:29', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (1, NULL, 7, 0, '系统管理', NULL, NULL, 1, 'system', 'system', b'0', b'0', b'0', NULL, NULL, 'admin', '2018-12-18 15:11:29', '2025-01-14 15:48:18');
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (2, 1, 3, 1, '用户管理', 'User', 'system/user/index', 2, 'peoples', 'user', b'0', b'0', b'0', 'user:list', NULL, NULL, '2018-12-18 15:14:44', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (3, 1, 3, 1, '角色管理', 'Role', 'system/role/index', 3, 'role', 'role', b'0', b'0', b'0', 'roles:list', NULL, NULL, '2018-12-18 15:16:07', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (5, 1, 3, 1, '菜单管理', 'Menu', 'system/menu/index', 5, 'menu', 'menu', b'0', b'0', b'0', 'menu:list', NULL, NULL, '2018-12-18 15:17:28', NULL);
|
||||
@ -271,7 +404,7 @@ INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`,
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (33, 10, 0, 1, 'Markdown', 'Markdown', 'components/MarkDown', 53, 'markdown', 'markdown', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-08 13:46:44', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (34, 10, 0, 1, 'Yaml编辑器', 'YamlEdit', 'components/YamlEdit', 54, 'dev', 'yaml', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-08 15:49:40', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (35, 1, 3, 1, '部门管理', 'Dept', 'system/dept/index', 6, 'dept', 'dept', b'0', b'0', b'0', 'dept:list', NULL, NULL, '2019-03-25 09:46:00', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (36, NULL, 7, 0, '系统工具', NULL, '', 30, 'sys-tools', 'sys-tools', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-29 10:57:35', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (36, NULL, 6, 0, '系统工具', NULL, '', 30, 'sys-tools', 'sys-tools', b'0', b'0', b'0', NULL, NULL, NULL, '2019-03-29 10:57:35', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (37, 1, 3, 1, '岗位管理', 'Job', 'system/job/index', 7, 'Steve-Jobs', 'job', b'0', b'0', b'0', 'job:list', NULL, NULL, '2019-03-29 13:51:18', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (39, 1, 3, 1, '字典管理', 'Dict', 'system/dict/index', 8, 'dictionary', 'dict', b'0', b'0', b'0', 'dict:list', NULL, NULL, '2019-04-10 11:49:04', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (41, 6, 0, 1, '在线用户', 'OnlineUser', 'monitor/online/index', 10, 'Steve-Jobs', 'online', b'0', b'0', b'0', NULL, NULL, NULL, '2019-10-26 22:08:43', NULL);
|
||||
@ -302,6 +435,22 @@ INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`,
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (80, 6, 0, 1, '服务监控', 'ServerMonitor', 'monitor/server/index', 14, 'codeConsole', 'server', b'0', b'0', b'0', 'monitor:list', NULL, 'admin', '2019-11-07 13:06:39', '2020-05-04 18:20:50');
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (82, 36, 0, 1, '生成配置', 'GeneratorConfig', 'generator/config', 33, 'dev', 'generator/config/:tableName', b'0', b'1', b'1', '', NULL, NULL, '2019-11-17 20:08:56', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (83, 10, 0, 1, '图表库', 'Echarts', 'components/Echarts', 50, 'chart', 'echarts', b'0', b'1', b'0', '', NULL, NULL, '2019-11-21 09:04:32', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (90, NULL, 5, 1, '运维管理', 'Mnt', '', 20, 'mnt', 'mnt', b'0', b'0', b'0', NULL, NULL, NULL, '2019-11-09 10:31:08', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (92, 90, 3, 1, '服务器', 'ServerDeploy', 'maint/server/index', 22, 'server', 'maint/serverDeploy', b'0', b'0', b'0', 'serverDeploy:list', NULL, NULL, '2019-11-10 10:29:25', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (93, 90, 3, 1, '应用管理', 'App', 'maint/app/index', 23, 'app', 'maint/app', b'0', b'0', b'0', 'app:list', NULL, NULL, '2019-11-10 11:05:16', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (94, 90, 3, 1, '部署管理', 'Deploy', 'maint/deploy/index', 24, 'deploy', 'maint/deploy', b'0', b'0', b'0', 'deploy:list', NULL, NULL, '2019-11-10 15:56:55', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (97, 90, 1, 1, '部署备份', 'DeployHistory', 'maint/deployHistory/index', 25, 'backup', 'maint/deployHistory', b'0', b'0', b'0', 'deployHistory:list', NULL, NULL, '2019-11-10 16:49:44', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (98, 90, 3, 1, '数据库管理', 'Database', 'maint/database/index', 26, 'database', 'maint/database', b'0', b'0', b'0', 'database:list', NULL, NULL, '2019-11-10 20:40:04', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (102, 97, 0, 2, '删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'deployHistory:del', NULL, NULL, '2019-11-17 09:32:48', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (103, 92, 0, 2, '服务器新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'serverDeploy:add', NULL, NULL, '2019-11-17 11:08:33', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (104, 92, 0, 2, '服务器编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'serverDeploy:edit', NULL, NULL, '2019-11-17 11:08:57', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (105, 92, 0, 2, '服务器删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'serverDeploy:del', NULL, NULL, '2019-11-17 11:09:15', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (106, 93, 0, 2, '应用新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'app:add', NULL, NULL, '2019-11-17 11:10:03', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (107, 93, 0, 2, '应用编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'app:edit', NULL, NULL, '2019-11-17 11:10:28', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (108, 93, 0, 2, '应用删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'app:del', NULL, NULL, '2019-11-17 11:10:55', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (109, 94, 0, 2, '部署新增', NULL, '', 999, '', '', b'0', b'0', b'0', 'deploy:add', NULL, NULL, '2019-11-17 11:11:22', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (110, 94, 0, 2, '部署编辑', NULL, '', 999, '', '', b'0', b'0', b'0', 'deploy:edit', NULL, NULL, '2019-11-17 11:11:41', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (111, 94, 0, 2, '部署删除', NULL, '', 999, '', '', b'0', b'0', b'0', 'deploy:del', NULL, NULL, '2019-11-17 11:12:01', NULL);
|
||||
INSERT INTO `sys_menu` (`menu_id`, `pid`, `sub_count`, `type`, `title`, `name`, `component`, `menu_sort`, `icon`, `path`, `i_frame`, `cache`, `hidden`, `permission`, `create_by`, `update_by`, `create_time`, `update_time`) VALUES (116, 36, 0, 1, '生成预览', 'Preview', 'generator/preview', 999, 'java', 'generator/preview/:tableName', b'0', b'1', b'1', NULL, NULL, NULL, '2019-11-26 14:54:36', NULL);
|
||||
COMMIT;
|
||||
|
||||
@ -503,6 +652,22 @@ INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (82, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (82, 2);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (83, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (83, 2);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (90, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (92, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (93, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (94, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (97, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (98, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (102, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (103, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (104, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (105, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (106, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (107, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (108, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (109, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (110, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (111, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (116, 1);
|
||||
INSERT INTO `sys_roles_menus` (`menu_id`, `role_id`) VALUES (116, 2);
|
||||
COMMIT;
|
||||
|
Loading…
Reference in New Issue
Block a user