diff --git a/pom.xml b/pom.xml index c5da82755..06c1a61d0 100644 --- a/pom.xml +++ b/pom.xml @@ -29,15 +29,19 @@ 3.4.3.4 3.9.1 5.7.15 + 29.0-jre 3.0.3 + 3.0.3 11.6 4.9.1 2.5.2 3.16.3 + 2.8.0 2.2.1 3.4.1 1.3.3 2.3.0 + 1.5.2.Final 3.0.1 @@ -53,7 +57,6 @@ http://${docker.registry.url}:2375 ruoyi 1.2.2 - @@ -88,6 +91,7 @@ + io.swagger swagger-annotations @@ -168,6 +172,18 @@ ${hutool.version} + + com.google.guava + guava + ${guava.version} + + + + org.springframework.cloud + spring-cloud-starter-gateway + ${gateway.version} + + org.springframework.cloud @@ -178,6 +194,10 @@ feign-core io.github.openfeign + + org.bouncycastle + bcprov-jdk15on + @@ -186,6 +206,11 @@ feign-okhttp ${feign-okhttp.version} + + com.squareup.okio + okio + ${okio.version} + com.squareup.okhttp3 @@ -204,7 +229,24 @@ ${spring-boot-admin.version} + + + org.springframework.boot + spring-boot-starter-data-redis + + + io.lettuce + lettuce-core + + + ${spring-boot.version} + + + org.redisson + redisson + ${redisson.version} + org.redisson redisson-spring-boot-starter @@ -216,11 +258,24 @@ ${lock4j.version} + + + org.wildfly.common + wildfly-common + ${wildfly-common.version} + + com.xuxueli xxl-job-core ${xxl-job.version} + + + org.javassist + javassist + + @@ -306,6 +361,23 @@ ${ruoyi-vue-plus.version} + + + com.ruoyi + ruoyi-isc-parent + ${ruoyi-vue-plus.version} + + + com.ruoyi + ruoyi-isc-common + ${ruoyi-vue-plus.version} + + + com.ruoyi + ruoyi-isc + ${ruoyi-vue-plus.version} + + com.ruoyi @@ -327,6 +399,7 @@ ruoyi-demo ruoyi-extend ruoyi-oss + ruoyi-isc-parent pom diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 9ec68cdd1..a768215aa 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -52,10 +52,11 @@ ruoyi-job + @@ -63,6 +64,12 @@ ruoyi-generator + + + com.ruoyi + ruoyi-isc + + com.ruoyi diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java index 98f5838fc..8a467060d 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java @@ -1,11 +1,11 @@ package com.ruoyi.web.controller.system; +import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.util.ArrayUtil; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.core.domain.TreeSelect; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.StringUtils; @@ -76,7 +76,7 @@ public class SysDeptController extends BaseController { */ @ApiOperation("获取部门下拉树列表") @GetMapping("/treeselect") - public AjaxResult> treeselect(SysDept dept) { + public AjaxResult>> treeselect(SysDept dept) { List depts = deptService.selectDeptList(dept); return AjaxResult.success(deptService.buildDeptTreeSelect(depts)); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java index 1fd181637..11371f843 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java @@ -1,10 +1,10 @@ package com.ruoyi.web.controller.system; +import cn.hutool.core.lang.tree.Tree; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.constant.UserConstants; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; -import com.ruoyi.common.core.domain.TreeSelect; import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.StringUtils; @@ -61,7 +61,7 @@ public class SysMenuController extends BaseController { */ @ApiOperation("获取菜单下拉树列表") @GetMapping("/treeselect") - public AjaxResult> treeselect(SysMenu menu) { + public AjaxResult>> treeselect(SysMenu menu) { List menus = menuService.selectMenuList(menu, getUserId()); return AjaxResult.success(menuService.buildMenuTreeSelect(menus)); } diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 015b3028e..f26cedf82 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -10,8 +10,8 @@ spring: url: http://localhost:9090/admin instance: prefer-ip: true # 注册实例时,优先使用 IP - username: ruoyi - password: 123456 + username: admin + password: admin123 --- # xxl-job 配置 xxl: @@ -51,7 +51,7 @@ spring: # 主库数据源 master: driverClassName: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true + url: jdbc:mysql://192.168.64.128:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true username: root password: root # 从库数据源 @@ -113,7 +113,7 @@ spring: spring: redis: # 地址 - host: localhost + host: 192.168.64.128 # 端口,默认为6379 port: 6379 # 数据库索引 diff --git a/ruoyi-admin/src/main/resources/application-local.yml b/ruoyi-admin/src/main/resources/application-local.yml new file mode 100644 index 000000000..123b1c508 --- /dev/null +++ b/ruoyi-admin/src/main/resources/application-local.yml @@ -0,0 +1,158 @@ +--- # 监控配置 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + # 增加客户端开关 + enabled: true + # 设置 Spring Boot Admin Server 地址 + url: http://localhost:9090/admin + instance: + prefer-ip: true # 注册实例时,优先使用 IP + username: admin + password: admin123 + +--- # xxl-job 配置 +xxl: + job: + # 执行器开关 + enabled: true + # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。 + admin-addresses: http://localhost:9100/xxl-job-admin + # 执行器通讯TOKEN:非空时启用 + access-token: xxl-job + # 执行器配置 + executor: + # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册 + appname: xxl-job-executor + # 执行器端口号 执行器从9101开始往后写 + port: 9101 + # 执行器注册:默认IP:PORT + address: + # 执行器IP:默认自动获取IP + ip: + # 执行器运行日志文件存储磁盘路径 + logpath: ./logs/xxl-job + # 执行器日志文件保存天数:大于3生效 + logretentiondays: 30 + +# 数据源配置 +spring: + datasource: + type: com.alibaba.druid.pool.DruidDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: true + # 设置默认的数据源或者数据源组,默认值即为 master + primary: master + datasource: + # 主库数据源 + master: + driverClassName: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true + username: root + password: root + # 从库数据源 + slave: + lazy: true + driverClassName: com.mysql.cj.jdbc.Driver + url: + username: + password: + druid: + # 初始连接数 + initialSize: 5 + # 最小连接池数量 + minIdle: 10 + # 最大连接池数量 + maxActive: 20 + # 配置获取连接等待超时的时间 + maxWait: 60000 + # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 + timeBetweenEvictionRunsMillis: 60000 + # 配置一个连接在池中最小生存的时间,单位是毫秒 + minEvictableIdleTimeMillis: 300000 + # 配置一个连接在池中最大生存的时间,单位是毫秒 + maxEvictableIdleTimeMillis: 900000 + # 配置检测连接是否有效 + validationQuery: SELECT 1 FROM DUAL + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + # 注意这个值和druid原生不一致,默认启动了stat + filters: stat + +--- # druid 配置 +spring: + datasource: + druid: + webStatFilter: + enabled: true + statViewServlet: + enabled: true + # 设置白名单,不填则允许所有访问 + allow: + url-pattern: /druid/* + # 控制台管理用户名和密码 + login-username: ruoyi + login-password: 123456 + filter: + stat: + enabled: true + # 慢SQL记录 + log-slow-sql: true + slow-sql-millis: 1000 + merge-sql: true + wall: + config: + multi-statement-allow: true + +--- # redis 配置 +spring: + redis: + # 地址 + host: 127.0.0.1 + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 11 + # 密码 + password: + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl: false + +redisson: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 传输模式 + transportMode: "NIO" + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。 + retryAttempts: 3 + # 命令重试发送时间间隔,单位:毫秒 + retryInterval: 1500 + # 发布和订阅连接的最小空闲连接数 + subscriptionConnectionMinimumIdleSize: 1 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + # 单个连接最大订阅数量 + subscriptionsPerConnection: 5 + # DNS监测时间间隔,单位:毫秒 + dnsMonitoringInterval: 5000 diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index 9aac0e3b3..3e55fac37 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -51,7 +51,7 @@ spring: # 主库数据源 master: driverClassName: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://172.30.0.36:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true + url: jdbc:mysql://172.17.0.1:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&autoReconnect=true username: root password: root # 从库数据源 @@ -113,7 +113,7 @@ spring: spring: redis: # 地址 - host: 172.30.0.48 + host: 172.17.0.1 # 端口,默认为6379 port: 6379 # 数据库索引 diff --git a/ruoyi-admin/src/main/resources/logback.xml b/ruoyi-admin/src/main/resources/logback.xml index 33a169725..8b19a63ef 100644 --- a/ruoyi-admin/src/main/resources/logback.xml +++ b/ruoyi-admin/src/main/resources/logback.xml @@ -2,8 +2,8 @@ - + value="%red(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %green([%thread]) %boldMagenta(%logger{36}) - %msg%n"/> + @@ -31,7 +31,7 @@ INFO - + ${log.path}/sys-info.log @@ -54,7 +54,7 @@ DENY - + ${log.path}/sys-error.log @@ -76,7 +76,7 @@ DENY - + ${log.path}/sys-user.log @@ -90,7 +90,7 @@ ${log.pattern} - + @@ -99,16 +99,16 @@ - + - + - \ No newline at end of file + diff --git a/ruoyi-admin/src/main/resources/spy.properties b/ruoyi-admin/src/main/resources/spy.properties index 0ed983b3b..3af094c2a 100644 --- a/ruoyi-admin/src/main/resources/spy.properties +++ b/ruoyi-admin/src/main/resources/spy.properties @@ -1,26 +1,26 @@ -# p6spy 性能分析插件配置文件 +# p6spy \u6027\u80FD\u5206\u6790\u63D2\u4EF6\u914D\u7F6E\u6587\u4EF6 modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory -# 自定义日志打印 +# \u81EA\u5B9A\u4E49\u65E5\u5FD7\u6253\u5370 logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger -#日志输出到控制台 +#\u65E5\u5FD7\u8F93\u51FA\u5230\u63A7\u5236\u53F0 appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger -# 使用日志系统记录 sql +# \u4F7F\u7528\u65E5\u5FD7\u7CFB\u7EDF\u8BB0\u5F55 sql #appender=com.p6spy.engine.spy.appender.Slf4JLogger -# 设置 p6spy driver 代理 +# \u8BBE\u7F6E p6spy driver \u4EE3\u7406 #deregisterdrivers=true -# 取消JDBC URL前缀 +# \u53D6\u6D88JDBC URL\u524D\u7F00 useprefix=true -# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset. +# \u914D\u7F6E\u8BB0\u5F55 Log \u4F8B\u5916,\u53EF\u53BB\u6389\u7684\u7ED3\u679C\u96C6\u6709error,info,batch,debug,statement,commit,rollback,result,resultset. excludecategories=info,debug,result,commit,resultset -# 日期格式 +# \u65E5\u671F\u683C\u5F0F dateformat=yyyy-MM-dd HH:mm:ss -# 实际驱动可多个 +# \u5B9E\u9645\u9A71\u52A8\u53EF\u591A\u4E2A #driverlist=org.h2.Driver -# 是否开启慢SQL记录 +# \u662F\u5426\u5F00\u542F\u6162SQL\u8BB0\u5F55 outagedetection=true -# 慢SQL记录标准 2 秒 +# \u6162SQL\u8BB0\u5F55\u6807\u51C6 2 \u79D2 outagedetectioninterval=2 -# 是否过滤 Log +# \u662F\u5426\u8FC7\u6EE4 Log filter=true -# 过滤 Log 时所排除的表名列表,以逗号分隔 +# \u8FC7\u6EE4 Log \u65F6\u6240\u6392\u9664\u7684\u8868\u540D\u5217\u8868\uFF0C\u4EE5\u9017\u53F7\u5206\u9694 exclude=QRTZ_ diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 12f14a06e..ba6f235b6 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -46,6 +46,10 @@ org.apache.commons commons-lang3 + + com.google.guava + guava + diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java index 6d83fe30e..4b1ae5101 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java @@ -142,4 +142,14 @@ public class Constants { * LDAP 远程方法调用 */ public static final String LOOKUP_LDAP = "ldap://"; + + /** 待审核 */ + public static final String AUDIT_WAIT = "0"; + + /** 审核通过 */ + public static final String AUDIT_PASS = "1"; + + /** 审核驳回 */ + public static final String AUDIT_REJECT = "2"; + } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/IscConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/IscConstants.java new file mode 100644 index 000000000..793140ed5 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/IscConstants.java @@ -0,0 +1,16 @@ +package com.ruoyi.common.constant; + +public class IscConstants { + + /** 在线状态 在线 */ + public static final String ONLINE_STATUS_ON = "1"; + + /** 申请类型 申请服务 */ + public static final String APPLY_TYPE_APPLY = "0"; + + /** 申请类型 服务续期 */ + public static final String APPLY_TYPE_RENEWAL = "1"; + + /** 申请类型 申请修改 */ + public static final String APPLY_TYPE_MODIFY = "2"; +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java index 963ac5c4d..e69de29bb 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java @@ -1,67 +0,0 @@ -package com.ruoyi.common.core.domain; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.ruoyi.common.core.domain.entity.SysDept; -import com.ruoyi.common.core.domain.entity.SysMenu; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; - -import java.io.Serializable; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Treeselect树结构实体类 - * - * @author Lion Li - */ - -@Data -@NoArgsConstructor -@Accessors(chain = true) -@ApiModel("树结构实体类") -public class TreeSelect implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * 节点ID - */ - @ApiModelProperty(value = "节点ID") - private Long id; - - /** - * 节点名称 - */ - @ApiModelProperty(value = "节点名称") - private String label; - - /** - * 子节点 - */ - @ApiModelProperty(value = "子节点") - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private List children; - - public TreeSelect(SysDept dept) { - this.id = dept.getDeptId(); - this.label = dept.getDeptName(); - this.children = dept.getChildren() - .stream() - .map(d -> new TreeSelect((SysDept) d)) - .collect(Collectors.toList()); - } - - public TreeSelect(SysMenu menu) { - this.id = menu.getMenuId(); - this.label = menu.getMenuName(); - this.children = menu.getChildren() - .stream() - .map(d -> new TreeSelect((SysMenu) d)) - .collect(Collectors.toList()); - } - -} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java index 2d2f2e463..23024fe32 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java @@ -55,4 +55,9 @@ public enum BusinessType { * 清空数据 */ CLEAN, + + /** + * 审核 + */ + AUDIT } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java index 1e27f2494..c8c7adb08 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java @@ -1,10 +1,12 @@ package com.ruoyi.common.utils; +import cn.hutool.core.date.LocalDateTimeUtil; import org.apache.commons.lang3.time.DateFormatUtils; import java.lang.management.ManagementFactory; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.time.ZoneId; import java.util.Date; /** @@ -133,4 +135,30 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { // long sec = diff % nd % nh % nm / ns; return day + "天" + hour + "小时" + min + "分钟"; } + + /** + * 获取一天的开始时间 即00:00:00 + * + * @param date 日期 + * @return 一天的开始时间 + */ + public static Date beginOfDay(Date date) + { + return Date.from(LocalDateTimeUtil.beginOfDay(LocalDateTimeUtil.of(date)) + .atZone(ZoneId.systemDefault()).toInstant()); + } + + + + /** + * 获取一天的结束时间 即23:59:59 + * + * @param date 日期 + * @return 一天的最后一秒 + */ + public static Date endOfDay(Date date) + { + return Date.from(LocalDateTimeUtil.endOfDay(LocalDateTimeUtil.of(date)) + .atZone(ZoneId.systemDefault()).toInstant()); + } } diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/FullPathUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/FullPathUtils.java new file mode 100644 index 000000000..861ecf311 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/FullPathUtils.java @@ -0,0 +1,87 @@ +package com.ruoyi.common.utils; + +public final class FullPathUtils { + + public static final int FULL_PATH_LENGTH = 30; + public static final int FULL_PATH_LEVEL_LENGTH = 3; + public static final char REPEAT_CHAR = '0'; + public static final char REPEAT_CHAR_MAX = '9'; + + /** + * 生成 FULL_PATH + * + * @param parentFullPath 父级full_path (可空) + * @param maxFullPath 同级最大 full_path(可空) + * @return + */ + public static String genFullPath(String parentFullPath, String maxFullPath) + { + int maxNum = 0; + String parentPath = StringUtils.EMPTY; + if (StringUtils.isNotBlank(maxFullPath)) + { + int start = maxFullPath.length() - FULL_PATH_LEVEL_LENGTH; + int end = maxFullPath.length() - 1; + int temp = 0; + while (start > -1) + { + temp = Integer.parseInt(maxFullPath.substring(start, end)); + if (temp > 0) + { + parentPath = maxFullPath.substring(0, start); + break; + } + end = start; + start -= FULL_PATH_LEVEL_LENGTH; + } + maxNum = temp; + } else if (StringUtils.isNotBlank(parentFullPath)) + { + parentPath = getParentPath(parentFullPath); + } + int repeat = FULL_PATH_LENGTH - parentPath.length() - FULL_PATH_LEVEL_LENGTH; + String suffix = StringUtils.repeat(REPEAT_CHAR, repeat); + return String.format("%s%03d%s", parentPath, ++maxNum, suffix); + } + + /** + * 根据FULL_PATH 获取最大 子FULL_PATH + * + * @param fullPath + */ + public static String genMaxFullPath(String fullPath) + { + String parentPath = StringUtils.EMPTY; + if (StringUtils.isNotBlank(fullPath)) + { + parentPath = getParentPath(fullPath); + } + int repeat = FULL_PATH_LENGTH - parentPath.length(); + String suffix = StringUtils.repeat(REPEAT_CHAR_MAX, repeat); + return parentPath + suffix; + } + + /** + * 获取父 Path + * + * @param fullPath + * @return + */ + private static String getParentPath(String fullPath) + { + int temp; + int start = fullPath.length() - FULL_PATH_LEVEL_LENGTH; + int end = fullPath.length() - 1; + while (start > -1) + { + temp = Integer.parseInt(fullPath.substring(start, end)); + if (temp > 0) + { + return fullPath.substring(0, end); + } + end = start; + start -= FULL_PATH_LEVEL_LENGTH; + } + return StringUtils.EMPTY; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeUtils.java new file mode 100644 index 000000000..73246dbe4 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeUtils.java @@ -0,0 +1,132 @@ +package com.ruoyi.common.utils; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeNodeConfig; +import cn.hutool.core.lang.tree.TreeUtil; +import cn.hutool.core.lang.tree.parser.NodeParser; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 树结构工具类 + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +public class TreeUtils +{ + + public static final TreeNodeConfig DEFAULT_TREE_NODE_CONFIG = new TreeNodeConfig(); + public static final long DEFAULT_PARENT_ID = 0L; + public static final String FIELD_NODE_EXIST = "exist"; + + static { + DEFAULT_TREE_NODE_CONFIG.setNameKey("label"); + } + + /** + * 设置默认 parentId + * + * @param list + * @param nodeParser + * @param + * @return + */ + public static List> build(List list, NodeParser nodeParser) + { + return TreeUtil.build(list, DEFAULT_PARENT_ID, DEFAULT_TREE_NODE_CONFIG, nodeParser); + } + + + /** + * 树构建 + * + * @param 转换的实体 为数据源里的对象类型 + * @param ID类型 + * @param list 源数据集合 + * @param parentId 最顶层父id值 一般为 0 之类 + * @param nodeParser 转换器 + * @param needExistField 是否需要 已存在字段 + * @return List + */ + public static List> build(List list, E parentId, NodeParser nodeParser, + boolean needExistField) + { + final List> treeList = CollUtil.newArrayList(); + final TreeNodeConfig treeNodeConfig = DEFAULT_TREE_NODE_CONFIG; + Tree tree; + for (T obj : list) { + tree = new Tree<>(treeNodeConfig); + nodeParser.parse(obj, tree); + treeList.add(tree); + } + + List> finalTreeList = CollUtil.newArrayList(); + for (Tree node : treeList) { + if (ObjectUtil.equals(parentId, node.getParentId())) { + finalTreeList.add(node); + innerBuild(treeList, node, 0, treeNodeConfig.getDeep(), needExistField); + } + } + // 内存每层已经排过了 这是最外层排序 + finalTreeList = finalTreeList.stream().sorted().collect(Collectors.toList()); + return finalTreeList; + } + + /** + * 递归处理 + * + * @param treeNodes 数据集合 + * @param parentNode 当前节点 + * @param deep 已递归深度 + * @param maxDeep 最大递归深度 可能为null即不限制 + * @param needExistField 是否需要 已存在字段 + */ + private static void innerBuild(List> treeNodes, Tree parentNode, int deep, Integer maxDeep, + boolean needExistField) + { + if (CollUtil.isEmpty(treeNodes)) { + return; + } + //maxDeep 可能为空 + if (maxDeep != null && deep >= maxDeep) { + return; + } + // 每层排序 TreeNodeMap 实现了Comparable接口 + treeNodes = treeNodes.stream().sorted().collect(Collectors.toList()); + for (Tree childNode : treeNodes) { + if (parentNode.getId().equals(childNode.getParentId())) { + List> children = parentNode.getChildren(); + if (children == null) { + children = CollUtil.newArrayList(); + parentNode.setChildren(children); + } + children.add(childNode); + childNode.setParent(parentNode); + if (needExistField) { + Object pobj = parentNode.get(FIELD_NODE_EXIST); + boolean exist = pobj == null ? true : (boolean) pobj; + if (exist && !CollectionUtils.isEmpty(children)) { + long count = children.stream().filter(t -> { + Object obj = t.get(FIELD_NODE_EXIST); + if (obj != null) { + return !(boolean) obj; + } else { + return false; + } + }).count(); + if (count > 0) { + exist = false; + } + } + parentNode.put(FIELD_NODE_EXIST, exist); + } + innerBuild(treeNodes, childNode, deep + 1, maxDeep, needExistField); + } + } + } +} diff --git a/ruoyi-extend/pom.xml b/ruoyi-extend/pom.xml index e44078a52..8910dfef2 100644 --- a/ruoyi-extend/pom.xml +++ b/ruoyi-extend/pom.xml @@ -14,6 +14,7 @@ ruoyi-monitor-admin ruoyi-xxl-job-admin + ruoyi-isc-gateway diff --git a/ruoyi-extend/ruoyi-isc-gateway/pom.xml b/ruoyi-extend/ruoyi-isc-gateway/pom.xml new file mode 100644 index 000000000..ec6d5d414 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/pom.xml @@ -0,0 +1,46 @@ + + + + ruoyi-vue-plus + com.ruoyi + 3.3.0 + ../../pom.xml + + 4.0.0 + + ruoyi-isc-gateway + + + + com.ruoyi + ruoyi-isc-common + + + org.springframework.cloud + spring-cloud-starter-gateway + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.redisson + redisson-spring-boot-starter + + + de.codecentric + spring-boot-admin-starter-client + + + org.projectlombok + lombok + + + cn.hutool + hutool-all + + + + diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/GatewayApplication.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/GatewayApplication.java new file mode 100644 index 000000000..8fbc70508 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/GatewayApplication.java @@ -0,0 +1,20 @@ +package com.ruoyi.gateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * 启动程序 + * + * @author Wenchao Gong + * @date 2021-09-11 + */ +@SpringBootApplication +public class GatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(GatewayApplication.class, args); + System.out.println("Gateway 启动成功" ); + } + +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java new file mode 100644 index 000000000..85cfe323f --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/GatewayConfig.java @@ -0,0 +1,112 @@ +package com.ruoyi.gateway.config; + +import cn.hutool.extra.spring.SpringUtil; +import com.ruoyi.gateway.config.handler.GlobalErrorWebExceptionHandler; +import com.ruoyi.gateway.config.provider.RedisRouteDefinitionRepository; +import com.ruoyi.gateway.filter.CustomerGlobalFilter; +import com.ruoyi.gateway.ratelimit.CustomerRedisRateLimiter; +import com.ruoyi.gateway.utils.caching.CachingRule; +import com.ruoyi.isc.common.utils.beans.TopicMsg; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RTopic; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.cloud.gateway.event.RefreshRoutesEvent; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter; +import org.springframework.cloud.gateway.route.RouteDefinitionRepository; +import org.springframework.cloud.gateway.support.ConfigurationService; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.ReactiveStringRedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.lang.NonNull; + +import java.util.List; +import java.util.function.Consumer; + +import static com.ruoyi.isc.common.constant.IscGatewayContants.*; + +/** + * Gateway 配置文件 + * + * @author Wenchao Gong + * @date 2021-09-11 + */ +@Slf4j +@Configuration +public class GatewayConfig implements ApplicationEventPublisherAware { + public ApplicationEventPublisher publisher; + private final RedissonClient client = SpringUtil.getBean(RedissonClient.class); + + { + subscribe(TOPIC_GATEWAY_REFRESH_ROUTE, TopicMsg.class, msg -> { + publisher.publishEvent(new RefreshRoutesEvent(this)); + log.info("网关接收通知[{}]刷新本地路由!", msg); + }); + subscribe(TOPIC_GATEWAY_RULE, TopicMsg.class, msg -> { + switch (msg.getType()) { + case ADD: + case UPDATE: + case DELETE: + CachingRule.evict(msg.getId()); + log.info("网关接收通知id:[{}], type:[{}], msg:[{}]清除本地规则!", msg.getId(), msg.getType(), msg.getMsg()); + break; + case REFRESH: + CachingRule.refresh(); + log.info("网关接收通知id:[{}], type:[{}], msg:[{}]本地所有规则!", msg.getId(), msg.getType(), msg.getMsg()); + break; + default: + break; + } + }); + } + + /** + * Redis 路由仓库 + * + * @return redis路由仓库 + */ + @Bean + public RouteDefinitionRepository redisRouteDefinitionRepository() { + return new RedisRouteDefinitionRepository(client); + } + + @Bean + public CustomerRedisRateLimiter customerRedisRateLimiter(ReactiveStringRedisTemplate redisTemplate, + @Qualifier(RedisRateLimiter.REDIS_SCRIPT_NAME) RedisScript> redisScript, + ConfigurationService configurationService, DefaultRedisScript timeRedisScript) { + return new CustomerRedisRateLimiter(redisTemplate, redisScript, configurationService, timeRedisScript); + } + + @Bean + public GlobalFilter customerGlobalFilter(CustomerRedisRateLimiter customerRedisRateLimiter) { + return new CustomerGlobalFilter(customerRedisRateLimiter); + } + + @Bean + public ErrorWebExceptionHandler errorWebExceptionHandler() { + return new GlobalErrorWebExceptionHandler(); + } + + /** + * 订阅通道接收消息 + * + * @param channelKey 通道key + * @param clazz 消息类型 + * @param consumer 自定义处理 + */ + public void subscribe(String channelKey, Class clazz, Consumer consumer) { + RTopic topic = client.getTopic(channelKey); + topic.addListener(clazz, (channel, msg) -> consumer.accept(msg)); + } + + @Override + public void setApplicationEventPublisher(@NonNull ApplicationEventPublisher publisher) { + this.publisher = publisher; + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/RedisConfig.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/RedisConfig.java new file mode 100644 index 000000000..c238e3b2e --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/RedisConfig.java @@ -0,0 +1,109 @@ +package com.ruoyi.gateway.config; + +import cn.hutool.core.util.StrUtil; +import com.ruoyi.gateway.config.provider.RedissonProperties; +import lombok.extern.slf4j.Slf4j; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.codec.JsonJacksonCodec; +import org.redisson.config.Config; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; +import org.springframework.cache.annotation.CachingConfigurerSupport; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.core.script.DefaultRedisScript; + +import java.io.IOException; + +/** + * redis配置 + * + * @author Lion Li + */ +@Slf4j +@Configuration +@EnableCaching +public class RedisConfig extends CachingConfigurerSupport { + + private static final String REDIS_PROTOCOL_PREFIX = "redis://"; + private static final String REDISS_PROTOCOL_PREFIX = "rediss://"; + + @Autowired + private RedisProperties redisProperties; + + @Autowired + private RedissonProperties redissonProperties; + + @Bean(destroyMethod = "shutdown") + @ConditionalOnMissingBean(RedissonClient.class) + public RedissonClient redisson() throws IOException { + String prefix = REDIS_PROTOCOL_PREFIX; + if (redisProperties.isSsl()) { + prefix = REDISS_PROTOCOL_PREFIX; + } + Config config = new Config(); + config.setThreads(redissonProperties.getThreads()) + .setNettyThreads(redissonProperties.getNettyThreads()) + .setCodec(JsonJacksonCodec.INSTANCE) + .setTransportMode(redissonProperties.getTransportMode()); + + RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); + // 使用单机模式 + config.useSingleServer() + .setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort()) + .setConnectTimeout(((Long) redisProperties.getTimeout().toMillis()).intValue()) + .setDatabase(redisProperties.getDatabase()) + .setPassword(StrUtil.isNotBlank(redisProperties.getPassword()) ? redisProperties.getPassword() : null) + .setTimeout(singleServerConfig.getTimeout()) + .setRetryAttempts(singleServerConfig.getRetryAttempts()) + .setRetryInterval(singleServerConfig.getRetryInterval()) + .setSubscriptionsPerConnection(singleServerConfig.getSubscriptionsPerConnection()) + .setClientName(singleServerConfig.getClientName()) + .setIdleConnectionTimeout(singleServerConfig.getIdleConnectionTimeout()) + .setSubscriptionConnectionMinimumIdleSize(singleServerConfig.getSubscriptionConnectionMinimumIdleSize()) + .setSubscriptionConnectionPoolSize(singleServerConfig.getSubscriptionConnectionPoolSize()) + .setConnectionMinimumIdleSize(singleServerConfig.getConnectionMinimumIdleSize()) + .setConnectionPoolSize(singleServerConfig.getConnectionPoolSize()) + .setDnsMonitoringInterval(singleServerConfig.getDnsMonitoringInterval()); + RedissonClient redissonClient = Redisson.create(config); + log.info("初始化 redis 配置"); + return redissonClient; + } + + @Bean + public DefaultRedisScript limitScript() { + DefaultRedisScript redisScript = new DefaultRedisScript<>(); + redisScript.setScriptText(limitScriptText()); + redisScript.setResultType(Long.class); + return redisScript; + } + + /** + * 限流脚本 + */ + private String limitScriptText() { + return StrUtil.builder() + .append("local key = KEYS[1]\n") + .append("local count = tonumber(ARGV[1])\n") + .append("local time = tonumber(ARGV[2])\n") + .append("local current = tonumber(redis.call('get', key));\n") + .append("if current == nil then\n") + .append(" current = 1 \n") + .append("end\n") + //.append("redis.log(redis.LOG_WARNING, \"current \" .. current)\n") + .append("if current > count then\n") + .append(" return current;\n") + .append("end\n") + .append("current = tonumber(redis.call('incr', key))\n") + //.append("redis.log(redis.LOG_WARNING, \"current \" .. current)\n") + .append("if current == 1 then\n") + .append(" redis.call('expire', key, time)\n") + .append("end\n") + .append("return current;") + .toString(); + } + +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/handler/GlobalErrorWebExceptionHandler.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/handler/GlobalErrorWebExceptionHandler.java new file mode 100644 index 000000000..e6684d255 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/handler/GlobalErrorWebExceptionHandler.java @@ -0,0 +1,100 @@ +package com.ruoyi.gateway.config.handler; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.core.annotation.Order; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.server.RequestPath; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.server.ResponseStatusException; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.handler.ResponseStatusExceptionHandler; +import reactor.core.publisher.Mono; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +/** + * 网关异常通用处理器,只作用在webflux 环境下 , 优先级低于 {@link ResponseStatusExceptionHandler} 执行 + * @author Wenchao Gong + * @date 2021-10-18 + */ +@Slf4j +@Order(-1) +public class GlobalErrorWebExceptionHandler implements ErrorWebExceptionHandler { + + public static final String NOT_FOUND_MESSAGE = "服务不存在"; + public static final String SERVICE_UNAVAILABLE_MESSAGE = "服务暂时不可用"; + public static final String GATEWAY_TIMEOUT_MESSAGE = "服务响应超时"; + + @Override + public Mono handle(ServerWebExchange exchange, Throwable ex) + { + ServerHttpResponse response = exchange.getResponse(); + + if (response.isCommitted()) { + return Mono.error(ex); + } + + // header set + response.getHeaders().setContentType(MediaType.APPLICATION_JSON); + if (ex instanceof ResponseStatusException) { + final ResponseStatusException statusException = (ResponseStatusException) ex; + response.setStatusCode(statusException.getStatus()); + } + Optional code = Optional.ofNullable(response.getRawStatusCode()); + final String message = getMessage(ex); + + return response.writeWith(Mono.fromSupplier(() -> { + DataBufferFactory bufferFactory = response.bufferFactory(); + return bufferFactory.wrap(JSONUtil.toJsonStr(result(code, message, exchange.getRequest().getPath())) + .getBytes(StandardCharsets.UTF_8)); + })); + } + + private String getMessage(Throwable ex) + { + String reason; + if(ex instanceof ResponseStatusException) { + ResponseStatusException statusException = (ResponseStatusException) ex; + switch (statusException.getStatus()) { + case NOT_FOUND: + reason = NOT_FOUND_MESSAGE; + break; + case SERVICE_UNAVAILABLE: + reason = SERVICE_UNAVAILABLE_MESSAGE; + break; + case GATEWAY_TIMEOUT: + reason = GATEWAY_TIMEOUT_MESSAGE; + break; + default: + reason = statusException.getReason(); + } + if(log.isDebugEnabled()){ + log.debug(reason, ex); + } + if(StrUtil.isNotBlank(reason)) { + return reason; + } + } + String message = ex.getMessage(); + log.error(message, ex); + return message; + } + + private Map result(Optional code, String message, RequestPath path) { + final HashMap result = MapUtil.newHashMap(3); + result.put("code", code.orElse(HttpStatus.INTERNAL_SERVER_ERROR.value())); + result.put("message", message); + result.put("path", path.value()); + result.put("data", null); + return result; + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/RedisRouteDefinitionRepository.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/RedisRouteDefinitionRepository.java new file mode 100644 index 000000000..492de65d2 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/RedisRouteDefinitionRepository.java @@ -0,0 +1,61 @@ +package com.ruoyi.gateway.config.provider; + +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RMap; +import org.redisson.api.RedissonClient; +import org.redisson.client.codec.Codec; +import org.redisson.codec.TypedJsonJacksonCodec; +import org.springframework.cloud.gateway.route.RouteDefinition; +import org.springframework.cloud.gateway.route.RouteDefinitionRepository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import static com.ruoyi.isc.common.constant.IscRedisKeys.KEY_ROUTES; + +/** + * Redis 路由仓库 + * + * @author Wenchao Gong + * @date 2021-09-11 + */ +@Slf4j +public class RedisRouteDefinitionRepository implements RouteDefinitionRepository +{ + public static final Codec ROUTE_CODES_INSTANCE = new TypedJsonJacksonCodec(String.class, RouteDefinition.class); + private final RedissonClient redissonClient; + + public RedisRouteDefinitionRepository(RedissonClient redissonClient) + { + this.redissonClient = redissonClient; + } + + @Override + public Flux getRouteDefinitions() + { + RMap map = redissonClient.getMap(KEY_ROUTES, ROUTE_CODES_INSTANCE); + log.debug("Routes from redis size:[{}]!", map.size()); + return Flux.fromIterable(map.values()); + } + + @Override + public Mono save(Mono route) + { + return route.flatMap(definition -> { + RMap map = redissonClient.getMap(KEY_ROUTES, ROUTE_CODES_INSTANCE); + map.put(definition.getId(), definition); + log.debug("Saving route to redis id:[{}]!", definition.getId()); + return Mono.empty(); + }); + } + + @Override + public Mono delete(Mono routeId) + { + return routeId.flatMap(id -> { + RMap map = redissonClient.getMap(KEY_ROUTES, ROUTE_CODES_INSTANCE); + map.remove(id); + log.debug("Remove route from redis id:[{}]!", id); + return Mono.empty(); + }); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/RedissonProperties.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/RedissonProperties.java new file mode 100644 index 000000000..9a74bc703 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/config/provider/RedissonProperties.java @@ -0,0 +1,134 @@ +package com.ruoyi.gateway.config.provider; + +import lombok.Data; +import lombok.NoArgsConstructor; +import org.redisson.config.TransportMode; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * Redisson 配置属性 + * + * @author Lion Li + */ +@Data +@Component +@ConfigurationProperties(prefix = "redisson") +public class RedissonProperties +{ + + /** + * 线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int threads; + + /** + * Netty线程池数量,默认值 = 当前处理核数量 * 2 + */ + private int nettyThreads; + + /** + * 传输模式 + */ + private TransportMode transportMode; + + /** + * 单机服务配置 + */ + private SingleServerConfig singleServerConfig; + + /** + * 缓存组 + */ + private List cacheGroup; + + @Data + @NoArgsConstructor + public static class SingleServerConfig { + + /** + * 客户端名称 + */ + private String clientName; + + /** + * 最小空闲连接数 + */ + private int connectionMinimumIdleSize; + + /** + * 连接池大小 + */ + private int connectionPoolSize; + + /** + * 连接空闲超时,单位:毫秒 + */ + private int idleConnectionTimeout; + + /** + * 命令等待超时,单位:毫秒 + */ + private int timeout; + + /** + * 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。 + */ + private int retryAttempts; + + /** + * 命令重试发送时间间隔,单位:毫秒 + */ + private int retryInterval; + + /** + * 发布和订阅连接的最小空闲连接数 + */ + private int subscriptionConnectionMinimumIdleSize; + + /** + * 发布和订阅连接池大小 + */ + private int subscriptionConnectionPoolSize; + + /** + * 单个连接最大订阅数量 + */ + private int subscriptionsPerConnection; + + /** + * DNS监测时间间隔,单位:毫秒 + */ + private int dnsMonitoringInterval; + + } + + @Data + @NoArgsConstructor + public static class CacheGroup { + + /** + * 组id + */ + private String groupId; + + /** + * 组过期时间 + */ + private long ttl; + + /** + * 组最大空闲时间 + */ + private long maxIdleTime; + + /** + * 组最大长度 + */ + private int maxSize; + + } + +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/constant/ErrorMessageConstant.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/constant/ErrorMessageConstant.java new file mode 100644 index 000000000..917c53a5e --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/constant/ErrorMessageConstant.java @@ -0,0 +1,15 @@ +package com.ruoyi.gateway.constant; + +/** + * 错误消息常量 + * @author Wenchao Gong + * @date 2021-10-18 + */ +public interface ErrorMessageConstant { + String AK_REQUIRE = "没有找到授权码[%s]"; + String CONTENT_TYPE_NOT_SUPPORTED = "请求ContentType[%s]不支持"; + String METHOD_NOT_SUPPORTED = "请求Method[%s]不支持"; + String RATE_LIMIT = "调用次数[>%d/%s]过多"; + String RULE_EXPIRED = "规则已过期[%s]"; + String RULE_NOT_EXIST = "授权码[%s]对应服务[%s]规则不存在"; +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/AkRequireException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/AkRequireException.java new file mode 100644 index 000000000..a51c555db --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/AkRequireException.java @@ -0,0 +1,17 @@ +package com.ruoyi.gateway.exception; + +import com.ruoyi.gateway.constant.ErrorMessageConstant; + +/** + * 网关异常-AK必要 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +public class AkRequireException extends GatewayException { + + public AkRequireException(String ak) + { + super(String.format(ErrorMessageConstant.AK_REQUIRE, ak)); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/ContentTypeNotSupportedException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/ContentTypeNotSupportedException.java new file mode 100644 index 000000000..4d133af0d --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/ContentTypeNotSupportedException.java @@ -0,0 +1,18 @@ +package com.ruoyi.gateway.exception; + +import com.ruoyi.gateway.constant.ErrorMessageConstant; +import org.springframework.http.MediaType; + +/** + * 网关异常-请求方法不支持 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +public class ContentTypeNotSupportedException extends GatewayException { + + public ContentTypeNotSupportedException(MediaType contentType) + { + super(String.format(ErrorMessageConstant.CONTENT_TYPE_NOT_SUPPORTED, contentType)); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/GatewayException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/GatewayException.java new file mode 100644 index 000000000..cd7f79a42 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/GatewayException.java @@ -0,0 +1,38 @@ +package com.ruoyi.gateway.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.server.ResponseStatusException; + +/** + * 网关异常 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +public class GatewayException extends ResponseStatusException { + + public GatewayException(String reason) + { + super(HttpStatus.INTERNAL_SERVER_ERROR, reason); + } + + public GatewayException(HttpStatus status) + { + super(status); + } + + public GatewayException(HttpStatus status, String reason) + { + super(status, reason); + } + + public GatewayException(HttpStatus status, String reason, Throwable cause) + { + super(status, reason, cause); + } + + public GatewayException(int rawStatusCode, String reason, Throwable cause) + { + super(rawStatusCode, reason, cause); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/MethodNotSupportedException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/MethodNotSupportedException.java new file mode 100644 index 000000000..15fe606ff --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/MethodNotSupportedException.java @@ -0,0 +1,18 @@ +package com.ruoyi.gateway.exception; + +import com.ruoyi.gateway.constant.ErrorMessageConstant; +import org.springframework.http.HttpMethod; + +/** + * 网关异常-请求方法不支持 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +public class MethodNotSupportedException extends GatewayException { + + public MethodNotSupportedException(HttpMethod httpMethod) + { + super(String.format(ErrorMessageConstant.METHOD_NOT_SUPPORTED, httpMethod)); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RateLimitException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RateLimitException.java new file mode 100644 index 000000000..e29728513 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RateLimitException.java @@ -0,0 +1,20 @@ +package com.ruoyi.gateway.exception; + +import com.ruoyi.gateway.constant.ErrorMessageConstant; +import org.springframework.http.HttpStatus; + +import java.util.concurrent.TimeUnit; + +/** + * 网关异常-限流异常 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +public class RateLimitException extends GatewayException { + + public RateLimitException(long limit, TimeUnit timeUnit) + { + super(HttpStatus.TOO_MANY_REQUESTS, String.format(ErrorMessageConstant.RATE_LIMIT, limit, timeUnit.name())); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleExpiredException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleExpiredException.java new file mode 100644 index 000000000..d2e1e918e --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleExpiredException.java @@ -0,0 +1,20 @@ +package com.ruoyi.gateway.exception; + +import cn.hutool.core.date.DateUtil; +import com.ruoyi.gateway.constant.ErrorMessageConstant; + +import java.util.Date; + +/** + * 网关异常-规则已过期 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +public class RuleExpiredException extends GatewayException { + + public RuleExpiredException(Date endTime) + { + super(String.format(ErrorMessageConstant.RULE_EXPIRED, DateUtil.formatDateTime(endTime))); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleNotExistException.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleNotExistException.java new file mode 100644 index 000000000..15cca6e2f --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/exception/RuleNotExistException.java @@ -0,0 +1,17 @@ +package com.ruoyi.gateway.exception; + +import com.ruoyi.gateway.constant.ErrorMessageConstant; + +/** + * 网关异常-规则不存在 + * + * @author Wenchao Gong + * @date 2021-10-04 + */ +public class RuleNotExistException extends GatewayException { + + public RuleNotExistException(String ak, String path) + { + super(String.format(ErrorMessageConstant.RULE_NOT_EXIST, ak, path)); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/filter/CustomerGlobalFilter.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/filter/CustomerGlobalFilter.java new file mode 100644 index 000000000..4b49b0796 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/filter/CustomerGlobalFilter.java @@ -0,0 +1,378 @@ +package com.ruoyi.gateway.filter; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONException; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import com.ruoyi.gateway.exception.*; +import com.ruoyi.gateway.ratelimit.CustomerRedisRateLimiter; +import com.ruoyi.gateway.utils.GatewayUtils; +import com.ruoyi.isc.common.utils.beans.IscRule; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.route.Route; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; +import org.springframework.core.Ordered; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.reactive.function.server.HandlerStrategies; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.util.UriComponentsBuilder; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import static com.ruoyi.gateway.filter.CustomerGlobalFilter.AccessKey.AccessKeyType; +import static com.ruoyi.gateway.filter.CustomerGlobalFilter.AccessKey.AccessKeyType.*; +import static com.ruoyi.isc.common.constant.IscGatewayContants.*; +import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap; + +/** + * 自定义全局过滤器,操作如下: + * 1.ak 是否存在 + * 2.是否到期 + * 3.是否限流 + * 4.删除参数ak + * 5.添加隐藏参数 + * + * @author Wenchao Gong + * @date 2021-10-15 + */ +public class CustomerGlobalFilter implements GlobalFilter, Ordered { + private final CustomerRedisRateLimiter rateLimiter; + + public CustomerGlobalFilter(CustomerRedisRateLimiter rateLimiter) { + this.rateLimiter = rateLimiter; + } + + private static final TimeUnit[] TIME_UNITS = {TimeUnit.SECONDS, TimeUnit.MINUTES, TimeUnit.HOURS, TimeUnit.DAYS}; + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + final Route route = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR); + final Map metadata = route.getMetadata(); + final ServerHttpRequest request = exchange.getRequest(); + //ak 是否存在 + final HttpMethod httpMethod = request.getMethod(); + AccessKey accessKey = new AccessKey(String.valueOf(metadata.getOrDefault(CONFIG_ACCESS_KEY_NAME_KEY, + ACCESS_KEY_NAME_DEFAULT))); + accessKey.set(GatewayUtils.getValue(null, () -> request.getHeaders().get(accessKey.name)), HEADER); + MultiValueMap queryParams = request.getQueryParams().containsKey(accessKey.name) ? + new LinkedMultiValueMap<>(request.getQueryParams()) : request.getQueryParams(); + if (HttpMethod.GET.equals(httpMethod)) { + return handleGetRequest(exchange, chain, route, request, accessKey, queryParams); + } else if (HttpMethod.POST.equals(httpMethod)) { + return handlePostRequest(exchange, chain, route, request, accessKey, queryParams); + } + throw new MethodNotSupportedException(httpMethod); + } + + /** + * 处理POST 请求 + * + * @param exchange 当前服务交换器 + * @param chain 当前过滤链 + * @param route 路由信息 + * @param request 请求信息 + * @param accessKey AK信息 + * @param queryParams URL查询参数 + * @return 指示请求处理何时完成 + */ + private Mono handlePostRequest(ServerWebExchange exchange, GatewayFilterChain chain, Route route, + ServerHttpRequest request, AccessKey accessKey, + MultiValueMap queryParams) { + //处理 URL AccessKey + handleAccessKey(accessKey, () -> queryParams.get(accessKey.name), URI, false); + ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders()); + final Mono modifiedBody = serverRequest.bodyToMono(String.class).defaultIfEmpty(StrUtil.EMPTY) + .flatMap(body -> { + MediaType mediaType = request.getHeaders().getContentType(); + if (Objects.isNull(mediaType) || MediaType.APPLICATION_JSON.equals(mediaType)) { + try { + JSONObject jsonObj = StrUtil.isBlank(body) ? new JSONObject() : JSONUtil.parseObj(body); + return handlePostRequestJson(exchange, route, request, accessKey, jsonObj, queryParams); + }catch (JSONException e) { + if(Objects.nonNull(mediaType)) { + return Mono.error(e); + } + } + } else if (MediaType.APPLICATION_FORM_URLENCODED.equals(mediaType)) { + return handlePostRequestFormUrlencoded(exchange, route, request, accessKey, body, queryParams); + } + return Mono.error(() -> new ContentTypeNotSupportedException(mediaType)); + }); + //如果 AccessKey 在URI部分 URI需要重新生成 + URI uri = URI.equals(accessKey.type) ? getNewUri().apply(request, queryParams) : null; + return GatewayUtils.modifyBody(exchange, chain, modifiedBody, uri); + } + + /** + * 处理POST APPLICATION_FORM_URLENCODED 请求 + * + * @param exchange 当前服务交换器 + * @param route 路由信息 + * @param request 请求信息 + * @param accessKey AK信息 + * @param body 请求Body信息 + * @return 处理后的Body信息 + */ + private Mono handlePostRequestFormUrlencoded(ServerWebExchange exchange, Route route, + ServerHttpRequest request, AccessKey accessKey, + String body, MultiValueMap queryParams) { + + if (StrUtil.isBlank(body)) { + Assert.notBlank(accessKey.value, () -> new AkRequireException(accessKey.name)); + } + final List srcParams = Arrays.stream(body.split("&")).map(param -> param.split("=")) + .collect(Collectors.toList()); + final IscRule rule = handleRule(accessKey, () -> srcParams.stream() + .filter(param -> param.length > 0 && accessKey.name.equals(param[0])) + .map(param -> param[1]).collect(Collectors.toList()), route, BODY); + Supplier> rateLimiterAfterSupplier = () -> { + removeParam(accessKey, request, null, queryParams); + final List params = srcParams.stream().filter(param -> !accessKey.name.equals(param[0])) + .collect(Collectors.toList()); + handleHiddenParams(route, params, (next, list) -> { + Object value; + if (Objects.isNull(value = next.getValue())) { + list.add(new String[]{next.getKey(), StrUtil.EMPTY}); + } else if (value instanceof JSONArray) { + ((JSONArray) value).stream().map(String::valueOf) + .forEach(v -> list.add(new String[]{next.getKey(), v})); + } else { + list.add(new String[]{next.getKey(), next.getValue().toString()}); + } + }); + return Mono.just(params.stream().map(param -> param[0] + '=' + param[1]).collect(Collectors.joining("&"))); + }; + + return rateLimiter(exchange, rule, route, 0, rateLimiterAfterSupplier); + } + + /** + * 处理POST APPLICATION_JSON 请求 + * + * @param exchange 当前服务交换器 + * @param route 路由信息 + * @param request 请求信息 + * @param accessKey AK信息 + * @param jsonObj 请求Body JSON信息 + * @return 处理后的Body信息 + */ + private Mono handlePostRequestJson(ServerWebExchange exchange, Route route, + ServerHttpRequest request, AccessKey accessKey, + JSONObject jsonObj, MultiValueMap queryParams) { + final IscRule rule = handleRule(accessKey, () -> Collections.singletonList(jsonObj.get(accessKey.name, + String.class, true)), route, BODY); + Supplier> rateLimiterAfterSupplier = () -> { + removeParam(accessKey, request, () -> jsonObj.remove(accessKey.name), queryParams); + handleHiddenParams(route, jsonObj, (next, map) -> map.set(next.getKey(), next.getValue())); + return Mono.just(jsonObj.toString()); + }; + + return rateLimiter(exchange, rule, route, 0, rateLimiterAfterSupplier); + } + + /** + * 处理GET 请求 + * + * @param exchange 当前服务交换器 + * @param chain 当前过滤链 + * @param route 路由信息 + * @param request 请求信息 + * @param accessKey AK信息 + * @param queryParams URL查询参数 + * @return 指示请求处理何时完成 + */ + private Mono handleGetRequest(ServerWebExchange exchange, GatewayFilterChain chain, Route route, + ServerHttpRequest request, AccessKey accessKey, + MultiValueMap queryParams) { + final IscRule rule = handleRule(accessKey, () -> queryParams.get(accessKey.name), route, URI); + Supplier> rateLimiterAfterSupplier = () -> { + removeParam(accessKey, request, null, queryParams); + handleHiddenParams(route, queryParams, (next, map) -> { + Object value; + if (Objects.isNull(value = next.getValue())) { + map.add(next.getKey(), StrUtil.EMPTY); + } else if (value instanceof JSONArray) { + map.put(next.getKey(), ((JSONArray) value).toList(String.class)); + } else { + map.add(next.getKey(), value.toString()); + } + }); + ServerHttpRequest req = exchange.getRequest().mutate().uri(getNewUri().apply(request, queryParams)).build(); + return chain.filter(exchange.mutate().request(req).build()); + }; + return rateLimiter(exchange, rule, route, 0, rateLimiterAfterSupplier); + } + + private BiFunction, URI> getNewUri() { + return (request, queryParams) -> UriComponentsBuilder.fromUri(request.getURI()) + .replaceQueryParams(unmodifiableMultiValueMap(queryParams)).build().toUri(); + } + + @Override + public int getOrder() { + return -1; + } + + /** + * 处理规则 + * + * @param accessKey AK信息 + * @param valueSupplier valueList 生产者 + * @param route 路由信息 + * @param type AK类型 + * @return AK对应服务规则信息 + */ + private IscRule handleRule(AccessKey accessKey, Supplier> valueSupplier, Route route, AccessKeyType type) { + if(Objects.nonNull(valueSupplier) && Objects.nonNull(type)) { + handleAccessKey(accessKey, valueSupplier, type, true); + } + //获取规则 + final IscRule rule = GatewayUtils.getRequiredValue(() -> GatewayUtils.getRule(accessKey.value, route.getId()), + () -> new RuleNotExistException(accessKey.value, route.getId())); + //是否到期 + GatewayUtils.isBefore(rule, () -> new RuleExpiredException(rule.getExpire())); + //设置AK 到ID 为了传参方便 + rule.setId(accessKey.value); + return rule; + } + + /** + * 处理 accessKey + * + * @param accessKey AccessKey + * @param valueSupplier valueList 生产者 + * @param type AccessKeyType + * @param throwException 是否抛出异常 + */ + private void handleAccessKey(AccessKey accessKey, Supplier> valueSupplier, AccessKeyType type, boolean throwException) { + //获取AK + String value; + if(throwException) { + value = GatewayUtils.getValue(accessKey.value, valueSupplier, () -> new AkRequireException(accessKey.name)); + }else { + value = GatewayUtils.getValue(accessKey.value, valueSupplier, null); + } + accessKey.set(value, type); + } + + /** + * 删除参数 + * + * @param accessKey AK信息 + * @param request 请求 + * @param removeSupplier 删除参数提供者 + * @param queryParams URI请求参数 + * @param 类型 + */ + private void removeParam(AccessKey accessKey, ServerHttpRequest request, Supplier removeSupplier, + MultiValueMap queryParams) { + //如果header中有AK,则删除 + if (HEADER.equals(accessKey.type)) { + final HttpHeaders headers = request.getHeaders(); + if(headers.containsKey(accessKey.name)) { + request.mutate().headers(headMap -> headMap.remove(accessKey.name)).build(); + } + }else if(URI.equals(accessKey.type)) { + queryParams.remove(accessKey.name); + } + if (Objects.nonNull(removeSupplier)) { + removeSupplier.get(); + } + } + + /** + * 处理隐藏参数 + * + * @param route 路由信息 + * @param result 参数 + * @param mapper 处理参数方法 + * @param 参数类型 + */ + private void handleHiddenParams(Route route, U result, BiConsumer, U> mapper) { + final Object obj = route.getMetadata().get(CONFIG_ADD_PARAM_KEY); + if (Objects.isNull(obj)) { + return; + } + final JSONObject json = JSONUtil.parseObj(obj.toString()); + if (json.isEmpty()) { + return; + } + for (Map.Entry next : json.entrySet()) { + mapper.accept(next, result); + } + } + + /** + * 限流 + * + * @param exchange 当前服务交换器 + * @param rule 限流规则 + * @param route 路由 + * @param rateLimiterAfterSupplier 限流后操作(删除参数、添加隐藏参数,跳转) + * @param 最终返回类型 + * @return rateLimiterAfterSupplier 返回类型 + */ + private Mono rateLimiter(ServerWebExchange exchange, IscRule rule, Route route, final int index, + Supplier> rateLimiterAfterSupplier) { + final TimeUnit timeUnit = TIME_UNITS[index]; + final Long limit = TimeUnit.SECONDS.equals(timeUnit) ? rule.getSecondsLimit() : TimeUnit.MINUTES.equals(timeUnit) + ? rule.getMinutesLimit() : TimeUnit.HOURS.equals(timeUnit) ? rule.getHoursLimit() : rule.getDaysLimit(); + if (Objects.isNull(limit) || limit <= 0L) { + if (TimeUnit.DAYS.equals(timeUnit)) { + return rateLimiterAfterSupplier.get(); + } + return rateLimiter(exchange, rule, route, index + 1, rateLimiterAfterSupplier); + } + return rateLimiter.isAllowed(route.getId(), rule.getId(), limit, timeUnit).flatMap(response -> { + for (Map.Entry header : response.getHeaders().entrySet()) { + exchange.getResponse().getHeaders().add(header.getKey(), header.getValue()); + } + if (response.isAllowed()) { + if (TimeUnit.DAYS.equals(timeUnit)) { + return rateLimiterAfterSupplier.get(); + } + return rateLimiter(exchange, rule, route, index + 1, rateLimiterAfterSupplier); + } + return Mono.error(() -> new RateLimitException(limit, timeUnit)); + }); + } + + /** + * AK 信息 + */ + public static class AccessKey { + public AccessKey(String name) { + this.name = name; + } + public void set(String value, AccessKeyType type) { + if(StrUtil.isNotBlank(value)) { + this.value = value; + this.type = type; + } + } + public enum AccessKeyType { + HEADER, + URI, + BODY + } + private final String name; + private String value; + private AccessKeyType type; + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/ratelimit/CustomerRedisRateLimiter.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/ratelimit/CustomerRedisRateLimiter.java new file mode 100644 index 000000000..0eea20016 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/ratelimit/CustomerRedisRateLimiter.java @@ -0,0 +1,199 @@ +package com.ruoyi.gateway.ratelimit; + +import cn.hutool.core.date.LocalDateTimeUtil; +import cn.hutool.core.util.StrUtil; +import com.ruoyi.gateway.utils.GatewayUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter; +import org.springframework.cloud.gateway.support.ConfigurationService; +import org.springframework.data.redis.core.ReactiveStringRedisTemplate; +import org.springframework.data.redis.core.script.DefaultRedisScript; +import org.springframework.data.redis.core.script.RedisScript; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * @author Wenchao Gong + * @date 2021-10-16 + */ +@Slf4j +public class CustomerRedisRateLimiter extends RedisRateLimiter { + + private final ReactiveStringRedisTemplate redisTemplate; + + private final RedisScript> script; + private final RedisScript timeRedisScript; + + private final AtomicBoolean initialized = new AtomicBoolean(false); + + public CustomerRedisRateLimiter(ReactiveStringRedisTemplate redisTemplate, RedisScript> script, + ConfigurationService configurationService, DefaultRedisScript timeRedisScript) { + super(redisTemplate, script, configurationService); + this.redisTemplate = redisTemplate; + this.script = script; + this.timeRedisScript = timeRedisScript; + this.initialized.compareAndSet(false, true); + } + + public Mono isAllowed(String routeId, String ak, Long replenishRate, TimeUnit timeUnit) { + Config routeConfig = new Config().setReplenishRate(replenishRate.intValue()); + String id = GatewayUtils.getRouteKey(ak, routeId); + int time = 60; + LocalDateTime now = LocalDateTime.now(); + List keys; + switch (timeUnit) { + case DAYS: + time += LocalDateTimeUtil.between(now, LocalDateTime.now().with(LocalTime.MAX), ChronoUnit.SECONDS); + keys = getKeys(id, now.getDayOfMonth(), timeUnit); + break; + case HOURS: + time += (60 - now.getMinute()) * 60 - now.getSecond(); + keys = getKeys(id, now.getHour(), timeUnit); + break; + case MINUTES: + time += 60 - now.getSecond(); + keys = getKeys(id, now.getMinute(), timeUnit); + break; + case SECONDS: + return isAllowed(routeConfig, id); + default: + return Mono.just(new Response(true, getHeaders(routeConfig, -1L))); + } + return isAllowed(routeConfig, keys, time, timeUnit); + } + + public Mono isAllowed(Config routeConfig, String id) { + if (!this.initialized.get()) { + throw new IllegalStateException("RedisRateLimiter is not initialized"); + } + + // How many requests per second do you want a user to be allowed to do? + int replenishRate = routeConfig.getReplenishRate(); + + // How much bursting do you want to allow? + int burstCapacity = routeConfig.getBurstCapacity(); + + // How many tokens are requested per request? + int requestedTokens = routeConfig.getRequestedTokens(); + + try { + List keys = getKeys(id); + + // The arguments to the LUA script. time() returns unixtime in seconds. + List scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "", + Instant.now().getEpochSecond() + "", requestedTokens + ""); + // allowed, tokens_left = redis.eval(SCRIPT, keys, args) + Flux> flux = this.redisTemplate.execute(this.script, keys, scriptArgs); + // .log("redisratelimiter", Level.FINER); + return flux.onErrorResume(throwable -> { + if (log.isDebugEnabled()) { + log.debug("Error calling rate limiter lua", throwable); + } + return Flux.just(Arrays.asList(1L, -1L)); + }).reduce(new ArrayList(), (longs, l) -> { + longs.addAll(l); + return longs; + }).map(results -> { + boolean allowed = results.get(0) == 1L; + Long tokensLeft = results.get(1); + + Response response = new Response(allowed, getHeaders(routeConfig, tokensLeft)); + + if (log.isDebugEnabled()) { + log.debug("response: " + response); + } + return response; + }); + } + catch (Exception e) { + /* + * We don't want a hard dependency on Redis to allow traffic. Make sure to set + * an alert so you know if this is happening too much. Stripe's observed + * failure rate is 0.01%. + */ + log.error("Error determining if user allowed from redis", e); + } + return Mono.just(new Response(true, getHeaders(routeConfig, -1L))); + } + + public Mono isAllowed(Config routeConfig, List keys, int time, TimeUnit timeUnit) { + if (!this.initialized.get()) { + throw new IllegalStateException("RedisRateLimiter is not initialized"); + } + + // How many requests per second do you want a user to be allowed to do? + int replenishRate = routeConfig.getReplenishRate(); + + // How much bursting do you want to allow? + int burstCapacity = routeConfig.getBurstCapacity(); + + // How many tokens are requested per request? + int requestedTokens = routeConfig.getRequestedTokens(); + + try { + // The arguments to the LUA script. time() returns unixtime in seconds. + List scriptArgs = Arrays.asList(replenishRate + "", time + ""); + // allowed, tokens_left = redis.eval(SCRIPT, keys, args) + Flux flux = this.redisTemplate.execute(this.timeRedisScript, keys, scriptArgs); + // .log("redisratelimiter", Level.FINER); + return flux.next().onErrorResume(throwable -> { + if (log.isDebugEnabled()) { + log.debug("Error calling rate limiter lua", throwable); + } + return Mono.just(-1L); + }).map(tokensLeft -> { + boolean allowed = tokensLeft > 0 && tokensLeft < replenishRate; + Response response = new Response(allowed, getHeaders(routeConfig, tokensLeft, timeUnit)); + if (log.isDebugEnabled()) { + log.debug("response: " + response); + } + return response; + }); + } + catch (Exception e) { + /* + * We don't want a hard dependency on Redis to allow traffic. Make sure to set + * an alert so you know if this is happening too much. Stripe's observed + * failure rate is 0.01%. + */ + log.error("Error determining if user allowed from redis", e); + } + return Mono.just(new Response(true, getHeaders(routeConfig, -1L, timeUnit))); + } + + public Map getHeaders(Config config, Long tokensLeft, TimeUnit timeUnit) { + Map headers = new HashMap<>(); + if (isIncludeHeaders()) { + String suffix = StrUtil.upperFirst(timeUnit.name().toLowerCase()); + headers.put(this.getRemainingHeader() + '-' + suffix, tokensLeft.toString()); + headers.put(this.getReplenishRateHeader() + '-' + suffix, String.valueOf(config.getReplenishRate())); + } + return headers; + } + + static List getKeys(String id) { + // use `{}` around keys to use Redis Key hash tags + // this allows for using redis cluster + + // Make a unique key per user. + String prefix = "rate_limiter.{" + id; + + // You need two Redis keys for Token Bucket. + String tokenKey = prefix + "}.tokens"; + String timestampKey = prefix + "}.timestamp"; + return Arrays.asList(tokenKey, timestampKey); + } + + static List getKeys(String id, int now, TimeUnit timeUnit) { + String tokenKey = "rate_limiter.{" + id + ':' + now + "}." + timeUnit.name(); + return Arrays.asList(tokenKey); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/utils/GatewayUtils.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/utils/GatewayUtils.java new file mode 100644 index 000000000..05035d4ba --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/utils/GatewayUtils.java @@ -0,0 +1,187 @@ +package com.ruoyi.gateway.utils; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.extra.spring.SpringUtil; +import com.ruoyi.gateway.utils.caching.CachingRule; +import com.ruoyi.isc.common.utils.beans.IscRule; +import org.redisson.api.RMap; +import org.redisson.api.RedissonClient; +import org.redisson.client.codec.Codec; +import org.redisson.codec.TypedJsonJacksonCodec; +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage; +import org.springframework.cloud.gateway.support.BodyInserterContext; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.http.HttpHeaders; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; +import org.springframework.util.StringUtils; +import org.springframework.web.reactive.function.BodyInserter; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.net.URI; +import java.sql.Date; +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import java.util.function.Supplier; + +import static com.ruoyi.isc.common.constant.IscGatewayContants.RULE_CODES_INSTANCE; +import static com.ruoyi.isc.common.constant.IscRedisKeys.KEY_RULES; + +/** + * @author Wenchao Gong + * @date 2021-10-15 + */ +public class GatewayUtils extends com.ruoyi.isc.common.utils.GatewayUtils { + private static RedissonClient client = SpringUtil.getBean(RedissonClient.class); + + /** + * 修改请求Body + * + * @param exchange 当前服务交换器 + * @param chain 当前过滤链 + * @param publisher body体提供者 + * @param newUri 新的URI(去掉AccessKey) + * @return 指示请求处理何时完成 + */ + public static Mono modifyBody(ServerWebExchange exchange, GatewayFilterChain chain, Mono publisher, URI newUri) { + BodyInserter bodyInserter = BodyInserters.fromPublisher(publisher, String.class); + HttpHeaders headers = new HttpHeaders(); + headers.putAll(exchange.getRequest().getHeaders()); + headers.remove(HttpHeaders.CONTENT_LENGTH); + CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers); + return bodyInserter.insert(outputMessage, new BodyInserterContext()) + .then(Mono.defer(() -> { + ServerHttpRequest request = decorate(exchange, headers, outputMessage, newUri); + return chain.filter(exchange.mutate().request(request).build()); + })); + } + + + public static ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers, + CachedBodyOutputMessage outputMessage, URI newUri) { + return new ServerHttpRequestDecorator(exchange.getRequest()) { + @Override + public HttpHeaders getHeaders() { + long contentLength = headers.getContentLength(); + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.putAll(super.getHeaders()); + if (contentLength > 0L) { + httpHeaders.setContentLength(contentLength); + } else { + httpHeaders.set("Transfer-Encoding", "chunked"); + } + return httpHeaders; + } + + @Override + public Flux getBody() { + return outputMessage.getBody(); + } + + @Override + public URI getURI() + { + return Objects.isNull(newUri) ? super.getURI() : newUri; + } + }; + } + + /** + * 从 values 中获取第一个不为空 的值 + * + * @param before 获取之前的值 如果不为空直接返回 + * @param valueSupplier 值列表生产者 + * @return + */ + public static String getValue(String before, Supplier> valueSupplier) { + return getValue(before, valueSupplier, null); + } + + /** + * 从 values 中获取第一个不为空 的值 + * + * @param before 获取之前的值 如果不为空直接返回 + * @param valueSupplier 值列表生产者 + * @param errorMsgSupplier 异常信息生产者 + * @param + * @return + */ + public static String getValue(String before, Supplier> valueSupplier, + Supplier errorMsgSupplier) { + if (StringUtils.hasText(before)) { + return before; + } + final List values = valueSupplier.get(); + if (CollectionUtil.isNotEmpty(values)) { + for (String value : values) { + if (StringUtils.hasText(value)) { + before = value; + break; + } + } + } + if (Objects.nonNull(errorMsgSupplier)) { + Assert.notBlank(before, errorMsgSupplier); + } + return before; + } + + /** + * 获取必要值,可抛出异常 + * + * @param valueSupplier + * @param errorMsgSupplier + * @param + * @param + * @return + */ + public static T getRequiredValue(Supplier valueSupplier, + Supplier errorMsgSupplier) { + final T value = valueSupplier.get(); + if (Objects.nonNull(errorMsgSupplier)) { + Assert.notNull(value, errorMsgSupplier); + } + return value; + } + + + /** + * 获取规则 + * + * @param ak AK + * @param routeId 路由ID + * @return + */ + public static IscRule getRule(String ak, String routeId) { + String key = getRouteKey(ak, routeId); + return CachingRule.getRule(key, GatewayUtils::getRedisRule); + } + + /** + * 获取Redis Rule + * @param key + * @return + */ + private static IscRule getRedisRule(String key) { + final RMap map = client.getMap(KEY_RULES, RULE_CODES_INSTANCE); + return map.get(key); + } + + /** + * 断言是否超过结束时间 + * + * @param rule + * @param errorMsgSupplier + * @param + */ + public static void isBefore(IscRule rule, Supplier errorMsgSupplier) { + Assert.isTrue(Objects.nonNull(rule.getExpire()) && Date.from(Instant.now()).before(rule.getExpire()), + errorMsgSupplier); + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/utils/caching/CachingRule.java b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/utils/caching/CachingRule.java new file mode 100644 index 000000000..5ff5db1fc --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/java/com/ruoyi/gateway/utils/caching/CachingRule.java @@ -0,0 +1,53 @@ +package com.ruoyi.gateway.utils.caching; + +import com.ruoyi.isc.common.utils.beans.IscRule; +import org.springframework.cache.Cache; +import org.springframework.cache.concurrent.ConcurrentMapCache; + +import java.util.Objects; +import java.util.function.Function; + +/** + * @author Wenchao Gong + * @date 2021-10-22 + */ +public class CachingRule { + public static final String RULE_CACHE_NAME = "RULE_CACHE"; + public static final Cache RULE_CACHE = new ConcurrentMapCache(RULE_CACHE_NAME); + + /** + * 通过 Key 获取缓存中的 Rule + * + * @param key 缓存key + * @param mapper 如果缓存中没有 key 从mapper 中获取 + * @return + */ + public static IscRule getRule(String key, Function mapper) { + Cache.ValueWrapper value = RULE_CACHE.get(key); + if (Objects.nonNull(value)) { + return (IscRule) value.get(); + } + IscRule rule = mapper.apply(key); + RULE_CACHE.put(key, rule); + return rule; + } + + /** + * 清除 缓存 如果key存在 + * + * @param key 缓存key + * @return 是否清除 + */ + public static boolean evict(String key) { + return RULE_CACHE.evictIfPresent(key); + } + + /** + * 清除所有缓存 一刷新整个缓存 + * @return + */ + public static boolean refresh() { + RULE_CACHE.clear(); + return true; + } +} diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-dev.yml b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-dev.yml new file mode 100644 index 000000000..7a45512e0 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-dev.yml @@ -0,0 +1,76 @@ +--- # 监控配置 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + # 增加客户端开关 + enabled: true + # 设置 Spring Boot Admin Server 地址 + url: http://localhost:9090/admin + instance: + prefer-ip: true # 注册实例时,优先使用 IP + username: admin + password: admin123 + +--- # redis 配置 +spring: + redis: + # 地址 + host: 192.168.64.128 + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码 + password: + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl: false + +redisson: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 传输模式 + transportMode: "NIO" + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。 + retryAttempts: 3 + # 命令重试发送时间间隔,单位:毫秒 + retryInterval: 1500 + # 发布和订阅连接的最小空闲连接数 + subscriptionConnectionMinimumIdleSize: 1 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + # 单个连接最大订阅数量 + subscriptionsPerConnection: 5 + # DNS监测时间间隔,单位:毫秒 + dnsMonitoringInterval: 5000 + +--- # Actuator 监控端点的配置项 +management: + endpoints: + web: + # Actuator 提供的 API 接口的根目录。默认为 /actuator + base-path: /actuator + exposure: + # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + # 生产环境不建议放开所有 根据项目需求放开即可 + include: @endpoints.include@ + endpoint: + logfile: + external-file: ./logs/sys-console.log diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-local.yml b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-local.yml new file mode 100644 index 000000000..4f07d97b8 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-local.yml @@ -0,0 +1,76 @@ +--- # 监控配置 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + # 增加客户端开关 + enabled: true + # 设置 Spring Boot Admin Server 地址 + url: http://localhost:9090/admin + instance: + prefer-ip: true # 注册实例时,优先使用 IP + username: admin + password: admin123 + +--- # redis 配置 +spring: + redis: + # 地址 + host: 127.0.0.1 + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 11 + # 密码 + password: + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl: false + +redisson: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 传输模式 + transportMode: "NIO" + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。 + retryAttempts: 3 + # 命令重试发送时间间隔,单位:毫秒 + retryInterval: 1500 + # 发布和订阅连接的最小空闲连接数 + subscriptionConnectionMinimumIdleSize: 1 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + # 单个连接最大订阅数量 + subscriptionsPerConnection: 5 + # DNS监测时间间隔,单位:毫秒 + dnsMonitoringInterval: 5000 + +--- # Actuator 监控端点的配置项 +management: + endpoints: + web: + # Actuator 提供的 API 接口的根目录。默认为 /actuator + base-path: /actuator + exposure: + # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + # 生产环境不建议放开所有 根据项目需求放开即可 + include: @endpoints.include@ + endpoint: + logfile: + external-file: ./logs/sys-console.log diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-prod.yml b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-prod.yml new file mode 100644 index 000000000..0cedf863f --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application-prod.yml @@ -0,0 +1,76 @@ +--- # 监控配置 +spring: + boot: + admin: + # Spring Boot Admin Client 客户端的相关配置 + client: + # 增加客户端开关 + enabled: true + # 设置 Spring Boot Admin Server 地址 + url: http://172.17.0.1:9090/admin + instance: + prefer-ip: true # 注册实例时,优先使用 IP + username: admin + password: admin@123456 + +--- # redis 配置 +spring: + redis: + # 地址 + host: 172.17.0.1 + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # 密码 + password: + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl: false + +redisson: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 传输模式 + transportMode: "NIO" + # 单节点配置 + singleServerConfig: + # 客户端名称 + clientName: ${ruoyi.name} + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 如果尝试在此限制之内发送成功,则开始启用 timeout 计时。 + retryAttempts: 3 + # 命令重试发送时间间隔,单位:毫秒 + retryInterval: 1500 + # 发布和订阅连接的最小空闲连接数 + subscriptionConnectionMinimumIdleSize: 1 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + # 单个连接最大订阅数量 + subscriptionsPerConnection: 5 + # DNS监测时间间隔,单位:毫秒 + dnsMonitoringInterval: 5000 + +--- # Actuator 监控端点的配置项 +management: + endpoints: + web: + # Actuator 提供的 API 接口的根目录。默认为 /actuator + base-path: /actuator + exposure: + # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。 + # 生产环境不建议放开所有 根据项目需求放开即可 + include: @endpoints.include@ + endpoint: + logfile: + external-file: ./logs/sys-console.log diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application.yml b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application.yml new file mode 100644 index 000000000..99a081b1e --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/application.yml @@ -0,0 +1,20 @@ +# 项目相关配置 +ruoyi: + # 名称 + name: RuoYi-Vue-Plus + # 版本 + version: ${ruoyi-vue-plus.version} + # 版权年份 + copyrightYear: 2021 + # 实例演示开关 + demoEnabled: true + # 获取ip地址开关 + addressEnabled: true +server: + port: 8090 +# Spring配置 +spring: + application: + name: RuoYi-Gateway + profiles: + active: @profiles.active@ diff --git a/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/logback.xml b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/logback.xml new file mode 100644 index 000000000..663eef0c5 --- /dev/null +++ b/ruoyi-extend/ruoyi-isc-gateway/src/main/resources/logback.xml @@ -0,0 +1,114 @@ + + + + + + + + + + ${console.log.pattern} + utf-8 + + + + + + ${log.path}/sys-console.log + + + ${log.path}/sys-console.%d{yyyy-MM-dd}.log + + 1 + + + ${log.pattern} + utf-8 + + + + INFO + + + + + + ${log.path}/sys-info.log + + + + ${log.path}/sys-info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/sys-error.log + + + + ${log.path}/sys-error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + ${log.path}/sys-user.log + + + ${log.path}/sys-user.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-extend/ruoyi-monitor-admin/pom.xml b/ruoyi-extend/ruoyi-monitor-admin/pom.xml index 33a78516d..1724e05a0 100644 --- a/ruoyi-extend/ruoyi-monitor-admin/pom.xml +++ b/ruoyi-extend/ruoyi-monitor-admin/pom.xml @@ -28,6 +28,22 @@ de.codecentric spring-boot-admin-starter-server + + + org.springframework.boot + spring-boot-starter-jdbc + + + + mysql + mysql-connector-java + + + + + com.alibaba + druid-spring-boot-starter + diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java index ca9072c78..2c41b3811 100644 --- a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/com/ruoyi/monitor/admin/config/SecurityConfig.java @@ -1,13 +1,19 @@ package com.ruoyi.monitor.admin.config; import de.codecentric.boot.admin.server.config.AdminServerProperties; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import javax.sql.DataSource; + /** * admin 监控 安全配置 * @@ -45,4 +51,20 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .headers().frameOptions().disable(); } + @Bean + public UserDetailsService userDetailsService(DataSource dataSource) { + JdbcDaoImpl service = new JdbcDaoImpl(); + service.setDataSource(dataSource); + return service; + } + + /** + * 强散列哈希加密实现 + */ + @Bean + public BCryptPasswordEncoder bCryptPasswordEncoder() + { + return new BCryptPasswordEncoder(); + } + } diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-dev.yml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-dev.yml new file mode 100644 index 000000000..89832e3ff --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-dev.yml @@ -0,0 +1,7 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + url: jdbc:mysql://192.168.64.128:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true + username: root + password: root \ No newline at end of file diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-local.yml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-local.yml new file mode 100644 index 000000000..0a9ae9bf1 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-local.yml @@ -0,0 +1,7 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + url: jdbc:mysql://127.0.0.1:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true + username: root + password: root \ No newline at end of file diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml new file mode 100644 index 000000000..68fb54360 --- /dev/null +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application-prod.yml @@ -0,0 +1,7 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + type: com.alibaba.druid.pool.DruidDataSource + url: jdbc:mysql://172.17.0.1:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&autoReconnect=true + username: root + password: root \ No newline at end of file diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml index 631f3e772..012bdab41 100644 --- a/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml +++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml @@ -1,11 +1,8 @@ server: port: 9090 - spring: - security: - user: - name: ruoyi - password: 123456 boot: admin: context-path: /admin + profiles: + active: @profiles.active@ \ No newline at end of file diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-dev.yml b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-dev.yml index 065b34262..0aa77cb64 100644 --- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-dev.yml +++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-dev.yml @@ -3,12 +3,12 @@ spring: datasource: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai + url: jdbc:mysql://192.168.64.128:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true username: root password: root hikari: auto-commit: true - connection-test-query: SELECT 1 + connection-test-query: SELECT 1 FROM DUAL connection-timeout: 10000 idle-timeout: 30000 max-lifetime: 900000 diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-local.yml b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-local.yml new file mode 100644 index 000000000..192d9226a --- /dev/null +++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-local.yml @@ -0,0 +1,36 @@ +--- # 数据库配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://127.0.0.1:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true + username: root + password: root + hikari: + auto-commit: true + connection-test-query: SELECT 1 FROM DUAL + connection-timeout: 10000 + idle-timeout: 30000 + max-lifetime: 900000 + maximum-pool-size: 30 + minimum-idle: 10 + pool-name: HikariCP + validation-timeout: 1000 + +--- # 邮件配置 +spring: + mail: + from: xxx@qq.com + host: smtp.qq.com + username: xxx@qq.com + password: xxx + port: 25 + properties: + mail: + smtp: + auth: true + socketFactory: + class: javax.net.ssl.SSLSocketFactory + starttls: + enable: true + required: true diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-prod.yml b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-prod.yml index 774d7f81c..2c221267f 100644 --- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-prod.yml +++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/application-prod.yml @@ -3,12 +3,12 @@ spring: datasource: type: com.zaxxer.hikari.HikariDataSource driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://172.30.0.92:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai + url: jdbc:mysql://172.17.0.1:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&autoReconnect=true username: root password: root hikari: auto-commit: true - connection-test-query: SELECT 1 + connection-test-query: SELECT 1 FROM DUAL connection-timeout: 10000 idle-timeout: 30000 max-lifetime: 900000 diff --git a/ruoyi-generator/src/main/resources/vm/java/service.java.vm b/ruoyi-generator/src/main/resources/vm/java/service.java.vm index 0041c398c..1cba5626b 100644 --- a/ruoyi-generator/src/main/resources/vm/java/service.java.vm +++ b/ruoyi-generator/src/main/resources/vm/java/service.java.vm @@ -18,43 +18,43 @@ import java.util.List; * @date ${datetime} */ public interface I${ClassName}Service extends IServicePlus<${ClassName}, ${ClassName}Vo> { - /** - * 查询单个 - * @return - */ - ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}); + /** + * 查询单个 + * @return + */ + ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}); #if($table.crud || $table.sub) - /** - * 查询列表 - */ + /** + * 查询列表 + */ TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo); #end - /** - * 查询列表 - */ - List<${ClassName}Vo> queryList(${ClassName}Bo bo); + /** + * 查询列表 + */ + List<${ClassName}Vo> queryList(${ClassName}Bo bo); - /** - * 根据新增业务对象插入${functionName} - * @param bo ${functionName}新增业务对象 - * @return - */ - Boolean insertByBo(${ClassName}Bo bo); + /** + * 根据新增业务对象插入${functionName} + * @param bo ${functionName}新增业务对象 + * @return + */ + Boolean insertByBo(${ClassName}Bo bo); - /** - * 根据编辑业务对象修改${functionName} - * @param bo ${functionName}编辑业务对象 - * @return - */ - Boolean updateByBo(${ClassName}Bo bo); + /** + * 根据编辑业务对象修改${functionName} + * @param bo ${functionName}编辑业务对象 + * @return + */ + Boolean updateByBo(${ClassName}Bo bo); - /** - * 校验并删除数据 - * @param ids 主键集合 - * @param isValid 是否校验,true-删除前校验,false-不校验 - * @return - */ - Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid); + /** + * 校验并删除数据 + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid); } diff --git a/ruoyi-isc-parent/pom.xml b/ruoyi-isc-parent/pom.xml new file mode 100644 index 000000000..1b0fcf665 --- /dev/null +++ b/ruoyi-isc-parent/pom.xml @@ -0,0 +1,33 @@ + + + + ruoyi-vue-plus + com.ruoyi + 3.3.0 + + 4.0.0 + + ruoyi-isc-parent + pom + + ruoyi-isc-common + ruoyi-isc + + + + + + com.ruoyi + ruoyi-isc-common + ${project.version} + + + com.ruoyi + ruoyi-isc + ${project.version} + + + + \ No newline at end of file diff --git a/ruoyi-isc-parent/ruoyi-isc-common/pom.xml b/ruoyi-isc-parent/ruoyi-isc-common/pom.xml new file mode 100644 index 000000000..6e911eae8 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc-common/pom.xml @@ -0,0 +1,30 @@ + + + + ruoyi-isc-parent + com.ruoyi + 3.3.0 + + 4.0.0 + + ruoyi-isc-common + + + + org.projectlombok + lombok + compile + + + com.fasterxml.jackson.core + jackson-annotations + + + org.redisson + redisson + + + + \ No newline at end of file diff --git a/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/constant/IscGatewayContants.java b/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/constant/IscGatewayContants.java new file mode 100644 index 000000000..c11959f5b --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/constant/IscGatewayContants.java @@ -0,0 +1,31 @@ +package com.ruoyi.isc.common.constant; + +import com.ruoyi.isc.common.utils.beans.IscRule; +import org.redisson.client.codec.Codec; +import org.redisson.codec.TypedJsonJacksonCodec; + +/** + * Isc Gateway 公共常量 + * @author Wenchao Gong + * @date 2021-10-30 + */ +public interface IscGatewayContants { + + /** AccessKey 默认名称 */ + String ACCESS_KEY_NAME_DEFAULT = "ak"; + + /** 路由刷新通知主题 */ + String TOPIC_GATEWAY_REFRESH_ROUTE = "TOPIC_GATEWAY_REFRESH_ROUTE"; + + /** 规则刷新通知主题 */ + String TOPIC_GATEWAY_RULE = "TOPIC_GATEWAY_RULE"; + + /** AccessKeyName 路由配置名称 */ + String CONFIG_ACCESS_KEY_NAME_KEY = "accessKeyName"; + + /** 添加参数 路由配置名称 */ + String CONFIG_ADD_PARAM_KEY = "addParam"; + + /** 规则编解码器 */ + Codec RULE_CODES_INSTANCE = new TypedJsonJacksonCodec(String.class, IscRule.class); +} diff --git a/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/constant/IscRedisKeys.java b/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/constant/IscRedisKeys.java new file mode 100644 index 000000000..af8e847c5 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/constant/IscRedisKeys.java @@ -0,0 +1,19 @@ +package com.ruoyi.isc.common.constant; + +/** + * Redis Keys + * @author Wenchao Gong + * @date 2021-10-30 + */ +public interface IscRedisKeys { + + /** + * Gateway 路由信息Redis Key + */ + String KEY_ROUTES = "ROUTES:"; + + /** + * Gateway 服务对应AK规则 + */ + String KEY_RULES = "RULES:"; +} diff --git a/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/utils/GatewayUtils.java b/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/utils/GatewayUtils.java new file mode 100644 index 000000000..620e4a8da --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/utils/GatewayUtils.java @@ -0,0 +1,30 @@ +package com.ruoyi.isc.common.utils; + +/** + * @author Wenchao Gong + * @date 2021-10-30 + */ +public class GatewayUtils { + + /** + * 获取 路由Key + * + * @param ak AccessKey + * @param serviceId 服务ID + * @return 路由Key + */ + public static String getRouteKey(String ak, String serviceId) { + return ak + ':' + serviceId; + } + + /** + * 获取 路由Key + * + * @param ak AccessKey + * @param serviceId 服务ID + * @return 路由Key + */ + public static String getRouteKey(String ak, Long serviceId) { + return getRouteKey(ak, String.valueOf(serviceId)); + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/utils/beans/IscRule.java b/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/utils/beans/IscRule.java new file mode 100644 index 000000000..a637fa164 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/utils/beans/IscRule.java @@ -0,0 +1,26 @@ +package com.ruoyi.isc.common.utils.beans; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.Getter; +import lombok.Setter; + +import java.io.Serializable; +import java.util.Date; + +/** + * 网关 规则信息(服务对应AK处理规则) + * @author Wechao Gong + * @date 2021-10-16 + */ +@Getter +@Setter +public class IscRule implements Serializable +{ + @JsonIgnore + private String id; + private Date expire; + private Long daysLimit; + private Long hoursLimit; + private Long minutesLimit; + private Long secondsLimit; +} diff --git a/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/utils/beans/TopicMsg.java b/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/utils/beans/TopicMsg.java new file mode 100644 index 000000000..91d64e5ee --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc-common/src/main/java/com/ruoyi/isc/common/utils/beans/TopicMsg.java @@ -0,0 +1,37 @@ +package com.ruoyi.isc.common.utils.beans; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author Wenchao Gong + * @date 2021-10-26 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class TopicMsg implements Serializable { + /** 消息ID */ + private String id; + + /** 消息内容 */ + private String msg; + + /** 消息类型 */ + private Type type; + + /** 消息类型枚举 */ + public static enum Type { + /** 新增单条记录 */ + ADD, + /** 更新单条记录 */ + UPDATE, + /** 删除单条记录 */ + DELETE, + /** 刷新所有 */ + REFRESH + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/pom.xml b/ruoyi-isc-parent/ruoyi-isc/pom.xml new file mode 100644 index 000000000..25ee9f7be --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/pom.xml @@ -0,0 +1,25 @@ + + + + ruoyi-isc-parent + com.ruoyi + 3.3.0 + + 4.0.0 + + ruoyi-isc + + + + com.ruoyi + ruoyi-isc-common + + + com.ruoyi + ruoyi-system + + + + \ No newline at end of file diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscAppServiceApplyController.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscAppServiceApplyController.java new file mode 100644 index 000000000..7da1fdbbb --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscAppServiceApplyController.java @@ -0,0 +1,87 @@ +package com.ruoyi.isc.controller; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.core.validate.QueryGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.isc.domain.bo.IscAppServiceApplyBo; +import com.ruoyi.isc.domain.bo.IscAuditBo; +import com.ruoyi.isc.domain.vo.IscAppServiceApplyVo; +import com.ruoyi.isc.service.IIscAppServiceApplyService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +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 javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 应用服务申请信息Controller + * + * @author Wenchao Gong + * @date 2021-09-09 + */ +@Validated +@Api(value = "应用服务申请信息控制器", tags = {"应用服务申请信息管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@RestController +@RequestMapping("/isc/serviceapply") +public class IscAppServiceApplyController extends BaseController { + + private final IIscAppServiceApplyService iIscAppServiceApplyService; + + /** + * 查询应用服务申请信息列表 + */ + @ApiOperation("查询应用服务申请信息列表") + @PreAuthorize("@ss.hasPermi('isc:serviceapply:list')") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) IscAppServiceApplyBo bo) { + return iIscAppServiceApplyService.queryPageList(bo); + } + + /** + * 导出应用服务申请信息列表 + */ + @ApiOperation("导出应用服务申请信息列表") + @PreAuthorize("@ss.hasPermi('isc:serviceapply:export')") + @Log(title = "应用服务申请信息", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public void export(@Validated IscAppServiceApplyBo bo, HttpServletResponse response) { + List list = iIscAppServiceApplyService.queryList(bo); + ExcelUtil.exportExcel(list, "应用服务申请信息", IscAppServiceApplyVo.class, response); + } + + /** + * 获取应用服务申请信息详细信息 + */ + @ApiOperation("获取应用服务申请信息详细信息") + @PreAuthorize("@ss.hasPermi('isc:serviceapply:query')") + @GetMapping("/{applyId}") + public AjaxResult getInfo(@NotNull(message = "主键不能为空") + @PathVariable("applyId") Long applyId) { + return AjaxResult.success(iIscAppServiceApplyService.queryById(applyId)); + } + + /** + * 应用服务申请信息审核 + */ + @ApiOperation("应用服务申请信息审核") + @PreAuthorize("@ss.hasPermi('isc:serviceapply:audit')") + @Log(title = "应用服务申请信息审核", businessType = BusinessType.AUDIT) + @RepeatSubmit() + @PutMapping("/audit") + public AjaxResult audit(@Validated @RequestBody IscAuditBo bo) { + return toAjax(iIscAppServiceApplyService.audit(bo) ? 1 : 0); + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscAppServiceController.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscAppServiceController.java new file mode 100644 index 000000000..833e750ab --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscAppServiceController.java @@ -0,0 +1,124 @@ +package com.ruoyi.isc.controller; + +import cn.hutool.core.lang.tree.Tree; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.core.validate.QueryGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.isc.domain.bo.IscAppServiceBo; +import com.ruoyi.isc.domain.vo.IscAppServiceVo; +import com.ruoyi.isc.service.IIscAppServiceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +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 javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.List; + +/** + * 应用服务Controller + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +@Validated +@Api(value = "应用服务控制器", tags = {"应用服务管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@RestController +@RequestMapping("/isc/appservice") +public class IscAppServiceController extends BaseController { + + private final IIscAppServiceService appServiceService; + + /** + * 查询应用服务列表 + */ + @ApiOperation("查询应用服务列表") + @PreAuthorize("@ss.hasPermi('isc:appservice:list')") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) IscAppServiceBo bo) { + return appServiceService.queryPageList(bo); + } + + /** + * 导出应用服务列表 + */ + @ApiOperation("导出应用服务列表") + @PreAuthorize("@ss.hasPermi('isc:appservice:export')") + @Log(title = "应用服务", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public void export(@Validated IscAppServiceBo bo, HttpServletResponse response) { + List list = appServiceService.queryList(bo); + ExcelUtil.exportExcel(list, "应用服务", IscAppServiceVo.class, response); + } + + /** + * 获取应用服务详细信息 + */ + @ApiOperation("获取应用服务详细信息") + @PreAuthorize("@ss.hasPermi('isc:appservice:query')") + @GetMapping("/{appServiceId}") + public AjaxResult getInfo(@NotNull(message = "主键不能为空") + @PathVariable("appServiceId") Long appServiceId) { + return AjaxResult.success(appServiceService.queryById(appServiceId)); + } + + /** + * 新增应用服务 + */ + @ApiOperation("新增应用服务") + @PreAuthorize("@ss.hasPermi('isc:appservice:add')") + @Log(title = "应用服务", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public AjaxResult add(@Validated(AddGroup.class) @RequestBody IscAppServiceBo bo) { + return toAjax(appServiceService.insertByBo(bo) ? 1 : 0); + } + + /** + * 修改应用服务 + */ + @ApiOperation("修改应用服务") + @PreAuthorize("@ss.hasPermi('isc:appservice:edit')") + @Log(title = "应用服务", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public AjaxResult edit(@Validated(EditGroup.class) @RequestBody IscAppServiceBo bo) { + return toAjax(appServiceService.updateByBo(bo) ? 1 : 0); + } + + /** + * 删除应用服务 + */ + @ApiOperation("删除应用服务") + @PreAuthorize("@ss.hasPermi('isc:appservice:remove')") + @Log(title = "应用服务" , businessType = BusinessType.DELETE) + @DeleteMapping("/{appServiceIds}") + public AjaxResult remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] appServiceIds) { + return toAjax(appServiceService.deleteWithValidByIds(Arrays.asList(appServiceIds), true) ? 1 : 0); + } + + /** + * 获取应用服务下拉树列表 + */ + @GetMapping("/treeselect/{applicationId}") + @ApiOperation("获取应用服务下拉树列表") + public AjaxResult>> treeselect(@NotNull(message = "应用主键不能为空") @PathVariable Long applicationId) + { + return AjaxResult.success(appServiceService.genAppServiceTree(applicationId)); + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscApplicationController.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscApplicationController.java new file mode 100644 index 000000000..e743203c0 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscApplicationController.java @@ -0,0 +1,113 @@ +package com.ruoyi.isc.controller; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.core.validate.QueryGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.isc.domain.bo.IscApplicationBo; +import com.ruoyi.isc.domain.vo.IscApplicationVo; +import com.ruoyi.isc.service.IIscApplicationService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +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 javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.List; + +/** + * 应用信息Controller + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +@Validated +@Api(value = "应用信息控制器", tags = {"应用信息管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@RestController +@RequestMapping("/isc/application") +public class IscApplicationController extends BaseController { + + private final IIscApplicationService iIscApplicationService; + + /** + * 查询应用信息列表 + */ + @ApiOperation("查询应用信息列表") + @PreAuthorize("@ss.hasPermi('isc:application:list')") + @GetMapping("/list") + public TableDataInfo list(@Validated(QueryGroup.class) IscApplicationBo bo) { + return iIscApplicationService.queryPageList(bo); + } + + /** + * 导出应用信息列表 + */ + @ApiOperation("导出应用信息列表") + @PreAuthorize("@ss.hasPermi('isc:application:export')") + @Log(title = "应用信息", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public void export(@Validated IscApplicationBo bo, HttpServletResponse response) { + List list = iIscApplicationService.queryList(bo); + ExcelUtil.exportExcel(list, "应用信息", IscApplicationVo.class, response); + } + + /** + * 获取应用信息详细信息 + */ + @ApiOperation("获取应用信息详细信息") + @PreAuthorize("@ss.hasPermi('isc:application:query')") + @GetMapping("/{applicationId}") + public AjaxResult getInfo(@NotNull(message = "主键不能为空") + @PathVariable("applicationId") Long applicationId) { + return AjaxResult.success(iIscApplicationService.queryById(applicationId)); + } + + /** + * 新增应用信息 + */ + @ApiOperation("新增应用信息") + @PreAuthorize("@ss.hasPermi('isc:application:add')") + @Log(title = "应用信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public AjaxResult add(@Validated(AddGroup.class) @RequestBody IscApplicationBo bo) { + return toAjax(iIscApplicationService.insertByBo(bo) ? 1 : 0); + } + + /** + * 修改应用信息 + */ + @ApiOperation("修改应用信息") + @PreAuthorize("@ss.hasPermi('isc:application:edit')") + @Log(title = "应用信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public AjaxResult edit(@Validated(EditGroup.class) @RequestBody IscApplicationBo bo) { + return toAjax(iIscApplicationService.updateByBo(bo) ? 1 : 0); + } + + /** + * 删除应用信息 + */ + @ApiOperation("删除应用信息") + @PreAuthorize("@ss.hasPermi('isc:application:remove')") + @Log(title = "应用信息" , businessType = BusinessType.DELETE) + @DeleteMapping("/{applicationIds}") + public AjaxResult remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] applicationIds) { + return toAjax(iIscApplicationService.deleteWithValidByIds(Arrays.asList(applicationIds), true) ? 1 : 0); + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscServiceCateController.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscServiceCateController.java new file mode 100644 index 000000000..15b57cd13 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscServiceCateController.java @@ -0,0 +1,135 @@ +package com.ruoyi.isc.controller; + +import java.util.List; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.TreeUtil; +import cn.hutool.core.lang.tree.parser.NodeParser; +import com.ruoyi.common.core.domain.entity.SysMenu; +import com.ruoyi.common.utils.TreeUtils; +import com.ruoyi.isc.domain.IscServiceCate; +import lombok.RequiredArgsConstructor; + +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.*; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.isc.domain.vo.IscServiceCateVo; +import com.ruoyi.isc.domain.bo.IscServiceCateBo; +import com.ruoyi.isc.service.IIscServiceCateService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; + +/** + * 服务分类Controller + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +@Validated +@Api(value = "服务分类控制器", tags = {"服务分类管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@RestController +@RequestMapping("/isc/cate") +public class IscServiceCateController extends BaseController { + + private final IIscServiceCateService cateService; + + /** + * 查询服务分类列表 + */ + @ApiOperation("查询服务分类列表") + @PreAuthorize("@ss.hasPermi('isc:cate:list')") + @GetMapping("/list") + public AjaxResult> list(@Validated IscServiceCateBo bo) + { + List list = cateService.queryList(bo); + return AjaxResult.success(list); + } + + /** + * 获取分类下拉树列表 + */ + @GetMapping("/treeselect") + @ApiOperation("获取分类下拉树列表") + public AjaxResult>> treeselect() + { + List cates = cateService.selectCateList(); + return AjaxResult.success(cateService.genCateTree(cates)); + } + + /** + * 导出服务分类列表 + */ + @ApiOperation("导出服务分类列表") + @PreAuthorize("@ss.hasPermi('isc:cate:export')") + @Log(title = "服务分类", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public void export(@Validated IscServiceCateBo bo, HttpServletResponse response) + { + List list = cateService.queryList(bo); + ExcelUtil.exportExcel(list, "服务分类", IscServiceCateVo.class, response); + } + + /** + * 获取服务分类详细信息 + */ + @ApiOperation("获取服务分类详细信息") + @PreAuthorize("@ss.hasPermi('isc:cate:query')") + @GetMapping("/{cateId}") + public AjaxResult getInfo(@NotNull(message = "主键不能为空") @PathVariable("cateId") Long cateId) + { + return AjaxResult.success(cateService.queryById(cateId)); + } + + /** + * 新增服务分类 + */ + @ApiOperation("新增服务分类") + @PreAuthorize("@ss.hasPermi('isc:cate:add')") + @Log(title = "服务分类", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public AjaxResult add(@Validated(AddGroup.class) @RequestBody IscServiceCateBo bo) + { + return toAjax(cateService.insertByBo(bo) ? 1 : 0); + } + + /** + * 修改服务分类 + */ + @ApiOperation("修改服务分类") + @PreAuthorize("@ss.hasPermi('isc:cate:edit')") + @Log(title = "服务分类", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public AjaxResult edit(@Validated(EditGroup.class) @RequestBody IscServiceCateBo bo) + { + return toAjax(cateService.updateByBo(bo) ? 1 : 0); + } + + /** + * 删除服务分类 + */ + @ApiOperation("删除服务分类") + @PreAuthorize("@ss.hasPermi('isc:cate:remove')") + @Log(title = "服务分类", businessType = BusinessType.DELETE) + @DeleteMapping("/{cateIds}") + public AjaxResult remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] cateIds) + { + return toAjax(cateService.deleteWithValidByIds(Arrays.asList(cateIds), true) ? 1 : 0); + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscServiceController.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscServiceController.java new file mode 100644 index 000000000..8faea9e73 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/controller/IscServiceController.java @@ -0,0 +1,125 @@ +package com.ruoyi.isc.controller; + +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.isc.domain.bo.IscAuditBo; +import com.ruoyi.isc.domain.bo.IscServiceBo; +import com.ruoyi.isc.domain.vo.IscServiceVo; +import com.ruoyi.isc.service.IIscServiceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +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 javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.Arrays; +import java.util.List; + +/** + * 服务信息Controller + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +@Validated +@Api(value = "服务信息控制器", tags = {"服务信息管理"}) +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@RestController +@RequestMapping("/isc/service") +public class IscServiceController extends BaseController { + + private final IIscServiceService iIscServiceService; + + /** + * 查询服务信息列表 + */ + @ApiOperation("查询服务信息列表") + @PreAuthorize("@ss.hasPermi('isc:service:list')") + @GetMapping("/list") + public TableDataInfo list(@Validated IscServiceBo bo) { + return iIscServiceService.queryPageList(bo); + } + + /** + * 导出服务信息列表 + */ + @ApiOperation("导出服务信息列表") + @PreAuthorize("@ss.hasPermi('isc:service:export')") + @Log(title = "服务信息", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public void export(@Validated IscServiceBo bo, HttpServletResponse response) { + List list = iIscServiceService.queryList(bo); + ExcelUtil.exportExcel(list, "服务信息", IscServiceVo.class, response); + } + + /** + * 获取服务信息详细信息 + */ + @ApiOperation("获取服务信息详细信息") + @PreAuthorize("@ss.hasPermi('isc:service:query')") + @GetMapping("/{serviceId}") + public AjaxResult getInfo(@NotNull(message = "主键不能为空") + @PathVariable("serviceId") Long serviceId) { + return AjaxResult.success(iIscServiceService.queryById(serviceId)); + } + + /** + * 新增服务信息 + */ + @ApiOperation("新增服务信息") + @PreAuthorize("@ss.hasPermi('isc:service:add')") + @Log(title = "服务信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public AjaxResult add(@Validated(AddGroup.class) @RequestBody IscServiceBo bo) { + return toAjax(iIscServiceService.insertByBo(bo) ? 1 : 0); + } + + /** + * 修改服务信息 + */ + @ApiOperation("修改服务信息") + @PreAuthorize("@ss.hasPermi('isc:service:edit')") + @Log(title = "服务信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public AjaxResult edit(@Validated(EditGroup.class) @RequestBody IscServiceBo bo) { + return toAjax(iIscServiceService.updateByBo(bo) ? 1 : 0); + } + + /** + * 删除服务信息 + */ + @ApiOperation("删除服务信息") + @PreAuthorize("@ss.hasPermi('isc:service:remove')") + @Log(title = "服务信息" , businessType = BusinessType.DELETE) + @DeleteMapping("/{serviceIds}") + public AjaxResult remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] serviceIds) { + return toAjax(iIscServiceService.deleteWithValidByIds(Arrays.asList(serviceIds), true) ? 1 : 0); + } + + /** + * 服务信息审核 + */ + @ApiOperation("服务信息审核") + @PreAuthorize("@ss.hasPermi('isc:service:audit')") + @Log(title = "服务信息审核", businessType = BusinessType.AUDIT) + @RepeatSubmit() + @PutMapping("/audit") + public AjaxResult audit(@Validated @RequestBody IscAuditBo bo) { + return toAjax(iIscServiceService.audit(bo) ? 1 : 0); + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscAppService.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscAppService.java new file mode 100644 index 000000000..fd1d2d1f3 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscAppService.java @@ -0,0 +1,127 @@ +package com.ruoyi.isc.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + * 应用服务对象 isc_app_service + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +@TableName("isc_app_service") +public class IscAppService implements Serializable { + + private static final long serialVersionUID=1L; + + + /** + * 应用服务ID + */ + @TableId(value = "app_service_id") + private Long appServiceId; + + /** + * 服务ID + */ + private Long serviceId; + + /** + * 应用ID + */ + private Long applicationId; + + /** + * 用户ID + */ + private Long userId; + + /** + * 启用状态(0启用 1停用) + */ + private String enabled; + + /** + * 审核状态(0待审核 1审核通过 2驳回) + */ + private String status; + + /** + * 审核意见 + */ + private String auditMind; + + /** + * 虚拟地址 + */ + private String virtualAddr; + + /** + * 到期时间 + */ + private Date endTime; + + /** + * 天配额 + */ + private Long quotaDays; + + /** + * 小时配额 + */ + private Long quotaHours; + + /** + * 分钟配额 + */ + private Long quotaMinutes; + + /** + * 秒配额 + */ + private Long quotaSeconds; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscAppServiceApply.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscAppServiceApply.java new file mode 100644 index 000000000..1f8cc6195 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscAppServiceApply.java @@ -0,0 +1,112 @@ +package com.ruoyi.isc.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + * 应用服务申请信息对象 isc_app_service_apply + * + * @author Wenchao Gong + * @date 2021-09-09 + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +@TableName("isc_app_service_apply") +public class IscAppServiceApply implements Serializable { + + private static final long serialVersionUID=1L; + + + /** + * 申请ID + */ + @TableId(value = "apply_id") + private Long applyId; + + /** + * 应用服务ID + */ + private Long appServiceId; + + /** + * 申请类型(0申请 1续期) + */ + private String applyType; + + /** + * 审核状态(0待审核 1审核通过 2驳回) + */ + private String status; + + /** + * 审核意见 + */ + private String auditMind; + + /** + * 续期时长(单位月) + */ + private Integer renewalDuration; + + /** + * 天配额 + */ + private Long quotaDays; + + /** + * 小时配额 + */ + private Long quotaHours; + + /** + * 分钟配额 + */ + private Long quotaMinutes; + + /** + * 秒配额 + */ + private Long quotaSeconds; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscApplication.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscApplication.java new file mode 100644 index 000000000..fb57b868a --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscApplication.java @@ -0,0 +1,82 @@ +package com.ruoyi.isc.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import java.io.Serializable; +import java.util.Date; +import java.math.BigDecimal; + +/** + * 应用信息对象 isc_application + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +@TableName("isc_application") +public class IscApplication implements Serializable { + + private static final long serialVersionUID=1L; + + + /** + * 应用ID + */ + @TableId(value = "application_id") + private Long applicationId; + + /** + * 应用名称 + */ + private String applicationName; + + /** + * 应用密钥 + */ + private String accessKey; + + /** + * 用户ID + */ + private Long userId; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscService.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscService.java new file mode 100644 index 000000000..e6ae66828 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscService.java @@ -0,0 +1,132 @@ +package com.ruoyi.isc.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import java.io.Serializable; +import java.util.Date; +import java.math.BigDecimal; + +/** + * 服务信息对象 isc_service + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +@TableName("isc_service") +public class IscService implements Serializable { + + private static final long serialVersionUID=1L; + + + /** + * 服务ID + */ + @TableId(value = "service_id") + private Long serviceId; + + /** + * 服务名称 + */ + private String serviceName; + + /** + * 服务地址 + */ + private String serviceAddr; + + /** + * 探活地址 + */ + private String probeActiveAddr; + + /** + * 请求方式(默认GET) + */ + private String requestMethod; + + /** + * 备注 + */ + private String remark; + + /** + * 跨域标志(Y是 N否) + */ + private String corsFlag; + + /** + * 隐藏参数 + */ + private String hiddenParams; + + /** + * 是否在线(0离线 1在线) + */ + private String onlineStatus; + + /** + * 审核状态(0待审核 1审核通过 2驳回) + */ + private String status; + + /** + * JSON文档 + */ + private String apiDoc; + + /** + * 审核意见 + */ + private String auditMind; + + /** + * 服务状态(0启用 1停用) + */ + private String enabled; + + /** + * 服务分类全路径 + */ + private String cateFullPath; + + /** + * 用户ID + */ + private Long userId; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscServiceCate.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscServiceCate.java new file mode 100644 index 000000000..195c1d90d --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/IscServiceCate.java @@ -0,0 +1,101 @@ +package com.ruoyi.isc.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.ruoyi.common.core.domain.entity.SysMenu; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * 服务分类对象 isc_service_cate + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +@TableName("isc_service_cate") +public class IscServiceCate implements Serializable { + + private static final long serialVersionUID=1L; + + + /** + * 分类ID + */ + @TableId(value = "cate_id") + private Long cateId; + + /** + * 父分类ID + */ + private Long parentId; + + /** + * 分类名称 + */ + private String cateName; + + /** + * 搜索全路径 + */ + private String fullPath; + + /** + * 启用状态(0启用 1停用) + */ + private String enabled; + + /** + * 创建者 + */ + @TableField(fill = FieldFill.INSERT) + private String createBy; + + /** + * 显示顺序 + */ + private Long orderNum; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新者 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updateBy; + + /** + * 更新时间 + */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private Date updateTime; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + + /** + * 子分类 + */ + @TableField(exist = false) + private List children = new ArrayList(); + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscAppServiceApplyBo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscAppServiceApplyBo.java new file mode 100644 index 000000000..f324bdfc2 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscAppServiceApplyBo.java @@ -0,0 +1,111 @@ +package com.ruoyi.isc.domain.bo; + +import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotNull; + +/** + * 应用服务申请信息业务对象 isc_app_service_apply + * + * @author Wenchao Gong + * @date 2021-09-09 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("应用服务申请信息业务对象") +public class IscAppServiceApplyBo extends BaseEntity { + + /** + * 申请ID + */ + @ApiModelProperty(value = "申请ID") + private Long applyId; + + /** + * 应用服务ID + */ + @ApiModelProperty(value = "应用服务ID", required = true) + @NotNull(message = "应用服务ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long appServiceId; + + /** + * 申请类型(0申请 1续期) + */ + @ApiModelProperty(value = "申请类型(0申请 1续期)") + private String applyType; + + /** + * 审核状态(0待审核 1审核通过 2驳回) + */ + @ApiModelProperty(value = "审核状态(0待审核 1审核通过 2驳回)") + private String status; + + /** + * 续期时长(单位月) + */ + @ApiModelProperty(value = "续期时长(单位月)") + private Integer renewalDuration; + + /** + * 天配额 + */ + @ApiModelProperty(value = "天配额") + private Long quotaDays; + + /** + * 小时配额 + */ + @ApiModelProperty(value = "小时配额") + private Long quotaHours; + + /** + * 分钟配额 + */ + @ApiModelProperty(value = "分钟配额") + private Long quotaMinutes; + + /** + * 秒配额 + */ + @ApiModelProperty(value = "秒配额") + private Long quotaSeconds; + + + /** + * 分页大小 + */ + @ApiModelProperty("分页大小") + private Integer pageSize; + + /** + * 当前页数 + */ + @ApiModelProperty("当前页数") + private Integer pageNum; + + /** + * 排序列 + */ + @ApiModelProperty("排序列") + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + @ApiModelProperty(value = "排序的方向", example = "asc,desc") + private String isAsc; + + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscAppServiceBo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscAppServiceBo.java new file mode 100644 index 000000000..1442d6709 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscAppServiceBo.java @@ -0,0 +1,132 @@ +package com.ruoyi.isc.domain.bo; + +import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 应用服务业务对象 isc_app_service + * + * @author Wenchao Gong + * @date 2021-09-08 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("应用服务业务对象") +public class IscAppServiceBo extends BaseEntity { + + /** + * 应用服务ID + */ + @ApiModelProperty(value = "应用服务ID") + private Long appServiceId; + + /** + * 服务ID + */ + @ApiModelProperty(value = "服务ID", required = true) + @NotNull(message = "服务ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long serviceId; + + /** + * 应用ID + */ + @ApiModelProperty(value = "应用ID", required = true) + @NotNull(message = "应用ID不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long applicationId; + + /** + * 启用状态(0启用 1停用) + */ + @ApiModelProperty(value = "启用状态(0启用 1停用)", required = true) + @NotBlank(message = "启用状态(0启用 1停用)不能为空", groups = { AddGroup.class, EditGroup.class }) + private String enabled; + + /** + * 审核状态(0待审核 1审核通过 2驳回) + */ + @ApiModelProperty(value = "审核状态(0待审核 1审核通过 2驳回)") + private String status; + + /** + * 到期时间 + */ + @ApiModelProperty(value = "到期时间") + private Date endTime; + + /** + * 天配额 + */ + @ApiModelProperty(value = "天配额") + private Long quotaDays; + + /** + * 小时配额 + */ + @ApiModelProperty(value = "小时配额") + private Long quotaHours; + + /** + * 分钟配额 + */ + @ApiModelProperty(value = "分钟配额") + private Long quotaMinutes; + + /** + * 秒配额 + */ + @ApiModelProperty(value = "秒配额") + private Long quotaSeconds; + + /** + * 续期时长(单位月) + */ + @NotNull(message = "续期时长不能为空", groups = { AddGroup.class }) + private Integer renewalDuration; + + /** + * 申请类型(0申请 1续期) + */ + @NotBlank(message = "申请类型必填") + private String applyType; + + + /** + * 分页大小 + */ + @ApiModelProperty("分页大小") + private Integer pageSize; + + /** + * 当前页数 + */ + @ApiModelProperty("当前页数") + private Integer pageNum; + + /** + * 排序列 + */ + @ApiModelProperty("排序列") + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + @ApiModelProperty(value = "排序的方向", example = "asc,desc") + private String isAsc; + + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String remark; +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscApplicationBo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscApplicationBo.java new file mode 100644 index 000000000..1ad040acb --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscApplicationBo.java @@ -0,0 +1,68 @@ +package com.ruoyi.isc.domain.bo; + +import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; + +/** + * 应用信息业务对象 isc_application + * + * @author Wenchao Gong + * @date 2021-09-08 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("应用信息业务对象") +public class IscApplicationBo extends BaseEntity { + + /** + * 应用ID + */ + @ApiModelProperty(value = "应用ID") + private Long applicationId; + + /** + * 应用名称 + */ + @ApiModelProperty(value = "应用名称", required = true) + @NotBlank(message = "应用名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String applicationName; + + /** + * 应用密钥 + */ + @ApiModelProperty(value = "应用密钥", required = true) + private String accessKey; + + /** + * 分页大小 + */ + @ApiModelProperty("分页大小") + private Integer pageSize; + + /** + * 当前页数 + */ + @ApiModelProperty("当前页数") + private Integer pageNum; + + /** + * 排序列 + */ + @ApiModelProperty("排序列") + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + @ApiModelProperty(value = "排序的方向", example = "asc,desc") + private String isAsc; + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscAuditBo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscAuditBo.java new file mode 100644 index 000000000..fd52ce73b --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscAuditBo.java @@ -0,0 +1,50 @@ +package com.ruoyi.isc.domain.bo; + +import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.List; + +/** + * 服务管控审核 + * + * @author Wenchao Gong + * @date 2021-09-09 + */ + +@Data +@ApiModel("服务管控审核业务对象") +public class IscAuditBo implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID集合 + */ + @ApiModelProperty(value = "ID集合") + @NotEmpty(message = "请选择记录") + private List ids; + + /** + * 审核状态(0待审核 1审核通过 2驳回) + */ + @ApiModelProperty(value = "审核状态(0待审核 1审核通过 2驳回)") + @NotBlank(message = "请填写审核结果") + private String status; + + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscServiceBo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscServiceBo.java new file mode 100644 index 000000000..0ec2e8b2b --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscServiceBo.java @@ -0,0 +1,131 @@ +package com.ruoyi.isc.domain.bo; + +import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 服务信息业务对象 isc_service + * + * @author Wenchao Gong + * @date 2021-08-22 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("服务信息业务对象") +public class IscServiceBo extends BaseEntity { + + /** + * 服务ID + */ + @ApiModelProperty(value = "服务ID", required = true) + @NotNull(message = "服务ID不能为空", groups = { EditGroup.class }) + private Long serviceId; + + /** + * 服务名称 + */ + @ApiModelProperty(value = "服务名称", required = true) + @NotBlank(message = "服务名称不能为空", groups = { AddGroup.class, EditGroup.class }) + private String serviceName; + + /** + * 服务地址 + */ + @ApiModelProperty(value = "服务地址", required = true) + @NotBlank(message = "服务地址不能为空", groups = { AddGroup.class, EditGroup.class }) + private String serviceAddr; + + /** + * 探活地址 + */ + @ApiModelProperty(value = "探活地址", required = true) + @NotBlank(message = "探活地址不能为空", groups = { AddGroup.class, EditGroup.class }) + private String probeActiveAddr; + + /** + * 请求方式(默认GET) + */ + @ApiModelProperty(value = "请求方式(默认GET)", required = true) + @NotBlank(message = "请求方式(默认GET)不能为空", groups = { AddGroup.class, EditGroup.class }) + private String requestMethod; + + /** + * 跨域标志(Y是 N否) + */ + @ApiModelProperty(value = "跨域标志(Y是 N否)", required = true) + @NotBlank(message = "跨域标志(Y是 N否)不能为空", groups = { AddGroup.class, EditGroup.class }) + private String corsFlag; + + /** + * 隐藏参数 + */ + @ApiModelProperty(value = "隐藏参数") + private String hiddenParams; + + /** + * 是否在线(0离线 1在线) + */ + @ApiModelProperty(value = "是否在线(0离线 1在线)") + private String onlineStatus; + + /** + * 审核状态(0待审核 1审核通过 2驳回) + */ + @ApiModelProperty(value = "审核状态(0待审核 1审核通过 2驳回)") + private String status; + + /** + * JSON文档 + */ + @ApiModelProperty(value = "JSON文档", required = true) + @NotBlank(message = "JSON文档不能为空", groups = { AddGroup.class, EditGroup.class }) + private String apiDoc; + + /** + * 服务状态(0启用 1停用) + */ + @ApiModelProperty(value = "服务状态(0启用 1停用)", required = true) + @NotBlank(message = "服务状态(0启用 1停用)不能为空", groups = { AddGroup.class, EditGroup.class }) + private String enabled; + + /** + * 服务分类 + */ + @ApiModelProperty(value = "服务分类", required = true) + @NotNull(message = "服务分类不能为空", groups = { AddGroup.class, EditGroup.class }) + private String cateFullPath; + + /** + * 分页大小 + */ + @ApiModelProperty("分页大小") + private Integer pageSize; + + /** + * 当前页数 + */ + @ApiModelProperty("当前页数") + private Integer pageNum; + + /** + * 排序列 + */ + @ApiModelProperty("排序列") + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + @ApiModelProperty(value = "排序的方向", example = "asc,desc") + private String isAsc; + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscServiceCateBo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscServiceCateBo.java new file mode 100644 index 000000000..4582e7c96 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/bo/IscServiceCateBo.java @@ -0,0 +1,69 @@ +package com.ruoyi.isc.domain.bo; + +import com.ruoyi.common.core.domain.TreeEntity; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import javax.validation.constraints.NotBlank; + +/** + * 服务分类业务对象 isc_service_cate + * + * @author Wenchao Gong + * @date 2021-08-22 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("服务分类业务对象") +public class IscServiceCateBo extends TreeEntity { + + /** + * 分类ID + */ + @ApiModelProperty(value = "分类ID") + private Long cateId; + + /** + * 分类名称 + */ + @ApiModelProperty(value = "分类名称") + private String cateName; + + /** + * 启用状态(0启用 1停用) + */ + @ApiModelProperty(value = "启用状态(0启用 1停用)", required = true) + @NotBlank(message = "启用状态(0启用 1停用)不能为空", groups = { AddGroup.class, EditGroup.class }) + private String enabled; + + + /** + * 分页大小 + */ + @ApiModelProperty("分页大小") + private Integer pageSize; + + /** + * 当前页数 + */ + @ApiModelProperty("当前页数") + private Integer pageNum; + + /** + * 排序列 + */ + @ApiModelProperty("排序列") + private String orderByColumn; + + /** + * 排序的方向desc或者asc + */ + @ApiModelProperty(value = "排序的方向", example = "asc,desc") + private String isAsc; + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscAppServiceApplyVo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscAppServiceApplyVo.java new file mode 100644 index 000000000..0d461831a --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscAppServiceApplyVo.java @@ -0,0 +1,127 @@ +package com.ruoyi.isc.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import java.util.Date; + + + +/** + * 应用服务申请信息视图对象 isc_app_service_apply + * + * @author Wenchao Gong + * @date 2021-09-09 + */ +@Data +@ApiModel("应用服务申请信息视图对象") +@ExcelIgnoreUnannotated +public class IscAppServiceApplyVo { + + private static final long serialVersionUID = 1L; + + /** + * 申请ID + */ + @ApiModelProperty("申请ID") + private Long applyId; + + /** + * 应用服务ID + */ + @ApiModelProperty("应用服务ID") + private Long appServiceId; + + /** + * 应用名称 + */ + @ExcelProperty(value = "应用名称") + @ApiModelProperty("应用名称") + private String applicationName; + + /** + * 服务名称 + */ + @ExcelProperty(value = "服务名称") + @ApiModelProperty("服务名称") + private String serviceName; + + /** + * 申请类型(0申请 1续期) + */ + @ExcelProperty(value = "申请类型(0申请 1续期)", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "isc_apply_type") + @ApiModelProperty("申请类型(0申请 1续期)") + private String applyType; + + /** + * 审核状态(0待审核 1审核通过 2驳回) + */ + @ExcelProperty(value = "审核状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_audit_status") + @ApiModelProperty("审核状态(0待审核 1审核通过 2驳回)") + private String status; + + /** + * 续期时长(单位月) + */ + @ExcelProperty(value = "续期时长", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "单=位月") + @ApiModelProperty("续期时长(单位月)") + private Integer renewalDuration; + + /** + * 天配额 + */ + @ExcelProperty(value = "天配额") + @ApiModelProperty("天配额") + private Long quotaDays; + + /** + * 小时配额 + */ + @ExcelProperty(value = "小时配额") + @ApiModelProperty("小时配额") + private Long quotaHours; + + /** + * 分钟配额 + */ + @ExcelProperty(value = "分钟配额") + @ApiModelProperty("分钟配额") + private Long quotaMinutes; + + /** + * 秒配额 + */ + @ExcelProperty(value = "秒配额") + @ApiModelProperty("秒配额") + private Long quotaSeconds; + + /** + * 更新者 + */ + @ExcelProperty(value = "更新者") + @ApiModelProperty("更新者") + private String updateBy; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + @ApiModelProperty("更新时间") + private Date updateTime; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + @ApiModelProperty("备注") + private String remark; + + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscAppServiceVo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscAppServiceVo.java new file mode 100644 index 000000000..a4eba30ef --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscAppServiceVo.java @@ -0,0 +1,150 @@ +package com.ruoyi.isc.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + + + +/** + * 应用服务视图对象 isc_app_service + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +@Data +@ApiModel("应用服务视图对象") +@ExcelIgnoreUnannotated +public class IscAppServiceVo { + + private static final long serialVersionUID = 1L; + + /** + * 应用服务ID + */ + @ApiModelProperty("应用服务ID") + private Long appServiceId; + + /** + * 服务ID + */ + @ApiModelProperty("服务ID") + private Long serviceId; + + /** + * 服务名称 + */ + @ExcelProperty(value = "服务名称") + @ApiModelProperty("服务名称") + private String serviceName; + + /** + * 应用ID + */ + @ExcelProperty(value = "应用ID") + @ApiModelProperty("应用ID") + private Long applicationId; + + /** + * 用户ID + */ + @ExcelProperty(value = "用户ID") + @ApiModelProperty("用户ID") + private Long userId; + + /** + * 启用状态(0启用 1停用) + */ + @ExcelProperty(value = "启用状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + @ApiModelProperty("启用状态(0启用 1停用)") + private String enabled; + + /** + * 申请类型(0申请 1续期) + */ + @ExcelProperty(value = "申请类型(0申请 1续期)", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "isc_apply_type") + @ApiModelProperty("申请类型(0申请 1续期)") + private String applyType; + + /** + * 审核状态(0待审核 1审核通过 2驳回) + */ + @ExcelProperty(value = "审核状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_audit_status") + @ApiModelProperty("审核状态(0待审核 1审核通过 2驳回)") + private String status; + + /** + * 审核意见 + */ + @ApiModelProperty("审核意见") + private String auditMind; + + /** + * 虚拟地址 + */ + @ExcelProperty(value = "虚拟地址") + @ApiModelProperty("虚拟地址") + private String virtualAddr; + + /** + * 到期时间 + */ + @ExcelProperty(value = "到期时间") + @ApiModelProperty("到期时间") + private Date endTime; + + /** + * 天配额 + */ + @ApiModelProperty(value = "天配额") + private Long quotaDays; + + /** + * 小时配额 + */ + @ApiModelProperty(value = "小时配额") + private Long quotaHours; + + /** + * 分钟配额 + */ + @ApiModelProperty(value = "分钟配额") + private Long quotaMinutes; + + /** + * 秒配额 + */ + @ApiModelProperty(value = "秒配额") + private Long quotaSeconds; + + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String remark; + + /** + * 更新者 + */ + @ExcelProperty(value = "更新者") + @ApiModelProperty("更新者") + private String updateBy; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + @ApiModelProperty("更新时间") + private Date updateTime; + + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscApplicationVo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscApplicationVo.java new file mode 100644 index 000000000..bfe4503b6 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscApplicationVo.java @@ -0,0 +1,67 @@ +package com.ruoyi.isc.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + + + +/** + * 应用信息视图对象 isc_application + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +@Data +@ApiModel("应用信息视图对象") +@ExcelIgnoreUnannotated +public class IscApplicationVo { + + private static final long serialVersionUID = 1L; + + /** + * 应用ID + */ + @ApiModelProperty("应用ID") + private Long applicationId; + + /** + * 应用名称 + */ + @ExcelProperty(value = "应用名称") + @ApiModelProperty("应用名称") + private String applicationName; + + /** + * 应用密钥 + */ + @ExcelProperty(value = "应用密钥") + @ApiModelProperty("应用密钥") + private String accessKey; + + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String remark; + + /** + * 更新者 + */ + @ExcelProperty(value = "更新者") + @ApiModelProperty("更新者") + private String updateBy; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + @ApiModelProperty("更新时间") + private Date updateTime; + + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscServiceCateVo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscServiceCateVo.java new file mode 100644 index 000000000..d7de8ce86 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscServiceCateVo.java @@ -0,0 +1,84 @@ +package com.ruoyi.isc.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import java.util.Date; + + + +/** + * 服务分类视图对象 isc_service_cate + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +@Data +@ApiModel("服务分类视图对象") +@ExcelIgnoreUnannotated +public class IscServiceCateVo { + + private static final long serialVersionUID = 1L; + + /** + * 分类ID + */ + @ApiModelProperty("分类ID") + private Long cateId; + + /** + * 父分类ID + */ + @ExcelProperty(value = "父分类ID") + @ApiModelProperty("父分类ID") + private Long parentId; + + /** + * 分类名称 + */ + @ExcelProperty(value = "分类名称") + @ApiModelProperty("分类名称") + private String cateName; + + /** + * 启用状态(0启用 1停用) + */ + @ExcelProperty(value = "启用状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + @ApiModelProperty("启用状态(0启用 1停用)") + private String enabled; + + /** + * 显示顺序 + */ + @ExcelProperty(value = "显示顺序") + @ApiModelProperty("显示顺序") + private Long orderNum; + + /** + * 更新者 + */ + @ExcelProperty(value = "更新者") + @ApiModelProperty("更新者") + private String updateBy; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + @ApiModelProperty("更新时间") + private Date updateTime; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + @ApiModelProperty("备注") + private String remark; + + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscServiceVo.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscServiceVo.java new file mode 100644 index 000000000..1eb67f1de --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/domain/vo/IscServiceVo.java @@ -0,0 +1,138 @@ +package com.ruoyi.isc.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import java.util.Date; + + + +/** + * 服务信息视图对象 isc_service + * + * @author ruoyi + * @date 2021-08-22 + */ +@Data +@ApiModel("服务信息视图对象") +@ExcelIgnoreUnannotated +public class IscServiceVo { + + private static final long serialVersionUID = 1L; + + /** + * 服务ID + */ + @ApiModelProperty("服务ID") + private Long serviceId; + + /** + * 服务名称 + */ + @ExcelProperty(value = "服务名称") + @ApiModelProperty("服务名称") + private String serviceName; + + /** + * 服务地址 + */ + @ExcelProperty(value = "服务地址") + @ApiModelProperty("服务地址") + private String serviceAddr; + + /** + * 探活地址 + */ + @ExcelProperty(value = "探活地址") + @ApiModelProperty("探活地址") + private String probeActiveAddr; + + /** + * 请求方式(默认GET) + */ + @ExcelProperty(value = "请求方式") + @ApiModelProperty("请求方式(默认GET)") + private String requestMethod; + + /** + * 备注 + */ + @ApiModelProperty("备注") + private String remark; + + /** + * 跨域标志(Y是 N否) + */ + @ExcelProperty(value = "跨域标志", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_yes_no") + @ApiModelProperty("跨域标志(Y是 N否)") + private String corsFlag; + + /** + * 隐藏参数 + */ + @ApiModelProperty("隐藏参数") + private String hiddenParams; + + /** + * JSON文档 + */ + @ApiModelProperty("JSON文档") + private String apiDoc; + + /** + * 是否在线(0离线 1在线) + */ + @ExcelProperty(value = "是否在线", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "isc_online_status") + @ApiModelProperty("是否在线(0离线 1在线)") + private String onlineStatus; + + /** + * 审核状态(0待审核 1审核通过 2驳回) + */ + @ExcelProperty(value = "审核状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_audit_status") + @ApiModelProperty("审核状态(0待审核 1审核通过 2驳回)") + private String status; + + /** + * 服务状态(0启用 1停用) + */ + @ExcelProperty(value = "服务状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + @ApiModelProperty("服务状态(0启用 1停用)") + private String enabled; + + /** + * 服务分类 + */ + @ApiModelProperty("服务分类") + private String cateFullPath; + + /** + * 服务分类名称 + */ + @ExcelProperty(value = "服务分类") + @ApiModelProperty("服务分类名称") + private String cateName; + + /** + * 更新人 + */ + @ExcelProperty(value = "更新人") + @ApiModelProperty("更新人") + private String updateBy; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + @ApiModelProperty("更新时间") + private Date updateTime; + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscAppServiceApplyMapper.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscAppServiceApplyMapper.java new file mode 100644 index 000000000..0e4ea03d7 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscAppServiceApplyMapper.java @@ -0,0 +1,16 @@ +package com.ruoyi.isc.mapper; + +import com.ruoyi.isc.domain.IscAppServiceApply; +import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus; +import com.ruoyi.common.core.mybatisplus.cache.MybatisPlusRedisCache; +import org.apache.ibatis.annotations.CacheNamespace; + +/** + * 应用服务申请信息Mapper接口 + * + * @author Wenchao Gong + * @date 2021-09-09 + */ +public interface IscAppServiceApplyMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscAppServiceMapper.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscAppServiceMapper.java new file mode 100644 index 000000000..2e0d5d22f --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscAppServiceMapper.java @@ -0,0 +1,16 @@ +package com.ruoyi.isc.mapper; + +import com.ruoyi.isc.domain.IscAppService; +import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus; +import com.ruoyi.common.core.mybatisplus.cache.MybatisPlusRedisCache; +import org.apache.ibatis.annotations.CacheNamespace; + +/** + * 应用服务Mapper接口 + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +public interface IscAppServiceMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscApplicationMapper.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscApplicationMapper.java new file mode 100644 index 000000000..23bd1a174 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscApplicationMapper.java @@ -0,0 +1,14 @@ +package com.ruoyi.isc.mapper; + +import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus; +import com.ruoyi.isc.domain.IscApplication; + +/** + * 应用信息Mapper接口 + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +public interface IscApplicationMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscServiceCateMapper.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscServiceCateMapper.java new file mode 100644 index 000000000..201d6fdcc --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscServiceCateMapper.java @@ -0,0 +1,16 @@ +package com.ruoyi.isc.mapper; + +import com.ruoyi.isc.domain.IscServiceCate; +import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus; +import com.ruoyi.common.core.mybatisplus.cache.MybatisPlusRedisCache; +import org.apache.ibatis.annotations.CacheNamespace; + +/** + * 服务分类Mapper接口 + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +public interface IscServiceCateMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscServiceMapper.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscServiceMapper.java new file mode 100644 index 000000000..d3969891e --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/mapper/IscServiceMapper.java @@ -0,0 +1,16 @@ +package com.ruoyi.isc.mapper; + +import com.ruoyi.isc.domain.IscService; +import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus; +import com.ruoyi.common.core.mybatisplus.cache.MybatisPlusRedisCache; +import org.apache.ibatis.annotations.CacheNamespace; + +/** + * 服务信息Mapper接口 + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +public interface IscServiceMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscAppServiceApplyService.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscAppServiceApplyService.java new file mode 100644 index 000000000..26cc0f3e6 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscAppServiceApplyService.java @@ -0,0 +1,64 @@ +package com.ruoyi.isc.service; + +import com.ruoyi.common.core.mybatisplus.core.IServicePlus; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.isc.domain.IscAppServiceApply; +import com.ruoyi.isc.domain.bo.IscAppServiceApplyBo; +import com.ruoyi.isc.domain.bo.IscAuditBo; +import com.ruoyi.isc.domain.vo.IscAppServiceApplyVo; + +import java.util.Collection; +import java.util.List; + +/** + * 应用服务申请信息Service接口 + * + * @author Wenchao Gong + * @date 2021-09-09 + */ +public interface IIscAppServiceApplyService extends IServicePlus { + /** + * 查询单个 + * @return + */ + IscAppServiceApplyVo queryById(Long applyId); + + /** + * 查询列表 + */ + TableDataInfo queryPageList(IscAppServiceApplyBo bo); + + /** + * 查询列表 + */ + List queryList(IscAppServiceApplyBo bo); + + /** + * 根据新增业务对象插入应用服务申请信息 + * @param bo 应用服务申请信息新增业务对象 + * @return + */ + Boolean insertByBo(IscAppServiceApplyBo bo); + + /** + * 根据编辑业务对象修改应用服务申请信息 + * @param bo 应用服务申请信息编辑业务对象 + * @return + */ + Boolean updateByBo(IscAppServiceApplyBo bo); + + /** + * 校验并删除数据 + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 应用服务审核 + * @param bo 审核业务数据 + * @return 是否审核成功 + */ + Boolean audit(IscAuditBo bo); +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscAppServiceService.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscAppServiceService.java new file mode 100644 index 000000000..f3d74ece8 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscAppServiceService.java @@ -0,0 +1,76 @@ +package com.ruoyi.isc.service; + +import cn.hutool.core.lang.tree.Tree; +import com.ruoyi.common.core.mybatisplus.core.IServicePlus; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.isc.domain.IscAppService; +import com.ruoyi.isc.domain.bo.IscAppServiceBo; +import com.ruoyi.isc.domain.vo.IscAppServiceVo; + +import java.util.Collection; +import java.util.List; + +/** + * 应用服务Service接口 + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +public interface IIscAppServiceService extends IServicePlus { + /** + * 查询单个 + * @return + */ + IscAppServiceVo queryById(Long appServiceId); + + /** + * 查询列表 + */ + TableDataInfo queryPageList(IscAppServiceBo bo); + + /** + * 查询列表 + */ + List queryList(IscAppServiceBo bo); + + /** + * 根据新增业务对象插入应用服务 + * @param bo 应用服务新增业务对象 + * @return + */ + Boolean insertByBo(IscAppServiceBo bo); + + /** + * 根据编辑业务对象修改应用服务 + * @param bo 应用服务编辑业务对象 + * @return + */ + Boolean updateByBo(IscAppServiceBo bo); + + /** + * 校验并删除数据 + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 构造 应用服务树结构 + * @param applicationId 应用ID + * @return 应用服务树结构 (标识服务是否存在) + */ + List> genAppServiceTree(Long applicationId); + + /** + * 通过 Id集合 返回列表 + * @param ids 应用服务ID + * @return 应用服务列表 + */ + List getAppServiceListByIds(Collection ids); + + /** + * 刷新规则信息(服务对应AK) + */ + void refreshRules(); +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscApplicationService.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscApplicationService.java new file mode 100644 index 000000000..4294390aa --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscApplicationService.java @@ -0,0 +1,64 @@ +package com.ruoyi.isc.service; + +import com.ruoyi.common.core.mybatisplus.core.IServicePlus; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.isc.domain.IscApplication; +import com.ruoyi.isc.domain.bo.IscApplicationBo; +import com.ruoyi.isc.domain.vo.IscApplicationVo; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 应用信息Service接口 + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +public interface IIscApplicationService extends IServicePlus { + /** + * 查询单个 + * @return + */ + IscApplicationVo queryById(Long applicationId); + + /** + * 查询列表 + */ + TableDataInfo queryPageList(IscApplicationBo bo); + + /** + * 查询列表 + */ + List queryList(IscApplicationBo bo); + + /** + * 根据新增业务对象插入应用信息 + * @param bo 应用信息新增业务对象 + * @return + */ + Boolean insertByBo(IscApplicationBo bo); + + /** + * 根据编辑业务对象修改应用信息 + * @param bo 应用信息编辑业务对象 + * @return + */ + Boolean updateByBo(IscApplicationBo bo); + + /** + * 校验并删除数据 + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 通过应用ID集合批量查询 应用名称 + * @param applicationIds 应用ID集合 + * @return 应用名称Map + */ + Map getNameMap(Collection applicationIds); +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscServiceCateService.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscServiceCateService.java new file mode 100644 index 000000000..6f40e00bd --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscServiceCateService.java @@ -0,0 +1,84 @@ +package com.ruoyi.isc.service; + +import cn.hutool.core.lang.tree.Tree; +import com.ruoyi.common.core.mybatisplus.core.IServicePlus; +import com.ruoyi.isc.domain.IscService; +import com.ruoyi.isc.domain.IscServiceCate; +import com.ruoyi.isc.domain.bo.IscServiceCateBo; +import com.ruoyi.isc.domain.vo.IscServiceCateVo; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 服务分类Service接口 + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +public interface IIscServiceCateService extends IServicePlus { + /** + * 查询单个 + * @return + */ + IscServiceCateVo queryById(Long cateId); + + + /** + * 查询列表 + */ + List queryList(IscServiceCateBo bo); + + /** + * 根据新增业务对象插入服务分类 + * @param bo 服务分类新增业务对象 + * @return + */ + Boolean insertByBo(IscServiceCateBo bo); + + /** + * 根据编辑业务对象修改服务分类 + * @param bo 服务分类编辑业务对象 + * @return + */ + Boolean updateByBo(IscServiceCateBo bo); + + /** + * 校验并删除数据 + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 获取分类信息 + * @return 分类列表 + */ + List selectCateList(); + + /** + * 批量获取分类名称 + * @param fullPathList + * @return + */ + Map batchCateName(Set fullPathList); + + /** + * 组装 服务分类 树结构 + * @param cates 所有分类 + * @return 树结构信息 + */ + List> genCateTree(List cates); + + /** + * 组装 服务分类 树结构 + * @param cates 所有分类 + * @param serviceList 可用服务列表 + * @param exitsIds 已存在服务ID集合 + * @return 树结构信息 + */ + List> genCateTree(List cates, List serviceList, Set exitsIds); +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscServiceService.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscServiceService.java new file mode 100644 index 000000000..48a675940 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/IIscServiceService.java @@ -0,0 +1,98 @@ +package com.ruoyi.isc.service; + +import cn.hutool.core.lang.tree.Tree; +import com.ruoyi.common.core.mybatisplus.core.IServicePlus; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.isc.domain.IscService; +import com.ruoyi.isc.domain.bo.IscAuditBo; +import com.ruoyi.isc.domain.bo.IscServiceBo; +import com.ruoyi.isc.domain.vo.IscServiceVo; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 服务信息Service接口 + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +public interface IIscServiceService extends IServicePlus { + /** + * 查询单个 + * @return + */ + IscServiceVo queryById(Long serviceId); + + /** + * 查询列表 + */ + TableDataInfo queryPageList(IscServiceBo bo); + + /** + * 查询列表 + */ + List queryList(IscServiceBo bo); + + /** + * 根据新增业务对象插入服务信息 + * @param bo 服务信息新增业务对象 + * @return + */ + Boolean insertByBo(IscServiceBo bo); + + /** + * 根据编辑业务对象修改服务信息 + * @param bo 服务信息编辑业务对象 + * @return + */ + Boolean updateByBo(IscServiceBo bo); + + /** + * 校验并删除数据 + * @param ids 主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 通过服务ID集合 查询服务名称map + * @param serviceIds 服务ID集合 + * @return 服务名称map + */ + Map getNameMap(Collection serviceIds); + + /** + * 组装 服务树结构 + * @return 服务树结构 + */ + List> genServiceTree(); + + /** + * 组装 服务树结构 + * @param exitsIds 已存在服务ID集合 + * @return 服务树结构 + */ + List> genServiceTree(Set exitsIds); + + /** + * 服务信息审核 + * @param bo 审核信息 + * @return 操作结果 + */ + Boolean audit(IscAuditBo bo); + + /** + * 校验 审核参数 + * @param bo 审核业务对象 + */ + void checkAuditBO(IscAuditBo bo); + + /** + * 刷新路由信息 + */ + void refreshRoutes(); +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscAppServiceApplyServiceImpl.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscAppServiceApplyServiceImpl.java new file mode 100644 index 000000000..8d6b7588f --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscAppServiceApplyServiceImpl.java @@ -0,0 +1,263 @@ +package com.ruoyi.isc.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.Assert; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.constant.IscConstants; +import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; +import com.ruoyi.common.core.page.PagePlus; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.PageUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.isc.domain.IscAppService; +import com.ruoyi.isc.domain.IscAppServiceApply; +import com.ruoyi.isc.domain.IscApplication; +import com.ruoyi.isc.domain.IscService; +import com.ruoyi.isc.domain.bo.IscAppServiceApplyBo; +import com.ruoyi.isc.domain.bo.IscAuditBo; +import com.ruoyi.isc.domain.vo.IscAppServiceApplyVo; +import com.ruoyi.isc.mapper.IscAppServiceApplyMapper; +import com.ruoyi.isc.service.IIscAppServiceApplyService; +import com.ruoyi.isc.service.IIscAppServiceService; +import com.ruoyi.isc.service.IIscApplicationService; +import com.ruoyi.isc.service.IIscServiceService; +import com.ruoyi.isc.utils.RouteUtils; +import com.ruoyi.isc.utils.beans.IscRouteDefinition; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 应用服务申请信息Service业务层处理 + * + * @author Wenchao Gong + * @date 2021-09-09 + */ +@Service +public class IscAppServiceApplyServiceImpl extends ServicePlusImpl implements IIscAppServiceApplyService { + + @Resource + private IIscAppServiceService appServiceService; + @Resource + private IIscApplicationService applicationService; + @Resource + private IIscServiceService serviceService; + + @Override + public IscAppServiceApplyVo queryById(Long applyId){ + IscAppServiceApplyVo vo = getVoById(applyId); + genServiceNameAndApplicationName(Arrays.asList(vo)); + return vo; + } + + @Override + public TableDataInfo queryPageList(IscAppServiceApplyBo bo) { + PagePlus result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo)); + genServiceNameAndApplicationName(result.getRecordsVo()); + return PageUtils.buildDataInfo(result); + } + + @Override + public List queryList(IscAppServiceApplyBo bo) { + List results = listVo(buildQueryWrapper(bo)); + genServiceNameAndApplicationName(results); + return results; + } + + /** + * 组装服务、应用名称 + * @param list 申请记录 + */ + private void genServiceNameAndApplicationName(List list) + { + if(CollectionUtil.isEmpty(list)) { + return; + } + Set appServiceIds = list.stream().map(IscAppServiceApplyVo::getAppServiceId).collect(Collectors.toSet()); + List appServiceList = appServiceService.getAppServiceListByIds(appServiceIds); + if(CollectionUtil.isEmpty(appServiceList)) { + return; + } + Map appServiceMap = appServiceList.stream() + .collect(Collectors.toMap(IscAppService::getAppServiceId, Function.identity())); + Map serviceNameMap = serviceService.getNameMap(appServiceList.stream() + .map(IscAppService::getServiceId).collect(Collectors.toSet())); + Map applicationNameMap = applicationService.getNameMap(appServiceList.stream() + .map(IscAppService::getApplicationId).collect(Collectors.toSet())); + for (IscAppServiceApplyVo vo : list) { + IscAppService appService = appServiceMap.get(vo.getAppServiceId()); + if(Objects.isNull(appService)) { + continue; + } + vo.setServiceName(serviceNameMap.get(appService.getServiceId())); + vo.setApplicationName(applicationNameMap.get(appService.getApplicationId())); + } + } + + private LambdaQueryWrapper buildQueryWrapper(IscAppServiceApplyBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getApplyType()), IscAppServiceApply::getApplyType, bo.getApplyType()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), IscAppServiceApply::getStatus, bo.getStatus()); + return lqw; + } + + @Override + public Boolean insertByBo(IscAppServiceApplyBo bo) { + IscAppServiceApply add = BeanUtil.toBean(bo, IscAppServiceApply.class); + validEntityBeforeSave(add); + return save(add); + } + + @Override + public Boolean updateByBo(IscAppServiceApplyBo bo) { + IscAppServiceApply update = BeanUtil.toBean(bo, IscAppServiceApply.class); + validEntityBeforeSave(update); + return updateById(update); + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(IscAppServiceApply entity){ + //TODO 做一些数据校验,如唯一约束 + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return removeByIds(ids); + } + + @Override + public Boolean audit(IscAuditBo bo) + { + serviceService.checkAuditBO(bo); + boolean result = true; + for (Long id : bo.getIds()) + { + IscAppServiceApply apply = getOne(Wrappers.lambdaQuery() + .eq(IscAppServiceApply::getApplyId, id) + .eq(IscAppServiceApply::getStatus, Constants.AUDIT_WAIT), false); + if(Objects.isNull(apply)) { + continue; + } + result = updateById(new IscAppServiceApply().setApplyId(id).setStatus(bo.getStatus()) + .setAuditMind(bo.getRemark())); + IscAppService appService = appServiceService.getById(apply.getAppServiceId()); + Assert.notNull(appService, () -> new ServiceException("申请信息不存在")); + + IscAppService updateData = null; + IscService service = null; + if(Constants.AUDIT_PASS.equals(bo.getStatus())) { + service = serviceService.getById(appService.getServiceId()); + Assert.notNull(service, () -> new ServiceException("服务信息不存在")); + updateData = genAuditPassData(apply, appService, service, bo.getStatus()); + updateData.setAuditMind(bo.getRemark()); + }else{ + //如果 应用服务 状态为不通过 时需要同步状态 + updateData = genAuditRejectData(appService, bo); + } + if(Objects.nonNull(updateData)) { + result = appServiceService.updateById(updateData); + if(Objects.nonNull(service)) { + IscAppService dbAppService = appServiceService.getById(apply.getAppServiceId()); + IscApplication application = applicationService.getById(dbAppService.getApplicationId()); + RouteUtils.saveRule(RouteUtils.generateRule(dbAppService, application.getAccessKey())); + } + } + } + return result; + } + + /** + * 审核通过处理 + * @param apply 申请信息 + * @param appService 应用服务信息 + * @param service 服务信息 + * @param status 操作状态 + * @return 更新数据 + */ + private IscAppService genAuditPassData(IscAppServiceApply apply, IscAppService appService, IscService service, + String status) + { + IscAppService updateData = new IscAppService().setAppServiceId(appService.getAppServiceId()); + //如果是 服务申请 修改 应用服务 审核状态、生成虚拟地址、服务到期时间 + //如果是续期申请 修改 服务到期时间 + switch (apply.getApplyType()) { + case IscConstants.APPLY_TYPE_APPLY: + genServicePassInit(apply, appService, status, updateData, service); + break; + case IscConstants.APPLY_TYPE_MODIFY: + //如果 应用服务 状态不为通过 则修改状态(如果是通过:续期不能影响使用) + if(!Constants.AUDIT_PASS.equals(appService.getStatus())) { + genServicePassInit(apply, appService, status, updateData, service); + } + updateData.setQuotaDays(apply.getQuotaDays()); + updateData.setQuotaHours(apply.getQuotaHours()); + updateData.setQuotaMinutes(apply.getQuotaMinutes()); + updateData.setQuotaSeconds(apply.getQuotaSeconds()); + break; + case IscConstants.APPLY_TYPE_RENEWAL: + Date startDate = Objects.isNull(appService.getEndTime()) ? DateUtils.getNowDate() : appService.getEndTime(); + updateData.setEndTime(DateUtils.beginOfDay(DateUtils.addMonths(startDate, apply.getRenewalDuration()))); + break; + default: + throw new ServiceException("申请类型异常"); + } + return updateData; + } + + /** + * 审核通过 初始化生成 虚拟地址、服务结束时间 + * @param apply 申请信息 + * @param appService 应用服务信息 + * @param status 审核状态 + * @param updateData 需要修改的数据 + * @param service 服务信息 + */ + private void genServicePassInit(IscAppServiceApply apply, IscAppService appService, String status, + IscAppService updateData, IscService service) + { + updateData.setStatus(status); + Integer renewalDuration = apply.getRenewalDuration(); + //如果 申请时长为空,需要查询审核记录 中的审核时长 + if(Objects.isNull(renewalDuration)) { + IscAppServiceApply log = getOne(Wrappers.lambdaQuery() + .eq(IscAppServiceApply::getAppServiceId, appService.getAppServiceId()) + .eq(IscAppServiceApply::getApplyType, IscConstants.APPLY_TYPE_APPLY) + .last("LIMIT 1"), false); + renewalDuration = Objects.nonNull(log) ? log.getRenewalDuration() : 1; + } + updateData.setEndTime(DateUtils.beginOfDay(DateUtils.addMonths(DateUtils.getNowDate(), renewalDuration))); + updateData.setVirtualAddr(RouteUtils.genVirtualAddrPath(service.getServiceAddr())); + } + + /** + * 审核不通过处理 + * @param appService 应用服务信息 + * @param bo 审核数据 + * @return 需要更新的信息 + */ + private IscAppService genAuditRejectData(IscAppService appService, IscAuditBo bo) { + if(!Constants.AUDIT_PASS.equals(appService.getStatus())) { + IscAppService updateData = new IscAppService().setAppServiceId(appService.getAppServiceId()); + updateData.setStatus(bo.getStatus()); + updateData.setAuditMind(bo.getRemark()); + return updateData; + } + return null; + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscAppServiceServiceImpl.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscAppServiceServiceImpl.java new file mode 100644 index 000000000..c3be743d5 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscAppServiceServiceImpl.java @@ -0,0 +1,262 @@ +package com.ruoyi.isc.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.tree.Tree; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.toolkit.SqlHelper; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.constant.IscConstants; +import com.ruoyi.common.constant.UserConstants; +import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; +import com.ruoyi.common.core.page.PagePlus; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.PageUtils; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.isc.common.utils.beans.IscRule; +import com.ruoyi.isc.domain.IscAppService; +import com.ruoyi.isc.domain.IscAppServiceApply; +import com.ruoyi.isc.domain.IscApplication; +import com.ruoyi.isc.domain.bo.IscAppServiceApplyBo; +import com.ruoyi.isc.domain.bo.IscAppServiceBo; +import com.ruoyi.isc.domain.vo.IscAppServiceVo; +import com.ruoyi.isc.mapper.IscAppServiceMapper; +import com.ruoyi.isc.service.IIscAppServiceApplyService; +import com.ruoyi.isc.service.IIscAppServiceService; +import com.ruoyi.isc.service.IIscApplicationService; +import com.ruoyi.isc.service.IIscServiceService; +import com.ruoyi.isc.utils.RouteUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 应用服务Service业务层处理 + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +@Slf4j +@Service +public class IscAppServiceServiceImpl extends ServicePlusImpl implements IIscAppServiceService +{ + + @Resource + private IIscServiceService serviceService; + @Resource + private IIscAppServiceApplyService applyService; + @Resource + private IIscApplicationService applicationService; + + @PostConstruct + public void init() { + refreshRules(); + } + + @Override + public IscAppServiceVo queryById(Long appServiceId) + { + IscAppServiceVo vo = getVoById(appServiceId); + genServiceName(Arrays.asList(vo)); + return vo; + } + + @Override + public TableDataInfo queryPageList(IscAppServiceBo bo) + { + PagePlus result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo)); + genServiceName(result.getRecordsVo()); + return PageUtils.buildDataInfo(result); + } + + @Override + public List queryList(IscAppServiceBo bo) + { + final List results = listVo(buildQueryWrapper(bo)); + genServiceName(results); + return results; + } + + /** + * 组装服务名称 + * + * @param results 应用服务列表 + */ + private void genServiceName(List results) + { + if (CollectionUtil.isEmpty(results)) { + return; + } + Set serviceIds = results.stream().map(IscAppServiceVo::getServiceId).collect(Collectors.toSet()); + Map nameMap = serviceService.getNameMap(serviceIds); + for (IscAppServiceVo result : results) { + result.setServiceName(nameMap.get(result.getServiceId())); + } + } + + private LambdaQueryWrapper buildQueryWrapper(IscAppServiceBo bo) + { + Map params = bo.getParams(); + Long userId = SecurityUtils.getUserId(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(bo.getServiceId() != null, IscAppService::getServiceId, bo.getServiceId()); + lqw.eq(bo.getApplicationId() != null, IscAppService::getApplicationId, bo.getApplicationId()); + lqw.eq(!SecurityUtils.isAdmin(userId), IscAppService::getUserId, userId); + lqw.eq(StringUtils.isNotBlank(bo.getEnabled()), IscAppService::getEnabled, bo.getEnabled()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), IscAppService::getStatus, bo.getStatus()); + return lqw; + } + + @Override + public Boolean insertByBo(IscAppServiceBo bo) + { + IscAppService add = BeanUtil.toBean(bo, IscAppService.class); + validEntityBeforeSave(add); + add.setStatus(Constants.AUDIT_WAIT); + add.setUserId(SecurityUtils.getUserId()); + boolean result = save(add); + addApplyRecord(bo, IscConstants.APPLY_TYPE_APPLY, add.getAppServiceId()); + return result; + } + + @Override + public Boolean updateByBo(IscAppServiceBo bo) + { + IscAppService appService = getById(bo.getAppServiceId()); + Assert.notNull(appService, () -> new ServiceException("申请信息不存在")); + IscAppService update = new IscAppService().setAppServiceId(bo.getAppServiceId()); + validEntityBeforeSave(update); + boolean result = true; + boolean changeStatus = !Constants.AUDIT_PASS.equals(appService.getStatus()); + boolean changeRemark = !IscConstants.APPLY_TYPE_RENEWAL.equals(bo.getApplyType()); + if (changeStatus || changeRemark) + { + if (changeStatus) + { + update.setStatus(Constants.AUDIT_WAIT); + } + if (changeRemark) + { + update.setRemark(bo.getRemark()); + } + result = updateById(update); + } + String applyType = IscConstants.APPLY_TYPE_RENEWAL.equals(bo.getApplyType()) + ? IscConstants.APPLY_TYPE_RENEWAL : IscConstants.APPLY_TYPE_MODIFY; + addApplyRecord(bo, applyType, bo.getAppServiceId()); + return result; + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(IscAppService entity) + { + //判断是否有申请未审核 + if (Objects.nonNull(entity.getAppServiceId())) { + long count = applyService.count(Wrappers.lambdaQuery() + .eq(IscAppServiceApply::getAppServiceId, entity.getAppServiceId()) + .eq(IscAppServiceApply::getStatus, Constants.AUDIT_WAIT)); + Assert.isFalse(SqlHelper.retBool(count), () -> new ServiceException("有申请未审核, 不能再申请")); + } + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) + { + if (isValid) { + //TODO 做一些业务上的校验,判断是否需要校验 + } + applyService.remove(Wrappers.lambdaQuery().in(IscAppServiceApply::getAppServiceId, ids)); + return removeByIds(ids); + } + + @Override + public List> genAppServiceTree(Long applicationId) + { + List serviceIds = listObjs(Wrappers.lambdaQuery() + .select(IscAppService::getServiceId) + .eq(IscAppService::getApplicationId, applicationId), o -> (Long) o); + return serviceService.genServiceTree(CollectionUtil.newHashSet(serviceIds)); + } + + @Override + public List getAppServiceListByIds(Collection ids) + { + return list(Wrappers.lambdaQuery() + .select(IscAppService::getAppServiceId, IscAppService::getApplicationId, IscAppService::getServiceId) + .in(IscAppService::getAppServiceId, ids)); + } + + @Override + public void refreshRules() + { + List list = list(Wrappers.lambdaQuery() + .eq(IscAppService::getEnabled, UserConstants.NORMAL) + .eq(IscAppService::getStatus, Constants.AUDIT_PASS) + .gt(IscAppService::getEndTime, DateUtils.getNowDate())); + if(CollectionUtil.isEmpty(list)) { + return; + } + Set applicationIds = list.stream().map(IscAppService::getApplicationId).collect(Collectors.toSet()); + Map accessKeyMap = applicationService.list(Wrappers.lambdaQuery() + .select(IscApplication::getApplicationId, IscApplication::getAccessKey) + .in(IscApplication::getApplicationId, applicationIds)).stream() + .collect(Collectors.toMap(IscApplication::getApplicationId, IscApplication::getAccessKey)); + List routes = new ArrayList<>(); + + for (IscAppService appService : list) + { + String ak = accessKeyMap.get(appService.getApplicationId()); + if(StringUtils.isBlank(ak)) { + log.error("路由初始化失败: id:[{}],ak[{}]信息不存在!", appService.getAppServiceId(), appService.getApplicationId()); + continue; + } + routes.add(RouteUtils.generateRule(appService, ak)); + } + RouteUtils.refreshRules(routes); + } + + /** + * 添加 服务申请记录 + * + * @param appService 应用服务信息 + * @param applyType 申请类型 + * @param appServiceId 应用服务ID + * @return 是否添加成功 + */ + private Boolean addApplyRecord(IscAppServiceBo appService, String applyType, Long appServiceId) + { + IscAppServiceApplyBo entity = new IscAppServiceApplyBo(); + entity.setAppServiceId(appServiceId); + entity.setApplyType(applyType); + entity.setStatus(Constants.AUDIT_WAIT); + entity.setRemark(appService.getRemark()); + switch (applyType) { + case IscConstants.APPLY_TYPE_APPLY: + case IscConstants.APPLY_TYPE_MODIFY: + entity.setRenewalDuration(appService.getRenewalDuration()); + entity.setQuotaDays(appService.getQuotaDays()); + entity.setQuotaHours(appService.getQuotaHours()); + entity.setQuotaMinutes(appService.getQuotaMinutes()); + entity.setQuotaSeconds(appService.getQuotaSeconds()); + break; + case IscConstants.APPLY_TYPE_RENEWAL: + entity.setRenewalDuration(appService.getRenewalDuration()); + break; + default: + } + return applyService.insertByBo(entity); + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscApplicationServiceImpl.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscApplicationServiceImpl.java new file mode 100644 index 000000000..3a466a11b --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscApplicationServiceImpl.java @@ -0,0 +1,106 @@ +package com.ruoyi.isc.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.IdUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; +import com.ruoyi.common.core.page.PagePlus; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.utils.PageUtils; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.isc.domain.IscApplication; +import com.ruoyi.isc.domain.bo.IscApplicationBo; +import com.ruoyi.isc.domain.vo.IscApplicationVo; +import com.ruoyi.isc.mapper.IscApplicationMapper; +import com.ruoyi.isc.service.IIscApplicationService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 应用信息Service业务层处理 + * + * @author Wenchao Gong + * @date 2021-09-08 + */ +@Service +public class IscApplicationServiceImpl extends ServicePlusImpl implements IIscApplicationService { + + @Override + public IscApplicationVo queryById(Long applicationId){ + return getVoById(applicationId); + } + + @Override + public TableDataInfo queryPageList(IscApplicationBo bo) { + PagePlus result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo)); + return PageUtils.buildDataInfo(result); + } + + @Override + public List queryList(IscApplicationBo bo) { + return listVo(buildQueryWrapper(bo)); + } + + private LambdaQueryWrapper buildQueryWrapper(IscApplicationBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getApplicationName()), IscApplication::getApplicationName, bo.getApplicationName()); + lqw.eq(StringUtils.isNotBlank(bo.getAccessKey()), IscApplication::getAccessKey, bo.getAccessKey()); + Long userId = SecurityUtils.getUserId(); + lqw.eq(!SecurityUtils.isAdmin(userId), IscApplication::getUserId, userId); + return lqw; + } + + @Override + public Boolean insertByBo(IscApplicationBo bo) { + IscApplication add = BeanUtil.toBean(bo, IscApplication.class); + validEntityBeforeSave(add); + add.setAccessKey(IdUtil.simpleUUID()); + add.setUserId(SecurityUtils.getUserId()); + return save(add); + } + + @Override + public Boolean updateByBo(IscApplicationBo bo) { + IscApplication update = BeanUtil.toBean(bo, IscApplication.class); + validEntityBeforeSave(update); + return updateById(update); + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(IscApplication entity){ + //TODO 做一些数据校验,如唯一约束 + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return removeByIds(ids); + } + + @Override + public Map getNameMap(Collection applicationIds) + { + if(CollectionUtil.isEmpty(applicationIds)) { + return MapUtil.empty(); + } + return list(Wrappers.lambdaQuery() + .select(IscApplication::getApplicationId, IscApplication::getApplicationName) + .in(IscApplication::getApplicationId, applicationIds)).stream() + .collect(Collectors.toMap(IscApplication::getApplicationId, IscApplication::getApplicationName)); + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscServiceCateServiceImpl.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscServiceCateServiceImpl.java new file mode 100644 index 000000000..ec38e68c6 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscServiceCateServiceImpl.java @@ -0,0 +1,221 @@ +package com.ruoyi.isc.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.lang.tree.parser.NodeParser; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ruoyi.common.constant.UserConstants; +import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; +import com.ruoyi.common.utils.FullPathUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.TreeUtils; +import com.ruoyi.isc.domain.IscService; +import com.ruoyi.isc.domain.IscServiceCate; +import com.ruoyi.isc.domain.bo.IscServiceCateBo; +import com.ruoyi.isc.domain.vo.IscServiceCateVo; +import com.ruoyi.isc.mapper.IscServiceCateMapper; +import com.ruoyi.isc.service.IIscServiceCateService; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 服务分类Service业务层处理 + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +@Service +public class IscServiceCateServiceImpl extends ServicePlusImpl implements IIscServiceCateService { + + public static final String FIELD_FULL_PATH = "fullPath"; + public static final String FIELD_NODE_TYPE = "type"; + public static final int NODE_TYPE_SERVICE = 1; + public static final int NODE_TYPE_CATE = 0; + + @Override + public IscServiceCateVo queryById(Long cateId){ + return getVoById(cateId); + } + + + @Override + public List queryList(IscServiceCateBo bo) { + return listVo(buildQueryWrapper(bo)); + } + + private LambdaQueryWrapper buildQueryWrapper(IscServiceCateBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getCateName()), IscServiceCate::getCateName, bo.getCateName()); + lqw.eq(StringUtils.isNotBlank(bo.getEnabled()), IscServiceCate::getEnabled, bo.getEnabled()); + return lqw; + } + + @Override + public Boolean insertByBo(IscServiceCateBo bo) { + IscServiceCate add = BeanUtil.toBean(bo, IscServiceCate.class); + validEntityBeforeSave(add); + add.setFullPath(getFullPath(bo.getParentId())); + return save(add); + } + + /** + * 通过父ID生成 FULL_PATH + * @param parentId + * @return + */ + private String getFullPath(Long parentId) + { + final boolean isRoot = parentId == 0L; + IscServiceCate cate = getOne(Wrappers.lambdaQuery() + .select(IscServiceCate::getCateId, IscServiceCate::getFullPath) + .eq(isRoot, IscServiceCate::getParentId, 0L).and(!isRoot, w -> w + .eq(IscServiceCate::getParentId, parentId) + .or() + .eq(IscServiceCate::getCateId, parentId)) + .orderByDesc(IscServiceCate::getFullPath) + .last("LIMIT 1")); + String parentFullPath = null; + String maxFullPath = null; + if(Objects.nonNull(cate)){ + if(cate.getCateId().intValue() == parentId) + { + parentFullPath = cate.getFullPath(); + }else{ + maxFullPath = cate.getFullPath(); + } + } + final String fullPath = FullPathUtils.genFullPath(parentFullPath, maxFullPath); + return fullPath; + } + + @Override + public Boolean updateByBo(IscServiceCateBo bo) { + IscServiceCate update = BeanUtil.toBean(bo, IscServiceCate.class); + validEntityBeforeSave(update); + return updateById(update); + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(IscServiceCate entity){ + //TODO 做一些数据校验,如唯一约束 + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return removeByIds(ids); + } + + @Override + public List selectCateList() + { + return list(Wrappers.lambdaQuery() + .eq(IscServiceCate::getEnabled, UserConstants.DICT_NORMAL) + .orderByAsc(IscServiceCate::getParentId) + .orderByAsc(IscServiceCate::getOrderNum)); + } + + @Override + public Map batchCateName(Set fullPathList) + { + Map results = new HashMap<>(); + if(CollectionUtils.isEmpty(fullPathList)) { + return results; + } + final List list = list(Wrappers.lambdaQuery() + .select(IscServiceCate::getCateId, IscServiceCate::getCateName, IscServiceCate::getFullPath, IscServiceCate::getParentId) + .in(IscServiceCate::getFullPath, fullPathList)); + Map cateNameMap = batchCateName(list); + for (IscServiceCate cate : list) + { + results.put(cate.getFullPath(), cateNameMap.get(cate.getCateId())); + } + return results; + } + + @Override + public List> genCateTree(List cates) + { + return genCateTree(cates, null, CollectionUtil.newHashSet()); + } + + @Override + public List> genCateTree(List cates, List serviceList, Set exitsIds) + { + boolean isServiceTree = Objects.nonNull(serviceList); + final Map> cateServiceMap = isServiceTree ? serviceList.stream() + .collect(Collectors.groupingBy(IscService::getCateFullPath)) : null; + + NodeParser parser = (cate, tree) -> { + tree.setId(cate.getCateId()); + tree.setParentId(cate.getParentId()); + tree.setName(cate.getCateName()); + tree.setWeight(cate.getOrderNum()); + tree.putExtra(FIELD_FULL_PATH, cate.getFullPath()); + if(isServiceTree) { + tree.putExtra(FIELD_NODE_TYPE, NODE_TYPE_CATE); + boolean exist = true; + List services = cateServiceMap.get(cate.getFullPath()); + if(CollectionUtil.isEmpty(services)) { + tree.putExtra(TreeUtils.FIELD_NODE_EXIST, true); + return; + } + for (int index = 0; index < services.size(); index++) + { + IscService service = services.get(index); + List> children = tree.getChildren(); + if(Objects.isNull(children)) { + children = CollectionUtil.newArrayList(); + tree.setChildren(children); + } + final Tree child = new Tree<>(TreeUtils.DEFAULT_TREE_NODE_CONFIG); + child.setId(service.getServiceId()); + child.setName(service.getServiceName()); + child.setWeight(index); + child.putExtra(FIELD_NODE_TYPE, NODE_TYPE_SERVICE); + boolean contains = exitsIds.contains(service.getServiceId()); + child.putExtra(TreeUtils.FIELD_NODE_EXIST, contains); + children.add(child); + if(exist && !contains) { + exist = false; + } + } + tree.putExtra(TreeUtils.FIELD_NODE_EXIST, exist); + } + }; + return TreeUtils.build(cates, TreeUtils.DEFAULT_PARENT_ID, parser, isServiceTree); + } + + private Map batchCateName(List list) { + Map results = new HashMap<>(); + final Set parentIds = list.stream().filter(m -> m.getParentId() != 0L).map(IscServiceCate::getParentId).collect(Collectors.toSet()); + if(CollectionUtils.isNotEmpty(parentIds)) { + final List parentList = list(Wrappers.lambdaQuery() + .select(IscServiceCate::getCateId, IscServiceCate::getCateName, IscServiceCate::getFullPath, IscServiceCate::getParentId) + .in(IscServiceCate::getCateId, parentIds)); + results.putAll(batchCateName(parentList)); + } + for (IscServiceCate cate : list) + { + final String parentName = results.get(cate.getParentId()); + if(StringUtils.isBlank(parentName)) { + results.put(cate.getCateId(), cate.getCateName()); + }else{ + results.put(cate.getCateId(), String.format("%s/%s", parentName, cate.getCateName())); + } + } + return results; + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscServiceServiceImpl.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscServiceServiceImpl.java new file mode 100644 index 000000000..4bbff4b59 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/service/impl/IscServiceServiceImpl.java @@ -0,0 +1,236 @@ +package com.ruoyi.isc.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.tree.Tree; +import cn.hutool.core.map.MapUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.constant.IscConstants; +import com.ruoyi.common.constant.UserConstants; +import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; +import com.ruoyi.common.core.page.PagePlus; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.FullPathUtils; +import com.ruoyi.common.utils.PageUtils; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.isc.domain.IscService; +import com.ruoyi.isc.domain.bo.IscAuditBo; +import com.ruoyi.isc.domain.bo.IscServiceBo; +import com.ruoyi.isc.domain.vo.IscServiceVo; +import com.ruoyi.isc.mapper.IscServiceMapper; +import com.ruoyi.isc.service.IIscServiceCateService; +import com.ruoyi.isc.service.IIscServiceService; +import com.ruoyi.isc.utils.RouteUtils; +import com.ruoyi.isc.utils.beans.IscRouteDefinition; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 服务信息Service业务层处理 + * + * @author Wenchao Gong + * @date 2021-08-22 + */ +@Service +public class IscServiceServiceImpl extends ServicePlusImpl implements IIscServiceService { + + @Resource + private IIscServiceCateService cateService; + + @PostConstruct + public void init() { + refreshRoutes(); + } + + @Override + public IscServiceVo queryById(Long serviceId) + { + final IscServiceVo vo = getVoById(serviceId); + genVoInfo(Arrays.asList(vo)); + return vo; + } + + @Override + public TableDataInfo queryPageList(IscServiceBo bo) + { + PagePlus result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo)); + genVoInfo(result.getRecordsVo()); + return PageUtils.buildDataInfo(result); + } + + @Override + public List queryList(IscServiceBo bo) + { + final List results = listVo(buildQueryWrapper(bo)); + genVoInfo(results); + return results; + } + + private void genVoInfo(List results) + { + if (CollectionUtils.isNotEmpty(results)) + { + Map cateNameMap = cateService.batchCateName(results.stream() + .map(IscServiceVo::getCateFullPath).collect(Collectors.toSet())); + for (IscServiceVo result : results) + { + result.setCateName(cateNameMap.get(result.getCateFullPath())); + } + } + } + + private LambdaQueryWrapper buildQueryWrapper(IscServiceBo bo) + { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.like(StringUtils.isNotBlank(bo.getServiceName()), IscService::getServiceName, bo.getServiceName()); + lqw.eq(StringUtils.isNotBlank(bo.getOnlineStatus()), IscService::getOnlineStatus, bo.getOnlineStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getStatus()), IscService::getStatus, bo.getStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getEnabled()), IscService::getEnabled, bo.getEnabled()); + lqw.ge(StringUtils.isNotBlank(bo.getCateFullPath()), IscService::getCateFullPath, bo.getCateFullPath()); + lqw.le(StringUtils.isNotBlank(bo.getCateFullPath()), IscService::getCateFullPath, FullPathUtils.genMaxFullPath(bo.getCateFullPath())); + Long userId = SecurityUtils.getUserId(); + lqw.eq(!SecurityUtils.isAdmin(userId), IscService::getUserId, userId); + return lqw; + } + + @Override + public Boolean insertByBo(IscServiceBo bo) + { + IscService add = BeanUtil.toBean(bo, IscService.class); + validEntityBeforeSave(add); + add.setUserId(SecurityUtils.getUserId()); + add.setOnlineStatus(IscConstants.ONLINE_STATUS_ON); + add.setStatus(Constants.AUDIT_WAIT); + return save(add); + } + + @Override + public Boolean updateByBo(IscServiceBo bo) + { + IscService update = BeanUtil.toBean(bo, IscService.class); + validEntityBeforeSave(update); + boolean result = updateById(update); + RouteUtils.updateRoute(RouteUtils.generateRoute(update)); + return result; + } + + /** + * 保存前的数据校验 + * + * @param entity 实体类数据 + */ + private void validEntityBeforeSave(IscService entity) + { + //TODO 做一些数据校验,如唯一约束 + } + + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) + { + if (isValid) + { + //TODO 做一些业务上的校验,判断是否需要校验 + } + boolean result = removeByIds(ids); + RouteUtils.deleteRoute(ids.stream().map(String::valueOf).collect(Collectors.toSet())); + return result; + } + + @Override + public Map getNameMap(Collection serviceIds) + { + if(CollectionUtil.isEmpty(serviceIds)) { + return MapUtil.empty(); + } + return list(Wrappers.lambdaQuery() + .select(IscService::getServiceId, IscService::getServiceName) + .in(IscService::getServiceId, serviceIds)).stream() + .collect(Collectors.toMap(IscService::getServiceId, IscService::getServiceName)); + } + + @Override + public List> genServiceTree() + { + return genServiceTree(CollectionUtil.newHashSet()); + } + + @Override + public List> genServiceTree(Set exitsIds) + { + List serviceList = list(Wrappers.lambdaQuery() + .select(IscService::getServiceId, IscService::getServiceName, IscService::getCateFullPath) + .eq(IscService::getStatus, Constants.AUDIT_PASS) + .eq(IscService::getEnabled, UserConstants.DICT_NORMAL) + .orderByDesc(IscService::getUpdateTime)); + return cateService.genCateTree(cateService.selectCateList(), serviceList, exitsIds); + } + + @Override + public Boolean audit(IscAuditBo bo) + { + checkAuditBO(bo); + boolean result = true; + boolean pass = Constants.AUDIT_PASS.equals(bo.getStatus()); + Collection routes = pass ? ListUtil.list(false) : null; + for (Long id : bo.getIds()) + { + IscService service = getOne(Wrappers.lambdaQuery() + .eq(IscService::getServiceId, id) + .eq(IscService::getStatus, Constants.AUDIT_WAIT), false); + if(Objects.isNull(service)) { + continue; + } + result = updateById(new IscService().setServiceId(id).setStatus(bo.getStatus()) + .setAuditMind(bo.getRemark())); + if(pass) { + //生成路由 + routes.add(RouteUtils.generateRoute(service)); + } + } + if(pass) { + //保存路由信息 + RouteUtils.saveRoute(routes); + } + return result; + } + + @Override + public void checkAuditBO(IscAuditBo bo) + { + switch (bo.getStatus()) { + case Constants.AUDIT_PASS: + break; + case Constants.AUDIT_REJECT: + Assert.notBlank(bo.getRemark(), () -> new ServiceException("审核意见不能为空")); + break; + default: + throw new ServiceException("审核状态异常"); + } + } + + @Override + public void refreshRoutes() + { + final List serviceList = list(Wrappers.lambdaQuery() + .select(IscService::getServiceId, IscService::getServiceAddr, IscService::getHiddenParams, IscService::getRequestMethod) + .eq(IscService::getStatus, Constants.AUDIT_PASS)); + List routes = new ArrayList<>(); + for (IscService service : serviceList) + { + routes.add(RouteUtils.generateRoute(service)); + } + RouteUtils.refreshRoute(routes); + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/RouteUtils.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/RouteUtils.java new file mode 100644 index 000000000..d13a5ab27 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/RouteUtils.java @@ -0,0 +1,330 @@ +package com.ruoyi.isc.utils; + +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateUtil; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.isc.common.constant.IscRedisKeys; +import com.ruoyi.isc.common.utils.GatewayUtils; +import com.ruoyi.isc.common.utils.beans.IscRule; +import com.ruoyi.isc.common.utils.beans.TopicMsg; +import com.ruoyi.isc.common.utils.beans.TopicMsg.Type; +import com.ruoyi.isc.domain.IscAppService; +import com.ruoyi.isc.domain.IscService; +import com.ruoyi.isc.utils.beans.*; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RMap; +import org.redisson.api.RTopic; +import org.redisson.api.RedissonClient; +import org.redisson.client.codec.Codec; +import org.redisson.codec.TypedJsonJacksonCodec; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static com.ruoyi.isc.common.constant.IscGatewayContants.*; + +/** + * @author Wenchao Gong + * @date 2021/9/10 14:46 + */ +@Slf4j +public class RouteUtils { + + public static final Codec ROUTE_CODES_INSTANCE = new TypedJsonJacksonCodec(String.class, IscRouteDefinition.class); + /** + * Gateway 虚拟路径前缀 + */ + public static final String PATH_PREFIX = "/proxy"; + private static final RedissonClient CLIENT = SpringUtils.getBean(RedissonClient.class); + + /** + * 获取虚拟URL Path 部分 + * + * @param serviceAddr 服务地址 + * @return 虚拟地址Path + */ + public static String genVirtualAddrPath(String serviceAddr) + { + return PATH_PREFIX + getPathUri(serviceAddr); + } + + /** + * 返回URI 的Path部分 + * + * @param uri URI + * @return path + */ + public static String getPathUri(String uri) + { + return getURI(uri).getPath(); + } + + /** + * 通过 URI字符串 生成URI对象 + * + * @param uri URI字符串 + * @return URI + */ + public static URI getURI(String uri) + { + try { + return new URI(uri); + } catch (URISyntaxException e) + { + throw new ServiceException("URL格式异常"); + } + } + + /** + * 发布通道消息 + * + * @param channelKey 通道key + * @param msg 发送数据 + * @param consumer 自定义处理 + */ + public static void publish(String channelKey, T msg, Consumer consumer) { + RTopic topic = CLIENT.getTopic(channelKey); + topic.publish(msg); + consumer.accept(msg); + } + + /** + * 发布路由刷新通知 + * @param consumer 发送消息后执行 + */ + public static void sendRefreshRouteToGateway(String id, Type type, Consumer consumer) { + publish(TOPIC_GATEWAY_REFRESH_ROUTE, new TopicMsg(id, DateUtil.now(), type), consumer); + } + + /** + * 发布规则通知 + * @param consumer 发送消息后执行 + */ + public static void sendRuleNoticeToGateway(String id, Type type, Consumer consumer) { + publish(TOPIC_GATEWAY_RULE, new TopicMsg(id, DateUtil.now(), type), consumer); + } + + /** + * 刷新路由信息 先清空再批量新增 + * + * @param routes 路由信息 + * @return 是否成功 + */ + public static boolean refreshRoute(List routes) + { + Map routeMap = routes.stream().collect(Collectors.toMap(IscRouteDefinition::getId, + Function.identity(), (o1, o2) -> o2)); + final RMap map = CLIENT.getMap(IscRedisKeys.KEY_ROUTES, ROUTE_CODES_INSTANCE); + map.clear(); + map.putAll(routeMap); + sendRefreshRouteToGateway(null, TopicMsg.Type.REFRESH, + (msg) -> log.info("路由刷新完成,通知网关刷新路由![{}]", msg.getMsg())); + return true; + } + + /** + * 保存路由信息 + * + * @param routes 路由信息 + * @return 是否成功 + */ + public static boolean saveRoute(Collection routes) { + return saveRoute(routes, null); + } + + /** + * 保存路由信息 + * + * @param routes 路由信息 + * @param consumer 回调操作 + * @return 是否成功 + */ + public static boolean saveRoute(Collection routes, Consumer consumer) + { + if(CollectionUtil.isEmpty(routes)) { + return true; + } + final RMap map = CLIENT.getMap(IscRedisKeys.KEY_ROUTES, ROUTE_CODES_INSTANCE); + Map collect = routes.stream().collect(Collectors.toMap(IscRouteDefinition::getId, Function.identity())); + map.putAll(collect); + final String id = String.join(",", collect.keySet()); + Type type = Type.UPDATE; + if(Objects.isNull(consumer)) { + type = Type.ADD; + consumer = (msg) -> log.info("保存[{}]路由[{}]完成,通知网关刷新路由![{}]", msg.getType(), msg.getId(), msg.getMsg()); + } + sendRefreshRouteToGateway(id, type, consumer); + return true; + } + + /** + * 删除路由信息 + * + * @param routeIds 路由ID + * @return 是否成功 + */ + public static boolean deleteRoute(Collection routeIds) + { + final RMap map = CLIENT.getMap(IscRedisKeys.KEY_ROUTES, ROUTE_CODES_INSTANCE); + final String[] ids = routeIds.toArray(new String[0]); + map.fastRemove(ids); + final String id = String.join(",", routeIds); + sendRefreshRouteToGateway(id, Type.DELETE, + (msg) -> log.info("删除[{}]路由[{}]完成,通知网关刷新路由![{}]", msg.getType(), msg.getId(), msg.getMsg())); + return true; + } + + /** + * 更新路由信息 + * + * @param route 路由信息 + * @return 是否成功 + */ + public static boolean updateRoute(IscRouteDefinition route) + { + return saveRoute(Collections.singletonList(route), + (msg) -> log.info("保存[{}]路由[{}]完成,通知网关刷新路由![{}]", msg.getType(), msg.getId(), msg.getMsg())); + } + + /** + * 生成 路由信息 + * + * @param service 服务信息 + * @return 路由信息 + */ + public static IscRouteDefinition generateRoute(IscService service) + { + IscRouteDefinition route = new IscRouteDefinition(); + route.setId(String.valueOf(service.getServiceId())); + final String serviceAddr = service.getServiceAddr(); + route.setUri(getURI(serviceAddr.substring(0, serviceAddr.length() - getPathUri(serviceAddr).length()))); + + //断言 + IscPredicateDefinition methodPredicate = new IscPredicateDefinition(); + methodPredicate.setName("Method"); + methodPredicate.getArgs().put("methods", service.getRequestMethod()); + + IscPredicateDefinition pathPredicate = new IscPredicateDefinition(); + pathPredicate.setName("Path"); + pathPredicate.getArgs().put("pattern", genVirtualAddrPath(service.getServiceAddr())); + route.setPredicates(Arrays.asList(methodPredicate, pathPredicate)); + + //过滤器 + List filters = new ArrayList<>(); + IscFilterDefinition stripPrefixFilter = new IscFilterDefinition(); + stripPrefixFilter.setName("StripPrefix"); + stripPrefixFilter.getArgs().put("parts", "1"); + filters.add(stripPrefixFilter); + + IscFilterDefinition retryFilter = new IscFilterDefinition(); + retryFilter.setName("Retry"); + retryFilter.getArgs().put("retries", "1"); + filters.add(retryFilter); + route.setFilters(filters); + + //其他信息 + Map metadata = route.getMetadata(); + metadata.put(CONFIG_ACCESS_KEY_NAME_KEY, ACCESS_KEY_NAME_DEFAULT); + metadata.put(CONFIG_ADD_PARAM_KEY, service.getHiddenParams()); + return route; + } + + /** + * 生成 服务对应AK调用规则 + * + * @param appService 服务申请信息 + * @param accessKey AccessKey + * @return 规则信息 + */ + public static IscRule generateRule(IscAppService appService, String accessKey) + { + IscRule rule = new IscRule(); + rule.setId(GatewayUtils.getRouteKey(accessKey, appService.getServiceId())); + rule.setExpire(appService.getEndTime()); + rule.setDaysLimit(appService.getQuotaDays()); + rule.setHoursLimit(appService.getQuotaHours()); + rule.setMinutesLimit(appService.getQuotaMinutes()); + rule.setSecondsLimit(appService.getQuotaSeconds()); + return rule; + } + + /** + * 刷新规则信息 先清空再批量新增 + * + * @param rules 规则信息 + * @return 是否成功 + */ + public static boolean refreshRules(List rules) + { + Map ruleMap = rules.stream().collect(Collectors.toMap(IscRule::getId, Function.identity(), (o1, o2) -> o2)); + final RMap map = CLIENT.getMap(IscRedisKeys.KEY_RULES, RULE_CODES_INSTANCE); + map.clear(); + map.putAll(ruleMap); + final String id = String.join(",", ruleMap.keySet()); + sendRuleNoticeToGateway(id, Type.REFRESH, + (msg) -> log.info("刷新[{}]所有规则[{}]完成,通知网关刷新规则![{}]", msg.getType(), msg.getId(), msg.getMsg())); + return true; + } + + /** + * 保存规则信息 + * + * @param rule 规则信息 + * @return 是否成功 + */ + public static boolean saveRule(IscRule rule) { + return saveRule(rule, null); + } + + /** + * 保存规则信息 + * + * @param rule 规则信息 + * @param consumer 回调 + * @return 是否成功 + */ + public static boolean saveRule(IscRule rule, Consumer consumer) + { + final RMap map = CLIENT.getMap(IscRedisKeys.KEY_RULES, RULE_CODES_INSTANCE); + map.put(rule.getId(), rule); + Type type = Type.UPDATE; + if(Objects.isNull(consumer)) { + type = Type.ADD; + consumer = (msg) -> log.info("新增[{}]规则[{}]完成,通知网关刷新规则![{}]", msg.getType(), msg.getId(), msg.getMsg()); + } + sendRuleNoticeToGateway(rule.getId(), type, consumer); + return true; + } + + /** + * 删除规则信息 + * + * @param ruleId 规则ID + * @return 是否成功 + */ + public static boolean deleteRule(String ruleId) + { + final RMap map = CLIENT.getMap(IscRedisKeys.KEY_RULES, RULE_CODES_INSTANCE); + map.remove(ruleId); + sendRuleNoticeToGateway(ruleId, Type.DELETE, + (msg) -> log.info("删除[{}]规则[{}]完成,通知网关刷新规则![{}]", msg.getType(), msg.getId(), msg.getMsg())); + return true; + } + + /** + * 更新规则信息 + * + * @param rule 规则信息 + * @return 是否成功 + */ + public static boolean updateRule(IscRule rule) + { + return saveRule(rule, + (msg) -> log.info("更新[{}]规则[{}]完成,通知网关刷新规则![{}]", msg.getType(), msg.getId(), msg.getMsg())); + } +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/beans/IscFilterDefinition.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/beans/IscFilterDefinition.java new file mode 100644 index 000000000..ffee7ab81 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/beans/IscFilterDefinition.java @@ -0,0 +1,22 @@ +package com.ruoyi.isc.utils.beans; + +import lombok.Data; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Wenchao Gong + * @date 2021-09-28 + */ +@Data +@Validated +public class IscFilterDefinition { + + @NotNull + private String name; + + private Map args = new LinkedHashMap<>(); +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/beans/IscPredicateDefinition.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/beans/IscPredicateDefinition.java new file mode 100644 index 000000000..efcee83c1 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/beans/IscPredicateDefinition.java @@ -0,0 +1,22 @@ +package com.ruoyi.isc.utils.beans; + +import lombok.Data; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Wenchao Gong + * @date 2021-09-28 + */ +@Data +@Validated +public class IscPredicateDefinition { + + @NotNull + private String name; + + private Map args = new LinkedHashMap<>(); +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/beans/IscRouteDefinition.java b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/beans/IscRouteDefinition.java new file mode 100644 index 000000000..f5cbb42d2 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/java/com/ruoyi/isc/utils/beans/IscRouteDefinition.java @@ -0,0 +1,38 @@ +package com.ruoyi.isc.utils.beans; + +import lombok.Data; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Wenchao Gong + * @date 2021-09-28 + */ +@Data +@Validated +public class IscRouteDefinition { + + private String id; + + @NotEmpty + @Valid + private List predicates = new ArrayList<>(); + + @Valid + private List filters = new ArrayList<>(); + + @NotNull + private URI uri; + + private Map metadata = new HashMap<>(); + + private int order = 0; +} diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscAppServiceApplyMapper.xml b/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscAppServiceApplyMapper.xml new file mode 100644 index 000000000..6951d02aa --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscAppServiceApplyMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscAppServiceMapper.xml b/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscAppServiceMapper.xml new file mode 100644 index 000000000..599d22355 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscAppServiceMapper.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscApplicationMapper.xml b/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscApplicationMapper.xml new file mode 100644 index 000000000..607808cf4 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscApplicationMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscServiceCateMapper.xml b/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscServiceCateMapper.xml new file mode 100644 index 000000000..c08b45e9d --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscServiceCateMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscServiceMapper.xml b/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscServiceMapper.xml new file mode 100644 index 000000000..e7924dd40 --- /dev/null +++ b/ruoyi-isc-parent/ruoyi-isc/src/main/resources/mapper/isc/IscServiceMapper.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-oss/pom.xml b/ruoyi-oss/pom.xml index adbb55502..c2d847318 100644 --- a/ruoyi-oss/pom.xml +++ b/ruoyi-oss/pom.xml @@ -42,6 +42,10 @@ org.slf4j slf4j-log4j12 + + org.bouncycastle + bcprov-jdk15on + diff --git a/ruoyi-system/pom.xml b/ruoyi-system/pom.xml index bf0a5c9c2..d3a596371 100644 --- a/ruoyi-system/pom.xml +++ b/ruoyi-system/pom.xml @@ -16,7 +16,11 @@ - + + org.jsoup + jsoup + 1.13.1 + com.ruoyi diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java index ea6afa2e5..bd8c5ffbf 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java @@ -1,7 +1,7 @@ package com.ruoyi.system.service; +import cn.hutool.core.lang.tree.Tree; import com.baomidou.mybatisplus.extension.service.IService; -import com.ruoyi.common.core.domain.TreeSelect; import com.ruoyi.common.core.domain.entity.SysDept; import java.util.List; @@ -20,21 +20,13 @@ public interface ISysDeptService extends IService { */ List selectDeptList(SysDept dept); - /** - * 构建前端所需要树结构 - * - * @param depts 部门列表 - * @return 树结构列表 - */ - List buildDeptTree(List depts); - /** * 构建前端所需要下拉树结构 * * @param depts 部门列表 * @return 下拉树结构列表 */ - List buildDeptTreeSelect(List depts); + List> buildDeptTreeSelect(List depts); /** * 根据角色ID查询部门树信息 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java index eea882e67..bc4c960af 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java @@ -1,7 +1,7 @@ package com.ruoyi.system.service; +import cn.hutool.core.lang.tree.Tree; import com.baomidou.mybatisplus.extension.service.IService; -import com.ruoyi.common.core.domain.TreeSelect; import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.system.domain.vo.RouterVo; @@ -64,21 +64,13 @@ public interface ISysMenuService extends IService { */ List buildMenus(List menus); - /** - * 构建前端所需要树结构 - * - * @param menus 菜单列表 - * @return 树结构列表 - */ - List buildMenuTree(List menus); - /** * 构建前端所需要下拉树结构 * * @param menus 菜单列表 * @return 下拉树结构列表 */ - List buildMenuTreeSelect(List menus); + List> buildMenuTreeSelect(List menus); /** * 根据菜单ID查询信息 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java index 45c6faed6..62ccbec6f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java @@ -1,11 +1,11 @@ package com.ruoyi.system.service.impl; import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.tree.Tree; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.ruoyi.common.annotation.DataScope; import com.ruoyi.common.constant.UserConstants; -import com.ruoyi.common.core.domain.TreeSelect; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysUser; @@ -14,6 +14,7 @@ import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.common.utils.TreeUtils; import com.ruoyi.system.mapper.SysDeptMapper; import com.ruoyi.system.mapper.SysRoleMapper; import com.ruoyi.system.mapper.SysUserMapper; @@ -21,10 +22,8 @@ import com.ruoyi.system.service.ISysDeptService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; /** * 部门管理 服务实现 @@ -52,32 +51,6 @@ public class SysDeptServiceImpl extends ServicePlusImpl buildDeptTree(List depts) { - List returnList = new ArrayList(); - List tempList = new ArrayList(); - for (SysDept dept : depts) { - tempList.add(dept.getDeptId()); - } - for (SysDept dept : depts) { - // 如果是顶级节点, 遍历该父节点的所有子节点 - if (!tempList.contains(dept.getParentId())) { - recursionFn(depts, dept); - returnList.add(dept); - } - } - if (returnList.isEmpty()) { - returnList = depts; - } - return returnList; - } - /** * 构建前端所需要下拉树结构 * @@ -85,9 +58,13 @@ public class SysDeptServiceImpl extends ServicePlusImpl buildDeptTreeSelect(List depts) { - List deptTrees = buildDeptTree(depts); - return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); + public List> buildDeptTreeSelect(List depts) { + return TreeUtils.build(depts, (dept, tree) -> { + tree.setId(dept.getDeptId()); + tree.setParentId(dept.getParentId()); + tree.setName(dept.getDeptName()); + tree.setWeight(dept.getOrderNum()); + }); } /** @@ -273,37 +250,4 @@ public class SysDeptServiceImpl extends ServicePlusImpl list, SysDept t) { - // 得到子节点列表 - List childList = getChildList(list, t); - t.setChildren(childList); - for (SysDept tChild : childList) { - if (hasChild(list, tChild)) { - recursionFn(list, tChild); - } - } - } - - /** - * 得到子节点列表 - */ - private List getChildList(List list, SysDept t) { - List tlist = new ArrayList(); - for (SysDept n : list) { - if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) { - tlist.add(n); - } - } - return tlist; - } - - /** - * 判断是否有子节点 - */ - private boolean hasChild(List list, SysDept t) { - return getChildList(list, t).size() > 0; - } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java index 643d304eb..5fd5487e3 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java @@ -1,15 +1,16 @@ package com.ruoyi.system.service.impl; +import cn.hutool.core.lang.tree.Tree; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.UserConstants; -import com.ruoyi.common.core.domain.TreeSelect; import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.common.core.domain.entity.SysRole; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.TreeUtils; import com.ruoyi.system.domain.SysRoleMenu; import com.ruoyi.system.domain.vo.MetaVo; import com.ruoyi.system.domain.vo.RouterVo; @@ -21,7 +22,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; -import java.util.stream.Collectors; /** * 菜单 业务层处理 @@ -170,32 +170,6 @@ public class SysMenuServiceImpl extends ServicePlusImpl buildMenuTree(List menus) { - List returnList = new ArrayList(); - List tempList = new ArrayList(); - for (SysMenu dept : menus) { - tempList.add(dept.getMenuId()); - } - for (SysMenu menu : menus) { - // 如果是顶级节点, 遍历该父节点的所有子节点 - if (!tempList.contains(menu.getParentId())) { - recursionFn(menus, menu); - returnList.add(menu); - } - } - if (returnList.isEmpty()) { - returnList = menus; - } - return returnList; - } - /** * 构建前端所需要下拉树结构 * @@ -203,9 +177,13 @@ public class SysMenuServiceImpl extends ServicePlusImpl buildMenuTreeSelect(List menus) { - List menuTrees = buildMenuTree(menus); - return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList()); + public List> buildMenuTreeSelect(List menus) { + return TreeUtils.build(menus, (menu, tree) -> { + tree.setId(menu.getMenuId()); + tree.setParentId(menu.getParentId()); + tree.setName(menu.getMenuName()); + tree.setWeight(menu.getOrderNum()); + }); } /** diff --git a/ruoyi-ui/src/api/isc/application.js b/ruoyi-ui/src/api/isc/application.js new file mode 100644 index 000000000..538b255e3 --- /dev/null +++ b/ruoyi-ui/src/api/isc/application.js @@ -0,0 +1,44 @@ +import request from '@/utils/request' + +// 查询应用信息列表 +export function listApplication(query) { + return request({ + url: '/isc/application/list', + method: 'get', + params: query + }) +} + +// 查询应用信息详细 +export function getApplication(applicationId) { + return request({ + url: '/isc/application/' + applicationId, + method: 'get' + }) +} + +// 新增应用信息 +export function addApplication(data) { + return request({ + url: '/isc/application', + method: 'post', + data: data + }) +} + +// 修改应用信息 +export function updateApplication(data) { + return request({ + url: '/isc/application', + method: 'put', + data: data + }) +} + +// 删除应用信息 +export function delApplication(applicationId) { + return request({ + url: '/isc/application/' + applicationId, + method: 'delete' + }) +} diff --git a/ruoyi-ui/src/api/isc/appservice.js b/ruoyi-ui/src/api/isc/appservice.js new file mode 100644 index 000000000..6e3abdba3 --- /dev/null +++ b/ruoyi-ui/src/api/isc/appservice.js @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +// 查询应用服务列表 +export function listAppservice(query) { + return request({ + url: '/isc/appservice/list', + method: 'get', + params: query + }) +} + +// 查询应用服务详细 +export function getAppservice(appServiceId) { + return request({ + url: '/isc/appservice/' + appServiceId, + method: 'get' + }) +} + +// 新增应用服务 +export function addAppservice(data) { + return request({ + url: '/isc/appservice', + method: 'post', + data: data + }) +} + +// 修改应用服务 +export function updateAppservice(data) { + return request({ + url: '/isc/appservice', + method: 'put', + data: data + }) +} + +// 删除应用服务 +export function delAppservice(appServiceId) { + return request({ + url: '/isc/appservice/' + appServiceId, + method: 'delete' + }) +} + +// 获取应用服务下拉树列表 +export function treeselect(applicationId) { + return request({ + url: '/isc/appservice/treeselect/' + applicationId, + method: 'get' + }) +} diff --git a/ruoyi-ui/src/api/isc/cate.js b/ruoyi-ui/src/api/isc/cate.js new file mode 100644 index 000000000..7c503e4d8 --- /dev/null +++ b/ruoyi-ui/src/api/isc/cate.js @@ -0,0 +1,52 @@ +import request from '@/utils/request' + +// 查询服务分类列表 +export function listCate(query) { + return request({ + url: '/isc/cate/list', + method: 'get', + params: query + }) +} + +// 查询服务分类详细 +export function getCate(cateId) { + return request({ + url: '/isc/cate/' + cateId, + method: 'get' + }) +} + +// 新增服务分类 +export function addCate(data) { + return request({ + url: '/isc/cate', + method: 'post', + data: data + }) +} + +// 修改服务分类 +export function updateCate(data) { + return request({ + url: '/isc/cate', + method: 'put', + data: data + }) +} + +// 删除服务分类 +export function delCate(cateId) { + return request({ + url: '/isc/cate/' + cateId, + method: 'delete' + }) +} + +// 查询服务分类下拉树结构 +export function treeselect() { + return request({ + url: '/isc/cate/treeselect', + method: 'get' + }) +} diff --git a/ruoyi-ui/src/api/isc/service.js b/ruoyi-ui/src/api/isc/service.js new file mode 100644 index 000000000..ba9c58336 --- /dev/null +++ b/ruoyi-ui/src/api/isc/service.js @@ -0,0 +1,53 @@ +import request from '@/utils/request' + +// 查询服务信息列表 +export function listService(query) { + return request({ + url: '/isc/service/list', + method: 'get', + params: query + }) +} + +// 查询服务信息详细 +export function getService(serviceId) { + return request({ + url: '/isc/service/' + serviceId, + method: 'get' + }) +} + +// 新增服务信息 +export function addService(data) { + return request({ + url: '/isc/service', + method: 'post', + data: data + }) +} + +// 修改服务信息 +export function updateService(data) { + return request({ + url: '/isc/service', + method: 'put', + data: data + }) +} + +// 删除服务信息 +export function delService(serviceId) { + return request({ + url: '/isc/service/' + serviceId, + method: 'delete' + }) +} + +// 服务信息审核 +export function auditService(data) { + return request({ + url: '/isc/service/audit', + method: 'put', + data: data + }) +} diff --git a/ruoyi-ui/src/api/isc/serviceapply.js b/ruoyi-ui/src/api/isc/serviceapply.js new file mode 100644 index 000000000..fdc6012a5 --- /dev/null +++ b/ruoyi-ui/src/api/isc/serviceapply.js @@ -0,0 +1,27 @@ +import request from '@/utils/request' + +// 查询应用服务申请信息列表 +export function listServiceapply(query) { + return request({ + url: '/isc/serviceapply/list', + method: 'get', + params: query + }) +} + +// 查询应用服务申请信息详细 +export function getServiceapply(applyId) { + return request({ + url: '/isc/serviceapply/' + applyId, + method: 'get' + }) +} + +// 应用服务申请信息审核 +export function auditServiceapply(data) { + return request({ + url: '/isc/serviceapply/audit', + method: 'put', + data: data + }) +} diff --git a/ruoyi-ui/src/components/CopyTag/index.vue b/ruoyi-ui/src/components/CopyTag/index.vue new file mode 100644 index 000000000..df5956179 --- /dev/null +++ b/ruoyi-ui/src/components/CopyTag/index.vue @@ -0,0 +1,48 @@ + + + + \ No newline at end of file diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js index cedf0b3aa..1f44ffbaa 100644 --- a/ruoyi-ui/src/router/index.js +++ b/ruoyi-ui/src/router/index.js @@ -163,6 +163,19 @@ export const constantRoutes = [ meta: { title: '修改生成配置', activeMenu: '/tool/gen'} } ] + }, + { + path: '/isc/app-service', + component: Layout, + hidden: true, + children: [ + { + path: 'index/:applicationId(\\d+)', + component: (resolve) => require(['@/views/isc/appservice/index'], resolve), + name: 'Appservice', + meta: { title: '应用服务', activeMenu: '/isc/application'} + } + ] } ] diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js index dba9252f4..2cfe995ff 100644 --- a/ruoyi-ui/src/store/modules/permission.js +++ b/ruoyi-ui/src/store/modules/permission.js @@ -21,12 +21,12 @@ const permission = { state.defaultRoutes = constantRoutes.concat(routes) }, SET_TOPBAR_ROUTES: (state, routes) => { - // 顶部导航菜单默认添加统计报表栏指向首页 + // 顶部导航菜单默认添加仪表盘栏指向首页 const index = [{ path: 'index', - meta: { title: '统计报表', icon: 'dashboard'} + meta: { title: '仪表盘', icon: 'dashboard'} }] - state.topbarRouters = routes.concat(index); + state.topbarRouters = index.concat(routes); }, SET_SIDEBAR_ROUTERS: (state, routes) => { state.sidebarRouters = routes diff --git a/ruoyi-ui/src/views/isc/application/index.vue b/ruoyi-ui/src/views/isc/application/index.vue new file mode 100644 index 000000000..2395d841e --- /dev/null +++ b/ruoyi-ui/src/views/isc/application/index.vue @@ -0,0 +1,323 @@ + + + diff --git a/ruoyi-ui/src/views/isc/appservice/index.vue b/ruoyi-ui/src/views/isc/appservice/index.vue new file mode 100644 index 000000000..6505942c5 --- /dev/null +++ b/ruoyi-ui/src/views/isc/appservice/index.vue @@ -0,0 +1,545 @@ + + + + \ No newline at end of file diff --git a/ruoyi-ui/src/views/isc/cate/index.vue b/ruoyi-ui/src/views/isc/cate/index.vue new file mode 100644 index 000000000..a1a500791 --- /dev/null +++ b/ruoyi-ui/src/views/isc/cate/index.vue @@ -0,0 +1,310 @@ + + + diff --git a/ruoyi-ui/src/views/isc/service/audit.vue b/ruoyi-ui/src/views/isc/service/audit.vue new file mode 100644 index 000000000..0df771acd --- /dev/null +++ b/ruoyi-ui/src/views/isc/service/audit.vue @@ -0,0 +1,412 @@ + + + + \ No newline at end of file diff --git a/ruoyi-ui/src/views/isc/service/index.vue b/ruoyi-ui/src/views/isc/service/index.vue new file mode 100644 index 000000000..95b785dd8 --- /dev/null +++ b/ruoyi-ui/src/views/isc/service/index.vue @@ -0,0 +1,425 @@ + + + \ No newline at end of file diff --git a/ruoyi-ui/src/views/isc/serviceapply/index.vue b/ruoyi-ui/src/views/isc/serviceapply/index.vue new file mode 100644 index 000000000..554b76cdc --- /dev/null +++ b/ruoyi-ui/src/views/isc/serviceapply/index.vue @@ -0,0 +1,358 @@ + + + + \ No newline at end of file diff --git a/ruoyi-ui/src/views/login.vue b/ruoyi-ui/src/views/login.vue index 6c35bd8d4..d19158dd5 100644 --- a/ruoyi-ui/src/views/login.vue +++ b/ruoyi-ui/src/views/login.vue @@ -68,8 +68,8 @@ export default { codeUrl: "", cookiePassword: "", loginForm: { - username: "admin", - password: "admin123", + username: "", + password: "", rememberMe: false, code: "", uuid: "" diff --git a/ruoyi-ui/src/views/system/role/index.vue b/ruoyi-ui/src/views/system/role/index.vue index 9ca11c0c0..f0db74325 100644 --- a/ruoyi-ui/src/views/system/role/index.vue +++ b/ruoyi-ui/src/views/system/role/index.vue @@ -112,6 +112,7 @@