mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-20 02:08:15 +08:00
添加POST 添加/删除参数过滤器、限流器配置
This commit is contained in:
parent
98722a6b22
commit
b5b765238d
@ -1,15 +1,21 @@
|
|||||||
package com.ruoyi.gateway.config;
|
package com.ruoyi.gateway.config;
|
||||||
|
|
||||||
import com.ruoyi.gateway.config.provider.RedisRouteDefinitionRepository;
|
import com.ruoyi.gateway.config.provider.RedisRouteDefinitionRepository;
|
||||||
|
import com.ruoyi.gateway.filter.factory.AddRequestParamGatewayFilterFactory;
|
||||||
|
import com.ruoyi.gateway.filter.factory.RemoveRequestParamGatewayFilterFactory;
|
||||||
import org.redisson.api.RedissonClient;
|
import org.redisson.api.RedissonClient;
|
||||||
|
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
|
||||||
|
import org.springframework.cloud.gateway.route.Route;
|
||||||
import org.springframework.cloud.gateway.route.RouteDefinition;
|
import org.springframework.cloud.gateway.route.RouteDefinition;
|
||||||
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
|
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
|
||||||
|
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
@ -52,4 +58,22 @@ public class GatewayConfig
|
|||||||
{
|
{
|
||||||
return new RedisRouteDefinitionRepository(redissonClient);
|
return new RedisRouteDefinitionRepository(redissonClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AddRequestParamGatewayFilterFactory addRequestParamGatewayFilterFactory()
|
||||||
|
{
|
||||||
|
return new AddRequestParamGatewayFilterFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RemoveRequestParamGatewayFilterFactory removeRequestParamGatewayFilterFactory()
|
||||||
|
{
|
||||||
|
return new RemoveRequestParamGatewayFilterFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean("routeIdKeyResolver")
|
||||||
|
public KeyResolver routeIdKeyResolver()
|
||||||
|
{
|
||||||
|
return exchange -> Mono.just(((Route) exchange.getAttributes().get(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR)).getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
package com.ruoyi.gateway.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Wenchao Gong
|
||||||
|
* @date 2021-10-04
|
||||||
|
*/
|
||||||
|
public class GatewayException extends RuntimeException {
|
||||||
|
public GatewayException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
package com.ruoyi.gateway.filter.factory;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.ruoyi.gateway.exception.GatewayException;
|
||||||
|
import com.ruoyi.gateway.utils.GatewayUtils;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
|
||||||
|
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
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 static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Wenchao Gong
|
||||||
|
* @date 2021-10-04
|
||||||
|
*/
|
||||||
|
public class AddRequestParamGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GatewayFilter apply(NameValueConfig config)
|
||||||
|
{
|
||||||
|
return new GatewayFilter() {
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||||
|
{
|
||||||
|
final ServerHttpRequest request = exchange.getRequest();
|
||||||
|
HttpMethod method = request.getMethod();
|
||||||
|
if (HttpMethod.GET.equals(method))
|
||||||
|
{
|
||||||
|
URI uri = request.getURI();
|
||||||
|
StringBuilder query = new StringBuilder();
|
||||||
|
String originalQuery = uri.getRawQuery();
|
||||||
|
|
||||||
|
if (StringUtils.hasText(originalQuery))
|
||||||
|
{
|
||||||
|
query.append(originalQuery);
|
||||||
|
if (originalQuery.charAt(originalQuery.length() - 1) != '&')
|
||||||
|
{
|
||||||
|
query.append('&');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
|
||||||
|
// TODO urlencode?
|
||||||
|
query.append(config.getName());
|
||||||
|
query.append('=');
|
||||||
|
query.append(value);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URI newUri = UriComponentsBuilder.fromUri(uri).replaceQuery(query.toString()).build(false).toUri();
|
||||||
|
return chain.filter(exchange.mutate().request(request.mutate().uri(newUri).build()).build());
|
||||||
|
} catch (RuntimeException ex)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Invalid URI query: \"" + query.toString() + "\"");
|
||||||
|
}
|
||||||
|
} else if (HttpMethod.POST.equals(method))
|
||||||
|
{
|
||||||
|
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
|
||||||
|
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)
|
||||||
|
.flatMap(body -> {
|
||||||
|
MediaType mediaType = request.getHeaders().getContentType();
|
||||||
|
if (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType))
|
||||||
|
{
|
||||||
|
JSONObject jsonObject = new JSONObject(body);
|
||||||
|
jsonObject.set(config.getName(), config.getValue());
|
||||||
|
return Mono.just(jsonObject.toString());
|
||||||
|
} else if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType))
|
||||||
|
{
|
||||||
|
StringBuilder newBody = new StringBuilder();
|
||||||
|
if (org.springframework.util.StringUtils.hasText(body))
|
||||||
|
{
|
||||||
|
newBody.append(body);
|
||||||
|
if (body.charAt(body.length() - 1) != '&')
|
||||||
|
{
|
||||||
|
newBody.append('&');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
|
||||||
|
newBody.append(config.getName());
|
||||||
|
newBody.append('=');
|
||||||
|
newBody.append(value);
|
||||||
|
return Mono.just(newBody.toString());
|
||||||
|
}
|
||||||
|
return Mono.empty();
|
||||||
|
});
|
||||||
|
return GatewayUtils.modifyBody(exchange, chain, modifiedBody);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
throw new GatewayException(String.format("Method %s Not Supported!", method.name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return filterToStringCreator(AddRequestParamGatewayFilterFactory.this)
|
||||||
|
.append(config.getName(), config.getValue()).toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
package com.ruoyi.gateway.filter.factory;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import com.ruoyi.gateway.exception.GatewayException;
|
||||||
|
import com.ruoyi.gateway.utils.GatewayUtils;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilter;
|
||||||
|
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||||
|
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
|
||||||
|
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.util.StringUtils;
|
||||||
|
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.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;
|
||||||
|
import static org.springframework.util.CollectionUtils.unmodifiableMultiValueMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Wenchao Gong
|
||||||
|
* @date 2021-10-15
|
||||||
|
*/
|
||||||
|
public class RemoveRequestParamGatewayFilterFactory extends AbstractGatewayFilterFactory<AbstractGatewayFilterFactory.NameConfig> {
|
||||||
|
|
||||||
|
public RemoveRequestParamGatewayFilterFactory()
|
||||||
|
{
|
||||||
|
super(NameConfig.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> shortcutFieldOrder()
|
||||||
|
{
|
||||||
|
return Arrays.asList(NAME_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GatewayFilter apply(NameConfig config)
|
||||||
|
{
|
||||||
|
return new GatewayFilter() {
|
||||||
|
@Override
|
||||||
|
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
|
||||||
|
{
|
||||||
|
ServerHttpRequest request = exchange.getRequest();
|
||||||
|
HttpMethod method = request.getMethod();
|
||||||
|
if (HttpMethod.GET.equals(method))
|
||||||
|
{
|
||||||
|
MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>(request.getQueryParams());
|
||||||
|
queryParams.remove(config.getName());
|
||||||
|
|
||||||
|
URI newUri = UriComponentsBuilder.fromUri(request.getURI())
|
||||||
|
.replaceQueryParams(unmodifiableMultiValueMap(queryParams)).build().toUri();
|
||||||
|
|
||||||
|
ServerHttpRequest updatedRequest = exchange.getRequest().mutate().uri(newUri).build();
|
||||||
|
|
||||||
|
return chain.filter(exchange.mutate().request(updatedRequest).build());
|
||||||
|
} else if (HttpMethod.POST.equals(method))
|
||||||
|
{
|
||||||
|
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
|
||||||
|
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)
|
||||||
|
.flatMap(body -> {
|
||||||
|
MediaType mediaType = request.getHeaders().getContentType();
|
||||||
|
if (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType))
|
||||||
|
{
|
||||||
|
JSONObject jsonObject = new JSONObject(body);
|
||||||
|
jsonObject.remove(config.getName());
|
||||||
|
return Mono.just(jsonObject.toString());
|
||||||
|
} else if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType))
|
||||||
|
{
|
||||||
|
if (StringUtils.hasText(body))
|
||||||
|
{
|
||||||
|
return Mono.just(Arrays.stream(body.split("&"))
|
||||||
|
.filter(str -> config.getName().equals(str.split("=")[0]))
|
||||||
|
.collect(Collectors.joining("&")));
|
||||||
|
}
|
||||||
|
return Mono.just(body);
|
||||||
|
}
|
||||||
|
return Mono.empty();
|
||||||
|
});
|
||||||
|
return GatewayUtils.modifyBody(exchange, chain, modifiedBody);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
throw new GatewayException(String.format("Method %s Not Supported!", method.name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return filterToStringCreator(RemoveRequestParamGatewayFilterFactory.this)
|
||||||
|
.append("name", config.getName()).toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
package com.ruoyi.gateway.utils;
|
||||||
|
|
||||||
|
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.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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Wenchao Gong
|
||||||
|
* @date 2021-10-15
|
||||||
|
*/
|
||||||
|
public class GatewayUtils {
|
||||||
|
|
||||||
|
public static Mono<Void> modifyBody(ServerWebExchange exchange, GatewayFilterChain chain, Mono<String> publisher)
|
||||||
|
{
|
||||||
|
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 decorator = decorate(exchange, headers, outputMessage);
|
||||||
|
return chain.filter(exchange.mutate().request(decorator).build());
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static ServerHttpRequestDecorator decorate(ServerWebExchange exchange, HttpHeaders headers, CachedBodyOutputMessage outputMessage)
|
||||||
|
{
|
||||||
|
return new ServerHttpRequestDecorator(exchange.getRequest()) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Flux<DataBuffer> getBody()
|
||||||
|
{
|
||||||
|
return outputMessage.getBody();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -33,6 +33,7 @@ public class RouteUtils {
|
|||||||
* Gateway 虚拟路径前缀
|
* Gateway 虚拟路径前缀
|
||||||
*/
|
*/
|
||||||
public static final String PATH_PREFIX = "/proxy";
|
public static final String PATH_PREFIX = "/proxy";
|
||||||
|
public static final String ACCESS_KEY_NAME = "ak";
|
||||||
private static RedissonClient client = SpringUtils.getBean(RedissonClient.class);
|
private static RedissonClient client = SpringUtils.getBean(RedissonClient.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,7 +152,7 @@ public class RouteUtils {
|
|||||||
|
|
||||||
IscPredicateDefinition queryPredicate = new IscPredicateDefinition();
|
IscPredicateDefinition queryPredicate = new IscPredicateDefinition();
|
||||||
queryPredicate.setName("Query");
|
queryPredicate.setName("Query");
|
||||||
queryPredicate.getArgs().put("param", "ak");
|
queryPredicate.getArgs().put("param", ACCESS_KEY_NAME);
|
||||||
|
|
||||||
IscPredicateDefinition pathPredicate = new IscPredicateDefinition();
|
IscPredicateDefinition pathPredicate = new IscPredicateDefinition();
|
||||||
pathPredicate.setName("Path");
|
pathPredicate.setName("Path");
|
||||||
@ -165,23 +166,34 @@ public class RouteUtils {
|
|||||||
stripPrefixFilter.getArgs().put("parts", "1");
|
stripPrefixFilter.getArgs().put("parts", "1");
|
||||||
filters.add(stripPrefixFilter);
|
filters.add(stripPrefixFilter);
|
||||||
|
|
||||||
IscFilterDefinition removeRequestParameterFilter = new IscFilterDefinition();
|
final Long quotaSeconds = appService.getQuotaSeconds();
|
||||||
removeRequestParameterFilter.setName("RemoveRequestParameter");
|
if (Objects.nonNull(quotaSeconds))
|
||||||
removeRequestParameterFilter.getArgs().put("name", "ak");
|
{
|
||||||
filters.add(removeRequestParameterFilter);
|
IscFilterDefinition requestRateLimiterFilter = new IscFilterDefinition();
|
||||||
|
requestRateLimiterFilter.setName("RequestRateLimiter");
|
||||||
|
requestRateLimiterFilter.getArgs().put("redis-rate-limiter.replenishRate", String.valueOf(quotaSeconds));
|
||||||
|
requestRateLimiterFilter.getArgs().put("redis-rate-limiter.burstCapacity", String.valueOf(quotaSeconds << 1));
|
||||||
|
requestRateLimiterFilter.getArgs().put("key-resolver", "#{@routeIdKeyResolver}");
|
||||||
|
filters.add(requestRateLimiterFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
IscFilterDefinition removeRequestParamFilter = new IscFilterDefinition();
|
||||||
|
removeRequestParamFilter.setName("RemoveRequestParam");
|
||||||
|
removeRequestParamFilter.getArgs().put("name", ACCESS_KEY_NAME);
|
||||||
|
filters.add(removeRequestParamFilter);
|
||||||
|
|
||||||
String hiddenParams = service.getHiddenParams();
|
String hiddenParams = service.getHiddenParams();
|
||||||
if(StringUtils.isNotBlank(hiddenParams)) {
|
if(StringUtils.isNotBlank(hiddenParams)) {
|
||||||
Map<String, Object> paramsMap = JsonUtils.parseMap(hiddenParams);
|
Map<String, Object> paramsMap = JsonUtils.parseMap(hiddenParams);
|
||||||
Iterator<Map.Entry<String, Object>> it = paramsMap.entrySet().iterator();
|
Iterator<Map.Entry<String, Object>> it = paramsMap.entrySet().iterator();
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
IscFilterDefinition addRequestParameterFilter = new IscFilterDefinition();
|
IscFilterDefinition addRequestParamFilter = new IscFilterDefinition();
|
||||||
Map<String, String> args = addRequestParameterFilter.getArgs();
|
Map<String, String> args = addRequestParamFilter.getArgs();
|
||||||
addRequestParameterFilter.setName("AddRequestParameter");
|
addRequestParamFilter.setName("AddRequestParam");
|
||||||
Map.Entry<String, Object> param = it.next();
|
Map.Entry<String, Object> param = it.next();
|
||||||
args.put("name", param.getKey());
|
args.put("name", param.getKey());
|
||||||
args.put("value", String.valueOf(param.getValue()));
|
args.put("value", String.valueOf(param.getValue()));
|
||||||
filters.add(addRequestParameterFilter);
|
filters.add(addRequestParamFilter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +205,6 @@ public class RouteUtils {
|
|||||||
|
|
||||||
//其他信息
|
//其他信息
|
||||||
Map<String, Object> metadata = route.getMetadata();
|
Map<String, Object> metadata = route.getMetadata();
|
||||||
metadata.put("secondsLimit", toString(appService.getQuotaSeconds()));
|
|
||||||
metadata.put("minutesLimit", toString(appService.getQuotaMinutes()));
|
metadata.put("minutesLimit", toString(appService.getQuotaMinutes()));
|
||||||
metadata.put("hoursLimit", toString(appService.getQuotaHours()));
|
metadata.put("hoursLimit", toString(appService.getQuotaHours()));
|
||||||
metadata.put("daysLimit", toString(appService.getQuotaDays()));
|
metadata.put("daysLimit", toString(appService.getQuotaDays()));
|
||||||
|
|||||||
@ -16,7 +16,11 @@
|
|||||||
</description>
|
</description>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jsoup</groupId>
|
||||||
|
<artifactId>jsoup</artifactId>
|
||||||
|
<version>1.13.1</version>
|
||||||
|
</dependency>
|
||||||
<!-- 通用工具-->
|
<!-- 通用工具-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ruoyi</groupId>
|
<groupId>com.ruoyi</groupId>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user