deploy-ease-platform/backend
2024-12-12 13:11:33 +08:00
..
.mvn/wrapper 首次提交 2024-11-26 13:37:58 +08:00
docs 通用解析 2024-12-11 23:33:05 +08:00
src 反序列化问题。 2024-12-12 13:11:33 +08:00
.cursorrules 增加接口连接成功时间 2024-12-03 20:12:02 +08:00
.cursorrules1 可正常启动 2024-12-03 18:16:16 +08:00
.gitattributes 首次提交 2024-11-26 13:37:58 +08:00
.gitignore 首次提交 2024-11-26 13:37:58 +08:00
.windsurfrules 反序列化问题。 2024-12-12 10:18:21 +08:00
frontend.rules 增加GIT同步实体类跟service 2024-12-03 10:22:44 +08:00
mvnw 通用解析 2024-12-10 21:51:07 +08:00
mvnw.cmd 首次提交 2024-11-26 13:37:58 +08:00
pom.xml 增加节点面板查询 2024-12-11 14:25:54 +08:00
README.md 解决死信队列的问题。 2024-12-10 20:00:00 +08:00

Deploy Ease Platform

Deploy Ease Platform 是一个现代化的部署管理平台,旨在简化和自动化应用程序的部署流程。

已实现功能

1. 外部系统管理

  • 基础功能
    • 创建外部系统支持Jenkins、Git等类型
    • 更新系统信息
    • 删除系统
    • 查询系统详情
    • 分页查询系统列表
    • 条件筛选查询
  • Jenkins集成
    • 连接测试
    • 任务同步
    • 状态检查
    • 支持用户名密码认证
    • 支持Token认证
  • Git集成
    • 仓库连接测试
    • 代码分支同步
    • 提交历史查询
    • 支持用户名密码认证
    • 支持SSH密钥认证
    • 支持Token认证

2. 用户权限管理

  • 用户管理
    • 用户注册
    • 用户登录
    • 密码重置
    • 用户信息修改
    • 用户状态管理
    • 部门分配
  • 角色管理
    • 角色创建与维护
    • 角色标签管理
    • 角色权限分配
    • 用户角色分配
  • 权限管理
    • 权限创建与维护
    • 权限分类管理
    • 权限与菜单关联
    • 权限检查与控制

3. 菜单管理

  • 基础功能
    • 菜单树维护
    • 菜单排序
    • 菜单显示控制
  • 权限集成
    • 菜单权限配置
    • 按钮权限配置
    • 数据权限配置
  • 前端集成
    • 动态路由生成
    • 菜单组件加载
    • 权限指令集成

4. 部门管理

  • 基础功能
    • 部门树维护
    • 部门编码管理
    • 部门描述维护
    • 部门排序
  • 人员管理
    • 部门负责人设置
    • 部门人员管理
    • 部门权限控制

5. 系统功能

  • 认证授权
    • JWT令牌认证
    • 权限拦截器
    • 角色检查器
    • 权限注解支持
  • 数据审计
    • 创建人记录
    • 创建时间记录
    • 更新人记录
    • 更新时间记录
    • 版本控制
  • 异常处理
    • 统一异常处理
    • 业务异常处理
    • 系统异常处理
    • 参数校验异常处理
  • 数据库支持
    • Flyway数据库版本控制
    • 基础表结构
    • 初始化数据
    • 软删除支持

6. 开发支持

  • 基础框架
    • 统一响应格式
    • 统一分页格式
    • 基础CRUD封装
    • DTO自动转换
  • 代码规范
    • 开发规范文档
    • 接口文档规范
    • 测试规范
    • 注释规范
  • 测试支持
    • 单元测试框架
    • 集成测试支持
    • 测试数据构建
    • Mock支持

7. 租户管理API

7.1 分页查询租户

GET /api/v1/tenant/page

