diff --git a/src/main/java/org/springframework/cloud/gateway/GatewayConfiguration.java b/src/main/java/org/springframework/cloud/gateway/GatewayConfiguration.java new file mode 100644 index 00000000..463f3c8a --- /dev/null +++ b/src/main/java/org/springframework/cloud/gateway/GatewayConfiguration.java @@ -0,0 +1,54 @@ +package org.springframework.cloud.gateway; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.gateway.filters.FindRouteFilter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.web.client.reactive.WebClient; + +/** + * @author Spencer Gibb + */ +@Configuration +@EnableConfigurationProperties +public class GatewayConfiguration { + + @Bean + @ConditionalOnMissingBean + public WebClient webClient() { + return WebClient.builder(new ReactorClientHttpConnector()).build(); + } + + @Bean + public FindRouteFilter findRouteFilter(GatewayProperties properties) { + return new FindRouteFilter(properties); + } + + @Bean + public GatewayProperties gatewayProperties() { + return new GatewayProperties(); + } + + @Bean + public GatewayWebHandler gatewayController(GatewayProperties properties, WebClient webClient) { + return new GatewayWebHandler(properties, webClient); + } + + @Bean + public GatewayHandlerMapping gatewayHandlerMapping(GatewayProperties properties, GatewayWebHandler gatewayWebHandler) { + return new GatewayHandlerMapping(properties, gatewayWebHandler); + } + + /*@Bean + public GatewayWebReactiveConfigurer gatewayWebReactiveConfiguration() { + return new GatewayWebReactiveConfigurer(); + } + + public static class GatewayWebReactiveConfigurer implements WebReactiveConfigurer { + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + } + }*/ +} diff --git a/src/main/java/org/springframework/cloud/gateway/GatewayHandlerMapping.java b/src/main/java/org/springframework/cloud/gateway/GatewayHandlerMapping.java new file mode 100644 index 00000000..87a1be5c --- /dev/null +++ b/src/main/java/org/springframework/cloud/gateway/GatewayHandlerMapping.java @@ -0,0 +1,39 @@ +package org.springframework.cloud.gateway; + +import org.springframework.beans.BeansException; +import org.springframework.cloud.gateway.GatewayProperties.Route; +import org.springframework.web.reactive.handler.AbstractUrlHandlerMapping; +import org.springframework.web.server.ServerWebExchange; + +import java.util.Map; + +/** + * @author Spencer Gibb + */ +public class GatewayHandlerMapping extends AbstractUrlHandlerMapping { + + private GatewayProperties properties; + private GatewayWebHandler gatewayWebHandler; + + public GatewayHandlerMapping(GatewayProperties properties, GatewayWebHandler gatewayWebHandler) { + this.properties = properties; + this.gatewayWebHandler = gatewayWebHandler; + } + + @Override + protected void initApplicationContext() throws BeansException { + super.initApplicationContext(); + registerHandlers(this.properties.getRoutes()); + } + + protected void registerHandlers(Map routes) { + for (Route route : routes.values()) { + registerHandler(route.getPath(), this.gatewayWebHandler); + } + } + + @Override + protected Object lookupHandler(String urlPath, ServerWebExchange exchange) throws Exception { + return super.lookupHandler(urlPath, exchange); + } +} diff --git a/src/main/java/org/springframework/cloud/gateway/GatewayProperties.java b/src/main/java/org/springframework/cloud/gateway/GatewayProperties.java new file mode 100644 index 00000000..66a62fda --- /dev/null +++ b/src/main/java/org/springframework/cloud/gateway/GatewayProperties.java @@ -0,0 +1,49 @@ +package org.springframework.cloud.gateway; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Spencer Gibb + */ +@ConfigurationProperties("spring.cloud.gateway") +public class GatewayProperties { + + + /** + * Map of route names to properties. + */ + private Map routes = new LinkedHashMap<>(); + + public Map getRoutes() { + return routes; + } + + public void setRoutes(Map routes) { + this.routes = routes; + } + + public static class Route { + private String id; + private String path; + private String url; + + public String getPath() { + return this.path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getUrl() { + return this.url; + } + + public void setUrl(String url) { + this.url = url; + } + } +} diff --git a/src/main/java/org/springframework/cloud/gateway/GatewayController.java b/src/main/java/org/springframework/cloud/gateway/GatewayWebHandler.java similarity index 75% rename from src/main/java/org/springframework/cloud/gateway/GatewayController.java rename to src/main/java/org/springframework/cloud/gateway/GatewayWebHandler.java index 4d825ac9..5eb09b69 100644 --- a/src/main/java/org/springframework/cloud/gateway/GatewayController.java +++ b/src/main/java/org/springframework/cloud/gateway/GatewayWebHandler.java @@ -1,34 +1,32 @@ package org.springframework.cloud.gateway; -import java.util.Optional; - import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.reactive.ClientRequest; import org.springframework.web.client.reactive.WebClient; import org.springframework.web.server.ServerWebExchange; - +import org.springframework.web.server.WebHandler; import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Optional; /** * @author Spencer Gibb */ -@RestController -@SuppressWarnings("unused") -public class GatewayController { +public class GatewayWebHandler implements WebHandler { + private final GatewayProperties properties; private final WebClient webClient; - public GatewayController(WebClient webClient) { + public GatewayWebHandler(GatewayProperties properties, WebClient webClient) { + this.properties = properties; this.webClient = webClient; } - //TODO: plugin to request mappings - @GetMapping(path = "/") - public Flux home(ServerWebExchange exchange) { + @Override + public Mono handle(ServerWebExchange exchange) { Optional requestUrl = exchange.getAttribute("requestUrl"); ServerHttpRequest request = exchange.getRequest(); ClientRequest clientRequest = ClientRequest @@ -42,6 +40,6 @@ public class GatewayController { response.setStatusCode(clientResponse.statusCode()); Flux body = clientResponse.body((inputMessage, context) -> inputMessage.getBody()); return response.writeWith(body); - }); + }).next(); // TODO: is this correct? } } diff --git a/src/main/java/org/springframework/cloud/gateway/SpringCloudGatewayApplication.java b/src/main/java/org/springframework/cloud/gateway/SpringCloudGatewayApplication.java index cf09c200..ac3a81d1 100644 --- a/src/main/java/org/springframework/cloud/gateway/SpringCloudGatewayApplication.java +++ b/src/main/java/org/springframework/cloud/gateway/SpringCloudGatewayApplication.java @@ -2,38 +2,25 @@ package org.springframework.cloud.gateway; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; import org.springframework.core.annotation.Order; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.web.client.reactive.WebClient; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; - import reactor.core.publisher.Mono; -@SpringBootApplication +//TODO: move to autoconfig +@Import(GatewayConfiguration.class) +@SpringBootConfiguration +@EnableAutoConfiguration public class SpringCloudGatewayApplication { private static final Log log = LogFactory.getLog(SpringCloudGatewayApplication.class); - @Bean - public WebClient webClient() { - return WebClient.builder(new ReactorClientHttpConnector()).build(); - } - - // TODO: request only, how to filter response? - @Bean - @Order(500) - public WebFilter findRouteFilter() { - return (exchange, chain) -> { - log.info("findRoutFilter start"); - exchange.getAttributes().put("requestUrl", "http://httpbin.org/get"); - return chain.filter(exchange); - }; - } - + // TODO: only apply filters to zuul? @Bean @Order(501) public WebFilter modifyResponseFilter() { @@ -60,6 +47,9 @@ public class SpringCloudGatewayApplication { } public static void main(String[] args) { - SpringApplication.run(SpringCloudGatewayApplication.class, args); + new SpringApplicationBuilder() + .sources(SpringCloudGatewayApplication.class) + //TODO: howto do programatically + .run(args); } } diff --git a/src/main/java/org/springframework/cloud/gateway/filters/FindRouteFilter.java b/src/main/java/org/springframework/cloud/gateway/filters/FindRouteFilter.java new file mode 100644 index 00000000..7f2cd99b --- /dev/null +++ b/src/main/java/org/springframework/cloud/gateway/filters/FindRouteFilter.java @@ -0,0 +1,48 @@ +package org.springframework.cloud.gateway.filters; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.cloud.gateway.GatewayProperties; +import org.springframework.cloud.gateway.GatewayProperties.Route; +import org.springframework.cloud.gateway.SpringCloudGatewayApplication; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; + +import java.net.URI; + +/** + * @author Spencer Gibb + */ +public class FindRouteFilter implements WebFilter { + + private static final Log log = LogFactory.getLog(SpringCloudGatewayApplication.class); + + private final GatewayProperties properties; + private final AntPathMatcher matcher; + + public FindRouteFilter(GatewayProperties properties) { + this.properties = properties; + this.matcher = new AntPathMatcher(); + } + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + log.info("FindRouteFilter start"); + //TODO: + ServerHttpRequest request = exchange.getRequest(); + URI uri = request.getURI(); + String path = uri.getPath(); + for (Route route : this.properties.getRoutes().values()) { + if (this.matcher.match(route.getPath(), path)) { + String url = route.getUrl() + path; + exchange.getAttributes().put("requestUrl", url); + return chain.filter(exchange); + } + } + return chain.filter(exchange); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 00000000..abd5b7ea --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,10 @@ +spring: + resources: + # TODO: how to add this programmatically + add-mappings: false + cloud: + gateway: + routes: + test1: + path: /** + url: http://httpbin.org