1.调整资源位置
2.完善功能
@ -1,10 +1,13 @@
|
||||
package ink.wgink.gateway.component;
|
||||
|
||||
import ink.wgink.gateway.consts.ISystemConst;
|
||||
import ink.wgink.gateway.dao.route.IRouteDao;
|
||||
import ink.wgink.gateway.filter.local.CommonFiltersDefinition;
|
||||
import ink.wgink.gateway.pojo.route.Route;
|
||||
import ink.wgink.gateway.util.UUIDUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cloud.gateway.filter.FilterDefinition;
|
||||
import org.springframework.cloud.gateway.filter.factory.*;
|
||||
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
|
||||
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
|
||||
import org.springframework.cloud.gateway.route.RouteDefinition;
|
||||
@ -100,8 +103,10 @@ public class MongoRouteDefinitionRepository implements RouteDefinitionRepository
|
||||
CommonFiltersDefinition commonFiltersDefinition = new CommonFiltersDefinition();
|
||||
// 定义过滤器
|
||||
List<FilterDefinition> filterDefinitions = new ArrayList<>();
|
||||
// 重写响应头中的location解决重定向问题
|
||||
filterDefinitions.add(commonFiltersDefinition.rewriteLocationResponseHeader(route));
|
||||
// 设置路径过滤器
|
||||
if (!StringUtils.isBlank(route.getSetPath())) {
|
||||
filterDefinitions.add(commonFiltersDefinition.setPath(route));
|
||||
}
|
||||
return filterDefinitions;
|
||||
}
|
||||
|
||||
|
29
src/main/java/ink/wgink/gateway/dao/log/IRequestLogDao.java
Normal file
@ -0,0 +1,29 @@
|
||||
package ink.wgink.gateway.dao.log;
|
||||
|
||||
import ink.wgink.gateway.pojo.log.RequestLog;
|
||||
import org.springframework.data.mongodb.repository.Aggregation;
|
||||
import org.springframework.data.mongodb.repository.Query;
|
||||
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: IRequestLogDao
|
||||
* @Description: 请求日志
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/5/15 3:02 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Repository
|
||||
public interface IRequestLogDao extends ReactiveMongoRepository<RequestLog, String> {
|
||||
|
||||
String COLLECTION_NAME = "log_request";
|
||||
|
||||
@Aggregation("[{$match: {gmtCreate: {$gte: 'startTime', $lte: 'endTime'}}}, {$group: {_id: '$gmtCreate', num_tutorial: {$sum: 1}}}, {$sort: {gmtCreate: -1}}]")
|
||||
List<RequestLog> countByStartTimeAndEndTime(String startTime, String endTime);
|
||||
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package ink.wgink.gateway.filter.global;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: CountGolbalFilter
|
||||
* @Description: 计数过滤器
|
||||
* @Author: WangGeng
|
||||
* @Date: 2021/4/13 12:10
|
||||
* @Version: 1.0
|
||||
**/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CountGlobalFilter implements GlobalFilter, Ordered {
|
||||
|
||||
private AtomicInteger count = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
URI uri = exchange.getRequest().getURI();
|
||||
System.out.println();
|
||||
System.out.println("uri: " + uri);
|
||||
System.out.println("count: "+ count.getAndAdd(1));
|
||||
System.out.println();
|
||||
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 10000;
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
package ink.wgink.gateway.filter.global;
|
||||
|
||||
import ink.wgink.gateway.dao.log.IRequestLogDao;
|
||||
import ink.wgink.gateway.handler.log.RequestLogHandler;
|
||||
import ink.wgink.gateway.pojo.log.RequestLog;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: CountGolbalFilter
|
||||
* @Description: 计数过滤器
|
||||
* @Author: WangGeng
|
||||
* @Date: 2021/4/13 12:10
|
||||
* @Version: 1.0
|
||||
**/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RequestLogGlobalFilter implements GlobalFilter, Ordered {
|
||||
|
||||
private RequestLogHandler requestLogHandler;
|
||||
|
||||
public RequestLogGlobalFilter(RequestLogHandler requestLogHandler) {
|
||||
this.requestLogHandler = requestLogHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain gatewayFilterChain) {
|
||||
ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest();
|
||||
ServerHttpResponse serverHttpResponse = serverWebExchange.getResponse();
|
||||
// 其它情况,一律放行,并做日志处理
|
||||
RequestLog requestLog = buildRequestLog(serverHttpRequest);
|
||||
return gatewayFilterChain.filter(serverWebExchange.mutate().response(new ServerHttpResponseDecorator(serverHttpResponse) {
|
||||
@Override
|
||||
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
|
||||
if (body instanceof Flux) {
|
||||
requestLog.setResponseCode(this.getStatusCode().value());
|
||||
requestLog.setEndTime(System.currentTimeMillis());
|
||||
requestLog.setUsedTime(requestLog.getEndTime() - requestLog.getStartTime());
|
||||
requestLogHandler.save(requestLog);
|
||||
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
|
||||
return super.writeWith(fluxBody.map(dataBuffer -> {
|
||||
byte[] content = new byte[dataBuffer.readableByteCount()];
|
||||
dataBuffer.read(content);
|
||||
// String responseResult = new String(content, Charset.forName("UTF-8"));
|
||||
return super.bufferFactory().wrap(content);
|
||||
}));
|
||||
}
|
||||
return super.writeWith(body);
|
||||
}
|
||||
}).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
// 调整到-10保证过滤器在执行时,路径没有被修改
|
||||
return -10;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建请求日志
|
||||
*
|
||||
* @param serverHttpRequest
|
||||
* @return
|
||||
*/
|
||||
private RequestLog buildRequestLog(ServerHttpRequest serverHttpRequest) {
|
||||
URI uri = serverHttpRequest.getURI();
|
||||
RequestLog requestLog = new RequestLog();
|
||||
requestLog.setMethod(serverHttpRequest.getMethod().name());
|
||||
requestLog.setHost(uri.getHost());
|
||||
requestLog.setPort(uri.getPort());
|
||||
requestLog.setPath(uri.getPath());
|
||||
requestLog.setQueryParams(uri.getQuery());
|
||||
requestLog.setScheme(uri.getScheme());
|
||||
requestLog.setStartTime(System.currentTimeMillis());
|
||||
return requestLog;
|
||||
}
|
||||
}
|
@ -40,7 +40,7 @@ public class CommonFiltersDefinition {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置路径过滤器,去除前缀,将路径中的gw删除,暂时无用
|
||||
* 设置路径过滤器
|
||||
*
|
||||
* @param route
|
||||
* @return
|
||||
@ -48,7 +48,7 @@ public class CommonFiltersDefinition {
|
||||
public FilterDefinition setPath(Route route) {
|
||||
FilterDefinition setPath = new FilterDefinition();
|
||||
Map<String, String> setPathMap = new HashMap<>(2);
|
||||
setPathMap.put(SetPathGatewayFilterFactory.TEMPLATE_KEY, route.getPath().replaceFirst(ISystemConst.ROUTE_PREFIX, "/"));
|
||||
setPathMap.put(SetPathGatewayFilterFactory.TEMPLATE_KEY, route.getSetPath());
|
||||
setPath.setArgs(setPathMap);
|
||||
setPath.setName("SetPath");
|
||||
return setPath;
|
||||
|
@ -1,20 +1,28 @@
|
||||
package ink.wgink.gateway.filter.web;
|
||||
|
||||
import ink.wgink.gateway.consts.ISystemConst;
|
||||
import ink.wgink.gateway.handler.log.RequestLogHandler;
|
||||
import ink.wgink.gateway.pojo.log.RequestLog;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import org.springframework.web.server.WebSession;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -0,0 +1,98 @@
|
||||
package ink.wgink.gateway.handler.count;
|
||||
|
||||
import ink.wgink.gateway.dao.log.IRequestLogDao;
|
||||
import ink.wgink.gateway.dao.route.IRouteDao;
|
||||
import ink.wgink.gateway.dao.routetype.IRouteTypeDao;
|
||||
import ink.wgink.gateway.handler.BaseHandler;
|
||||
import ink.wgink.gateway.pojo.count.HomeCount;
|
||||
import ink.wgink.gateway.pojo.count.RequestLogCount;
|
||||
import ink.wgink.gateway.pojo.log.RequestLog;
|
||||
import ink.wgink.gateway.pojo.result.SuccessResult;
|
||||
import ink.wgink.gateway.pojo.result.SuccessResultData;
|
||||
import ink.wgink.gateway.util.DateUtil;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.ExampleMatcher;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: CountHandler
|
||||
* @Description: 统计
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/5/15 3:01 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Service
|
||||
public class CountHandler extends BaseHandler {
|
||||
|
||||
private IRouteTypeDao routeTypeDao;
|
||||
private IRouteDao routeDao;
|
||||
private IRequestLogDao requestLogDao;
|
||||
|
||||
public CountHandler(IRouteTypeDao routeTypeDao, IRouteDao routeDao, IRequestLogDao requestLogDao) {
|
||||
this.routeTypeDao = routeTypeDao;
|
||||
this.routeDao = routeDao;
|
||||
this.requestLogDao = requestLogDao;
|
||||
}
|
||||
|
||||
/**
|
||||
* 所有路由类型
|
||||
*
|
||||
* @param serverResponse
|
||||
* @return
|
||||
*/
|
||||
public Mono<ServerResponse> countHome(ServerRequest serverResponse) {
|
||||
return ServerResponse.ok().contentType(MediaType.TEXT_EVENT_STREAM).body(
|
||||
Flux.interval(Duration.ofSeconds(0), Duration.ofSeconds(15))
|
||||
.flatMap(second -> routeTypeDao.count()
|
||||
.flatMap(routeTypeCount -> routeDao.count()
|
||||
.flatMap(routeCount -> requestLogDao.count()
|
||||
.flatMap(requestCount -> {
|
||||
RequestLog requestLogExample = new RequestLog();
|
||||
requestLogExample.setGmtCreate(DateUtil.getDay());
|
||||
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matching()
|
||||
.withMatcher("gmtCreate", ExampleMatcher.GenericPropertyMatcher::contains)
|
||||
.withIgnoreCase("id");
|
||||
Example example = Example.of(requestLogExample, exampleMatcher);
|
||||
|
||||
return requestLogDao.count(example)
|
||||
.flatMap(requestTodayCount -> {
|
||||
HomeCount homeCount = new HomeCount();
|
||||
homeCount.setRouteTypeCount(routeTypeCount);
|
||||
homeCount.setRouteCount(routeCount);
|
||||
homeCount.setRequestCount(requestCount);
|
||||
homeCount.setRequestTodayCount((Long) requestTodayCount);
|
||||
return Mono.just(homeCount);
|
||||
});
|
||||
})
|
||||
)
|
||||
)
|
||||
),
|
||||
HomeCount.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 最新请求数量列表
|
||||
*
|
||||
* @param serverRequest
|
||||
* @return
|
||||
*/
|
||||
// 每分钟跟新依次统计数据
|
||||
public Mono<ServerResponse> listLastCount(ServerRequest serverRequest) {
|
||||
return ServerResponse.ok().contentType(MediaType.TEXT_EVENT_STREAM).body(requestLogDao.count().flatMap(count -> {
|
||||
RequestLogCount requestLogCount = new RequestLogCount();
|
||||
return Mono.just(requestLogCount);
|
||||
}), RequestLogCount.class);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package ink.wgink.gateway.handler.log;
|
||||
|
||||
import ink.wgink.gateway.dao.log.IRequestLogDao;
|
||||
import ink.wgink.gateway.handler.BaseHandler;
|
||||
import ink.wgink.gateway.pojo.log.RequestLog;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: RequestLogHandler
|
||||
* @Description: 请求日志
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/5/15 5:27 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Service
|
||||
public class RequestLogHandler extends BaseHandler {
|
||||
|
||||
private IRequestLogDao requestLogDao;
|
||||
|
||||
public RequestLogHandler(IRequestLogDao requestLogDao) {
|
||||
this.requestLogDao = requestLogDao;
|
||||
}
|
||||
|
||||
public Mono<Void> save(RequestLog requestLog) {
|
||||
setSave(requestLog);
|
||||
requestLogDao.save(requestLog).subscribe();
|
||||
return Mono.empty();
|
||||
}
|
||||
}
|
@ -3,10 +3,14 @@ package ink.wgink.gateway.handler.route;
|
||||
import ink.wgink.gateway.consts.ISystemConst;
|
||||
import ink.wgink.gateway.dao.route.IRouteDao;
|
||||
import ink.wgink.gateway.exception.ParamsException;
|
||||
import ink.wgink.gateway.exception.SearchException;
|
||||
import ink.wgink.gateway.handler.BaseHandler;
|
||||
import ink.wgink.gateway.pojo.result.SuccessResult;
|
||||
import ink.wgink.gateway.pojo.route.Route;
|
||||
import ink.wgink.gateway.pojo.routetype.RouteType;
|
||||
import ink.wgink.gateway.util.RegexUtil;
|
||||
import ink.wgink.gateway.util.RequestFieldCheckUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
@ -52,12 +56,26 @@ public class RouteHandler extends BaseHandler implements ApplicationEventPublish
|
||||
public Mono<ServerResponse> save(ServerRequest serverRequest) {
|
||||
Mono<Route> routeMono = serverRequest.bodyToMono(Route.class);
|
||||
return routeMono.flatMap(route -> {
|
||||
setSave(route);
|
||||
|
||||
RequestFieldCheckUtil.check(route);
|
||||
if (route.getPath().startsWith(ISystemConst.ROOT_PATH_PREFIX)) {
|
||||
return Mono.error(new ParamsException("根路径不能配置通配符"));
|
||||
}
|
||||
setSave(route);
|
||||
return routeDao.save(route);
|
||||
if (route.getPath().startsWith(ISystemConst.ADMIN_ROUTER_PREFIX)) {
|
||||
return Mono.error(new ParamsException("根路径不能以/wg/*开头"));
|
||||
}
|
||||
if (!StringUtils.isBlank(route.getSetPath()) && !RegexUtil.isPath(route.getSetPath())) {
|
||||
return Mono.error(new ParamsException("设置路径格式错误"));
|
||||
}
|
||||
// 判断路径是否存在
|
||||
Route routeExample = new Route();
|
||||
routeExample.setPath(route.getPath());
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matching().withMatcher("path", ExampleMatcher.GenericPropertyMatcher::exact).withIgnoreCase("id");
|
||||
Example example = Example.of(routeExample, exampleMatcher);
|
||||
return routeDao.findOne(example).flatMap(
|
||||
r -> Mono.error(new SearchException("路径已经存在"))
|
||||
).switchIfEmpty(routeDao.save(route));
|
||||
}).then(ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(Flux.just(new SuccessResult()), SuccessResult.class));
|
||||
}
|
||||
|
||||
@ -84,24 +102,45 @@ public class RouteHandler extends BaseHandler implements ApplicationEventPublish
|
||||
public Mono<ServerResponse> update(ServerRequest serverRequest) {
|
||||
String id = serverRequest.pathVariable("id");
|
||||
Mono<Route> routeMono = serverRequest.bodyToMono(Route.class);
|
||||
return routeDao.findById(id).flatMap(
|
||||
route -> routeMono.flatMap(r -> {
|
||||
RequestFieldCheckUtil.check(r);
|
||||
if (r.getPath().startsWith(ISystemConst.ROOT_PATH_PREFIX)) {
|
||||
return Mono.error(new ParamsException("根路径不能配置通配符"));
|
||||
return routeDao.findById(id).flatMap(route -> {
|
||||
setUpdate(route);
|
||||
return routeMono.flatMap(r -> {
|
||||
route.setTitle(r.getTitle());
|
||||
route.setSummary(r.getSummary());
|
||||
route.setPath(r.getPath());
|
||||
route.setUri(r.getUri());
|
||||
route.setTestPath(r.getTestPath());
|
||||
route.setRouteType(r.getRouteType());
|
||||
route.setSetPath(r.getSetPath());
|
||||
|
||||
RequestFieldCheckUtil.check(r);
|
||||
if (r.getPath().startsWith(ISystemConst.ROOT_PATH_PREFIX)) {
|
||||
return Mono.error(new ParamsException("根路径不能配置通配符"));
|
||||
}
|
||||
if (r.getPath().startsWith(ISystemConst.ADMIN_ROUTER_PREFIX)) {
|
||||
return Mono.error(new ParamsException("根路径不能以/wg/*开头"));
|
||||
}
|
||||
if (!StringUtils.isBlank(route.getSetPath()) && !RegexUtil.isPath(route.getSetPath())) {
|
||||
return Mono.error(new ParamsException("设置路径格式错误"));
|
||||
}
|
||||
|
||||
// 检索路径是否存在
|
||||
Route routeExample = new Route();
|
||||
routeExample.setPath(r.getPath());
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matching()
|
||||
.withMatcher("path", ExampleMatcher.GenericPropertyMatcher::exact)
|
||||
.withIgnoreCase("id");
|
||||
Example example = Example.of(routeExample, exampleMatcher);
|
||||
return routeDao.findOne(example).flatMap(er -> {
|
||||
Route existRoute = (Route) er;
|
||||
// 如果已经存在
|
||||
if (!StringUtils.equals(existRoute.getUuid(), id)) {
|
||||
return Mono.error(new SearchException("路径已经存在"));
|
||||
}
|
||||
if (r.getPath().startsWith(ISystemConst.ADMIN_ROUTER_PREFIX)) {
|
||||
return Mono.error(new ParamsException("根路径不能以/wg/*开头"));
|
||||
}
|
||||
route.setTitle(r.getTitle());
|
||||
route.setSummary(r.getSummary());
|
||||
route.setPath(r.getPath());
|
||||
route.setUri(r.getUri());
|
||||
route.setTestPath(r.getTestPath());
|
||||
setUpdate(route);
|
||||
return routeDao.save(route);
|
||||
}).then(ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(Flux.just(new SuccessResult()), SuccessResult.class))
|
||||
).switchIfEmpty(ServerResponse.notFound().build());
|
||||
}).switchIfEmpty(routeDao.save(route));
|
||||
});
|
||||
}).then(ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8).body(Flux.just(new SuccessResult()), SuccessResult.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,17 +151,24 @@ public class RouteHandler extends BaseHandler implements ApplicationEventPublish
|
||||
*/
|
||||
public Mono<ServerResponse> list(ServerRequest serverRequest) {
|
||||
Optional<String> keywords = serverRequest.queryParam("keywords");
|
||||
Optional<String> routeType = serverRequest.queryParam("routeType");
|
||||
|
||||
Route route = new Route();
|
||||
Example example = Example.of(route);
|
||||
if (keywords.isPresent()) {
|
||||
String keywordTrim = keywords.get().trim();
|
||||
route.setTitle(keywordTrim);
|
||||
route.setSummary(keywordTrim);
|
||||
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matchingAny()
|
||||
if (keywords.isPresent() || routeType.isPresent()) {
|
||||
if (keywords.isPresent()) {
|
||||
String keywordTrim = keywords.get().trim();
|
||||
route.setTitle(keywordTrim);
|
||||
route.setSummary(keywordTrim);
|
||||
}
|
||||
if (routeType.isPresent()) {
|
||||
String routeTypeTrim = routeType.get().trim();
|
||||
route.setRouteType(routeTypeTrim);
|
||||
}
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matching()
|
||||
.withMatcher("title", ExampleMatcher.GenericPropertyMatcher::contains)
|
||||
.withMatcher("summary", ExampleMatcher.GenericPropertyMatcher::contains)
|
||||
.withMatcher("routeType", ExampleMatcher.GenericPropertyMatcher::exact)
|
||||
.withIgnoreCase("id");
|
||||
example = Example.of(route, exampleMatcher);
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ public class RouteTypeHandler extends BaseHandler {
|
||||
|
||||
RouteType routeTypeExample = new RouteType();
|
||||
routeTypeExample.setTitle(routeType.getTitle().trim());
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matchingAny().withMatcher("title", ExampleMatcher.GenericPropertyMatcher::exact).withIgnoreCase("id");
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matching().withMatcher("title", ExampleMatcher.GenericPropertyMatcher::exact).withIgnoreCase("id");
|
||||
Example example = Example.of(routeTypeExample, exampleMatcher);
|
||||
return routeTypeDao.findOne(example).flatMap(
|
||||
r -> Mono.error(new SearchException("类型已经存在"))
|
||||
@ -87,15 +87,16 @@ public class RouteTypeHandler extends BaseHandler {
|
||||
return routeTypeDao.findById(id).flatMap(routeType -> {
|
||||
setUpdate(routeType);
|
||||
return routeTypeMono.flatMap(rt -> {
|
||||
RequestFieldCheckUtil.check(rt);
|
||||
routeType.setTitle(rt.getTitle());
|
||||
routeType.setSummary(rt.getSummary());
|
||||
|
||||
RequestFieldCheckUtil.check(rt);
|
||||
rt.setSummary(null );
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matchingAny()
|
||||
RouteType routeTypeExample = new RouteType();
|
||||
routeTypeExample.setTitle(rt.getTitle());
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matching()
|
||||
.withMatcher("title", ExampleMatcher.GenericPropertyMatcher::exact)
|
||||
.withIgnoreCase("id");
|
||||
Example example = Example.of(rt, exampleMatcher);
|
||||
Example example = Example.of(routeTypeExample, exampleMatcher);
|
||||
// 查询title是否存在
|
||||
return routeTypeDao.findOne(example).flatMap(ert -> {
|
||||
RouteType existRouteType = (RouteType) ert;
|
||||
@ -125,7 +126,7 @@ public class RouteTypeHandler extends BaseHandler {
|
||||
routeType.setTitle(keywordTrim);
|
||||
routeType.setSummary(keywordTrim);
|
||||
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matchingAny()
|
||||
ExampleMatcher exampleMatcher = ExampleMatcher.matching()
|
||||
.withMatcher("title", ExampleMatcher.GenericPropertyMatcher::contains)
|
||||
.withMatcher("summary", ExampleMatcher.GenericPropertyMatcher::contains)
|
||||
.withIgnoreCase("id");
|
||||
|
56
src/main/java/ink/wgink/gateway/pojo/count/HomeCount.java
Normal file
@ -0,0 +1,56 @@
|
||||
package ink.wgink.gateway.pojo.count;
|
||||
|
||||
import lombok.ToString;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: HomeCount
|
||||
* @Description: 首页统计
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/5/15 4:53 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@ToString
|
||||
@Document
|
||||
public class HomeCount {
|
||||
|
||||
private Long routeTypeCount;
|
||||
private Long routeCount;
|
||||
private Long requestCount;
|
||||
private Long requestTodayCount;
|
||||
|
||||
public Long getRouteTypeCount() {
|
||||
return routeTypeCount == null ? 0 : routeTypeCount;
|
||||
}
|
||||
|
||||
public void setRouteTypeCount(Long routeTypeCount) {
|
||||
this.routeTypeCount = routeTypeCount;
|
||||
}
|
||||
|
||||
public Long getRouteCount() {
|
||||
return routeCount == null ? 0 : routeCount;
|
||||
}
|
||||
|
||||
public void setRouteCount(Long routeCount) {
|
||||
this.routeCount = routeCount;
|
||||
}
|
||||
|
||||
public Long getRequestCount() {
|
||||
return requestCount == null ? 0 : requestCount;
|
||||
}
|
||||
|
||||
public void setRequestCount(Long requestCount) {
|
||||
this.requestCount = requestCount;
|
||||
}
|
||||
|
||||
public Long getRequestTodayCount() {
|
||||
return requestTodayCount == null ? 0 : requestTodayCount;
|
||||
}
|
||||
|
||||
public void setRequestTodayCount(Long requestTodayCount) {
|
||||
this.requestTodayCount = requestTodayCount;
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package ink.wgink.gateway.pojo.count;
|
||||
|
||||
import ink.wgink.gateway.dao.log.IRequestLogDao;
|
||||
import ink.wgink.gateway.pojo.BasePOJO;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: RequestLog
|
||||
* @Description: 请求日志
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/5/15 3:03 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
@Document(collection = IRequestLogDao.COLLECTION_NAME)
|
||||
public class RequestLogCount implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 289254213770448241L;
|
||||
private String gmtCreate;
|
||||
private Long count;
|
||||
|
||||
}
|
38
src/main/java/ink/wgink/gateway/pojo/log/RequestLog.java
Normal file
@ -0,0 +1,38 @@
|
||||
package ink.wgink.gateway.pojo.log;
|
||||
|
||||
import ink.wgink.gateway.dao.log.IRequestLogDao;
|
||||
import ink.wgink.gateway.pojo.BasePOJO;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: RequestLog
|
||||
* @Description: 请求日志
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/5/15 3:03 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
@Document(collection = IRequestLogDao.COLLECTION_NAME)
|
||||
public class RequestLog extends BasePOJO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 289254213770448241L;
|
||||
private String method;
|
||||
private String scheme;
|
||||
private String host;
|
||||
private Integer port;
|
||||
private String path;
|
||||
private String queryParams;
|
||||
private Integer responseCode;
|
||||
private Long startTime;
|
||||
private Long endTime;
|
||||
private Long usedTime;
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package ink.wgink.gateway.pojo.result;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
/**
|
||||
* @ClassName: SuccessResult
|
||||
* @Description: 成功结果
|
||||
* @Author: WangGeng
|
||||
* @Date: 2019/3/2 11:52 PM
|
||||
* @Version: 1.0
|
||||
**/
|
||||
@Data
|
||||
@ToString
|
||||
@Document
|
||||
public class SuccessResultData<T> {
|
||||
|
||||
private T data;
|
||||
|
||||
public SuccessResultData() {}
|
||||
|
||||
public SuccessResultData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
@ -33,6 +33,8 @@ public class Route extends BasePOJO implements Serializable {
|
||||
private String uri;
|
||||
@CheckEmptyAnnotation(name = "测试接口", verifyType = "path")
|
||||
private String testPath;
|
||||
private String routeType;
|
||||
private String setPath;
|
||||
|
||||
public String getTitle() {
|
||||
return title == null ? "" : title.trim();
|
||||
@ -73,4 +75,20 @@ public class Route extends BasePOJO implements Serializable {
|
||||
public void setTestPath(String testPath) {
|
||||
this.testPath = testPath;
|
||||
}
|
||||
|
||||
public String getRouteType() {
|
||||
return routeType == null ? "" : routeType;
|
||||
}
|
||||
|
||||
public void setRouteType(String routeType) {
|
||||
this.routeType = routeType;
|
||||
}
|
||||
|
||||
public String getSetPath() {
|
||||
return setPath == null ? "" : setPath;
|
||||
}
|
||||
|
||||
public void setSetPath(String setPath) {
|
||||
this.setPath = setPath;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
package ink.wgink.gateway.router.count;
|
||||
|
||||
import ink.wgink.gateway.consts.ISystemConst;
|
||||
import ink.wgink.gateway.handler.count.CountHandler;
|
||||
import ink.wgink.gateway.router.BaseRouter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicates;
|
||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
|
||||
/**
|
||||
* When you feel like quitting. Think about why you started
|
||||
* 当你想要放弃的时候,想想当初你为何开始
|
||||
*
|
||||
* @ClassName: CountRouter
|
||||
* @Description: 统计
|
||||
* @Author: wanggeng
|
||||
* @Date: 2021/5/15 4:36 下午
|
||||
* @Version: 1.0
|
||||
*/
|
||||
@Component
|
||||
public class CountRouter extends BaseRouter {
|
||||
|
||||
@Bean
|
||||
public RouterFunction<ServerResponse> countRouterFunction(CountHandler countHandler) {
|
||||
return RouterFunctions.nest(RequestPredicates.path(ISystemConst.ADMIN_ROUTER_PREFIX + "/api/count"),
|
||||
RouterFunctions
|
||||
.route(RequestPredicates.GET("/count-home"), countHandler::countHome)
|
||||
.andRoute(RequestPredicates.GET("list-last-count"), countHandler::listLastCount)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
21
src/main/resources/static/wg/assets/js/echarts.min.js
vendored
Normal file
@ -1,99 +0,0 @@
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>测试 - layui</title>
|
||||
<link rel="stylesheet" href="layui/css/layui.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="layui-container">
|
||||
<div class="layui-progress" style="margin: 15px 0 30px;">
|
||||
<div class="layui-progress-bar" lay-percent="100%"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn" test-active="test-form">一个按钮</button>
|
||||
<button class="layui-btn layui-btn-normal" id="test2">当前日期</button>
|
||||
</div>
|
||||
|
||||
<blockquote class="layui-elem-quote" style="margin-top: 30px;">
|
||||
<div class="layui-text">
|
||||
<ul>
|
||||
<li>你当前预览的是:<span>layui-v<span id="version"></span></span></li>
|
||||
<li>这是一个极其简洁的演示页面</li>
|
||||
</ul>
|
||||
</div>
|
||||
</blockquote>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- 引入 layui.js 的 <script> 标签最好放置在 html 末尾 -->
|
||||
<script src="layui/layui.js"></script>
|
||||
<script>
|
||||
layui.use(function(){
|
||||
var layer = layui.layer
|
||||
,form = layui.form
|
||||
,laypage = layui.laypage
|
||||
,element = layui.element
|
||||
,laydate = layui.laydate
|
||||
,util = layui.util;
|
||||
|
||||
//欢迎信息
|
||||
layer.msg('Hello World');
|
||||
|
||||
//输出版本号
|
||||
lay('#version').html(layui.v);
|
||||
|
||||
//日期
|
||||
laydate.render({
|
||||
elem: '#test2'
|
||||
,value: new Date()
|
||||
,isInitValue: true
|
||||
});
|
||||
|
||||
//触发事件
|
||||
util.event('test-active', {
|
||||
'test-form': function(){
|
||||
layer.open({
|
||||
type: 1
|
||||
,resize: false
|
||||
,shadeClose: true
|
||||
,content: ['<ul class="layui-form" style="margin: 10px;">'
|
||||
,'<li class="layui-form-item">'
|
||||
,'<label class="layui-form-label">输入框</label>'
|
||||
,'<div class="layui-input-block">'
|
||||
,'<input class="layui-input" name="field1">'
|
||||
,'</div>'
|
||||
,'</li>'
|
||||
,'<li class="layui-form-item">'
|
||||
,'<label class="layui-form-label">选择框</label>'
|
||||
,'<div class="layui-input-block">'
|
||||
,'<select name="field2">'
|
||||
,'<option value="A">A</option>'
|
||||
,'<option value="B">B</option>'
|
||||
,'<select>'
|
||||
,'</div>'
|
||||
,'</li>'
|
||||
,'<li class="layui-form-item" style="text-align:center;">'
|
||||
,'<button type="submit" lay-submit lay-filter="*" class="layui-btn">提交</button>'
|
||||
,'</li>'
|
||||
,'</ul>'].join('')
|
||||
,success: function(layero){
|
||||
layero.find('.layui-layer-content').css('overflow', 'visible');
|
||||
|
||||
form.render().on('submit(*)', function(data){
|
||||
layer.msg(JSON.stringify(data.field));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,6 +0,0 @@
|
||||
[{000214A0-0000-0000-C000-000000000046}]
|
||||
Prop3=19,11
|
||||
[InternetShortcut]
|
||||
URL=https://www.layui.com/about/disclaimer.html
|
||||
IDList=
|
||||
HotKey=0
|
@ -4,7 +4,6 @@ html {
|
||||
|
||||
.iframe-container {
|
||||
margin: 15px;
|
||||
background: #FFFFFF;
|
||||
}
|
||||
|
||||
.iframe-container .iframe-box {
|
||||
@ -17,6 +16,7 @@ html {
|
||||
.iframe-container .iframe-breadcrumb-box {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #F3F3F3;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
|
||||
.list-page-container {
|
||||
@ -241,3 +241,23 @@ html, body, #LAY_app {
|
||||
text-align: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.search-item {
|
||||
height: 30px !important;
|
||||
}
|
||||
|
||||
.search-item input, .search-item select {
|
||||
height: 30px !important;
|
||||
}
|
||||
|
||||
.search-item-width-100 {
|
||||
width: 100px !important;
|
||||
}
|
||||
|
||||
.search-item-width-200 {
|
||||
width: 200px !important;
|
||||
}
|
||||
|
||||
.search-item-width-300 {
|
||||
width: 300px !important;
|
||||
}
|
1
src/main/resources/static/wg/assets/layui/css/layui.css
Normal file
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 701 B After Width: | Height: | Size: 701 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 299 KiB After Width: | Height: | Size: 299 KiB |
6
src/main/resources/static/wg/assets/layui/layui.js
Normal file
@ -0,0 +1,25 @@
|
||||
layui.define(function(exports) {
|
||||
var $ = layui.$;
|
||||
$.fn.animateNumbers = function(stop, commas, duration, ease) {
|
||||
return this.each(function() {
|
||||
var $this = $(this);
|
||||
var start = parseInt($this.text().replace(/,/g, ""));
|
||||
commas = (commas === undefined) ? true : commas;
|
||||
$({value: start}).animate({value: stop}, {
|
||||
duration: duration == undefined ? 1000 : duration,
|
||||
easing: ease == undefined ? "swing" : ease,
|
||||
step: function() {
|
||||
$this.text(Math.floor(this.value));
|
||||
if (commas) { $this.text($this.text().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,")); }
|
||||
},
|
||||
complete: function() {
|
||||
if (parseInt($this.text()) !== stop) {
|
||||
$this.text(stop);
|
||||
if (commas) { $this.text($this.text().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,")); }
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
exports('animate-numbers', null);
|
||||
});
|
151
src/main/resources/static/wg/home.html
Normal file
@ -0,0 +1,151 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<base href="/wg/">
|
||||
<meta charset="utf-8">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="assets/layui/css/layui.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/admin.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/admin.css"/>
|
||||
<style>
|
||||
#app {padding: 15px 0;}
|
||||
.layuiadmin-badge {float: right; height: 42px; line-height: 42px;}
|
||||
.layuiadmin-card-list {padding: 15px;line-height: 38px !important; text-align: right;}
|
||||
.layuiadmin-card-list .layuiadmin-big-font {font-size: 38px;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md3 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
累计调用量
|
||||
<span class="layui-badge layui-bg-cyan layuiadmin-badge">次</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p id="requestCount" class="layuiadmin-big-font">0</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
今日调用量
|
||||
<span class="layui-badge layui-bg-green layuiadmin-badge">次</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p id="requestTodayCount" class="layuiadmin-big-font">0</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
路由类型总量
|
||||
<span class="layui-badge layui-bg-blue layuiadmin-badge">个</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p id="routeTypeCount" class="layuiadmin-big-font">0</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-md3 layui-col-sm6 layui-col-xs12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
映射路由总量
|
||||
<span class="layui-badge layui-bg-orange layuiadmin-badge">个</span>
|
||||
</div>
|
||||
<div class="layui-card-body layuiadmin-card-list">
|
||||
<p id="routeCount" class="layuiadmin-big-font">0</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-sm12 layui-col-md6">
|
||||
<div class="layui-col-sm12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div id="loginEChart" style="width: 100%; height: 267px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript" src="assets/js/vue.min.js"></script>
|
||||
<script type="text/javascript" src="assets/js/echarts.min.js"></script>
|
||||
<script src="assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: 'assets/layui/modules/'
|
||||
}).extend({}).use(['layer', 'animate-numbers'], function () {
|
||||
var $ = layui.$;
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
requestCount: 0,
|
||||
requestTodayCount: 0,
|
||||
routeTypeCount: 0,
|
||||
routeCount: 0
|
||||
},
|
||||
watch: {
|
||||
'requestCount': function(value, old) {
|
||||
$('#requestCount').animateNumbers(value);
|
||||
},
|
||||
'requestTodayCount': function(value, old) {
|
||||
$('#requestTodayCount').animateNumbers(value);
|
||||
},
|
||||
'routeTypeCount': function(value, old) {
|
||||
$('#routeTypeCount').animateNumbers(value);
|
||||
},
|
||||
'routeCount': function(value, old) {
|
||||
$('#routeCount').animateNumbers(value);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
sseCountHome: function() {
|
||||
var self = this;
|
||||
var source = new EventSource(top.restAjax.path('api/count/count-home', []));
|
||||
source.addEventListener('message', function(e) {
|
||||
var data = JSON.parse(e.data);
|
||||
self.requestCount = data.requestCount;
|
||||
self.requestTodayCount = data.requestTodayCount;
|
||||
self.routeTypeCount = data.routeTypeCount;
|
||||
self.routeCount = data.routeCount;
|
||||
});
|
||||
source.addEventListener('open', function(e) {}, false);
|
||||
// 响应finish事件,主动关闭EventSource
|
||||
source.addEventListener('finish', function(e) {
|
||||
source.close();
|
||||
}, false);
|
||||
// 异常
|
||||
source.addEventListener('error', function(e) {
|
||||
if (e.readyState == EventSource.CLOSED) {
|
||||
console.log("连接关闭");
|
||||
} else {
|
||||
console.log(e);
|
||||
}
|
||||
}, false);
|
||||
},
|
||||
countHome: function() {
|
||||
var self = this;
|
||||
if (window.EventSource) {
|
||||
self.sseCountHome();
|
||||
} else {
|
||||
console.log('浏览器不支持sse');
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted: function() {
|
||||
var self = this;
|
||||
self.countHome();
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -8,9 +8,8 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="icon" href="assets/favicon.ico" type="image/x-icon"/>
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/layui.css"/>
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/admin.css"/>
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/admin.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/layui.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/admin.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-app">
|
||||
@ -34,18 +33,18 @@
|
||||
<div class="iframe-container">
|
||||
<div class="iframe-breadcrumb-box">
|
||||
<span id="breadcrumbTitle" class="layui-breadcrumb">
|
||||
<a href="">首页</a>
|
||||
<a href="javascript:void(0);" class="menu-item" data-href="home.html">首页</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="iframe-box">
|
||||
<iframe id="defaultIFrame" frameborder="0" class="layadmin-iframe"></iframe>
|
||||
<iframe id="defaultIFrame" frameborder="0" border="0" class="layadmin-iframe"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="assets/layui-v2.6.4/layui/layui.js"></script>
|
||||
<script src="assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: 'assets/layui-v2.6.4/layui/modules/'
|
||||
base: 'assets/layui/modules/'
|
||||
}).extend({}).use(['restajax', 'datamessage', 'dialog'], function () {
|
||||
var $ = layui.$;
|
||||
var $win = $(window);
|
||||
@ -57,14 +56,14 @@
|
||||
function resize() {
|
||||
$('#defaultIFrame').css({
|
||||
width: ($win.width() - 30) +'px',
|
||||
height: ($win.height() - 145) +'px'
|
||||
height: ($win.height() - 140) +'px'
|
||||
})
|
||||
}
|
||||
resize();
|
||||
|
||||
window.onresize = resize;
|
||||
|
||||
$('#defaultIFrame').attr('src', 'route/route/list.html');
|
||||
$('#defaultIFrame').attr('src', 'home.html');
|
||||
|
||||
$('.menu-item').on('click', function() {
|
||||
$('#defaultIFrame').attr('src', this.dataset.href);
|
||||
|
@ -8,8 +8,8 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="icon" href="assets/favicon.ico" type="image/x-icon"/>
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/layui.css"/>
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/admin.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/layui.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/admin.css"/>
|
||||
<script>
|
||||
if(top.location != window.location) {
|
||||
top.location.href = window.location.href;
|
||||
@ -39,10 +39,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="assets/layui-v2.6.4/layui/layui.js"></script>
|
||||
<script src="assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: 'assets/layui-v2.6.4/layui/modules/'
|
||||
base: 'assets/layui/modules/'
|
||||
}).extend({}).use(['form', 'restajax', 'datamessage', 'dialog'], function () {
|
||||
var $ = layui.$;
|
||||
var $win = $(window);
|
||||
|
@ -7,8 +7,8 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="assets/font/font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/admin.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui/css/admin.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-anim layui-anim-fadein list-page-container">
|
||||
@ -40,10 +40,10 @@
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
<script src="assets/layui-v2.6.4/layui/layui.js"></script>
|
||||
<script src="assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: 'assets/layui-v2.6.4/layui/modules/'
|
||||
base: 'assets/layui/modules/'
|
||||
}).extend({}).use(['layer', 'table'], function () {
|
||||
var $ = layui.$;
|
||||
var $win = $(window);
|
||||
@ -66,9 +66,11 @@
|
||||
});
|
||||
}
|
||||
function initTable() {
|
||||
top.restAjax.get(top.restAjax.path(tableData.tableUrl, []), {
|
||||
keywords: $('#keywords').val(),
|
||||
}, null, function(code, data) {
|
||||
var params = {};
|
||||
if($('#keywords').val()) {
|
||||
params.keywords = $('#keywords').val()
|
||||
}
|
||||
top.restAjax.get(top.restAjax.path(tableData.tableUrl, []), params, null, function(code, data) {
|
||||
tableData.dataArray = [];
|
||||
for(var i = 0, item; item = data[i++];) {
|
||||
tableData.dataArray.push(item);
|
||||
@ -81,10 +83,11 @@
|
||||
elem: '#dataTable',
|
||||
id: 'dataTable',
|
||||
width: '100%',
|
||||
height: $win.height() - 78,
|
||||
height: $win.height() - 73,
|
||||
limit: 20,
|
||||
limits: [20, 40, 60, 80, 100, 200],
|
||||
toolbar: '#headerToolBar',
|
||||
defaultToolbar: [],
|
||||
cols: [[
|
||||
{type: 'checkbox', fixed: 'left'},
|
||||
{field: 'rowNum', width: 80, title: '序号', fixed: 'left', align: 'center', templet: '<span>{{d.LAY_INDEX}}</span>'},
|
||||
|
@ -6,8 +6,8 @@
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/admin.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui/css/admin.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-anim layui-anim-fadein">
|
||||
@ -44,10 +44,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="assets/layui-v2.6.4/layui/layui.js"></script>
|
||||
<script src="assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: 'assets/layui-v2.6.4/layui/modules/'
|
||||
base: 'assets/layui/modules/'
|
||||
}).extend({}).use(['form', 'laydate', 'laytpl', 'regex'], function(){
|
||||
var $ = layui.$;
|
||||
var form = layui.form;
|
||||
|
@ -6,8 +6,8 @@
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/admin.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui/css/admin.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-anim layui-anim-fadein">
|
||||
@ -44,10 +44,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="assets/layui-v2.6.4/layui/layui.js"></script>
|
||||
<script src="assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: 'assets/layui-v2.6.4/layui/modules/'
|
||||
base: 'assets/layui/modules/'
|
||||
}).extend({}).use(['form', 'laydate', 'laytpl', 'regex'], function(){
|
||||
var $ = layui.$;
|
||||
var form = layui.form;
|
||||
|
@ -7,15 +7,24 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="assets/font/font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/admin.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui/css/admin.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-anim layui-anim-fadein list-page-container">
|
||||
<div class="test-table-reload-btn">
|
||||
<div class="layui-inline">
|
||||
<input type="text" id="keywords" class="layui-input search-item" placeholder="输入关键字">
|
||||
<input type="text" id="keywords" class="layui-input search-item search-item-width-100" placeholder="输入关键字">
|
||||
</div>
|
||||
<div class="layui-inline layui-form search-item search-item-width-100" id="routeTypeTplBox"></div>
|
||||
<script id="routeTypeTpl" type="text/html">
|
||||
<select id="routeType" name="routeType" lay-filter="routeTypeFilter">
|
||||
<option value="">路由分类</option>
|
||||
{{# for(var i = 0, item; item = d.data[i++];) { }}
|
||||
<option value="{{item.uuid}}">{{item.title}}</option>
|
||||
{{# } }}
|
||||
</select>
|
||||
</script>
|
||||
<div class="layui-btn-group">
|
||||
<button type="button" id="search" class="layui-btn layui-btn-sm">
|
||||
<i class="fa fa-lg fa-search"></i> 搜索
|
||||
@ -43,14 +52,16 @@
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
<script src="assets/layui-v2.6.4/layui/layui.js"></script>
|
||||
<script src="assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: 'assets/layui-v2.6.4/layui/modules/'
|
||||
base: 'assets/layui/modules/'
|
||||
}).extend({}).use(['layer', 'table'], function () {
|
||||
var $ = layui.$;
|
||||
var $win = $(window);
|
||||
var layer = layui.layer;
|
||||
var laytpl = layui.laytpl;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var laydate = layui.laydate;
|
||||
var resizeTimeout = null;
|
||||
@ -59,6 +70,18 @@
|
||||
dataArray: [],
|
||||
currentPage: null
|
||||
}
|
||||
// 初始化路由类型
|
||||
function initRouteType() {
|
||||
top.restAjax.get(top.restAjax.path('api/route-type/list', []), {}, null, function(code, data) {
|
||||
laytpl(document.getElementById('routeTypeTpl').innerHTML).render({data: data}, function(html) {
|
||||
document.getElementById('routeTypeTplBox').innerHTML = html;
|
||||
});
|
||||
form.render('select');
|
||||
}, function(code, data) {
|
||||
top.dialog.msg(data.msg);
|
||||
});
|
||||
}
|
||||
initRouteType();
|
||||
|
||||
function reloadTable(currentPage) {
|
||||
table.reload('dataTable', {
|
||||
@ -69,9 +92,14 @@
|
||||
});
|
||||
}
|
||||
function initTable() {
|
||||
top.restAjax.get(top.restAjax.path(tableData.tableUrl, []), {
|
||||
keywords: $('#keywords').val(),
|
||||
}, null, function(code, data) {
|
||||
var params = {};
|
||||
if($('#keywords').val()) {
|
||||
params.keywords = $('#keywords').val()
|
||||
}
|
||||
if($('#routeType').val()) {
|
||||
params.routeType = $('#routeType').val();
|
||||
}
|
||||
top.restAjax.get(top.restAjax.path(tableData.tableUrl, []), params, null, function(code, data) {
|
||||
tableData.dataArray = [];
|
||||
for(var i = 0, item; item = data[i++];) {
|
||||
tableData.dataArray.push(item);
|
||||
@ -84,10 +112,11 @@
|
||||
elem: '#dataTable',
|
||||
id: 'dataTable',
|
||||
width: '100%',
|
||||
height: $win.height() - 78,
|
||||
height: $win.height() - 73,
|
||||
limit: 20,
|
||||
limits: [20, 40, 60, 80, 100, 200],
|
||||
toolbar: '#headerToolBar',
|
||||
defaultToolbar: [],
|
||||
cols: [[
|
||||
{type: 'checkbox', fixed: 'left'},
|
||||
{field: 'rowNum', width: 80, title: '序号', fixed: 'left', align: 'center', templet: '<span>{{d.LAY_INDEX}}</span>'},
|
||||
|
@ -6,8 +6,8 @@
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/admin.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui/css/admin.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-anim layui-anim-fadein">
|
||||
@ -21,30 +21,32 @@
|
||||
<div class="layui-card-body" style="padding: 15px;">
|
||||
<form class="layui-form layui-form-pane" lay-filter="dataForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称</label>
|
||||
<label class="layui-form-label">映射名称 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入名称">
|
||||
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入映射名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">描述</label>
|
||||
<label class="layui-form-label">映射描述 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="summary" class="layui-input" lay-verify="required" placeholder="请输入描述">
|
||||
<input type="text" name="summary" class="layui-input" lay-verify="required" placeholder="请输入映射描述">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">映射路径</label>
|
||||
<label class="layui-form-label">映射路径 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="path" class="layui-input" lay-verify="required|path" placeholder="请输入映射路径">
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
直接访问网关的路径<br/>
|
||||
不能以 /wg/ 开头 <br/>
|
||||
根路径不能设置通配符,如:/**<br/>
|
||||
支持通配符,如:/p1/**,表示p1后的人和路径都匹配;<br/>
|
||||
路径中的变量用{}包含,如:/p2/{pq1}/{pq2}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">被映射服务</label>
|
||||
<label class="layui-form-label">被映射服务 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="uri" class="layui-input" lay-verify="required|uri" placeholder="请输入服务地址">
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
@ -54,12 +56,38 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">测试接口</label>
|
||||
<label class="layui-form-label">测试接口 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="testPath" class="layui-input" lay-verify="required|path" placeholder="填写测试接口地址">
|
||||
<input type="text" name="testPath" class="layui-input" lay-verify="path" placeholder="填写测试接口地址">
|
||||
<div class="layui-form-mid layui-word-aux">填写测试接口地址,如:/p1/a/b/c</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">路由分类</label>
|
||||
<div class="layui-input-block" id="routeTypeTplBox"></div>
|
||||
<script id="routeTypeTpl" type="text/html">
|
||||
<select name="routeType" lay-filter="routeTypeFilter">
|
||||
<option value="">请选择路由分类</option>
|
||||
{{# for(var i = 0, item; item = d.data[i++];) { }}
|
||||
<option value="{{item.uuid}}">{{item.title}}</option>
|
||||
{{# } }}
|
||||
</select>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">设置路径</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="setPath" class="layui-input" lay-verify="path" placeholder="请设置路径">
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
网关转发实际地址时的路径,不支持通配符,如:填写 /a 在实际转发时,会把 <b>映射路径</b> 替换为 /a;如果是根路径,填写 / 即可<br/>
|
||||
示例说明:<br/>
|
||||
请求网关的地址为:http:127.0.0.1:9999/baidu<br/>
|
||||
实际的转发地址为:https://www.baidu.com<br/>
|
||||
如果设置路径,那么实际的访问方式为:https://www.baidu.com/<b>baidu</b>,会导致百度无法找到这个路径<br/>
|
||||
将路径设置为 / 之后,实际的请求路径就变为:https://www.baidu.com
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-layout-admin">
|
||||
<div class="layui-input-block">
|
||||
<div class="footer-button-box layui-btn-group">
|
||||
@ -72,23 +100,37 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="assets/layui-v2.6.4/layui/layui.js"></script>
|
||||
<script src="assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: 'assets/layui-v2.6.4/layui/modules/'
|
||||
base: 'assets/layui/modules/'
|
||||
}).extend({}).use(['form', 'laydate', 'laytpl', 'regex'], function(){
|
||||
var $ = layui.$;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var regex = layui.regex;
|
||||
var laytpl = layui.laytpl;
|
||||
var uuid = top.restAjax.params(window.location.href).uuid;
|
||||
|
||||
function closeBox() {
|
||||
parent.layer.close(parent.layer.getFrameIndex(window.name));
|
||||
}
|
||||
|
||||
// 初始化路由类型
|
||||
function initRouteType() {
|
||||
top.restAjax.get(top.restAjax.path('api/route-type/list', []), {}, null, function(code, data) {
|
||||
laytpl(document.getElementById('routeTypeTpl').innerHTML).render({data: data}, function(html) {
|
||||
document.getElementById('routeTypeTplBox').innerHTML = html;
|
||||
});
|
||||
form.render('select', 'dataForm');
|
||||
}, function(code, data) {
|
||||
top.dialog.msg(data.msg);
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化内容
|
||||
function initData() {
|
||||
initRouteType();
|
||||
}
|
||||
initData();
|
||||
|
||||
@ -133,6 +175,9 @@
|
||||
}
|
||||
},
|
||||
path: function(value, item) {
|
||||
if(!value) {
|
||||
return;
|
||||
}
|
||||
if(!regex.path(value)) {
|
||||
return '路径格式不正确'
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui-v2.6.4/layui/css/admin.css"/>
|
||||
<link rel="stylesheet" href="assets/layui/css/layui.css">
|
||||
<link rel="stylesheet" href="assets/layui/css/admin.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layui-anim layui-anim-fadein">
|
||||
@ -21,30 +21,32 @@
|
||||
<div class="layui-card-body" style="padding: 15px;">
|
||||
<form class="layui-form layui-form-pane" lay-filter="dataForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">名称</label>
|
||||
<label class="layui-form-label">映射名称 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="title" class="layui-input" lay-verify="required" placeholder="请输入名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">描述</label>
|
||||
<label class="layui-form-label">映射描述 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="summary" class="layui-input" lay-verify="required" placeholder="请输入描述">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">映射路径</label>
|
||||
<label class="layui-form-label">映射路径 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="path" class="layui-input" lay-verify="required|path" placeholder="请输入映射路径">
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
直接访问网关的路径<br/>
|
||||
不能以 /wg/ 开头 <br/>
|
||||
根路径不能设置通配符,如:/**<br/>
|
||||
支持通配符,如:/p1/**,表示p1后的人和路径都匹配;<br/>
|
||||
路径中的变量用{}包含,如:/p2/{pq1}/{pq2}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">被映射服务</label>
|
||||
<label class="layui-form-label">被映射服务 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="uri" class="layui-input" lay-verify="required|uri" placeholder="请输入服务地址">
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
@ -54,12 +56,38 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">测试接口</label>
|
||||
<label class="layui-form-label">测试接口 *</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="testPath" class="layui-input" lay-verify="required|path" placeholder="填写测试接口地址">
|
||||
<div class="layui-form-mid layui-word-aux">填写测试接口地址,如:/p1/a/b/c</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">路由分类</label>
|
||||
<div class="layui-input-block" id="routeTypeTplBox"></div>
|
||||
<script id="routeTypeTpl" type="text/html">
|
||||
<select name="routeType" lay-filter="routeTypeFilter">
|
||||
<option value="">请选择路由分类</option>
|
||||
{{# for(var i = 0, item; item = d.data[i++];) { }}
|
||||
<option value="{{item.uuid}}">{{item.title}}</option>
|
||||
{{# } }}
|
||||
</select>
|
||||
</script>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">设置路径</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="setPath" class="layui-input" lay-verify="path" placeholder="请设置路径">
|
||||
<div class="layui-form-mid layui-word-aux">
|
||||
网关转发实际地址时的路径,不支持通配符,如:填写 /a 在实际转发时,会把 <b>映射路径</b> 替换为 /a;如果是根路径,填写 / 即可<br/>
|
||||
示例说明:<br/>
|
||||
请求网关的地址为:http:127.0.0.1:9999/baidu<br/>
|
||||
实际的转发地址为:https://www.baidu.com<br/>
|
||||
如果设置路径,那么实际的访问方式为:https://www.baidu.com/<b>baidu</b>,会导致百度无法找到这个路径<br/>
|
||||
将路径设置为 / 之后,实际的请求路径就变为:https://www.baidu.com
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-layout-admin">
|
||||
<div class="layui-input-block">
|
||||
<div class="footer-button-box layui-btn-group">
|
||||
@ -72,21 +100,35 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="assets/layui-v2.6.4/layui/layui.js"></script>
|
||||
<script src="assets/layui/layui.js"></script>
|
||||
<script>
|
||||
layui.config({
|
||||
base: 'assets/layui-v2.6.4/layui/modules/'
|
||||
base: 'assets/layui/modules/'
|
||||
}).extend({}).use(['form', 'laydate', 'laytpl', 'regex'], function(){
|
||||
var $ = layui.$;
|
||||
var form = layui.form;
|
||||
var layer = layui.layer;
|
||||
var regex = layui.regex;
|
||||
var laytpl = layui.laytpl;
|
||||
var uuid = top.restAjax.params(window.location.href).uuid;
|
||||
|
||||
function closeBox() {
|
||||
parent.layer.close(parent.layer.getFrameIndex(window.name));
|
||||
}
|
||||
|
||||
// 初始化路由类型
|
||||
function initRouteType(selectValue) {
|
||||
top.restAjax.get(top.restAjax.path('api/route-type/list', []), {}, null, function(code, data) {
|
||||
laytpl(document.getElementById('routeTypeTpl').innerHTML).render({data: data}, function(html) {
|
||||
document.getElementById('routeTypeTplBox').innerHTML = html;
|
||||
});
|
||||
form.val('dataForm', {routeType: selectValue});
|
||||
form.render('select', 'dataForm');
|
||||
}, function(code, data) {
|
||||
top.dialog.msg(data.msg);
|
||||
});
|
||||
}
|
||||
|
||||
// 初始化内容
|
||||
function initData() {
|
||||
var loadLayerIndex;
|
||||
@ -95,6 +137,7 @@
|
||||
for(var i in data) {
|
||||
dataFormData[i] = data[i] +'';
|
||||
}
|
||||
initRouteType(data.routeType);
|
||||
form.val('dataForm', dataFormData);
|
||||
form.render(null, 'dataForm');
|
||||
}, function(code, data) {
|
||||
@ -148,6 +191,9 @@
|
||||
}
|
||||
},
|
||||
path: function(value, item) {
|
||||
if(!value) {
|
||||
return;
|
||||
}
|
||||
if(!regex.path(value)) {
|
||||
return '路径格式不正确'
|
||||
}
|
||||
|