请求参数:
{
    "pageNum": 1,              // 页码从1开始
    "pageSize": 10,            // 每页大小
    "sortField": "createTime", // 排序字段
    "sortOrder": "desc",       // 排序方式
    "code": "string",          // 租户编码(可选)
    "name": "string",          // 租户名称(可选)
    "enabled": true           // 是否启用(可选)
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "content": [{
            "id": 1,
            "createTime": "2024-01-01 12:00:00",
            "createBy": "admin",
            "updateTime": "2024-01-01 12:00:00",
            "updateBy": "admin",
            "code": "TEST",
            "name": "测试租户",
            "address": "北京市朝阳区",
            "contactName": "张三",
            "contactPhone": "13800138000",
            "email": "test@example.com",
            "enabled": true
        }],
        "totalElements": 100,
        "totalPages": 10,
        "size": 10,
        "number": 0,
        "first": true,
        "last": false,
        "empty": false
    }
}

7.2 创建租户

POST /api/v1/tenant

请求参数:
{
    "code": "TEST",                    // 租户编码(必填)
    "name": "测试租户",                // 租户名称(必填)
    "address": "北京市朝阳区",         // 地址(可选)
    "contactName": "张三",            // 联系人姓名(可选)
    "contactPhone": "13800138000",    // 联系人电话(可选)
    "email": "test@example.com",      // 联系人邮箱(可选)
    "enabled": true                   // 是否启用可选默认true
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "id": 1,
        // ... 其他字段同上
    }
}

7.3 更新租户

PUT /api/v1/tenant/{id}

请求参数:
{
    // 同创建接口
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "id": 1,
        // ... 其他字段同上
    }
}

7.4 删除租户

DELETE /api/v1/tenant/{id}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功"
}

7.5 获取租户状态

GET /api/v1/tenant/{id}/enabled

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": true    // true: 启用false: 禁用
}

7.6 更新租户状态

PUT /api/v1/tenant/{id}/enabled

请求参数:
enabled=true    // 是否启用(必填)

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功"
}

技术栈

后端技术栈

  • Spring Boot 3.x
  • Spring Security + JWT
  • Spring Data JPA
  • Flyway数据库版本控制
  • MapStruct对象映射
  • Lombok
  • JUnit 5

数据库

  • MySQL 8.0+

API文档

1. 外部系统管理API

1.1 分页查询

GET /api/v1/external-system/page

请求参数:
{
    "pageNum": 1,              // 页码从1开始
    "pageSize": 10,            // 每页大小
    "sortField": "createTime", // 排序字段
    "sortOrder": "desc",       // 排序方式
    "name": "string",          // 系统名称(可选)
    "type": "JENKINS",         // 系统类型(可选)
    "enabled": true           // 是否启用(可选)
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "content": [{
            "id": 1,
            "createTime": "2024-01-01 12:00:00",
            "createBy": "admin",
            "updateTime": "2024-01-01 12:00:00",
            "updateBy": "admin",
            "name": "Jenkins测试环境",
            "type": "JENKINS",
            "url": "http://jenkins.test.com",
            "remark": "测试环境Jenkins服务器",
            "sort": 1,
            "enabled": true,
            "authType": "USERNAME_PASSWORD",
            "username": "admin",
            "password": "******",
            "token": null,
            "syncStatus": "SUCCESS",
            "lastSyncTime": "2024-01-01 12:00:00",
            "config": "{}"
        }],
        "totalElements": 100,
        "totalPages": 10,
        "size": 10,
        "number": 0,
        "first": true,
        "last": false,
        "empty": false
    }
}

1.2 创建外部系统

POST /api/v1/external-system

请求参数:
{
    "name": "Jenkins测试环境",           // 系统名称(必填)
    "type": "JENKINS",                  // 系统类型(必填)
    "url": "http://jenkins.test.com",   // 系统地址(必填)
    "remark": "测试环境Jenkins服务器",    // 备注(可选)
    "sort": 1,                         // 排序(可选)
    "enabled": true,                   // 是否启用可选默认true
    "authType": "USERNAME_PASSWORD",    // 认证方式(必填)
    "username": "admin",               // 用户名(可选)
    "password": "password123",         // 密码(可选)
    "token": null,                     // 访问令牌(可选)
    "config": "{}"                     // 配置信息(可选)
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "id": 1,
        // ... 其他字段同上
    }
}

1.3 更新外部系统

PUT /api/v1/external-system/{id}

