mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-19 17:58:17 +08:00
Pre Merge pull request !108 from wenchaogong/develop
This commit is contained in:
commit
a08f703e45
75
pom.xml
75
pom.xml
@ -29,15 +29,19 @@
|
||||
<mybatis-plus.version>3.4.3.4</mybatis-plus.version>
|
||||
<p6spy.version>3.9.1</p6spy.version>
|
||||
<hutool.version>5.7.15</hutool.version>
|
||||
<guava.version>29.0-jre</guava.version>
|
||||
<feign.version>3.0.3</feign.version>
|
||||
<gateway.version>3.0.3</gateway.version>
|
||||
<feign-okhttp.version>11.6</feign-okhttp.version>
|
||||
<okhttp.version>4.9.1</okhttp.version>
|
||||
<spring-boot-admin.version>2.5.2</spring-boot-admin.version>
|
||||
<redisson.version>3.16.3</redisson.version>
|
||||
<okio.version>2.8.0</okio.version>
|
||||
<lock4j.version>2.2.1</lock4j.version>
|
||||
<dynamic-ds.version>3.4.1</dynamic-ds.version>
|
||||
<tlog.version>1.3.3</tlog.version>
|
||||
<xxl-job.version>2.3.0</xxl-job.version>
|
||||
<wildfly-common.version>1.5.2.Final</wildfly-common.version>
|
||||
|
||||
<!-- jdk11 缺失依赖 jaxb-->
|
||||
<jaxb.version>3.0.1</jaxb.version>
|
||||
@ -53,7 +57,6 @@
|
||||
<docker.registry.host>http://${docker.registry.url}:2375</docker.registry.host>
|
||||
<docker.namespace>ruoyi</docker.namespace>
|
||||
<docker.plugin.version>1.2.2</docker.plugin.version>
|
||||
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
@ -88,6 +91,7 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- 指定 swagger-annotations 版本冲突-->
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
@ -168,6 +172,18 @@
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
<version>${gateway.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- @deprecated 由于使用人数较少 决定与 3.4.0 版本移除 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
@ -178,6 +194,10 @@
|
||||
<artifactId>feign-core</artifactId>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- @deprecated 由于使用人数较少 决定与 3.4.0 版本移除 -->
|
||||
@ -186,6 +206,11 @@
|
||||
<artifactId>feign-okhttp</artifactId>
|
||||
<version>${feign-okhttp.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okio</groupId>
|
||||
<artifactId>okio</artifactId>
|
||||
<version>${okio.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
@ -204,7 +229,24 @@
|
||||
<version>${spring-boot-admin.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- redis 缓存操作 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.lettuce</groupId>
|
||||
<artifactId>lettuce-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<version>${spring-boot.version}</version>
|
||||
</dependency>
|
||||
<!--redisson-->
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
<version>${redisson.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||
@ -216,11 +258,24 @@
|
||||
<version>${lock4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- undertow 中的wildfly-common包冲突处理 -->
|
||||
<dependency>
|
||||
<groupId>org.wildfly.common</groupId>
|
||||
<artifactId>wildfly-common</artifactId>
|
||||
<version>${wildfly-common.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- xxl-job-core -->
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
<version>${xxl-job.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@ -306,6 +361,23 @@
|
||||
<version>${ruoyi-vue-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- isc模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-isc-parent</artifactId>
|
||||
<version>${ruoyi-vue-plus.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-isc-common</artifactId>
|
||||
<version>${ruoyi-vue-plus.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-isc</artifactId>
|
||||
<version>${ruoyi-vue-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- demo模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
@ -327,6 +399,7 @@
|
||||
<module>ruoyi-demo</module>
|
||||
<module>ruoyi-extend</module>
|
||||
<module>ruoyi-oss</module>
|
||||
<module>ruoyi-isc-parent</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
|
||||
@ -52,10 +52,11 @@
|
||||
<artifactId>ruoyi-job</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-oss</artifactId>
|
||||
</dependency>
|
||||
</dependency>-->
|
||||
|
||||
<!-- 代码生成-->
|
||||
<dependency>
|
||||
@ -63,6 +64,12 @@
|
||||
<artifactId>ruoyi-generator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- isc模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-isc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- demo模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
|
||||
@ -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<List<TreeSelect>> treeselect(SysDept dept) {
|
||||
public AjaxResult<List<Tree<Long>>> treeselect(SysDept dept) {
|
||||
List<SysDept> depts = deptService.selectDeptList(dept);
|
||||
return AjaxResult.success(deptService.buildDeptTreeSelect(depts));
|
||||
}
|
||||
|
||||
@ -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<List<TreeSelect>> treeselect(SysMenu menu) {
|
||||
public AjaxResult<List<Tree<Long>>> treeselect(SysMenu menu) {
|
||||
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
|
||||
return AjaxResult.success(menuService.buildMenuTreeSelect(menus));
|
||||
}
|
||||
|
||||
@ -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
|
||||
# 数据库索引
|
||||
|
||||
158
ruoyi-admin/src/main/resources/application-local.yml
Normal file
158
ruoyi-admin/src/main/resources/application-local.yml
Normal file
@ -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
|
||||
@ -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
|
||||
# 数据库索引
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
<configuration>
|
||||
<property name="log.path" value="./logs"/>
|
||||
<property name="console.log.pattern"
|
||||
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
|
||||
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"/>
|
||||
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %green([%thread]) %boldMagenta(%logger{36}) - %msg%n"/>
|
||||
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n"/>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
@ -31,7 +31,7 @@
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-info.log</file>
|
||||
@ -54,7 +54,7 @@
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
@ -76,7 +76,7 @@
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
|
||||
<!-- 用户访问日志输出 -->
|
||||
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-user.log</file>
|
||||
@ -90,7 +90,7 @@
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
|
||||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.ruoyi" level="info" />
|
||||
<!-- Spring日志级别控制 -->
|
||||
@ -99,16 +99,16 @@
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="file_info" />
|
||||
<appender-ref ref="file_error" />
|
||||
<appender-ref ref="file_console" />
|
||||
</root>
|
||||
|
||||
|
||||
<!--系统用户操作日志-->
|
||||
<logger name="sys-user" level="info">
|
||||
<appender-ref ref="sys-user"/>
|
||||
</logger>
|
||||
</configuration>
|
||||
</configuration>
|
||||
|
||||
@ -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_
|
||||
|
||||
@ -46,6 +46,10 @@
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON工具类 -->
|
||||
<dependency>
|
||||
|
||||
@ -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";
|
||||
|
||||
}
|
||||
|
||||
@ -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";
|
||||
}
|
||||
@ -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<TreeSelect> 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());
|
||||
}
|
||||
|
||||
}
|
||||
@ -55,4 +55,9 @@ public enum BusinessType {
|
||||
* 清空数据
|
||||
*/
|
||||
CLEAN,
|
||||
|
||||
/**
|
||||
* 审核
|
||||
*/
|
||||
AUDIT
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
132
ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeUtils.java
Normal file
132
ruoyi-common/src/main/java/com/ruoyi/common/utils/TreeUtils.java
Normal file
@ -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 <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<Tree<Long>> build(List<T> list, NodeParser<T, Long> nodeParser)
|
||||
{
|
||||
return TreeUtil.build(list, DEFAULT_PARENT_ID, DEFAULT_TREE_NODE_CONFIG, nodeParser);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 树构建
|
||||
*
|
||||
* @param <T> 转换的实体 为数据源里的对象类型
|
||||
* @param <E> ID类型
|
||||
* @param list 源数据集合
|
||||
* @param parentId 最顶层父id值 一般为 0 之类
|
||||
* @param nodeParser 转换器
|
||||
* @param needExistField 是否需要 已存在字段
|
||||
* @return List
|
||||
*/
|
||||
public static <T, E> List<Tree<E>> build(List<T> list, E parentId, NodeParser<T, E> nodeParser,
|
||||
boolean needExistField)
|
||||
{
|
||||
final List<Tree<E>> treeList = CollUtil.newArrayList();
|
||||
final TreeNodeConfig treeNodeConfig = DEFAULT_TREE_NODE_CONFIG;
|
||||
Tree<E> tree;
|
||||
for (T obj : list) {
|
||||
tree = new Tree<>(treeNodeConfig);
|
||||
nodeParser.parse(obj, tree);
|
||||
treeList.add(tree);
|
||||
}
|
||||
|
||||
List<Tree<E>> finalTreeList = CollUtil.newArrayList();
|
||||
for (Tree<E> 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 <T> void innerBuild(List<Tree<T>> treeNodes, Tree<T> 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<T> childNode : treeNodes) {
|
||||
if (parentNode.getId().equals(childNode.getParentId())) {
|
||||
List<Tree<T>> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,6 +14,7 @@
|
||||
<modules>
|
||||
<module>ruoyi-monitor-admin</module>
|
||||
<module>ruoyi-xxl-job-admin</module>
|
||||
<module>ruoyi-isc-gateway</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
||||
46
ruoyi-extend/ruoyi-isc-gateway/pom.xml
Normal file
46
ruoyi-extend/ruoyi-isc-gateway/pom.xml
Normal file
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi-vue-plus</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-isc-gateway</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-isc-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -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 启动成功" );
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<List<Long>> redisScript,
|
||||
ConfigurationService configurationService, DefaultRedisScript<Long> 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 <T> void subscribe(String channelKey, Class<T> clazz, Consumer<T> consumer) {
|
||||
RTopic topic = client.getTopic(channelKey);
|
||||
topic.addListener(clazz, (channel, msg) -> consumer.accept(msg));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(@NonNull ApplicationEventPublisher publisher) {
|
||||
this.publisher = publisher;
|
||||
}
|
||||
}
|
||||
@ -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<Long> limitScript() {
|
||||
DefaultRedisScript<Long> 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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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<Void> 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<Integer> 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<String, Object> result(Optional<Integer> code, String message, RequestPath path) {
|
||||
final HashMap<String, Object> 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;
|
||||
}
|
||||
}
|
||||
@ -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<RouteDefinition> getRouteDefinitions()
|
||||
{
|
||||
RMap<String, RouteDefinition> map = redissonClient.getMap(KEY_ROUTES, ROUTE_CODES_INSTANCE);
|
||||
log.debug("Routes from redis size:[{}]!", map.size());
|
||||
return Flux.fromIterable(map.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> save(Mono<RouteDefinition> route)
|
||||
{
|
||||
return route.flatMap(definition -> {
|
||||
RMap<String, RouteDefinition> 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<Void> delete(Mono<String> routeId)
|
||||
{
|
||||
return routeId.flatMap(id -> {
|
||||
RMap<String, RouteDefinition> map = redissonClient.getMap(KEY_ROUTES, ROUTE_CODES_INSTANCE);
|
||||
map.remove(id);
|
||||
log.debug("Remove route from redis id:[{}]!", id);
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -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> 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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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]规则不存在";
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
@ -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()));
|
||||
}
|
||||
}
|
||||
@ -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)));
|
||||
}
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
@ -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<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
final Route route = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
|
||||
final Map<String, Object> 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<String, String> 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<Void> handlePostRequest(ServerWebExchange exchange, GatewayFilterChain chain, Route route,
|
||||
ServerHttpRequest request, AccessKey accessKey,
|
||||
MultiValueMap<String, String> queryParams) {
|
||||
//处理 URL AccessKey
|
||||
handleAccessKey(accessKey, () -> queryParams.get(accessKey.name), URI, false);
|
||||
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
|
||||
final Mono<String> 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<? extends String> handlePostRequestFormUrlencoded(ServerWebExchange exchange, Route route,
|
||||
ServerHttpRequest request, AccessKey accessKey,
|
||||
String body, MultiValueMap<String, String> queryParams) {
|
||||
|
||||
if (StrUtil.isBlank(body)) {
|
||||
Assert.notBlank(accessKey.value, () -> new AkRequireException(accessKey.name));
|
||||
}
|
||||
final List<String[]> 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<Mono<String>> rateLimiterAfterSupplier = () -> {
|
||||
removeParam(accessKey, request, null, queryParams);
|
||||
final List<String[]> 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<? extends String> handlePostRequestJson(ServerWebExchange exchange, Route route,
|
||||
ServerHttpRequest request, AccessKey accessKey,
|
||||
JSONObject jsonObj, MultiValueMap<String, String> queryParams) {
|
||||
final IscRule rule = handleRule(accessKey, () -> Collections.singletonList(jsonObj.get(accessKey.name,
|
||||
String.class, true)), route, BODY);
|
||||
Supplier<Mono<String>> 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<Void> handleGetRequest(ServerWebExchange exchange, GatewayFilterChain chain, Route route,
|
||||
ServerHttpRequest request, AccessKey accessKey,
|
||||
MultiValueMap<String, String> queryParams) {
|
||||
final IscRule rule = handleRule(accessKey, () -> queryParams.get(accessKey.name), route, URI);
|
||||
Supplier<Mono<Void>> 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<ServerHttpRequest, MultiValueMap<String, String>, 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<List<String>> 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<List<String>> 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 <T> 类型
|
||||
*/
|
||||
private <T> void removeParam(AccessKey accessKey, ServerHttpRequest request, Supplier<T> removeSupplier,
|
||||
MultiValueMap<String, String> 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 <U> 参数类型
|
||||
*/
|
||||
private <U> void handleHiddenParams(Route route, U result, BiConsumer<Map.Entry<String, Object>, 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<String, Object> next : json.entrySet()) {
|
||||
mapper.accept(next, result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 限流
|
||||
*
|
||||
* @param exchange 当前服务交换器
|
||||
* @param rule 限流规则
|
||||
* @param route 路由
|
||||
* @param rateLimiterAfterSupplier 限流后操作(删除参数、添加隐藏参数,跳转)
|
||||
* @param <T> 最终返回类型
|
||||
* @return rateLimiterAfterSupplier 返回类型
|
||||
*/
|
||||
private <T> Mono<T> rateLimiter(ServerWebExchange exchange, IscRule rule, Route route, final int index,
|
||||
Supplier<Mono<T>> 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<String, String> 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;
|
||||
}
|
||||
}
|
||||
@ -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<List<Long>> script;
|
||||
private final RedisScript<Long> timeRedisScript;
|
||||
|
||||
private final AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
public CustomerRedisRateLimiter(ReactiveStringRedisTemplate redisTemplate, RedisScript<List<Long>> script,
|
||||
ConfigurationService configurationService, DefaultRedisScript<Long> timeRedisScript) {
|
||||
super(redisTemplate, script, configurationService);
|
||||
this.redisTemplate = redisTemplate;
|
||||
this.script = script;
|
||||
this.timeRedisScript = timeRedisScript;
|
||||
this.initialized.compareAndSet(false, true);
|
||||
}
|
||||
|
||||
public Mono<Response> 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<String> 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<Response> 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<String> keys = getKeys(id);
|
||||
|
||||
// The arguments to the LUA script. time() returns unixtime in seconds.
|
||||
List<String> scriptArgs = Arrays.asList(replenishRate + "", burstCapacity + "",
|
||||
Instant.now().getEpochSecond() + "", requestedTokens + "");
|
||||
// allowed, tokens_left = redis.eval(SCRIPT, keys, args)
|
||||
Flux<List<Long>> 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<Long>(), (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<Response> isAllowed(Config routeConfig, List<String> 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<String> scriptArgs = Arrays.asList(replenishRate + "", time + "");
|
||||
// allowed, tokens_left = redis.eval(SCRIPT, keys, args)
|
||||
Flux<Long> 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<String, String> getHeaders(Config config, Long tokensLeft, TimeUnit timeUnit) {
|
||||
Map<String, String> 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<String> 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<String> getKeys(String id, int now, TimeUnit timeUnit) {
|
||||
String tokenKey = "rate_limiter.{" + id + ':' + now + "}." + timeUnit.name();
|
||||
return Arrays.asList(tokenKey);
|
||||
}
|
||||
}
|
||||
@ -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<Void> modifyBody(ServerWebExchange exchange, GatewayFilterChain chain, Mono<String> 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<DataBuffer> 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<List<String>> valueSupplier) {
|
||||
return getValue(before, valueSupplier, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 values 中获取第一个不为空 的值
|
||||
*
|
||||
* @param before 获取之前的值 如果不为空直接返回
|
||||
* @param valueSupplier 值列表生产者
|
||||
* @param errorMsgSupplier 异常信息生产者
|
||||
* @param <X>
|
||||
* @return
|
||||
*/
|
||||
public static <X extends RuntimeException> String getValue(String before, Supplier<List<String>> valueSupplier,
|
||||
Supplier<X> errorMsgSupplier) {
|
||||
if (StringUtils.hasText(before)) {
|
||||
return before;
|
||||
}
|
||||
final List<String> 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 <T>
|
||||
* @param <X>
|
||||
* @return
|
||||
*/
|
||||
public static <T, X extends RuntimeException> T getRequiredValue(Supplier<T> valueSupplier,
|
||||
Supplier<X> 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<String, IscRule> map = client.getMap(KEY_RULES, RULE_CODES_INSTANCE);
|
||||
return map.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言是否超过结束时间
|
||||
*
|
||||
* @param rule
|
||||
* @param errorMsgSupplier
|
||||
* @param <X>
|
||||
*/
|
||||
public static <X extends RuntimeException> void isBefore(IscRule rule, Supplier<X> errorMsgSupplier) {
|
||||
Assert.isTrue(Objects.nonNull(rule.getExpire()) && Date.from(Instant.now()).before(rule.getExpire()),
|
||||
errorMsgSupplier);
|
||||
}
|
||||
}
|
||||
@ -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<String, IscRule> 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;
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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@
|
||||
114
ruoyi-extend/ruoyi-isc-gateway/src/main/resources/logback.xml
Normal file
114
ruoyi-extend/ruoyi-isc-gateway/src/main/resources/logback.xml
Normal file
@ -0,0 +1,114 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<property name="log.path" value="./logs"/>
|
||||
<property name="console.log.pattern"
|
||||
value="%red(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %green([%thread]) %boldMagenta(%logger{36}) - %msg%n"/>
|
||||
<property name="log.pattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{36} - %msg%n"/>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>${console.log.pattern}</pattern>
|
||||
<charset>utf-8</charset>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="file_console" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-console.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-console.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大 1天 -->
|
||||
<maxHistory>1</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
<charset>utf-8</charset>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 系统日志输出 -->
|
||||
<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-info.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>INFO</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-error.log</file>
|
||||
<!-- 循环政策:基于时间创建日志文件 -->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 日志文件名格式 -->
|
||||
<fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<!-- 过滤的级别 -->
|
||||
<level>ERROR</level>
|
||||
<!-- 匹配时的操作:接收(记录) -->
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<!-- 不匹配时的操作:拒绝(不记录) -->
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
</appender>
|
||||
|
||||
<!-- 用户访问日志输出 -->
|
||||
<appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.path}/sys-user.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- 按天回滚 daily -->
|
||||
<fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<!-- 日志最大的历史 60天 -->
|
||||
<maxHistory>60</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>${log.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- 系统模块日志级别控制 -->
|
||||
<logger name="com.ruoyi" level="info" />
|
||||
<!-- Spring日志级别控制 -->
|
||||
<logger name="org.springframework" level="warn" />
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
<!--系统操作日志-->
|
||||
<root level="info">
|
||||
<appender-ref ref="file_info" />
|
||||
<appender-ref ref="file_error" />
|
||||
<appender-ref ref="file_console" />
|
||||
</root>
|
||||
|
||||
<!--系统用户操作日志-->
|
||||
<logger name="sys-user" level="info">
|
||||
<appender-ref ref="sys-user"/>
|
||||
</logger>
|
||||
</configuration>
|
||||
@ -28,6 +28,22 @@
|
||||
<groupId>de.codecentric</groupId>
|
||||
<artifactId>spring-boot-admin-starter-server</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里数据库连接池 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -1,11 +1,8 @@
|
||||
server:
|
||||
port: 9090
|
||||
|
||||
spring:
|
||||
security:
|
||||
user:
|
||||
name: ruoyi
|
||||
password: 123456
|
||||
boot:
|
||||
admin:
|
||||
context-path: /admin
|
||||
profiles:
|
||||
active: @profiles.active@
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
33
ruoyi-isc-parent/pom.xml
Normal file
33
ruoyi-isc-parent/pom.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi-vue-plus</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.3.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-isc-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>ruoyi-isc-common</module>
|
||||
<module>ruoyi-isc</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-isc-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-isc</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
</project>
|
||||
30
ruoyi-isc-parent/ruoyi-isc-common/pom.xml
Normal file
30
ruoyi-isc-parent/ruoyi-isc-common/pom.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi-isc-parent</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.3.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-isc-common</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -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);
|
||||
}
|
||||
@ -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:";
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
25
ruoyi-isc-parent/ruoyi-isc/pom.xml
Normal file
25
ruoyi-isc-parent/ruoyi-isc/pom.xml
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi-isc-parent</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.3.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ruoyi-isc</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-isc-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@ -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<IscAppServiceApplyVo> 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<IscAppServiceApplyVo> list = iIscAppServiceApplyService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "应用服务申请信息", IscAppServiceApplyVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用服务申请信息详细信息
|
||||
*/
|
||||
@ApiOperation("获取应用服务申请信息详细信息")
|
||||
@PreAuthorize("@ss.hasPermi('isc:serviceapply:query')")
|
||||
@GetMapping("/{applyId}")
|
||||
public AjaxResult<IscAppServiceApplyVo> 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<Void> audit(@Validated @RequestBody IscAuditBo bo) {
|
||||
return toAjax(iIscAppServiceApplyService.audit(bo) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
@ -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<IscAppServiceVo> 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<IscAppServiceVo> list = appServiceService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "应用服务", IscAppServiceVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用服务详细信息
|
||||
*/
|
||||
@ApiOperation("获取应用服务详细信息")
|
||||
@PreAuthorize("@ss.hasPermi('isc:appservice:query')")
|
||||
@GetMapping("/{appServiceId}")
|
||||
public AjaxResult<IscAppServiceVo> 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<Void> 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<Void> 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<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] appServiceIds) {
|
||||
return toAjax(appServiceService.deleteWithValidByIds(Arrays.asList(appServiceIds), true) ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用服务下拉树列表
|
||||
*/
|
||||
@GetMapping("/treeselect/{applicationId}")
|
||||
@ApiOperation("获取应用服务下拉树列表")
|
||||
public AjaxResult<List<Tree<Long>>> treeselect(@NotNull(message = "应用主键不能为空") @PathVariable Long applicationId)
|
||||
{
|
||||
return AjaxResult.success(appServiceService.genAppServiceTree(applicationId));
|
||||
}
|
||||
}
|
||||
@ -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<IscApplicationVo> 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<IscApplicationVo> list = iIscApplicationService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "应用信息", IscApplicationVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取应用信息详细信息
|
||||
*/
|
||||
@ApiOperation("获取应用信息详细信息")
|
||||
@PreAuthorize("@ss.hasPermi('isc:application:query')")
|
||||
@GetMapping("/{applicationId}")
|
||||
public AjaxResult<IscApplicationVo> 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<Void> 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<Void> 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<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] applicationIds) {
|
||||
return toAjax(iIscApplicationService.deleteWithValidByIds(Arrays.asList(applicationIds), true) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
@ -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<IscServiceCateVo>> list(@Validated IscServiceCateBo bo)
|
||||
{
|
||||
List<IscServiceCateVo> list = cateService.queryList(bo);
|
||||
return AjaxResult.success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分类下拉树列表
|
||||
*/
|
||||
@GetMapping("/treeselect")
|
||||
@ApiOperation("获取分类下拉树列表")
|
||||
public AjaxResult<List<Tree<Long>>> treeselect()
|
||||
{
|
||||
List<IscServiceCate> 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<IscServiceCateVo> list = cateService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "服务分类", IscServiceCateVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务分类详细信息
|
||||
*/
|
||||
@ApiOperation("获取服务分类详细信息")
|
||||
@PreAuthorize("@ss.hasPermi('isc:cate:query')")
|
||||
@GetMapping("/{cateId}")
|
||||
public AjaxResult<IscServiceCateVo> 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<Void> 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<Void> 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<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] cateIds)
|
||||
{
|
||||
return toAjax(cateService.deleteWithValidByIds(Arrays.asList(cateIds), true) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
@ -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<IscServiceVo> 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<IscServiceVo> list = iIscServiceService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "服务信息", IscServiceVo.class, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务信息详细信息
|
||||
*/
|
||||
@ApiOperation("获取服务信息详细信息")
|
||||
@PreAuthorize("@ss.hasPermi('isc:service:query')")
|
||||
@GetMapping("/{serviceId}")
|
||||
public AjaxResult<IscServiceVo> 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<Void> 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<Void> 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<Void> 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<Void> audit(@Validated @RequestBody IscAuditBo bo) {
|
||||
return toAjax(iIscServiceService.audit(bo) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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<SysMenu> children = new ArrayList<SysMenu>();
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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<Long> ids;
|
||||
|
||||
/**
|
||||
* 审核状态(0待审核 1审核通过 2驳回)
|
||||
*/
|
||||
@ApiModelProperty(value = "审核状态(0待审核 1审核通过 2驳回)")
|
||||
@NotBlank(message = "请填写审核结果")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@ApiModelProperty(value = "备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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<IscAppServiceApply> {
|
||||
|
||||
}
|
||||
@ -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<IscAppService> {
|
||||
|
||||
}
|
||||
@ -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<IscApplication> {
|
||||
|
||||
}
|
||||
@ -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<IscServiceCate> {
|
||||
|
||||
}
|
||||
@ -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<IscService> {
|
||||
|
||||
}
|
||||
@ -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<IscAppServiceApply, IscAppServiceApplyVo> {
|
||||
/**
|
||||
* 查询单个
|
||||
* @return
|
||||
*/
|
||||
IscAppServiceApplyVo queryById(Long applyId);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
TableDataInfo<IscAppServiceApplyVo> queryPageList(IscAppServiceApplyBo bo);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
List<IscAppServiceApplyVo> 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<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 应用服务审核
|
||||
* @param bo 审核业务数据
|
||||
* @return 是否审核成功
|
||||
*/
|
||||
Boolean audit(IscAuditBo bo);
|
||||
}
|
||||
@ -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<IscAppService, IscAppServiceVo> {
|
||||
/**
|
||||
* 查询单个
|
||||
* @return
|
||||
*/
|
||||
IscAppServiceVo queryById(Long appServiceId);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
TableDataInfo<IscAppServiceVo> queryPageList(IscAppServiceBo bo);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
List<IscAppServiceVo> 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<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 构造 应用服务树结构
|
||||
* @param applicationId 应用ID
|
||||
* @return 应用服务树结构 (标识服务是否存在)
|
||||
*/
|
||||
List<Tree<Long>> genAppServiceTree(Long applicationId);
|
||||
|
||||
/**
|
||||
* 通过 Id集合 返回列表
|
||||
* @param ids 应用服务ID
|
||||
* @return 应用服务列表
|
||||
*/
|
||||
List<IscAppService> getAppServiceListByIds(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 刷新规则信息(服务对应AK)
|
||||
*/
|
||||
void refreshRules();
|
||||
}
|
||||
@ -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<IscApplication, IscApplicationVo> {
|
||||
/**
|
||||
* 查询单个
|
||||
* @return
|
||||
*/
|
||||
IscApplicationVo queryById(Long applicationId);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
TableDataInfo<IscApplicationVo> queryPageList(IscApplicationBo bo);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
List<IscApplicationVo> 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<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 通过应用ID集合批量查询 应用名称
|
||||
* @param applicationIds 应用ID集合
|
||||
* @return 应用名称Map
|
||||
*/
|
||||
Map<Long, String> getNameMap(Collection<Long> applicationIds);
|
||||
}
|
||||
@ -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<IscServiceCate, IscServiceCateVo> {
|
||||
/**
|
||||
* 查询单个
|
||||
* @return
|
||||
*/
|
||||
IscServiceCateVo queryById(Long cateId);
|
||||
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
List<IscServiceCateVo> 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<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 获取分类信息
|
||||
* @return 分类列表
|
||||
*/
|
||||
List<IscServiceCate> selectCateList();
|
||||
|
||||
/**
|
||||
* 批量获取分类名称
|
||||
* @param fullPathList
|
||||
* @return
|
||||
*/
|
||||
Map<String, String> batchCateName(Set<String> fullPathList);
|
||||
|
||||
/**
|
||||
* 组装 服务分类 树结构
|
||||
* @param cates 所有分类
|
||||
* @return 树结构信息
|
||||
*/
|
||||
List<Tree<Long>> genCateTree(List<IscServiceCate> cates);
|
||||
|
||||
/**
|
||||
* 组装 服务分类 树结构
|
||||
* @param cates 所有分类
|
||||
* @param serviceList 可用服务列表
|
||||
* @param exitsIds 已存在服务ID集合
|
||||
* @return 树结构信息
|
||||
*/
|
||||
List<Tree<Long>> genCateTree(List<IscServiceCate> cates, List<IscService> serviceList, Set<Long> exitsIds);
|
||||
}
|
||||
@ -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<IscService, IscServiceVo> {
|
||||
/**
|
||||
* 查询单个
|
||||
* @return
|
||||
*/
|
||||
IscServiceVo queryById(Long serviceId);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
TableDataInfo<IscServiceVo> queryPageList(IscServiceBo bo);
|
||||
|
||||
/**
|
||||
* 查询列表
|
||||
*/
|
||||
List<IscServiceVo> 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<Long> ids, Boolean isValid);
|
||||
|
||||
/**
|
||||
* 通过服务ID集合 查询服务名称map
|
||||
* @param serviceIds 服务ID集合
|
||||
* @return 服务名称map
|
||||
*/
|
||||
Map<Long, String> getNameMap(Collection<Long> serviceIds);
|
||||
|
||||
/**
|
||||
* 组装 服务树结构
|
||||
* @return 服务树结构
|
||||
*/
|
||||
List<Tree<Long>> genServiceTree();
|
||||
|
||||
/**
|
||||
* 组装 服务树结构
|
||||
* @param exitsIds 已存在服务ID集合
|
||||
* @return 服务树结构
|
||||
*/
|
||||
List<Tree<Long>> genServiceTree(Set<Long> exitsIds);
|
||||
|
||||
/**
|
||||
* 服务信息审核
|
||||
* @param bo 审核信息
|
||||
* @return 操作结果
|
||||
*/
|
||||
Boolean audit(IscAuditBo bo);
|
||||
|
||||
/**
|
||||
* 校验 审核参数
|
||||
* @param bo 审核业务对象
|
||||
*/
|
||||
void checkAuditBO(IscAuditBo bo);
|
||||
|
||||
/**
|
||||
* 刷新路由信息
|
||||
*/
|
||||
void refreshRoutes();
|
||||
}
|
||||
@ -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<IscAppServiceApplyMapper, IscAppServiceApply, IscAppServiceApplyVo> 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<IscAppServiceApplyVo> queryPageList(IscAppServiceApplyBo bo) {
|
||||
PagePlus<IscAppServiceApply, IscAppServiceApplyVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo));
|
||||
genServiceNameAndApplicationName(result.getRecordsVo());
|
||||
return PageUtils.buildDataInfo(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IscAppServiceApplyVo> queryList(IscAppServiceApplyBo bo) {
|
||||
List<IscAppServiceApplyVo> results = listVo(buildQueryWrapper(bo));
|
||||
genServiceNameAndApplicationName(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装服务、应用名称
|
||||
* @param list 申请记录
|
||||
*/
|
||||
private void genServiceNameAndApplicationName(List<IscAppServiceApplyVo> list)
|
||||
{
|
||||
if(CollectionUtil.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
Set<Long> appServiceIds = list.stream().map(IscAppServiceApplyVo::getAppServiceId).collect(Collectors.toSet());
|
||||
List<IscAppService> appServiceList = appServiceService.getAppServiceListByIds(appServiceIds);
|
||||
if(CollectionUtil.isEmpty(appServiceList)) {
|
||||
return;
|
||||
}
|
||||
Map<Long, IscAppService> appServiceMap = appServiceList.stream()
|
||||
.collect(Collectors.toMap(IscAppService::getAppServiceId, Function.identity()));
|
||||
Map<Long, String> serviceNameMap = serviceService.getNameMap(appServiceList.stream()
|
||||
.map(IscAppService::getServiceId).collect(Collectors.toSet()));
|
||||
Map<Long, String> 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<IscAppServiceApply> buildQueryWrapper(IscAppServiceApplyBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<IscAppServiceApply> 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<Long> 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.<IscAppServiceApply>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.<IscAppServiceApply>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;
|
||||
}
|
||||
}
|
||||
@ -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<IscAppServiceMapper, IscAppService, IscAppServiceVo> 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<IscAppServiceVo> queryPageList(IscAppServiceBo bo)
|
||||
{
|
||||
PagePlus<IscAppService, IscAppServiceVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo));
|
||||
genServiceName(result.getRecordsVo());
|
||||
return PageUtils.buildDataInfo(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IscAppServiceVo> queryList(IscAppServiceBo bo)
|
||||
{
|
||||
final List<IscAppServiceVo> results = listVo(buildQueryWrapper(bo));
|
||||
genServiceName(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组装服务名称
|
||||
*
|
||||
* @param results 应用服务列表
|
||||
*/
|
||||
private void genServiceName(List<IscAppServiceVo> results)
|
||||
{
|
||||
if (CollectionUtil.isEmpty(results)) {
|
||||
return;
|
||||
}
|
||||
Set<Long> serviceIds = results.stream().map(IscAppServiceVo::getServiceId).collect(Collectors.toSet());
|
||||
Map<Long, String> nameMap = serviceService.getNameMap(serviceIds);
|
||||
for (IscAppServiceVo result : results) {
|
||||
result.setServiceName(nameMap.get(result.getServiceId()));
|
||||
}
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<IscAppService> buildQueryWrapper(IscAppServiceBo bo)
|
||||
{
|
||||
Map<String, Object> params = bo.getParams();
|
||||
Long userId = SecurityUtils.getUserId();
|
||||
LambdaQueryWrapper<IscAppService> 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.<IscAppServiceApply>lambdaQuery()
|
||||
.eq(IscAppServiceApply::getAppServiceId, entity.getAppServiceId())
|
||||
.eq(IscAppServiceApply::getStatus, Constants.AUDIT_WAIT));
|
||||
Assert.isFalse(SqlHelper.retBool(count), () -> new ServiceException("有申请未审核, 不能再申请"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid)
|
||||
{
|
||||
if (isValid) {
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
applyService.remove(Wrappers.<IscAppServiceApply>lambdaQuery().in(IscAppServiceApply::getAppServiceId, ids));
|
||||
return removeByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<Long>> genAppServiceTree(Long applicationId)
|
||||
{
|
||||
List<Long> serviceIds = listObjs(Wrappers.<IscAppService>lambdaQuery()
|
||||
.select(IscAppService::getServiceId)
|
||||
.eq(IscAppService::getApplicationId, applicationId), o -> (Long) o);
|
||||
return serviceService.genServiceTree(CollectionUtil.newHashSet(serviceIds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IscAppService> getAppServiceListByIds(Collection<Long> ids)
|
||||
{
|
||||
return list(Wrappers.<IscAppService>lambdaQuery()
|
||||
.select(IscAppService::getAppServiceId, IscAppService::getApplicationId, IscAppService::getServiceId)
|
||||
.in(IscAppService::getAppServiceId, ids));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshRules()
|
||||
{
|
||||
List<IscAppService> list = list(Wrappers.<IscAppService>lambdaQuery()
|
||||
.eq(IscAppService::getEnabled, UserConstants.NORMAL)
|
||||
.eq(IscAppService::getStatus, Constants.AUDIT_PASS)
|
||||
.gt(IscAppService::getEndTime, DateUtils.getNowDate()));
|
||||
if(CollectionUtil.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
Set<Long> applicationIds = list.stream().map(IscAppService::getApplicationId).collect(Collectors.toSet());
|
||||
Map<Long, String> accessKeyMap = applicationService.list(Wrappers.<IscApplication>lambdaQuery()
|
||||
.select(IscApplication::getApplicationId, IscApplication::getAccessKey)
|
||||
.in(IscApplication::getApplicationId, applicationIds)).stream()
|
||||
.collect(Collectors.toMap(IscApplication::getApplicationId, IscApplication::getAccessKey));
|
||||
List<IscRule> 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);
|
||||
}
|
||||
}
|
||||
@ -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<IscApplicationMapper, IscApplication, IscApplicationVo> implements IIscApplicationService {
|
||||
|
||||
@Override
|
||||
public IscApplicationVo queryById(Long applicationId){
|
||||
return getVoById(applicationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<IscApplicationVo> queryPageList(IscApplicationBo bo) {
|
||||
PagePlus<IscApplication, IscApplicationVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo));
|
||||
return PageUtils.buildDataInfo(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IscApplicationVo> queryList(IscApplicationBo bo) {
|
||||
return listVo(buildQueryWrapper(bo));
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<IscApplication> buildQueryWrapper(IscApplicationBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<IscApplication> 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<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return removeByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Long, String> getNameMap(Collection<Long> applicationIds)
|
||||
{
|
||||
if(CollectionUtil.isEmpty(applicationIds)) {
|
||||
return MapUtil.empty();
|
||||
}
|
||||
return list(Wrappers.<IscApplication>lambdaQuery()
|
||||
.select(IscApplication::getApplicationId, IscApplication::getApplicationName)
|
||||
.in(IscApplication::getApplicationId, applicationIds)).stream()
|
||||
.collect(Collectors.toMap(IscApplication::getApplicationId, IscApplication::getApplicationName));
|
||||
}
|
||||
}
|
||||
@ -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<IscServiceCateMapper, IscServiceCate, IscServiceCateVo> 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<IscServiceCateVo> queryList(IscServiceCateBo bo) {
|
||||
return listVo(buildQueryWrapper(bo));
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<IscServiceCate> buildQueryWrapper(IscServiceCateBo bo) {
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<IscServiceCate> 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.<IscServiceCate>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<Long> ids, Boolean isValid) {
|
||||
if(isValid){
|
||||
//TODO 做一些业务上的校验,判断是否需要校验
|
||||
}
|
||||
return removeByIds(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IscServiceCate> selectCateList()
|
||||
{
|
||||
return list(Wrappers.<IscServiceCate>lambdaQuery()
|
||||
.eq(IscServiceCate::getEnabled, UserConstants.DICT_NORMAL)
|
||||
.orderByAsc(IscServiceCate::getParentId)
|
||||
.orderByAsc(IscServiceCate::getOrderNum));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> batchCateName(Set<String> fullPathList)
|
||||
{
|
||||
Map<String, String> results = new HashMap<>();
|
||||
if(CollectionUtils.isEmpty(fullPathList)) {
|
||||
return results;
|
||||
}
|
||||
final List<IscServiceCate> list = list(Wrappers.<IscServiceCate>lambdaQuery()
|
||||
.select(IscServiceCate::getCateId, IscServiceCate::getCateName, IscServiceCate::getFullPath, IscServiceCate::getParentId)
|
||||
.in(IscServiceCate::getFullPath, fullPathList));
|
||||
Map<Long, String> cateNameMap = batchCateName(list);
|
||||
for (IscServiceCate cate : list)
|
||||
{
|
||||
results.put(cate.getFullPath(), cateNameMap.get(cate.getCateId()));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<Long>> genCateTree(List<IscServiceCate> cates)
|
||||
{
|
||||
return genCateTree(cates, null, CollectionUtil.newHashSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<Long>> genCateTree(List<IscServiceCate> cates, List<IscService> serviceList, Set<Long> exitsIds)
|
||||
{
|
||||
boolean isServiceTree = Objects.nonNull(serviceList);
|
||||
final Map<String, List<IscService>> cateServiceMap = isServiceTree ? serviceList.stream()
|
||||
.collect(Collectors.groupingBy(IscService::getCateFullPath)) : null;
|
||||
|
||||
NodeParser<IscServiceCate, Long> 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<IscService> 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<Tree<Long>> children = tree.getChildren();
|
||||
if(Objects.isNull(children)) {
|
||||
children = CollectionUtil.newArrayList();
|
||||
tree.setChildren(children);
|
||||
}
|
||||
final Tree<Long> 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<Long, String> batchCateName(List<IscServiceCate> list) {
|
||||
Map<Long, String> results = new HashMap<>();
|
||||
final Set<Long> parentIds = list.stream().filter(m -> m.getParentId() != 0L).map(IscServiceCate::getParentId).collect(Collectors.toSet());
|
||||
if(CollectionUtils.isNotEmpty(parentIds)) {
|
||||
final List<IscServiceCate> parentList = list(Wrappers.<IscServiceCate>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;
|
||||
}
|
||||
}
|
||||
@ -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<IscServiceMapper, IscService, IscServiceVo> 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<IscServiceVo> queryPageList(IscServiceBo bo)
|
||||
{
|
||||
PagePlus<IscService, IscServiceVo> result = pageVo(PageUtils.buildPagePlus(), buildQueryWrapper(bo));
|
||||
genVoInfo(result.getRecordsVo());
|
||||
return PageUtils.buildDataInfo(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IscServiceVo> queryList(IscServiceBo bo)
|
||||
{
|
||||
final List<IscServiceVo> results = listVo(buildQueryWrapper(bo));
|
||||
genVoInfo(results);
|
||||
return results;
|
||||
}
|
||||
|
||||
private void genVoInfo(List<IscServiceVo> results)
|
||||
{
|
||||
if (CollectionUtils.isNotEmpty(results))
|
||||
{
|
||||
Map<String, String> cateNameMap = cateService.batchCateName(results.stream()
|
||||
.map(IscServiceVo::getCateFullPath).collect(Collectors.toSet()));
|
||||
for (IscServiceVo result : results)
|
||||
{
|
||||
result.setCateName(cateNameMap.get(result.getCateFullPath()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<IscService> buildQueryWrapper(IscServiceBo bo)
|
||||
{
|
||||
Map<String, Object> params = bo.getParams();
|
||||
LambdaQueryWrapper<IscService> 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<Long> 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<Long, String> getNameMap(Collection<Long> serviceIds)
|
||||
{
|
||||
if(CollectionUtil.isEmpty(serviceIds)) {
|
||||
return MapUtil.empty();
|
||||
}
|
||||
return list(Wrappers.<IscService>lambdaQuery()
|
||||
.select(IscService::getServiceId, IscService::getServiceName)
|
||||
.in(IscService::getServiceId, serviceIds)).stream()
|
||||
.collect(Collectors.toMap(IscService::getServiceId, IscService::getServiceName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<Long>> genServiceTree()
|
||||
{
|
||||
return genServiceTree(CollectionUtil.newHashSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tree<Long>> genServiceTree(Set<Long> exitsIds)
|
||||
{
|
||||
List<IscService> serviceList = list(Wrappers.<IscService>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<IscRouteDefinition> routes = pass ? ListUtil.list(false) : null;
|
||||
for (Long id : bo.getIds())
|
||||
{
|
||||
IscService service = getOne(Wrappers.<IscService>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<IscService> serviceList = list(Wrappers.<IscService>lambdaQuery()
|
||||
.select(IscService::getServiceId, IscService::getServiceAddr, IscService::getHiddenParams, IscService::getRequestMethod)
|
||||
.eq(IscService::getStatus, Constants.AUDIT_PASS));
|
||||
List<IscRouteDefinition> routes = new ArrayList<>();
|
||||
for (IscService service : serviceList)
|
||||
{
|
||||
routes.add(RouteUtils.generateRoute(service));
|
||||
}
|
||||
RouteUtils.refreshRoute(routes);
|
||||
}
|
||||
}
|
||||
@ -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 <T> void publish(String channelKey, T msg, Consumer<T> consumer) {
|
||||
RTopic topic = CLIENT.getTopic(channelKey);
|
||||
topic.publish(msg);
|
||||
consumer.accept(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布路由刷新通知
|
||||
* @param consumer 发送消息后执行
|
||||
*/
|
||||
public static void sendRefreshRouteToGateway(String id, Type type, Consumer<TopicMsg> consumer) {
|
||||
publish(TOPIC_GATEWAY_REFRESH_ROUTE, new TopicMsg(id, DateUtil.now(), type), consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发布规则通知
|
||||
* @param consumer 发送消息后执行
|
||||
*/
|
||||
public static void sendRuleNoticeToGateway(String id, Type type, Consumer<TopicMsg> consumer) {
|
||||
publish(TOPIC_GATEWAY_RULE, new TopicMsg(id, DateUtil.now(), type), consumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新路由信息 先清空再批量新增
|
||||
*
|
||||
* @param routes 路由信息
|
||||
* @return 是否成功
|
||||
*/
|
||||
public static boolean refreshRoute(List<IscRouteDefinition> routes)
|
||||
{
|
||||
Map<String, IscRouteDefinition> routeMap = routes.stream().collect(Collectors.toMap(IscRouteDefinition::getId,
|
||||
Function.identity(), (o1, o2) -> o2));
|
||||
final RMap<String, IscRouteDefinition> 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<IscRouteDefinition> routes) {
|
||||
return saveRoute(routes, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存路由信息
|
||||
*
|
||||
* @param routes 路由信息
|
||||
* @param consumer 回调操作
|
||||
* @return 是否成功
|
||||
*/
|
||||
public static boolean saveRoute(Collection<IscRouteDefinition> routes, Consumer<TopicMsg> consumer)
|
||||
{
|
||||
if(CollectionUtil.isEmpty(routes)) {
|
||||
return true;
|
||||
}
|
||||
final RMap<String, IscRouteDefinition> map = CLIENT.getMap(IscRedisKeys.KEY_ROUTES, ROUTE_CODES_INSTANCE);
|
||||
Map<String, IscRouteDefinition> 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<String> routeIds)
|
||||
{
|
||||
final RMap<String, IscRouteDefinition> 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<IscFilterDefinition> 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<String, Object> 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<IscRule> rules)
|
||||
{
|
||||
Map<String, IscRule> ruleMap = rules.stream().collect(Collectors.toMap(IscRule::getId, Function.identity(), (o1, o2) -> o2));
|
||||
final RMap<String, IscRule> 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<TopicMsg> consumer)
|
||||
{
|
||||
final RMap<String, IscRule> 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<String, IscRule> 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()));
|
||||
}
|
||||
}
|
||||
@ -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<String, String> args = new LinkedHashMap<>();
|
||||
}
|
||||
@ -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<String, String> args = new LinkedHashMap<>();
|
||||
}
|
||||
@ -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<IscPredicateDefinition> predicates = new ArrayList<>();
|
||||
|
||||
@Valid
|
||||
private List<IscFilterDefinition> filters = new ArrayList<>();
|
||||
|
||||
@NotNull
|
||||
private URI uri;
|
||||
|
||||
private Map<String, Object> metadata = new HashMap<>();
|
||||
|
||||
private int order = 0;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user