diff --git a/README.md b/README.md index e704a69..ab2d6a7 100644 --- a/README.md +++ b/README.md @@ -17,11 +17,10 @@ #### VPS推荐 - +帮瓦工 使用优惠码: `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限流等功能 #### 项目捐赠 diff --git a/eladmin-web/src/api/maint/app.js b/eladmin-web/src/api/maint/app.js new file mode 100644 index 0000000..2a27054 --- /dev/null +++ b/eladmin-web/src/api/maint/app.js @@ -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 } diff --git a/eladmin-web/src/api/maint/connect.js b/eladmin-web/src/api/maint/connect.js new file mode 100644 index 0000000..1bbe90b --- /dev/null +++ b/eladmin-web/src/api/maint/connect.js @@ -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 + }) +} diff --git a/eladmin-web/src/api/maint/database.js b/eladmin-web/src/api/maint/database.js new file mode 100644 index 0000000..91797fb --- /dev/null +++ b/eladmin-web/src/api/maint/database.js @@ -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 } diff --git a/eladmin-web/src/api/maint/deploy.js b/eladmin-web/src/api/maint/deploy.js new file mode 100644 index 0000000..c1475ea --- /dev/null +++ b/eladmin-web/src/api/maint/deploy.js @@ -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 } diff --git a/eladmin-web/src/api/maint/deployHistory.js b/eladmin-web/src/api/maint/deployHistory.js new file mode 100644 index 0000000..30335e4 --- /dev/null +++ b/eladmin-web/src/api/maint/deployHistory.js @@ -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 + }) +} diff --git a/eladmin-web/src/api/maint/serverDeploy.js b/eladmin-web/src/api/maint/serverDeploy.js new file mode 100644 index 0000000..e796114 --- /dev/null +++ b/eladmin-web/src/api/maint/serverDeploy.js @@ -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 } diff --git a/eladmin-web/src/views/maint/app/index.vue b/eladmin-web/src/views/maint/app/index.vue new file mode 100644 index 0000000..3310dec --- /dev/null +++ b/eladmin-web/src/views/maint/app/index.vue @@ -0,0 +1,144 @@ + + + + + diff --git a/eladmin-web/src/views/maint/database/execute.vue b/eladmin-web/src/views/maint/database/execute.vue new file mode 100644 index 0000000..94622fc --- /dev/null +++ b/eladmin-web/src/views/maint/database/execute.vue @@ -0,0 +1,86 @@ + + + + + diff --git a/eladmin-web/src/views/maint/database/index.vue b/eladmin-web/src/views/maint/database/index.vue new file mode 100644 index 0000000..0a720db --- /dev/null +++ b/eladmin-web/src/views/maint/database/index.vue @@ -0,0 +1,148 @@ + + + + + diff --git a/eladmin-web/src/views/maint/deploy/deploy.vue b/eladmin-web/src/views/maint/deploy/deploy.vue new file mode 100644 index 0000000..e2409c1 --- /dev/null +++ b/eladmin-web/src/views/maint/deploy/deploy.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/eladmin-web/src/views/maint/deploy/index.vue b/eladmin-web/src/views/maint/deploy/index.vue new file mode 100644 index 0000000..1ae106d --- /dev/null +++ b/eladmin-web/src/views/maint/deploy/index.vue @@ -0,0 +1,229 @@ + + + + + diff --git a/eladmin-web/src/views/maint/deploy/sysRestore.vue b/eladmin-web/src/views/maint/deploy/sysRestore.vue new file mode 100644 index 0000000..40d5677 --- /dev/null +++ b/eladmin-web/src/views/maint/deploy/sysRestore.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/eladmin-web/src/views/maint/deployHistory/index.vue b/eladmin-web/src/views/maint/deployHistory/index.vue new file mode 100644 index 0000000..432da23 --- /dev/null +++ b/eladmin-web/src/views/maint/deployHistory/index.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/eladmin-web/src/views/maint/server/index.vue b/eladmin-web/src/views/maint/server/index.vue new file mode 100644 index 0000000..13161d2 --- /dev/null +++ b/eladmin-web/src/views/maint/server/index.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/eladmin/README.md b/eladmin/README.md index 01747ef..ab2d6a7 100644 --- a/eladmin/README.md +++ b/eladmin/README.md @@ -17,7 +17,7 @@ #### VPS推荐 - +帮瓦工 使用优惠码: `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限流等功能 #### 项目捐赠 diff --git a/eladmin/eladmin-common/src/main/java/me/zhengjie/config/webConfig/WebSocketConfig.java b/eladmin/eladmin-common/src/main/java/me/zhengjie/config/webConfig/WebSocketConfig.java new file mode 100644 index 0000000..1a2cdd7 --- /dev/null +++ b/eladmin/eladmin-common/src/main/java/me/zhengjie/config/webConfig/WebSocketConfig.java @@ -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(); + } +} diff --git a/eladmin/eladmin-system/pom.xml b/eladmin/eladmin-system/pom.xml index 0024510..8c20b01 100644 --- a/eladmin/eladmin-system/pom.xml +++ b/eladmin/eladmin-system/pom.xml @@ -62,6 +62,18 @@ ${jjwt.version} + + + ch.ethz.ganymed + ganymed-ssh2 + build210 + + + com.jcraft + jsch + 0.1.55 + + com.github.oshi diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/App.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/App.java new file mode 100644 index 0000000..f114e72 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/App.java @@ -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)); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/Database.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/Database.java new file mode 100644 index 0000000..0285a34 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/Database.java @@ -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)); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/Deploy.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/Deploy.java new file mode 100644 index 0000000..92243aa --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/Deploy.java @@ -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 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 ""; + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/DeployHistory.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/DeployHistory.java new file mode 100644 index 0000000..39ac8ef --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/DeployHistory.java @@ -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)); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/Server.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/Server.java new file mode 100644 index 0000000..dcce38e --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/Server.java @@ -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); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/AppQueryCriteria.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/AppQueryCriteria.java new file mode 100644 index 0000000..3f06456 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/AppQueryCriteria.java @@ -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 createTime; + + @ApiModelProperty(value = "页码", example = "1") + private Integer page = 1; + + @ApiModelProperty(value = "每页数据量", example = "10") + private Integer size = 10; +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/DatabaseQueryCriteria.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/DatabaseQueryCriteria.java new file mode 100644 index 0000000..0e808c5 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/DatabaseQueryCriteria.java @@ -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 createTime; + + @ApiModelProperty(value = "页码", example = "1") + private Integer page = 1; + + @ApiModelProperty(value = "每页数据量", example = "10") + private Integer size = 10; +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/DeployHistoryQueryCriteria.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/DeployHistoryQueryCriteria.java new file mode 100644 index 0000000..60a2445 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/DeployHistoryQueryCriteria.java @@ -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 deployDate; + + @ApiModelProperty(value = "页码", example = "1") + private Integer page = 1; + + @ApiModelProperty(value = "每页数据量", example = "10") + private Integer size = 10; +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/DeployQueryCriteria.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/DeployQueryCriteria.java new file mode 100644 index 0000000..da367e2 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/DeployQueryCriteria.java @@ -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 createTime; + + @ApiModelProperty(value = "页码", example = "1") + private Integer page = 1; + + @ApiModelProperty(value = "每页数据量", example = "10") + private Integer size = 10; + + @ApiModelProperty(value = "查询分页偏移量", hidden = true) + private Long offset; +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/ServerQueryCriteria.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/ServerQueryCriteria.java new file mode 100644 index 0000000..30f839a --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/dto/ServerQueryCriteria.java @@ -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 createTime; + + @ApiModelProperty(value = "页码", example = "1") + private Integer page = 1; + + @ApiModelProperty(value = "每页数据量", example = "10") + private Integer size = 10; +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/enums/DataTypeEnum.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/enums/DataTypeEnum.java new file mode 100644 index 0000000..6d4ab1c --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/enums/DataTypeEnum.java @@ -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; + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/enums/MsgType.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/enums/MsgType.java new file mode 100644 index 0000000..1c1fbf6 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/domain/enums/MsgType.java @@ -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 +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/AppMapper.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/AppMapper.java new file mode 100644 index 0000000..715d8cd --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/AppMapper.java @@ -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 { + + IPage queryAll(@Param("criteria") AppQueryCriteria criteria, Page page); + + List queryAll(@Param("criteria") AppQueryCriteria criteria); +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DatabaseMapper.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DatabaseMapper.java new file mode 100644 index 0000000..bf6d3bd --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DatabaseMapper.java @@ -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 { + + IPage findAll(@Param("criteria") DatabaseQueryCriteria criteria, Page page); + + List findAll(@Param("criteria") DatabaseQueryCriteria criteria); +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DeployHistoryMapper.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DeployHistoryMapper.java new file mode 100644 index 0000000..ddc966d --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DeployHistoryMapper.java @@ -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 { + + IPage findAll(@Param("criteria") DeployHistoryQueryCriteria criteria, Page page); + + List findAll(@Param("criteria") DeployHistoryQueryCriteria criteria); +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DeployMapper.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DeployMapper.java new file mode 100644 index 0000000..5445994 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DeployMapper.java @@ -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 { + + Long countAll(@Param("criteria") DeployQueryCriteria criteria); + + List findAll(@Param("criteria") DeployQueryCriteria criteria); + + Set getIdByAppIds(@Param("appIds") Set appIds); + + Deploy getDeployById(@Param("deployId") Long deployId); +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DeployServerMapper.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DeployServerMapper.java new file mode 100644 index 0000000..edf7cc4 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/DeployServerMapper.java @@ -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 servers); + + void deleteByDeployId(@Param("deployId") Long deployId); + + void deleteByDeployIds(@Param("deployIds") Set deployIds); + + void deleteByServerIds(@Param("serverIds") Set serverIds); +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/ServerMapper.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/ServerMapper.java new file mode 100644 index 0000000..a065dad --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/mapper/ServerMapper.java @@ -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 findByIp(@Param("ip") String ip); + + IPage findAll(@Param("criteria") ServerQueryCriteria criteria, Page page); + + List findAll(@Param("criteria") ServerQueryCriteria criteria); +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/AppController.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/AppController.java new file mode 100644 index 0000000..3091abf --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/AppController.java @@ -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> queryApp(AppQueryCriteria criteria){ + Page 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 createApp(@Validated @RequestBody App resources){ + appService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改应用") + @ApiOperation(value = "修改应用") + @PutMapping + @PreAuthorize("@el.check('app:edit')") + public ResponseEntity 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 deleteApp(@RequestBody Set ids){ + appService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/DatabaseController.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/DatabaseController.java new file mode 100644 index 0000000..7b5049d --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/DatabaseController.java @@ -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> queryDatabase(DatabaseQueryCriteria criteria){ + Page 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 createDatabase(@Validated @RequestBody Database resources){ + databaseService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改数据库") + @ApiOperation(value = "修改数据库") + @PutMapping + @PreAuthorize("@el.check('database:edit')") + public ResponseEntity 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 deleteDatabase(@RequestBody Set ids){ + databaseService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("测试数据库链接") + @ApiOperation(value = "测试数据库链接") + @PostMapping("/testConnect") + @PreAuthorize("@el.check('database:testConnect')") + public ResponseEntity 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 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"); + } + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/DeployController.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/DeployController.java new file mode 100644 index 0000000..4998f2f --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/DeployController.java @@ -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> queryDeployData(DeployQueryCriteria criteria){ + Page 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 createDeploy(@Validated @RequestBody Deploy resources){ + deployService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改部署") + @ApiOperation(value = "修改部署") + @PutMapping + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity 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 deleteDeploy(@RequestBody Set ids){ + deployService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("上传文件部署") + @ApiOperation(value = "上传文件部署") + @PostMapping(value = "/upload") + @PreAuthorize("@el.check('deploy:edit')") + public ResponseEntity 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 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 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 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 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 stopServer(@Validated @RequestBody Deploy resources){ + String result = deployService.stopServer(resources); + return new ResponseEntity<>(result,HttpStatus.OK); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/DeployHistoryController.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/DeployHistoryController.java new file mode 100644 index 0000000..f87c0e9 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/DeployHistoryController.java @@ -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> queryDeployHistory(DeployHistoryQueryCriteria criteria){ + Page 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 deleteDeployHistory(@RequestBody Set ids){ + deployhistoryService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/ServerController.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/ServerController.java new file mode 100644 index 0000000..4f155af --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/rest/ServerController.java @@ -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> queryServerDeploy(ServerQueryCriteria criteria){ + Page 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 createServerDeploy(@Validated @RequestBody Server resources){ + serverService.create(resources); + return new ResponseEntity<>(HttpStatus.CREATED); + } + + @Log("修改服务器") + @ApiOperation(value = "修改服务器") + @PutMapping + @PreAuthorize("@el.check('serverDeploy:edit')") + public ResponseEntity 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 deleteServerDeploy(@RequestBody Set ids){ + serverService.delete(ids); + return new ResponseEntity<>(HttpStatus.OK); + } + + @Log("测试连接服务器") + @ApiOperation(value = "测试连接服务器") + @PostMapping("/testConnect") + @PreAuthorize("@el.check('serverDeploy:add')") + public ResponseEntity testConnectServerDeploy(@Validated @RequestBody Server resources){ + return new ResponseEntity<>(serverService.testConnect(resources),HttpStatus.CREATED); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/AppService.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/AppService.java new file mode 100644 index 0000000..d7500a6 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/AppService.java @@ -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 { + + /** + * 分页查询 + * @param criteria 条件 + * @param page 分页参数 + * @return / + */ + PageResult queryAll(AppQueryCriteria criteria, Page page); + + /** + * 查询全部数据 + * + * @param criteria 条件 + * @return / + */ + List queryAll(AppQueryCriteria criteria); + + /** + * 创建 + * @param resources / + */ + void create(App resources); + + /** + * 编辑 + * @param resources / + */ + void update(App resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 导出数据 + * @param apps / + * @param response / + * @throws IOException / + */ + void download(List apps, HttpServletResponse response) throws IOException; +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/DatabaseService.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/DatabaseService.java new file mode 100644 index 0000000..454a73a --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/DatabaseService.java @@ -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 { + + /** + * 分页查询 + * + * @param criteria 条件 + * @param page 分页参数 + * @return / + */ + PageResult queryAll(DatabaseQueryCriteria criteria, Page page); + + /** + * 查询全部 + * @param criteria 条件 + * @return / + */ + List queryAll(DatabaseQueryCriteria criteria); + + /** + * 创建 + * @param resources / + */ + void create(Database resources); + + /** + * 编辑 + * @param resources / + */ + void update(Database resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 测试连接 + * @param resources / + * @return / + */ + boolean testConnection(Database resources); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException e + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/DeployHistoryService.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/DeployHistoryService.java new file mode 100644 index 0000000..beff32a --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/DeployHistoryService.java @@ -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 { + + /** + * 分页查询 + * + * @param criteria 条件 + * @param page 分页参数 + * @return / + */ + PageResult queryAll(DeployHistoryQueryCriteria criteria, Page page); + + /** + * 查询全部 + * + * @param criteria 条件 + * @return / + */ + List queryAll(DeployHistoryQueryCriteria criteria); + + /** + * 创建 + * @param resources / + */ + void create(DeployHistory resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set ids); + + /** + * 导出数据 + * @param queryAll / + * @param response / + * @throws IOException / + */ + void download(List queryAll, HttpServletResponse response) throws IOException; +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/DeployService.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/DeployService.java new file mode 100644 index 0000000..08c9b97 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/DeployService.java @@ -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 { + + /** + * 分页查询 + * + * @param criteria 条件 + * @param page 分页参数 + * @return / + */ + PageResult queryAll(DeployQueryCriteria criteria, Page page); + + /** + * 查询全部数据 + * @param criteria 条件 + * @return / + */ + List queryAll(DeployQueryCriteria criteria); + + /** + * 创建 + * @param resources / + */ + void create(Deploy resources); + + + /** + * 编辑 + * @param resources / + */ + void update(Deploy resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set 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 queryAll, HttpServletResponse response) throws IOException; +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/ServerService.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/ServerService.java new file mode 100644 index 0000000..0ebe5d9 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/ServerService.java @@ -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 { + + /** + * 分页查询 + * + * @param criteria 条件 + * @param page 分页参数 + * @return / + */ + PageResult queryAll(ServerQueryCriteria criteria, Page page); + + /** + * 查询全部数据 + * @param criteria 条件 + * @return / + */ + List queryAll(ServerQueryCriteria criteria); + + /** + * 创建 + * @param resources / + */ + void create(Server resources); + + /** + * 编辑 + * @param resources / + */ + void update(Server resources); + + /** + * 删除 + * @param ids / + */ + void delete(Set 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 queryAll, HttpServletResponse response) throws IOException; +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/AppServiceImpl.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/AppServiceImpl.java new file mode 100644 index 0000000..8bd5668 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/AppServiceImpl.java @@ -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 implements AppService { + + private final AppMapper appMapper; + private final DeployMapper deployMapper; + private final DeployServerMapper deployServerMapper; + + @Override + public PageResult queryAll(AppQueryCriteria criteria, Page page){ + return PageUtil.toPage(appMapper.queryAll(criteria, page)); + } + + @Override + public List 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 ids) { + // 删除应用 + removeBatchByIds(ids); + // 删除部署 + Set deployIds = deployMapper.getIdByAppIds(ids); + if(CollUtil.isNotEmpty(deployIds)){ + deployServerMapper.deleteByDeployIds(deployIds); + deployMapper.deleteBatchIds(deployIds); + } + } + + @Override + public void download(List apps, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (App app : apps) { + Map 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); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DatabaseServiceImpl.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DatabaseServiceImpl.java new file mode 100644 index 0000000..0d18730 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DatabaseServiceImpl.java @@ -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 implements DatabaseService { + + private final DatabaseMapper databaseMapper; + + @Override + public PageResult queryAll(DatabaseQueryCriteria criteria, Page page){ + return PageUtil.toPage(databaseMapper.findAll(criteria, page)); + } + + @Override + public List 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 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 databases, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (Database database : databases) { + Map 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); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DeployHistoryServiceImpl.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DeployHistoryServiceImpl.java new file mode 100644 index 0000000..49da777 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DeployHistoryServiceImpl.java @@ -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 implements DeployHistoryService { + + private final DeployHistoryMapper deployhistoryMapper; + + @Override + public PageResult queryAll(DeployHistoryQueryCriteria criteria, Page page){ + return PageUtil.toPage(deployhistoryMapper.findAll(criteria, page)); + } + + @Override + public List 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 ids) { + removeBatchByIds(ids); + } + + @Override + public void download(List deployHistories, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (DeployHistory deployHistory : deployHistories) { + Map 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); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DeployServiceImpl.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DeployServiceImpl.java new file mode 100644 index 0000000..d77968c --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/DeployServiceImpl.java @@ -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 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 queryAll(DeployQueryCriteria criteria, Page page) { + criteria.setOffset(page.offset()); + List deploys = deployMapper.findAll(criteria); + Long total = deployMapper.countAll(criteria); + return PageUtil.toPage(deploys, total); + } + + @Override + public List 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 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 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
目录:%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("
应用:").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 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("
应用:").append(app.getName()); + boolean result = checkIsRunningStatus(app.getPort(), executeShellUtil); + if (result) { + sb.append("
正在运行"); + sendMsg(sb.toString(), MsgType.INFO); + } else { + sb.append("
已停止!"); + 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 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("
应用:").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 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("
应用:").append(app.getName()); + sendMsg("下发停止命令", MsgType.INFO); + //停止应用 + stopApp(app.getPort(), executeShellUtil); + sleep(1); + boolean result = checkIsRunningStatus(app.getPort(), executeShellUtil); + if (result) { + sb.append("
关闭失败!"); + sendMsg(sb.toString(), MsgType.ERROR); + } else { + sb.append("
关闭成功!"); + 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("
应用:").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("
启动成功!"); + sendMsg(sb.toString(), MsgType.INFO); + } else { + sb.append("
启动失败!"); + sendMsg(sb.toString(), MsgType.ERROR); + } + } + + @Override + public void download(List deploys, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (Deploy deploy : deploys) { + Map map = new LinkedHashMap<>(); + map.put("应用名称", deploy.getApp().getName()); + map.put("服务器", deploy.getServers()); + map.put("部署日期", deploy.getCreateTime()); + list.add(map); + } + FileUtil.downloadExcel(list, response); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/ServerServiceImpl.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/ServerServiceImpl.java new file mode 100644 index 0000000..6ccf865 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/impl/ServerServiceImpl.java @@ -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 implements ServerService { + + private final ServerMapper serverMapper; + private final DeployServerMapper deployServerMapper; + + @Override + public PageResult queryAll(ServerQueryCriteria criteria, Page page){ + return PageUtil.toPage(serverMapper.findAll(criteria, page)); + } + + @Override + public List 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 ids) { + removeBatchByIds(ids); + // 删除与之关联的服务 + deployServerMapper.deleteByServerIds(ids); + } + + @Override + public void download(List servers, HttpServletResponse response) throws IOException { + List> list = new ArrayList<>(); + for (Server deploy : servers) { + Map 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); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/websocket/SocketMsg.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/websocket/SocketMsg.java new file mode 100644 index 0000000..5003f6f --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/websocket/SocketMsg.java @@ -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; + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/websocket/WebSocketServer.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/websocket/WebSocketServer.java new file mode 100644 index 0000000..bcf0f9c --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/service/websocket/WebSocketServer.java @@ -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 webSocketSet = new CopyOnWriteArraySet(); + + /** + * 与某个客户端的连接会话,需要通过它来给客户端发送数据 + */ + 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); + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/util/ExecuteShellUtil.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/util/ExecuteShellUtil.java new file mode 100644 index 0000000..78c3c60 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/util/ExecuteShellUtil.java @@ -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 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(); + } + +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/util/ScpClientUtil.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/util/ScpClientUtil.java new file mode 100644 index 0000000..f54b3b5 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/util/ScpClientUtil.java @@ -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 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(); + } + } +} diff --git a/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/util/SqlUtils.java b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/util/SqlUtils.java new file mode 100644 index 0000000..75baea0 --- /dev/null +++ b/eladmin/eladmin-system/src/main/java/me/zhengjie/modules/maint/util/SqlUtils.java @@ -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 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 readSqlList(File sqlFile) { + List 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; + } +} diff --git a/eladmin/eladmin-system/src/main/resources/logback.xml b/eladmin/eladmin-system/src/main/resources/logback.xml index 05f055b..eb66625 100644 --- a/eladmin/eladmin-system/src/main/resources/logback.xml +++ b/eladmin/eladmin-system/src/main/resources/logback.xml @@ -18,5 +18,6 @@ + \ No newline at end of file diff --git a/eladmin/eladmin-system/src/main/resources/mapper/maint/AppMapper.xml b/eladmin/eladmin-system/src/main/resources/mapper/maint/AppMapper.xml new file mode 100644 index 0000000..a2542e1 --- /dev/null +++ b/eladmin/eladmin-system/src/main/resources/mapper/maint/AppMapper.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + app_id,name,port,upload_path,deploy_path,backup_path,start_script,deploy_script,create_by,update_by,create_time,update_time + + + + \ No newline at end of file diff --git a/eladmin/eladmin-system/src/main/resources/mapper/maint/DatabaseMapper.xml b/eladmin/eladmin-system/src/main/resources/mapper/maint/DatabaseMapper.xml new file mode 100644 index 0000000..1f347a3 --- /dev/null +++ b/eladmin/eladmin-system/src/main/resources/mapper/maint/DatabaseMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + db_id, name, jdbc_url, pwd, user_name, create_by, update_by, create_time, update_time + + + + \ No newline at end of file diff --git a/eladmin/eladmin-system/src/main/resources/mapper/maint/DeployHistoryMapper.xml b/eladmin/eladmin-system/src/main/resources/mapper/maint/DeployHistoryMapper.xml new file mode 100644 index 0000000..f290e42 --- /dev/null +++ b/eladmin/eladmin-system/src/main/resources/mapper/maint/DeployHistoryMapper.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + history_id, app_name, ip, deploy_date, deploy_user, deploy_id + + + + + \ No newline at end of file diff --git a/eladmin/eladmin-system/src/main/resources/mapper/maint/DeployMapper.xml b/eladmin/eladmin-system/src/main/resources/mapper/maint/DeployMapper.xml new file mode 100644 index 0000000..793b655 --- /dev/null +++ b/eladmin/eladmin-system/src/main/resources/mapper/maint/DeployMapper.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + 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 + + + + + + and app.name like concat('%',#{criteria.appName},'%') + + + and deploy.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]} + + + + + + + + + + + + \ No newline at end of file diff --git a/eladmin/eladmin-system/src/main/resources/mapper/maint/DeployServerMapper.xml b/eladmin/eladmin-system/src/main/resources/mapper/maint/DeployServerMapper.xml new file mode 100644 index 0000000..19560e9 --- /dev/null +++ b/eladmin/eladmin-system/src/main/resources/mapper/maint/DeployServerMapper.xml @@ -0,0 +1,33 @@ + + + + + + insert into mnt_deploy_server (deploy_id, server_id) + values + + #{deployId}, #{item.id} + + + + + delete from mnt_deploy_server + where deploy_id = #{deployId} + + + + delete from mnt_deploy_server + where deploy_id in + + #{id} + + + + + delete from mnt_deploy_server + where server_id in + + #{id} + + + \ No newline at end of file diff --git a/eladmin/eladmin-system/src/main/resources/mapper/maint/ServerMapper.xml b/eladmin/eladmin-system/src/main/resources/mapper/maint/ServerMapper.xml new file mode 100644 index 0000000..9252cf6 --- /dev/null +++ b/eladmin/eladmin-system/src/main/resources/mapper/maint/ServerMapper.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + server_id, name, ip, port, account, password, create_by, update_by, create_time, update_time + + + + + + \ No newline at end of file diff --git a/eladmin/pom.xml b/eladmin/pom.xml index 0d84c3a..9a0bd26 100644 --- a/eladmin/pom.xml +++ b/eladmin/pom.xml @@ -55,13 +55,6 @@ org.springframework.boot spring-boot-starter-undertow - - - - io.undertow - undertow-websockets-jsr - - diff --git a/sql/eladmin.sql b/sql/eladmin.sql index be7591d..02db5ea 100644 --- a/sql/eladmin.sql +++ b/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;