请求参数:
{
    // 同创建接口
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "id": 1,
        // ... 其他字段同上
    }
}

1.4 删除外部系统

DELETE /api/v1/external-system/{id}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功"
}

1.5 测试连接

POST /api/v1/external-system/{id}/test-connection

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": true
}

1.6 同步数据

POST /api/v1/external-system/{id}/sync

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功"
}

1.7 检查状态

GET /api/v1/external-system/{id}/status

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "syncStatus": "SUCCESS",
        "lastSyncTime": "2024-01-01 12:00:00"
    }
}

2. 用户认证API

2.1 用户登录

POST /api/v1/user/login

请求参数:
{
    "username": "admin",     // 用户名(必填)
    "password": "password"   // 密码(必填)
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "登录成功",
    "data": {
        "token": "eyJhbGciOiJIUzI1NiJ9...",
        "user": {
            "id": 1,
            "username": "admin",
            "nickname": "管理员",
            "email": "admin@example.com",
            "phone": "13800138000",
            "departmentId": 1,
            "departmentName": "技术部"
        }
    }
}

2.2 获取当前用户信息

GET /api/v1/user/current

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "id": 1,
        "username": "admin",
        "nickname": "管理员",
        "email": "admin@example.com",
        "phone": "13800138000",
        "departmentId": 1,
        "departmentName": "技术部"
    }
}

3. 菜单管理API

3.1 获取当前用户菜单

GET /api/v1/menu/current

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": [{
        "id": 1,
        "name": "系统管理",
        "path": "/system",
        "component": "Layout",
        "icon": "setting",
        "permission": "system:view",
        "type": 1,           // 1目录 2菜单 3按钮
        "parentId": null,
        "sort": 1,
        "hidden": false,
        "children": [{
            "id": 2,
            "name": "用户管理",
            "path": "/system/user",
            "component": "system/user/index",
            "icon": "user",
            "permission": "system:user:view",
            "type": 2,
            "parentId": 1,
            "sort": 1,
            "hidden": false,
            "children": []
        }]
    }]
}

3.2 获取菜单树

GET /api/v1/menu/tree

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": [{
        // 结构同上
    }]
}

3.3 获取权限树

GET /api/v1/menu/permission-tree

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": [{
        "id": 1,
        "name": "系统管理",
        "type": 1,
        "children": [{
            "id": 2,
            "name": "用户管理",
            "type": 2,
            "permissions": [{
                "id": 3,
                "code": "system:user:add",
                "name": "新增用户",
                "type": "BUTTON"
            }]
        }]
    }]
}

4. 部门管理API

4.1 获取部门树

GET /api/v1/department/tree

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": [{
        "id": 1,
        "code": "TECH",
        "name": "技术部",
        "description": "技术研发部门",
        "parentId": null,
        "sort": 1,
        "enabled": true,
        "leaderId": 1,
        "leaderName": "张三",
        "children": [{
            "id": 2,
            "code": "DEV",
            "name": "研发组",
            "description": "研发团队",
            "parentId": 1,
            "sort": 1,
            "enabled": true,
            "leaderId": 2,
            "leaderName": "李四",
            "children": []
        }]
    }]
}

4.2 创建部门

POST /api/v1/department

请求参数:
{
    "code": "TECH",           // 部门编码(必填)
    "name": "技术部",         // 部门名称(必填)
    "description": "技术研发部门", // 描述(可选)
    "parentId": null,         // 上级部门ID可选
    "sort": 1,               // 排序(可选)
    "enabled": true,         // 是否启用可选默认true
    "leaderId": 1,           // 负责人ID可选
    "leaderName": "张三"      // 负责人姓名(可选)
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "id": 1,
        // ... 其他字段同上
    }
}

5. 角色管理API

5.1 分配角色标签

POST /api/v1/role/{id}/tags

请求参数:
{
    "tagIds": [1, 2, 3]      // 标签ID列表
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功"
}

5.2 分配用户角色

POST /api/v1/role/{userId}/assignRoles

请求参数:
{
    "roleIds": [1, 2, 3]     // 角色ID列表
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功"
}

5.3 获取角色权限

