Commit e347e5b29e754113d2e27d1bef8d22f1e4fb3dfe
1 parent
afc80a49
优化
Showing
20 changed files
with
119 additions
and
109 deletions
doc/xtrade-gateway说明.docx
No preview for this file type
src/main/java/com/diligrp/xtrade/gateway/api/ApiManager.java
@@ -4,13 +4,8 @@ import com.diligrp.xtrade.gateway.config.property.AuthPathProperties; | @@ -4,13 +4,8 @@ import com.diligrp.xtrade.gateway.config.property.AuthPathProperties; | ||
4 | import org.springframework.beans.factory.annotation.Autowired; | 4 | import org.springframework.beans.factory.annotation.Autowired; |
5 | import org.springframework.http.server.PathContainer; | 5 | import org.springframework.http.server.PathContainer; |
6 | import org.springframework.stereotype.Component; | 6 | import org.springframework.stereotype.Component; |
7 | -import org.springframework.web.util.pattern.PathPattern; | ||
8 | 7 | ||
9 | -import java.util.List; | ||
10 | import java.util.Optional; | 8 | import java.util.Optional; |
11 | -import java.util.function.Consumer; | ||
12 | -import java.util.function.Function; | ||
13 | -import java.util.function.Predicate; | ||
14 | 9 | ||
15 | /** | 10 | /** |
16 | * @Auther: miaoguoxin | 11 | * @Auther: miaoguoxin |
src/main/java/com/diligrp/xtrade/gateway/application/TestAggregationApplication.java
@@ -4,6 +4,8 @@ import com.diligrp.xtrade.gateway.common.annotation.DispatchMapping; | @@ -4,6 +4,8 @@ import com.diligrp.xtrade.gateway.common.annotation.DispatchMapping; | ||
4 | import com.diligrp.xtrade.gateway.domain.TestRequestDto; | 4 | import com.diligrp.xtrade.gateway.domain.TestRequestDto; |
5 | import com.diligrp.xtrade.gateway.support.dispatch.DispatchContext; | 5 | import com.diligrp.xtrade.gateway.support.dispatch.DispatchContext; |
6 | import com.diligrp.xtrade.gateway.support.dispatch.RequestDispatcher; | 6 | import com.diligrp.xtrade.gateway.support.dispatch.RequestDispatcher; |
7 | +import org.springframework.beans.factory.annotation.Autowired; | ||
8 | +import org.springframework.http.server.reactive.ServerHttpRequest; | ||
7 | import org.springframework.stereotype.Component; | 9 | import org.springframework.stereotype.Component; |
8 | import org.springframework.validation.annotation.Validated; | 10 | import org.springframework.validation.annotation.Validated; |
9 | 11 | ||
@@ -19,13 +21,16 @@ import javax.validation.groups.Default; | @@ -19,13 +21,16 @@ import javax.validation.groups.Default; | ||
19 | @DispatchMapping | 21 | @DispatchMapping |
20 | public class TestAggregationApplication { | 22 | public class TestAggregationApplication { |
21 | 23 | ||
24 | + @Autowired | ||
25 | + private ServerHttpRequest serverHttpRequest; | ||
26 | + | ||
22 | @DispatchMapping("/test") | 27 | @DispatchMapping("/test") |
23 | public String test(DispatchContext<TestRequestDto> dispatchContext){ | 28 | public String test(DispatchContext<TestRequestDto> dispatchContext){ |
24 | return "ffff"; | 29 | return "ffff"; |
25 | } | 30 | } |
26 | 31 | ||
27 | @DispatchMapping("test2") | 32 | @DispatchMapping("test2") |
28 | - public void test2(@Validated(value = Default.class) DispatchContext<TestRequestDto> dispatchContext){ | 33 | + public void test2(@Validated DispatchContext<TestRequestDto> dispatchContext){ |
29 | 34 | ||
30 | } | 35 | } |
31 | 36 |
src/main/java/com/diligrp/xtrade/gateway/common/constant/GatewayAttrType.java
@@ -16,9 +16,9 @@ public enum GatewayAttrType implements IEnumType { | @@ -16,9 +16,9 @@ public enum GatewayAttrType implements IEnumType { | ||
16 | /** | 16 | /** |
17 | * 编码 | 17 | * 编码 |
18 | */ | 18 | */ |
19 | - private int value; | 19 | + private final int value; |
20 | 20 | ||
21 | - private String desc; | 21 | + private final String desc; |
22 | 22 | ||
23 | 23 | ||
24 | GatewayAttrType(int value, String desc) { | 24 | GatewayAttrType(int value, String desc) { |
src/main/java/com/diligrp/xtrade/gateway/common/constant/GatewayConst.java
1 | package com.diligrp.xtrade.gateway.common.constant; | 1 | package com.diligrp.xtrade.gateway.common.constant; |
2 | 2 | ||
3 | +import org.springframework.cloud.gateway.filter.factory.StripPrefixGatewayFilterFactory; | ||
4 | + | ||
3 | import java.util.concurrent.atomic.AtomicBoolean; | 5 | import java.util.concurrent.atomic.AtomicBoolean; |
4 | 6 | ||
5 | /** | 7 | /** |
@@ -15,7 +17,11 @@ public class GatewayConst { | @@ -15,7 +17,11 @@ public class GatewayConst { | ||
15 | /**缓存Api配置key*/ | 17 | /**缓存Api配置key*/ |
16 | public static final String CACHE_API_OBJECT_KEY = "cachedApiConfigObject"; | 18 | public static final String CACHE_API_OBJECT_KEY = "cachedApiConfigObject"; |
17 | 19 | ||
18 | - public static final int CACHE_BODY_FILTER_ORDER = -10; | ||
19 | - | ||
20 | - public static final int AUTH_FILTER_ORDER = -9; | 20 | + /* 自定义的过滤器顺序都从100开始(除ResponseBodyRead),避免顺序问题*/ |
21 | + /**缓存请求体过滤器*/ | ||
22 | + public static final int CACHE_BODY_FILTER_ORDER = 100; | ||
23 | + /** 权限过滤器 */ | ||
24 | + public static final int AUTH_FILTER_ORDER = 101; | ||
25 | + /**分发器,需要保证在最后执行,并且在10000之前*/ | ||
26 | + public static final int DISPATCH_FACTORY_FILTER_ORDER = 150; | ||
21 | } | 27 | } |
src/main/java/com/diligrp/xtrade/gateway/common/utils/PathUtils.java
@@ -14,7 +14,7 @@ import java.util.concurrent.CopyOnWriteArrayList; | @@ -14,7 +14,7 @@ import java.util.concurrent.CopyOnWriteArrayList; | ||
14 | * @Date: 2020/4/15 10:37 | 14 | * @Date: 2020/4/15 10:37 |
15 | */ | 15 | */ |
16 | public class PathUtils { | 16 | public class PathUtils { |
17 | - private static PathPatternParser pathPatternParser = new PathPatternParser(); | 17 | + private static final PathPatternParser PATH_PATTERN_PARSER = new PathPatternParser(); |
18 | 18 | ||
19 | /** | 19 | /** |
20 | * 多个路径拼接成一个标准uri,ex: /test + gateway = /test/gateway | 20 | * 多个路径拼接成一个标准uri,ex: /test + gateway = /test/gateway |
@@ -95,7 +95,7 @@ public class PathUtils { | @@ -95,7 +95,7 @@ public class PathUtils { | ||
95 | pathPatterns.clear(); | 95 | pathPatterns.clear(); |
96 | } | 96 | } |
97 | for (String path : paths) { | 97 | for (String path : paths) { |
98 | - PathPattern pathPattern = pathPatternParser.parse(path); | 98 | + PathPattern pathPattern = PATH_PATTERN_PARSER.parse(path); |
99 | pathPatterns.add(pathPattern); | 99 | pathPatterns.add(pathPattern); |
100 | } | 100 | } |
101 | return pathPatterns; | 101 | return pathPatterns; |
src/main/java/com/diligrp/xtrade/gateway/common/utils/ValidateUtils.java
@@ -31,8 +31,8 @@ public class ValidateUtils { | @@ -31,8 +31,8 @@ public class ValidateUtils { | ||
31 | validate(params, new Class[]{}); | 31 | validate(params, new Class[]{}); |
32 | } | 32 | } |
33 | 33 | ||
34 | - public static void validate(Object params, Class... groups) { | ||
35 | - Set<Class> groupSet = new HashSet<>(); | 34 | + public static void validate(Object params, Class<?>... groups) { |
35 | + Set<Class<?>> groupSet = new HashSet<>(); | ||
36 | groupSet.add(Default.class); | 36 | groupSet.add(Default.class); |
37 | if (groups != null && groups.length > 0) { | 37 | if (groups != null && groups.length > 0) { |
38 | groupSet.addAll(Arrays.asList(groups)); | 38 | groupSet.addAll(Arrays.asList(groups)); |
src/main/java/com/diligrp/xtrade/gateway/controller/TestController.java
1 | package com.diligrp.xtrade.gateway.controller; | 1 | package com.diligrp.xtrade.gateway.controller; |
2 | 2 | ||
3 | +import com.diligrp.xtrade.gateway.domain.TestRequestDto; | ||
3 | import com.diligrp.xtrade.shared.domain.Message; | 4 | import com.diligrp.xtrade.shared.domain.Message; |
5 | +import com.diligrp.xtrade.shared.util.DateUtils; | ||
4 | import com.google.common.collect.Lists; | 6 | import com.google.common.collect.Lists; |
5 | import org.springframework.beans.factory.annotation.Autowired; | 7 | import org.springframework.beans.factory.annotation.Autowired; |
6 | import org.springframework.beans.factory.annotation.Value; | 8 | import org.springframework.beans.factory.annotation.Value; |
@@ -8,12 +10,18 @@ import org.springframework.cloud.context.config.annotation.RefreshScope; | @@ -8,12 +10,18 @@ import org.springframework.cloud.context.config.annotation.RefreshScope; | ||
8 | import org.springframework.cloud.gateway.config.GatewayProperties; | 10 | import org.springframework.cloud.gateway.config.GatewayProperties; |
9 | import org.springframework.cloud.gateway.route.RouteDefinition; | 11 | import org.springframework.cloud.gateway.route.RouteDefinition; |
10 | import org.springframework.http.server.PathContainer; | 12 | import org.springframework.http.server.PathContainer; |
13 | +import org.springframework.validation.annotation.Validated; | ||
11 | import org.springframework.web.bind.annotation.GetMapping; | 14 | import org.springframework.web.bind.annotation.GetMapping; |
15 | +import org.springframework.web.bind.annotation.PathVariable; | ||
12 | import org.springframework.web.bind.annotation.RequestMapping; | 16 | import org.springframework.web.bind.annotation.RequestMapping; |
13 | import org.springframework.web.bind.annotation.RestController; | 17 | import org.springframework.web.bind.annotation.RestController; |
14 | import org.springframework.web.util.pattern.PathPattern; | 18 | import org.springframework.web.util.pattern.PathPattern; |
15 | import org.springframework.web.util.pattern.PathPatternParser; | 19 | import org.springframework.web.util.pattern.PathPatternParser; |
16 | 20 | ||
21 | +import javax.validation.constraints.Min; | ||
22 | +import javax.validation.constraints.NotBlank; | ||
23 | +import javax.validation.groups.Default; | ||
24 | +import java.time.LocalDateTime; | ||
17 | import java.util.ArrayList; | 25 | import java.util.ArrayList; |
18 | import java.util.List; | 26 | import java.util.List; |
19 | import java.util.Optional; | 27 | import java.util.Optional; |
@@ -26,22 +34,21 @@ import java.util.Optional; | @@ -26,22 +34,21 @@ import java.util.Optional; | ||
26 | @RestController | 34 | @RestController |
27 | @RequestMapping("/test") | 35 | @RequestMapping("/test") |
28 | @RefreshScope | 36 | @RefreshScope |
37 | +@Validated | ||
29 | public class TestController { | 38 | public class TestController { |
30 | - private static PathPatternParser pathPatternParser = new PathPatternParser(); | ||
31 | @Autowired | 39 | @Autowired |
32 | private GatewayProperties gatewayProperties; | 40 | private GatewayProperties gatewayProperties; |
33 | @Value("${ribbon.ServerListRefreshInterval}") | 41 | @Value("${ribbon.ServerListRefreshInterval}") |
34 | private String interval; | 42 | private String interval; |
35 | 43 | ||
36 | - @GetMapping("/gateway") | ||
37 | - public Message<List<RouteDefinition>> test() { | 44 | + @GetMapping("/gateway/{id}") |
45 | + public Message test(@Min(value = 5,message = "id不能小于5") @PathVariable Integer id) { | ||
38 | List<RouteDefinition> routes = gatewayProperties.getRoutes(); | 46 | List<RouteDefinition> routes = gatewayProperties.getRoutes(); |
39 | - return Message.builder().success(routes); | ||
40 | - //throw new RuntimeException("gfdg"); | 47 | + return Message.builder().success(); |
41 | } | 48 | } |
42 | 49 | ||
43 | @GetMapping("/test_dynamic") | 50 | @GetMapping("/test_dynamic") |
44 | - public Message<String> test1() { | ||
45 | - return Message.builder().success(interval); | 51 | + public Message<String> test1( TestRequestDto testRequestDto) { |
52 | + throw new RuntimeException("fffff"); | ||
46 | } | 53 | } |
47 | } | 54 | } |
src/main/java/com/diligrp/xtrade/gateway/domain/TestRequestDto.java
1 | package com.diligrp.xtrade.gateway.domain; | 1 | package com.diligrp.xtrade.gateway.domain; |
2 | 2 | ||
3 | +import com.fasterxml.jackson.annotation.JsonFormat; | ||
3 | import lombok.Data; | 4 | import lombok.Data; |
4 | 5 | ||
5 | import javax.validation.constraints.NotBlank; | 6 | import javax.validation.constraints.NotBlank; |
7 | +import javax.validation.groups.Default; | ||
8 | +import java.time.LocalDateTime; | ||
6 | 9 | ||
7 | /** | 10 | /** |
8 | * @Auther: miaoguoxin | 11 | * @Auther: miaoguoxin |
@@ -12,5 +15,6 @@ import javax.validation.constraints.NotBlank; | @@ -12,5 +15,6 @@ import javax.validation.constraints.NotBlank; | ||
12 | public class TestRequestDto { | 15 | public class TestRequestDto { |
13 | @NotBlank(message = "{request.username.not.blank}") | 16 | @NotBlank(message = "{request.username.not.blank}") |
14 | private String username; | 17 | private String username; |
15 | - | 18 | + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
19 | + private LocalDateTime localDateTime; | ||
16 | } | 20 | } |
src/main/java/com/diligrp/xtrade/gateway/filters/factory/DispatchGatewayFilterFactory.java
1 | package com.diligrp.xtrade.gateway.filters.factory; | 1 | package com.diligrp.xtrade.gateway.filters.factory; |
2 | 2 | ||
3 | +import com.diligrp.xtrade.gateway.common.constant.GatewayConst; | ||
3 | import com.diligrp.xtrade.gateway.common.utils.ResponseUtils; | 4 | import com.diligrp.xtrade.gateway.common.utils.ResponseUtils; |
4 | import com.diligrp.xtrade.gateway.support.dispatch.RequestDispatcher; | 5 | import com.diligrp.xtrade.gateway.support.dispatch.RequestDispatcher; |
5 | import com.diligrp.xtrade.shared.domain.Message; | 6 | import com.diligrp.xtrade.shared.domain.Message; |
@@ -7,12 +8,15 @@ import lombok.Data; | @@ -7,12 +8,15 @@ import lombok.Data; | ||
7 | import org.reactivestreams.Publisher; | 8 | import org.reactivestreams.Publisher; |
8 | import org.springframework.beans.factory.annotation.Autowired; | 9 | import org.springframework.beans.factory.annotation.Autowired; |
9 | import org.springframework.cloud.gateway.filter.GatewayFilter; | 10 | import org.springframework.cloud.gateway.filter.GatewayFilter; |
11 | +import org.springframework.cloud.gateway.filter.GatewayFilterChain; | ||
10 | import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; | 12 | import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; |
13 | +import org.springframework.core.Ordered; | ||
11 | import org.springframework.core.io.buffer.DataBuffer; | 14 | import org.springframework.core.io.buffer.DataBuffer; |
12 | import org.springframework.http.HttpHeaders; | 15 | import org.springframework.http.HttpHeaders; |
13 | import org.springframework.http.MediaType; | 16 | import org.springframework.http.MediaType; |
14 | import org.springframework.http.server.reactive.ServerHttpResponseDecorator; | 17 | import org.springframework.http.server.reactive.ServerHttpResponseDecorator; |
15 | import org.springframework.stereotype.Component; | 18 | import org.springframework.stereotype.Component; |
19 | +import org.springframework.web.server.ServerWebExchange; | ||
16 | import reactor.core.publisher.Mono; | 20 | import reactor.core.publisher.Mono; |
17 | 21 | ||
18 | import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.CACHE_REQUEST_BODY_OBJECT_KEY; | 22 | import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.CACHE_REQUEST_BODY_OBJECT_KEY; |
@@ -34,30 +38,35 @@ public class DispatchGatewayFilterFactory extends AbstractGatewayFilterFactory<D | @@ -34,30 +38,35 @@ public class DispatchGatewayFilterFactory extends AbstractGatewayFilterFactory<D | ||
34 | 38 | ||
35 | @Override | 39 | @Override |
36 | public GatewayFilter apply(Config config) { | 40 | public GatewayFilter apply(Config config) { |
37 | - return (exchange, chain) -> { | 41 | + return new DispatchGatewayFilter(requestDispatcher); |
42 | + } | ||
43 | + | ||
44 | + private static class DispatchGatewayFilter implements GatewayFilter,Ordered{ | ||
45 | + private final RequestDispatcher requestDispatcher; | ||
46 | + | ||
47 | + public DispatchGatewayFilter(RequestDispatcher requestDispatcher) { | ||
48 | + this.requestDispatcher = requestDispatcher; | ||
49 | + } | ||
50 | + | ||
51 | + @Override | ||
52 | + public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { | ||
38 | String rawPath = exchange.getRequest().getURI().getRawPath(); | 53 | String rawPath = exchange.getRequest().getURI().getRawPath(); |
39 | String paramsJson = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY); | 54 | String paramsJson = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY); |
40 | - Message message = requestDispatcher.executeMethod(rawPath, paramsJson,exchange); | 55 | + Message message = requestDispatcher.executeMethod(rawPath, paramsJson, exchange); |
41 | //throw new RuntimeException("gggg"); | 56 | //throw new RuntimeException("gggg"); |
42 | - return ResponseUtils.writeResponse( | ||
43 | - new ServerHttpResponseDecorator(exchange.getResponse()) { | ||
44 | - @Override | ||
45 | - public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { | ||
46 | - //这里需要设置响应content-Type,不然后面的过滤器拿不到这个值会报错 | ||
47 | - exchange.getAttributes().put(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR, MediaType.APPLICATION_JSON_VALUE); | ||
48 | - String originalResponseContentType = exchange | ||
49 | - .getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR); | ||
50 | - HttpHeaders httpHeaders = exchange.getResponse().getHeaders(); | ||
51 | - httpHeaders.add(HttpHeaders.CONTENT_TYPE, originalResponseContentType); | ||
52 | - return super.writeWith(body); | ||
53 | - } | ||
54 | - }, message); | ||
55 | - }; | 57 | + exchange.getAttributes().put(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR, MediaType.APPLICATION_JSON_VALUE); |
58 | + return ResponseUtils.writeResponse(exchange.getResponse(),message); | ||
59 | + } | ||
60 | + | ||
61 | + @Override | ||
62 | + public int getOrder() { | ||
63 | + return GatewayConst.DISPATCH_FACTORY_FILTER_ORDER; | ||
64 | + } | ||
56 | } | 65 | } |
57 | 66 | ||
67 | + | ||
58 | @Data | 68 | @Data |
59 | public static class Config { | 69 | public static class Config { |
60 | - private String keyResolverName; | ||
61 | } | 70 | } |
62 | 71 | ||
63 | } | 72 | } |
src/main/java/com/diligrp/xtrade/gateway/filters/global/AuthGlobalFilter.java
@@ -2,31 +2,24 @@ package com.diligrp.xtrade.gateway.filters.global; | @@ -2,31 +2,24 @@ package com.diligrp.xtrade.gateway.filters.global; | ||
2 | 2 | ||
3 | import com.diligrp.xtrade.gateway.api.ApiManager; | 3 | import com.diligrp.xtrade.gateway.api.ApiManager; |
4 | import com.diligrp.xtrade.gateway.common.utils.ResponseUtils; | 4 | import com.diligrp.xtrade.gateway.common.utils.ResponseUtils; |
5 | -import com.diligrp.xtrade.shared.domain.Message; | ||
6 | -import com.diligrp.xtrade.shared.util.JsonUtils; | ||
7 | import lombok.extern.slf4j.Slf4j; | 5 | import lombok.extern.slf4j.Slf4j; |
8 | import org.springframework.beans.factory.annotation.Autowired; | 6 | import org.springframework.beans.factory.annotation.Autowired; |
9 | import org.springframework.cloud.gateway.filter.GatewayFilterChain; | 7 | import org.springframework.cloud.gateway.filter.GatewayFilterChain; |
10 | import org.springframework.cloud.gateway.filter.GlobalFilter; | 8 | import org.springframework.cloud.gateway.filter.GlobalFilter; |
11 | import org.springframework.core.Ordered; | 9 | import org.springframework.core.Ordered; |
12 | -import org.springframework.core.io.buffer.PooledDataBuffer; | ||
13 | -import org.springframework.http.HttpStatus; | ||
14 | import org.springframework.http.MediaType; | 10 | import org.springframework.http.MediaType; |
15 | -import org.springframework.http.server.reactive.ServerHttpRequest; | ||
16 | import org.springframework.http.server.reactive.ServerHttpResponse; | 11 | import org.springframework.http.server.reactive.ServerHttpResponse; |
17 | import org.springframework.stereotype.Component; | 12 | import org.springframework.stereotype.Component; |
18 | import org.springframework.web.server.ServerWebExchange; | 13 | import org.springframework.web.server.ServerWebExchange; |
19 | -import reactor.core.Disposable; | ||
20 | -import reactor.core.publisher.Flux; | ||
21 | import reactor.core.publisher.Mono; | 14 | import reactor.core.publisher.Mono; |
22 | 15 | ||
23 | -import java.nio.charset.Charset; | ||
24 | -import java.nio.charset.StandardCharsets; | ||
25 | -import java.util.Map; | 16 | +import java.net.URI; |
17 | +import java.util.LinkedHashSet; | ||
18 | +import java.util.Optional; | ||
26 | 19 | ||
27 | import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.AUTH_FILTER_ORDER; | 20 | import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.AUTH_FILTER_ORDER; |
28 | -import static com.diligrp.xtrade.gateway.common.constant.GatewayConst.CACHE_REQUEST_BODY_OBJECT_KEY; | ||
29 | -import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR; | 21 | +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR; |
22 | +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR; | ||
30 | 23 | ||
31 | /** | 24 | /** |
32 | * @Auther: miaoguoxin | 25 | * @Auther: miaoguoxin |
@@ -38,17 +31,27 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.C | @@ -38,17 +31,27 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.C | ||
38 | public class AuthGlobalFilter implements GlobalFilter, Ordered { | 31 | public class AuthGlobalFilter implements GlobalFilter, Ordered { |
39 | @Autowired | 32 | @Autowired |
40 | private ApiManager apiManager; | 33 | private ApiManager apiManager; |
34 | + | ||
41 | @Override | 35 | @Override |
42 | public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { | 36 | public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { |
43 | - String rawPath = exchange.getRequest().getURI().getRawPath(); | 37 | + String originalUri = getOriginalUri(exchange); |
44 | ServerHttpResponse response = exchange.getResponse(); | 38 | ServerHttpResponse response = exchange.getResponse(); |
45 | //排除在外的Uri跳过权限 | 39 | //排除在外的Uri跳过权限 |
46 | - if (apiManager.isExcludePathMatch(rawPath)){ | ||
47 | - return chain.filter(exchange); | 40 | + if (apiManager.isExcludePathMatch(originalUri)) { |
41 | + // return chain.filter(exchange); | ||
42 | + throw new RuntimeException("异常测试"); | ||
48 | } | 43 | } |
44 | + exchange.getAttributes().put(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR, MediaType.APPLICATION_JSON_VALUE); | ||
49 | return ResponseUtils.writeForbidden(response); | 45 | return ResponseUtils.writeForbidden(response); |
50 | } | 46 | } |
51 | 47 | ||
48 | + private static String getOriginalUri(ServerWebExchange exchange) { | ||
49 | + LinkedHashSet<URI> uris = exchange.getAttribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR); | ||
50 | + return Optional.ofNullable(uris) | ||
51 | + .flatMap(us -> us.stream().findFirst().map(URI::getRawPath)) | ||
52 | + .orElse(exchange.getRequest().getURI().getRawPath()); | ||
53 | + } | ||
54 | + | ||
52 | @Override | 55 | @Override |
53 | public int getOrder() { | 56 | public int getOrder() { |
54 | return AUTH_FILTER_ORDER; | 57 | return AUTH_FILTER_ORDER; |
src/main/java/com/diligrp/xtrade/gateway/filters/global/ResponseReadBodyGlobalFilter.java
@@ -77,7 +77,7 @@ public class ResponseReadBodyGlobalFilter implements GlobalFilter, Ordered { | @@ -77,7 +77,7 @@ public class ResponseReadBodyGlobalFilter implements GlobalFilter, Ordered { | ||
77 | HttpHeaders httpHeaders = new HttpHeaders(); | 77 | HttpHeaders httpHeaders = new HttpHeaders(); |
78 | httpHeaders.setContentType(originalResponseContentType); | 78 | httpHeaders.setContentType(originalResponseContentType); |
79 | 79 | ||
80 | - ClientResponse clientResponse = this.prepareClientResponse( exchange.getResponse().getStatusCode(),body, httpHeaders); | 80 | + ClientResponse clientResponse = this.prepareClientResponse(exchange.getResponse().getStatusCode(),body, httpHeaders); |
81 | Mono<String> bodyMono = clientResponse.bodyToMono(String.class); | 81 | Mono<String> bodyMono = clientResponse.bodyToMono(String.class); |
82 | return bodyMono.flatMap(respBody -> { | 82 | return bodyMono.flatMap(respBody -> { |
83 | //打印返回响应日志 | 83 | //打印返回响应日志 |
@@ -100,9 +100,8 @@ public class ResponseReadBodyGlobalFilter implements GlobalFilter, Ordered { | @@ -100,9 +100,8 @@ public class ResponseReadBodyGlobalFilter implements GlobalFilter, Ordered { | ||
100 | 100 | ||
101 | private ClientResponse prepareClientResponse(HttpStatus httpStatus, Publisher<? extends DataBuffer> body, | 101 | private ClientResponse prepareClientResponse(HttpStatus httpStatus, Publisher<? extends DataBuffer> body, |
102 | HttpHeaders httpHeaders) { | 102 | HttpHeaders httpHeaders) { |
103 | - ClientResponse.Builder builder; | ||
104 | - builder = ClientResponse.create(httpStatus, messageReaders); | ||
105 | - return builder.headers(headers -> headers.putAll(httpHeaders)) | 103 | + return ClientResponse.create(httpStatus, messageReaders) |
104 | + .headers(headers -> headers.putAll(httpHeaders)) | ||
106 | .body(Flux.from(body)).build(); | 105 | .body(Flux.from(body)).build(); |
107 | } | 106 | } |
108 | 107 |
src/main/java/com/diligrp/xtrade/gateway/filters/web/ReactiveContextWebFilter.java
1 | package com.diligrp.xtrade.gateway.filters.web; | 1 | package com.diligrp.xtrade.gateway.filters.web; |
2 | 2 | ||
3 | import com.diligrp.xtrade.gateway.support.context.ReactiveExchangeContextHolder; | 3 | import com.diligrp.xtrade.gateway.support.context.ReactiveExchangeContextHolder; |
4 | +import lombok.extern.slf4j.Slf4j; | ||
4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; | 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; |
5 | import org.springframework.http.server.reactive.ServerHttpRequest; | 6 | import org.springframework.http.server.reactive.ServerHttpRequest; |
6 | import org.springframework.stereotype.Component; | 7 | import org.springframework.stereotype.Component; |
@@ -10,6 +11,8 @@ import org.springframework.web.server.WebFilterChain; | @@ -10,6 +11,8 @@ import org.springframework.web.server.WebFilterChain; | ||
10 | import reactor.core.publisher.Mono; | 11 | import reactor.core.publisher.Mono; |
11 | import reactor.core.publisher.SignalType; | 12 | import reactor.core.publisher.SignalType; |
12 | 13 | ||
14 | +import java.util.function.Consumer; | ||
15 | + | ||
13 | /** | 16 | /** |
14 | * @Auther: miaoguoxin | 17 | * @Auther: miaoguoxin |
15 | * @Date: 2020/4/16 09:17 | 18 | * @Date: 2020/4/16 09:17 |
@@ -17,9 +20,11 @@ import reactor.core.publisher.SignalType; | @@ -17,9 +20,11 @@ import reactor.core.publisher.SignalType; | ||
17 | */ | 20 | */ |
18 | @Component | 21 | @Component |
19 | @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) | 22 | @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) |
23 | +@Slf4j | ||
20 | public class ReactiveContextWebFilter implements WebFilter { | 24 | public class ReactiveContextWebFilter implements WebFilter { |
21 | @Override | 25 | @Override |
22 | public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { | 26 | public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { |
27 | + long l = System.currentTimeMillis(); | ||
23 | ServerHttpRequest request = exchange.getRequest(); | 28 | ServerHttpRequest request = exchange.getRequest(); |
24 | String path = request.getURI().getRawPath(); | 29 | String path = request.getURI().getRawPath(); |
25 | if (path.contains("favicon.ico")) { | 30 | if (path.contains("favicon.ico")) { |
@@ -27,7 +32,8 @@ public class ReactiveContextWebFilter implements WebFilter { | @@ -27,7 +32,8 @@ public class ReactiveContextWebFilter implements WebFilter { | ||
27 | } | 32 | } |
28 | ReactiveExchangeContextHolder.put(exchange); | 33 | ReactiveExchangeContextHolder.put(exchange); |
29 | return chain.filter(exchange).doFinally(signalType -> { | 34 | return chain.filter(exchange).doFinally(signalType -> { |
30 | - ReactiveExchangeContextHolder.remove(); | 35 | + ReactiveExchangeContextHolder.remove(); |
36 | + log.info("消耗时间:{}",System.currentTimeMillis()-l); | ||
31 | }); | 37 | }); |
32 | } | 38 | } |
33 | } | 39 | } |
src/main/java/com/diligrp/xtrade/gateway/route/GatewayResourcesLoader.java
@@ -16,7 +16,7 @@ public class GatewayResourcesLoader implements ApplicationRunner { | @@ -16,7 +16,7 @@ public class GatewayResourcesLoader implements ApplicationRunner { | ||
16 | private DynamicRouteLoaderIntf dynamicRouteLoader; | 16 | private DynamicRouteLoaderIntf dynamicRouteLoader; |
17 | 17 | ||
18 | @Override | 18 | @Override |
19 | - public void run(ApplicationArguments args) throws Exception { | 19 | + public void run(ApplicationArguments args) { |
20 | dynamicRouteLoader.init(); | 20 | dynamicRouteLoader.init(); |
21 | } | 21 | } |
22 | } | 22 | } |
src/main/java/com/diligrp/xtrade/gateway/route/impl/CloudRouteResourceLoader.java
@@ -34,7 +34,7 @@ public class CloudRouteResourceLoader implements DynamicRouteLoaderIntf { | @@ -34,7 +34,7 @@ public class CloudRouteResourceLoader implements DynamicRouteLoaderIntf { | ||
34 | /**标记当前gatewayproties的hash值,用于判断配置是否更新过*/ | 34 | /**标记当前gatewayproties的hash值,用于判断配置是否更新过*/ |
35 | private static int gatewayPropertiesHash; | 35 | private static int gatewayPropertiesHash; |
36 | /**防止重复初始化的标记*/ | 36 | /**防止重复初始化的标记*/ |
37 | - private static AtomicBoolean hasInit = new AtomicBoolean(false); | 37 | + private static final AtomicBoolean HAS_INIT = new AtomicBoolean(false); |
38 | 38 | ||
39 | private final static String GROUP = "DEFAULT_GROUP"; | 39 | private final static String GROUP = "DEFAULT_GROUP"; |
40 | private final static String ROUTE_CONFIG_NAME = "route.properties"; | 40 | private final static String ROUTE_CONFIG_NAME = "route.properties"; |
@@ -57,7 +57,7 @@ public class CloudRouteResourceLoader implements DynamicRouteLoaderIntf { | @@ -57,7 +57,7 @@ public class CloudRouteResourceLoader implements DynamicRouteLoaderIntf { | ||
57 | 57 | ||
58 | @Override | 58 | @Override |
59 | public void init() { | 59 | public void init() { |
60 | - if (hasInit.compareAndSet(false, true)) { | 60 | + if (HAS_INIT.compareAndSet(false, true)) { |
61 | this.loadRoutes(); | 61 | this.loadRoutes(); |
62 | //用来判断routes是否改变过,避免无效刷新 | 62 | //用来判断routes是否改变过,避免无效刷新 |
63 | gatewayPropertiesHash = gatewayProperties.getRoutes().hashCode(); | 63 | gatewayPropertiesHash = gatewayProperties.getRoutes().hashCode(); |
src/main/java/com/diligrp/xtrade/gateway/support/context/ReactiveRequestBeanProcessor.java renamed to src/main/java/com/diligrp/xtrade/gateway/support/context/ReactiveWebContextBeanProcessor.java
@@ -13,10 +13,9 @@ import java.io.Serializable; | @@ -13,10 +13,9 @@ import java.io.Serializable; | ||
13 | /** | 13 | /** |
14 | * @Auther: miaoguoxin | 14 | * @Auther: miaoguoxin |
15 | * @Date: 2020/4/16 09:13 | 15 | * @Date: 2020/4/16 09:13 |
16 | - * @Description: | ||
17 | */ | 16 | */ |
18 | @Component | 17 | @Component |
19 | -public class ReactiveRequestBeanProcessor implements BeanFactoryPostProcessor { | 18 | +public class ReactiveWebContextBeanProcessor implements BeanFactoryPostProcessor { |
20 | 19 | ||
21 | @Override | 20 | @Override |
22 | public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { | 21 | public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { |
src/main/java/com/diligrp/xtrade/gateway/support/dispatch/RequestDispatcher.java
1 | package com.diligrp.xtrade.gateway.support.dispatch; | 1 | package com.diligrp.xtrade.gateway.support.dispatch; |
2 | 2 | ||
3 | -import com.diligrp.xtrade.gateway.application.TestAggregationApplication; | ||
4 | import com.diligrp.xtrade.gateway.common.utils.PathUtils; | 3 | import com.diligrp.xtrade.gateway.common.utils.PathUtils; |
5 | import com.diligrp.xtrade.gateway.common.utils.ValidateUtils; | 4 | import com.diligrp.xtrade.gateway.common.utils.ValidateUtils; |
6 | -import com.diligrp.xtrade.gateway.domain.TestRequestDto; | ||
7 | import com.diligrp.xtrade.gateway.exception.GatewayParamNotValidException; | 5 | import com.diligrp.xtrade.gateway.exception.GatewayParamNotValidException; |
8 | import com.diligrp.xtrade.gateway.exception.GatewayServiceException; | 6 | import com.diligrp.xtrade.gateway.exception.GatewayServiceException; |
9 | import com.diligrp.xtrade.gateway.filters.factory.DispatchGatewayFilterFactory; | 7 | import com.diligrp.xtrade.gateway.filters.factory.DispatchGatewayFilterFactory; |
10 | -import com.diligrp.xtrade.gateway.route.DynamicRouteLoaderIntf; | ||
11 | -import com.diligrp.xtrade.gateway.route.impl.MysqlRouteResourceLoader; | ||
12 | import com.diligrp.xtrade.shared.domain.Message; | 8 | import com.diligrp.xtrade.shared.domain.Message; |
13 | -import com.diligrp.xtrade.shared.type.SystemCode; | 9 | +import com.diligrp.xtrade.shared.type.ErrorCode; |
14 | import com.diligrp.xtrade.shared.util.JsonUtils; | 10 | import com.diligrp.xtrade.shared.util.JsonUtils; |
15 | import com.google.common.base.Strings; | 11 | import com.google.common.base.Strings; |
16 | import lombok.extern.slf4j.Slf4j; | 12 | import lombok.extern.slf4j.Slf4j; |
17 | -import org.bouncycastle.util.Arrays; | ||
18 | import org.springframework.beans.factory.annotation.Autowired; | 13 | import org.springframework.beans.factory.annotation.Autowired; |
19 | import org.springframework.cloud.gateway.support.NotFoundException; | 14 | import org.springframework.cloud.gateway.support.NotFoundException; |
20 | import org.springframework.context.ApplicationContext; | 15 | import org.springframework.context.ApplicationContext; |
@@ -22,13 +17,10 @@ import org.springframework.stereotype.Component; | @@ -22,13 +17,10 @@ import org.springframework.stereotype.Component; | ||
22 | import org.springframework.validation.annotation.Validated; | 17 | import org.springframework.validation.annotation.Validated; |
23 | import org.springframework.web.server.ResponseStatusException; | 18 | import org.springframework.web.server.ResponseStatusException; |
24 | import org.springframework.web.server.ServerWebExchange; | 19 | import org.springframework.web.server.ServerWebExchange; |
25 | -import org.springframework.web.server.ServerWebInputException; | ||
26 | import org.springframework.web.util.pattern.PathPattern; | 20 | import org.springframework.web.util.pattern.PathPattern; |
27 | 21 | ||
28 | import java.lang.reflect.InvocationTargetException; | 22 | import java.lang.reflect.InvocationTargetException; |
29 | import java.lang.reflect.Method; | 23 | import java.lang.reflect.Method; |
30 | -import java.lang.reflect.ParameterizedType; | ||
31 | -import java.lang.reflect.Type; | ||
32 | import java.util.List; | 24 | import java.util.List; |
33 | import java.util.Map; | 25 | import java.util.Map; |
34 | import java.util.Optional; | 26 | import java.util.Optional; |
@@ -38,7 +30,7 @@ import java.util.concurrent.atomic.AtomicBoolean; | @@ -38,7 +30,7 @@ import java.util.concurrent.atomic.AtomicBoolean; | ||
38 | 30 | ||
39 | /** | 31 | /** |
40 | * @Auther: miaoguoxin | 32 | * @Auther: miaoguoxin |
41 | - * @Date: 2020/4/15 09:29 | 33 | + * @date: 2020/4/15 09:29 |
42 | * @Description: 映射分发器, 用于聚合服务执行对应方法 | 34 | * @Description: 映射分发器, 用于聚合服务执行对应方法 |
43 | * {@link DispatchGatewayFilterFactory} | 35 | * {@link DispatchGatewayFilterFactory} |
44 | */ | 36 | */ |
@@ -52,7 +44,7 @@ public class RequestDispatcher { | @@ -52,7 +44,7 @@ public class RequestDispatcher { | ||
52 | 44 | ||
53 | private static final List<PathPattern> PATH_PATTERNS = new CopyOnWriteArrayList<>(); | 45 | private static final List<PathPattern> PATH_PATTERNS = new CopyOnWriteArrayList<>(); |
54 | 46 | ||
55 | - private static AtomicBoolean hasInit = new AtomicBoolean(false); | 47 | + private static final AtomicBoolean HAS_INIT = new AtomicBoolean(false); |
56 | 48 | ||
57 | @Autowired | 49 | @Autowired |
58 | private ApplicationContext applicationContext; | 50 | private ApplicationContext applicationContext; |
@@ -63,9 +55,9 @@ public class RequestDispatcher { | @@ -63,9 +55,9 @@ public class RequestDispatcher { | ||
63 | * @author miaoguoxin | 55 | * @author miaoguoxin |
64 | * @date 2020/4/15 | 56 | * @date 2020/4/15 |
65 | */ | 57 | */ |
66 | - public Message executeMethod(String uri, String paramsJson, ServerWebExchange exchange) { | 58 | + public Message<Object> executeMethod(String uri, String paramsJson, ServerWebExchange exchange) { |
67 | try { | 59 | try { |
68 | - if (hasInit.compareAndSet(false, true)) { | 60 | + if (HAS_INIT.compareAndSet(false, true)) { |
69 | String[] paths = MAPPING_INFO_MAP.keySet().toArray(new String[0]); | 61 | String[] paths = MAPPING_INFO_MAP.keySet().toArray(new String[0]); |
70 | PATH_PATTERNS.addAll(PathUtils.assemblePath(paths, PATH_PATTERNS)); | 62 | PATH_PATTERNS.addAll(PathUtils.assemblePath(paths, PATH_PATTERNS)); |
71 | } | 63 | } |
@@ -75,7 +67,7 @@ public class RequestDispatcher { | @@ -75,7 +67,7 @@ public class RequestDispatcher { | ||
75 | } | 67 | } |
76 | //分发逻辑 | 68 | //分发逻辑 |
77 | Object resultData = this.beginDispatch(matchUri, paramsJson,exchange); | 69 | Object resultData = this.beginDispatch(matchUri, paramsJson,exchange); |
78 | - return Message.builder().success(resultData); | 70 | + return Message.success(resultData); |
79 | } catch (Throwable e) { | 71 | } catch (Throwable e) { |
80 | return handleException(e); | 72 | return handleException(e); |
81 | } | 73 | } |
@@ -83,8 +75,6 @@ public class RequestDispatcher { | @@ -83,8 +75,6 @@ public class RequestDispatcher { | ||
83 | 75 | ||
84 | /** | 76 | /** |
85 | * 注册mapping信息 | 77 | * 注册mapping信息 |
86 | - * @param | ||
87 | - * @return | ||
88 | * @author miaoguoxin | 78 | * @author miaoguoxin |
89 | * @date 2020/4/16 | 79 | * @date 2020/4/16 |
90 | */ | 80 | */ |
@@ -117,7 +107,7 @@ public class RequestDispatcher { | @@ -117,7 +107,7 @@ public class RequestDispatcher { | ||
117 | } | 107 | } |
118 | } | 108 | } |
119 | 109 | ||
120 | - DispatchContext dispatchContext = new DispatchContext( | 110 | + DispatchContext<Object> dispatchContext = new DispatchContext<>( |
121 | exchange.getRequest(), | 111 | exchange.getRequest(), |
122 | exchange.getResponse(), | 112 | exchange.getResponse(), |
123 | paramData); | 113 | paramData); |
@@ -132,25 +122,18 @@ public class RequestDispatcher { | @@ -132,25 +122,18 @@ public class RequestDispatcher { | ||
132 | } | 122 | } |
133 | } | 123 | } |
134 | 124 | ||
135 | - private static Message handleException(Throwable ex) { | 125 | + private static Message<Object> handleException(Throwable ex) { |
136 | if (ex instanceof ResponseStatusException) { | 126 | if (ex instanceof ResponseStatusException) { |
137 | int statusCode = ((ResponseStatusException) ex).getStatus().value(); | 127 | int statusCode = ((ResponseStatusException) ex).getStatus().value(); |
138 | log.error("aggregation dispatch {}:{}", statusCode, ex.getMessage()); | 128 | log.error("aggregation dispatch {}:{}", statusCode, ex.getMessage()); |
139 | - return Message.builder() | ||
140 | - .code(statusCode) | ||
141 | - .message(ex.getMessage()) | ||
142 | - .build(); | 129 | + return Message.failure(statusCode,ex.getMessage()); |
143 | } else if (ex instanceof GatewayParamNotValidException) { | 130 | } else if (ex instanceof GatewayParamNotValidException) { |
144 | - return Message.builder() | ||
145 | - .code(SystemCode.ILLEGAL_PARAMS.getCode()) | ||
146 | - .message(ex.getMessage()) | ||
147 | - .build(); | 131 | + return Message.failure( |
132 | + ErrorCode.ILLEGAL_PARAMS.getCode(),ex.getMessage()); | ||
148 | } else { | 133 | } else { |
149 | log.error("aggregation dispatch error:{}", ex); | 134 | log.error("aggregation dispatch error:{}", ex); |
150 | - return Message.builder() | ||
151 | - .code(SystemCode.SERVER_ERROR.getCode()) | ||
152 | - .message(SystemCode.SERVER_ERROR.getName()) | ||
153 | - .build(); | 135 | + return Message.failure( |
136 | + ErrorCode.UNKNOWN_ERROR.getCode(),ErrorCode.UNKNOWN_ERROR.getName()); | ||
154 | } | 137 | } |
155 | } | 138 | } |
156 | 139 |
src/main/resources/bootstrap-dev.yml
@@ -2,12 +2,12 @@ spring: | @@ -2,12 +2,12 @@ spring: | ||
2 | cloud: | 2 | cloud: |
3 | nacos: | 3 | nacos: |
4 | discovery: | 4 | discovery: |
5 | - username: nacos | ||
6 | - password: microtest | ||
7 | - server-addr: apitest.51shiban.com:80/n | ||
8 | - namespace: c86d8673-4d0a-469f-8bb8-1434c57c236c | 5 | + username: xtrade |
6 | + password: abcd1234 | ||
7 | + server-addr: 10.28.1.79:8848 | ||
8 | + namespace: 35211f71-92a9-4f3e-975e-37b1132e05c8 | ||
9 | config: | 9 | config: |
10 | - username: nacos | ||
11 | - password: microtest | ||
12 | - server-addr: apitest.51shiban.com:80/n | ||
13 | - namespace: c86d8673-4d0a-469f-8bb8-1434c57c236c | 10 | + username: xtrade |
11 | + password: abcd1234 | ||
12 | + server-addr: 10.28.1.79:8848 | ||
13 | + namespace: 35211f71-92a9-4f3e-975e-37b1132e05c8 |
src/main/resources/bootstrap.yml
@@ -21,7 +21,5 @@ mybatis: | @@ -21,7 +21,5 @@ mybatis: | ||
21 | mapper-locations: classpath:/mapper/*.xml | 21 | mapper-locations: classpath:/mapper/*.xml |
22 | config-location: classpath:/mybatis-config.xml | 22 | config-location: classpath:/mybatis-config.xml |
23 | xtrade: | 23 | xtrade: |
24 | - json: | ||
25 | - format: false | ||
26 | gateway-loader: cloud | 24 | gateway-loader: cloud |
27 | aggregation-scan-packages: com.diligrp.xtrade.gateway.application | 25 | aggregation-scan-packages: com.diligrp.xtrade.gateway.application |
src/test/java/com/diligrp/xtrade/gateway/XtradeGatewayApplicationTests.java
@@ -6,8 +6,4 @@ import org.springframework.boot.test.context.SpringBootTest; | @@ -6,8 +6,4 @@ import org.springframework.boot.test.context.SpringBootTest; | ||
6 | @SpringBootTest | 6 | @SpringBootTest |
7 | class XtradeGatewayApplicationTests { | 7 | class XtradeGatewayApplicationTests { |
8 | 8 | ||
9 | - @Test | ||
10 | - void contextLoads() { | ||
11 | - } | ||
12 | - | ||
13 | } | 9 | } |