GET /api/v1/role/{id}/permissions

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": [{
        "id": 1,
        "code": "system:user:view",
        "name": "查看用户",
        "type": "MENU",
        "sort": 1,
        "menuName": "用户管理"
    }]
}

5.4 分配角色权限

POST /api/v1/role/{id}/permissions

请求参数:
{
    "permissionIds": [1, 2, 3]    // 权限ID列表
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功"
}

6. 权限管理API

6.1 分页查询权限

GET /api/v1/permission/page

请求参数:
{
    "pageNum": 1,
    "pageSize": 10,
    "code": "system",        // 权限编码(可选)
    "name": "系统",          // 权限名称(可选)
    "type": "MENU",         // 权限类型(可选)
    "enabled": true,        // 是否启用(可选)
    "menuId": 1             // 菜单ID可选
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "content": [{
            "id": 1,
            "code": "system:user:view",
            "name": "查看用户",
            "type": "MENU",
            "sort": 1,
            "menuId": 2,
            "menuName": "用户管理"
        }],
        "totalElements": 100,
        "totalPages": 10,
        "size": 10,
        "number": 0,
        "first": true,
        "last": false,
        "empty": false
    }
}

6.2 创建权限

POST /api/v1/permission

请求参数:
{
    "code": "system:user:add",    // 权限编码(必填)
    "name": "新增用户",           // 权限名称(必填)
    "type": "BUTTON",            // 权限类型(必填)
    "menuId": 2,                 // 菜单ID必填
    "sort": 1                    // 排序(可选)
}

响应结果:
{
    "success": true,
    "code": 200,
    "message": "操作成功",
    "data": {
        "id": 1,
        // ... 其他字段同上
    }
}

开发规范

后端开发规范

  • 遵循DDD设计思想
  • 统一的异常处理
  • 统一的返回格式
  • 完整的单元测试
  • 详细的接口文档
  • 规范的代码注释

详细规范请参考:后端开发规范

前端开发规范

  • 统一的接口调用方式
  • 统一的错误处理
  • 标准的时间格式
  • 规范的国际化实现

详细规范请参考:前端开发规范

注意事项

1. 数据库

  • 所有表必须包含基础字段:
    id          BIGINT PRIMARY KEY   # 主键
    create_time DATETIME             # 创建时间
    create_by   VARCHAR(50)          # 创建人
    update_time DATETIME             # 更新时间
    update_by   VARCHAR(50)          # 更新人
    version     INT                  # 版本号
    deleted     BOOLEAN              # 是否删除
    
  • 使用Flyway进行数据库版本控制
  • 新建表结构写入V1.0.0__init_schema.sql
  • 初始数据写入V1.0.1__init_data.sql

2. 接口开发

  • 所有接口都需要JWT认证
  • 接口版本统一使用v1
  • 返回数据格式统一为:
    {
      "success": true,
      "code": 200,
      "message": "操作成功",
      "data": {}
    }
    
  • 分页查询参数统一使用:
    {
      "pageNum": 1,
      "pageSize": 10,
      "sortField": "createTime",
      "sortOrder": "desc"
    }
    

3. 异常处理

  • 业务异常统一使用BusinessException
  • 异常码在ResponseCode中定义
  • 异常信息在messages.properties中定义
  • 所有异常都通过GlobalExceptionHandler处理

4. 安全性

  • 敏感信息密码、Token等需要加密存储
  • 外部系统认证信息需要加密传输
  • 定期清理过期的Token
  • 限制API调用频率

5. 测试

  • 所有Service层代码必须有单元测试
  • 所有Controller必须有集成测试
  • 测试覆盖率要求80%以上
  • 测试数据使用@Sql注入避免影响生产数据

环境要求

  • JDK 17+
  • Maven 3.8+
  • MySQL 8.0+
  • Node.js 16+

快速开始

  1. 克隆项目
git clone [项目地址]
  1. 配置数据库
# 创建数据库
CREATE DATABASE deploy_ease DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  1. 修改配置
# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/deploy_ease
    username: your_username
    password: your_password
  1. 启动项目
mvn spring-boot:run

贡献指南

  1. Fork 项目
  2. 创建功能分支
  3. 提交代码
  4. 创建Pull Request

许可证

MIT License



workflow_definition工作流定义表
存储我们自定义的工作流定义信息
包含流程名称、标识、版本、BPMN XML内容等
与Flowable的act_re_procdef表是一对一的关系
额外存储了图形编辑器的JSON数据方便前端展示和编辑
workflow_instance工作流实例表
记录工作流的执行实例信息
存储流程实例ID、业务标识、状态、变量等
与Flowable的act_ru_execution表是一对一的关系
提供了更多的业务字段,如开始时间、结束时间等
workflow_node_instance工作流节点实例表
记录工作流中每个节点的执行情况
存储节点ID、名称、类型、状态等
与Flowable的act_ru_task和act_hi_actinst表有关联
特别记录了Shell任务的执行结果、错误信息等
workflow_log工作流日志表
记录工作流执行过程中的详细日志
可以关联到具体的实例和节点
包含日志类型、级别、内容等
方便排查问题和审计
这些表与Flowable的原生表的主要区别是

更贴近业务需求,字段设计更符合我们的使用场景
提供了更丰富的元数据和状态信息
支持更细粒度的日志记录
可以存储自定义的业务数据
这样的设计让我们可以在使用Flowable强大的工作流引擎的同时也能满足特定的业务需求。


{
    "name": "Simple Shell Workflow6",
    "key": "simple_shell_workflow",
    "description": "A simple workflow with shell task",
    "graphJson": {
        "cells": [
            {
                "id": "start",
                "shape": "start",
                "data": {
                    "label": "开始"
                },
                "position": {
                    "x": 100,
                    "y": 100
                }
            },
            {
                "id": "shell",
                "shape": "serviceTask",
                "data": {
                    "label": "Shell脚本",
                    "serviceTask": {
                        "type": "shell",
                        "implementation": "${shellTaskDelegate}",
                        "fields": {
                            "script": "timeout 10000000",
                            "workDir": "/tmp",
                            "env": {
                                "TEST_VAR": "test_value"
                            }
                        }
                    }
                },
                "position": {
                    "x": 300,
                    "y": 100
                }
            },
            {
                "id": "shellErrorBoundary",
                "shape": "boundaryEvent",
                "data": {
                    "label": "Shell错误",
                    "boundaryEvent": {
                        "type": "error",
                        "attachedToRef": "shell",
                        "errorRef": "SHELL_EXECUTION_ERROR"
                    }
                },
                "position": {
                    "x": 300,
                    "y": 160
                }
            },
            {
                "id": "errorHandler",
                "shape": "serviceTask",
                "data": {
                    "label": "错误处理",
                    "serviceTask": {
                        "type": "service",
                        "implementation": "${errorHandlerDelegate}"
                    }
                },
                "position": {
                    "x": 300,
                    "y": 220
                }
            },
            {
                "id": "end",
                "shape": "end",
                "data": {
                    "label": "结束"
                },
                "position": {
                    "x": 500,
                    "y": 100
                }
            },
            {
                "id": "flow1",
                "shape": "edge",
                "source": "start",
                "target": "shell",
                "data": {
                    "label": "流转到Shell"
                }
            },
            {
                "id": "flow2",
                "shape": "edge",
                "source": "shell",
                "target": "end",
                "data": {
                    "label": "完成"
                }
            },
            {
                "id": "flow_error",
                "shape": "edge",
                "source": "shellErrorBoundary",
                "target": "errorHandler",
                "data": {
                    "label": "错误处理"
                }
            },
            {
                "id": "flow_error_end",
                "shape": "edge",
                "source": "errorHandler",
                "target": "end",
                "data": {
                    "label": "处理完成"
                }
            }
        ]
    }
}

死信队列的问题:
需要再异常里直接移除:
runtimeService.deleteProcessInstance(processInstanceId, errorMessage);

const eventSource = new EventSource(`/api/v1/shell-logs/${processInstanceId}`);

eventSource.addEventListener('STDOUT', (event) => {
    console.log('Output:', event.data);
});

eventSource.addEventListener('STDERR', (event) => {
    console.error('Error:', event.data);
});

// 当流程结束时关闭连接
eventSource.onerror = () => {
    eventSource.close();
};