BAEL-944 Exploring the Spring MVC URL Matching Improvements (#1954)

* Example Code For Evaluation Article

This is an example code for the evaluation article on "Different Types of Bean Injection in Spring"

* Added unit tests

* Minor changes to application context

* Removed code committed for evaluation article

* BAEL-944 Demonstrating the problems with new Url pattern matching in Spring 5

* BAEL-944 Demonstrating the problems with new Url pattern matching in Spring 5

* BAEL-944 Exploring the Spring MVC URL Matching Improvements

* BAEL-944 Exploring the Spring MVC URL Matching Improvements

* BAEL-944 Exploring the Spring MVC URL Matching Improvements

* BAEL-944 Code Formatting and solving build issue

* BAEL-944 Resolving build issue due to change in Spring version

* BAEL-944 Resolving build issue

* BAEL-944 Formatting code

* BAEL-944 Moving tests to correct package

* BAEL-944 Moving tests to correct package

* BAEL-944 Replacing @RequestMapping by @GetMapping

* BAEL-944 Remove unnecessary attribute name, "value" in annotations
This commit is contained in:
Mansi 2017-06-21 06:30:10 +05:30 committed by yetanotherallisonf
parent ec46b8b338
commit 91b0efccd2
11 changed files with 323 additions and 4 deletions

View File

@ -177,6 +177,7 @@
<junit.platform.version>1.0.0-M4</junit.platform.version>
<junit.jupiter.version>5.0.0-M4</junit.jupiter.version>
<maven-surefire-plugin.version>2.20</maven-surefire-plugin.version>
<spring.version>5.0.0.RC2</spring.version>
</properties>
</project>

View File

@ -2,8 +2,10 @@ package com.baeldung;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = {"com.baeldung.web"})
public class Spring5Application {
public static void main(String[] args) {

View File

@ -0,0 +1,61 @@
package com.baeldung.functional;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.boot.web.server.WebServer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.http.server.reactive.ServletHttpHandlerAdapter;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
public class ExploreSpring5URLPatternUsingRouterFunctions {
private RouterFunction<ServerResponse> routingFunction() {
return route(GET("/p?ths"), serverRequest -> ok().body(fromObject("/p?ths"))).andRoute(GET("/test/{*id}"), serverRequest -> ok().body(fromObject(serverRequest.pathVariable("id"))))
.andRoute(GET("/*card"), serverRequest -> ok().body(fromObject("/*card path was accessed")))
.andRoute(GET("/{var1}_{var2}"), serverRequest -> ok().body(fromObject(serverRequest.pathVariable("var1") + " , " + serverRequest.pathVariable("var2"))))
.andRoute(GET("/{baeldung:[a-z]+}"), serverRequest -> ok().body(fromObject("/{baeldung:[a-z]+} was accessed and baeldung=" + serverRequest.pathVariable("baeldung"))))
.and(RouterFunctions.resources("/files/{*filepaths}", new ClassPathResource("files/")));
}
WebServer start() throws Exception {
WebHandler webHandler = (WebHandler) toHttpHandler(routingFunction());
HttpHandler httpHandler = WebHttpHandlerBuilder.webHandler(webHandler)
.prependFilter(new IndexRewriteFilter())
.build();
Tomcat tomcat = new Tomcat();
tomcat.setHostname("localhost");
tomcat.setPort(9090);
Context rootContext = tomcat.addContext("", System.getProperty("java.io.tmpdir"));
ServletHttpHandlerAdapter servlet = new ServletHttpHandlerAdapter(httpHandler);
Tomcat.addServlet(rootContext, "httpHandlerServlet", servlet);
rootContext.addServletMappingDecoded("/", "httpHandlerServlet");
TomcatWebServer server = new TomcatWebServer(tomcat);
server.start();
return server;
}
public static void main(String[] args) {
try {
new FunctionalWebApplication().start();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -15,6 +15,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.WebHandler;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import reactor.core.publisher.Flux;
@ -58,7 +59,7 @@ public class FunctionalSpringBootApplication {
@Bean
public ServletRegistrationBean servletRegistrationBean() throws Exception {
HttpHandler httpHandler = WebHttpHandlerBuilder
.webHandler(toHttpHandler(routingFunction()))
.webHandler((WebHandler) toHttpHandler(routingFunction()))
.prependFilter(new IndexRewriteFilter())
.build();
ServletRegistrationBean registrationBean = new ServletRegistrationBean<>(new RootServlet(httpHandler), "/");

View File

@ -50,7 +50,7 @@ public class FunctionalWebApplication {
}
WebServer start() throws Exception {
WebHandler webHandler = toHttpHandler(routingFunction());
WebHandler webHandler = (WebHandler) toHttpHandler(routingFunction());
HttpHandler httpHandler = WebHttpHandlerBuilder
.webHandler(webHandler)
.prependFilter(new IndexRewriteFilter())

View File

@ -19,7 +19,7 @@ class IndexRewriteFilter implements WebFilter {
.mutate()
.request(builder -> builder
.method(request.getMethod())
.contextPath(request.getContextPath())
.contextPath(request.getPath().toString())
.path("/test"))
.build());
}

View File

@ -23,12 +23,13 @@ import static org.springframework.web.reactive.function.server.RequestPredicates
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.RouterFunctions.toHttpHandler;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;
import org.springframework.web.server.WebHandler;
public class RootServlet extends ServletHttpHandlerAdapter {
public RootServlet() {
this(WebHttpHandlerBuilder
.webHandler(toHttpHandler(routingFunction()))
.webHandler((WebHandler) toHttpHandler(routingFunction()))
.prependFilter(new IndexRewriteFilter())
.build());
}

View File

@ -0,0 +1,40 @@
package com.baeldung.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PathPatternController {
@GetMapping("/spring5/{*id}")
public String URIVariableHandler(@PathVariable String id) {
return id;
}
@GetMapping("/s?ring5")
public String wildcardTakingExactlyOneChar() {
return "/s?ring5";
}
@GetMapping("/spring5/*id")
public String wildcardTakingZeroOrMoreChar() {
return "/spring5/*id";
}
@GetMapping("/resources/**")
public String wildcardTakingZeroOrMorePathSegments() {
return "/resources/**";
}
@GetMapping("/{baeldung:[a-z]+}")
public String regexInPathVariable(@PathVariable String baeldung) {
return baeldung;
}
@GetMapping("/{var1}_{var2}")
public String multiplePathVariablesInSameSegment(@PathVariable String var1, @PathVariable String var2) {
return "Two variables are var1=" + var1 + " and var2=" + var2;
}
}

View File

@ -0,0 +1 @@
test

View File

@ -0,0 +1,110 @@
package com.baeldung.functional;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.web.server.WebServer;
import org.springframework.test.web.reactive.server.WebTestClient;
public class ExploreSpring5URLPatternUsingRouterFunctionsTest {
private static WebTestClient client;
private static WebServer server;
@BeforeClass
public static void setup() throws Exception {
server = new ExploreSpring5URLPatternUsingRouterFunctions().start();
client = WebTestClient.bindToServer()
.baseUrl("http://localhost:" + server.getPort())
.build();
}
@AfterClass
public static void destroy() {
server.stop();
}
@Test
public void givenRouter_whenGetPathWithSingleCharWildcard_thenGotPathPattern() throws Exception {
client.get()
.uri("/paths")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/p?ths");
}
@Test
public void givenRouter_whenMultipleURIVariablePattern_thenGotPathVariable() throws Exception {
client.get()
.uri("/test/ab/cd")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/ab/cd");
}
@Test
public void givenRouter_whenGetMultipleCharWildcard_thenGotPathPattern() throws Exception {
client.get()
.uri("/wildcard")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/*card path was accessed");
}
@Test
public void givenRouter_whenGetMultiplePathVaribleInSameSegment_thenGotPathVariables() throws Exception {
client.get()
.uri("/baeldung_tutorial")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("baeldung , tutorial");
}
@Test
public void givenRouter_whenGetRegexInPathVarible_thenGotPathVariable() throws Exception {
client.get()
.uri("/abcd")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("/{baeldung:[a-z]+} was accessed and baeldung=abcd");
client.get()
.uri("/1234")
.exchange()
.expectStatus()
.is4xxClientError();
}
@Test
public void givenResources_whenAccess_thenGot() throws Exception {
client.get()
.uri("/files/test/test.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("test");
client.get()
.uri("/files/hello.txt")
.exchange()
.expectStatus()
.isOk()
.expectBody(String.class)
.isEqualTo("hello");
}
}

View File

@ -0,0 +1,102 @@
package com.baeldung.web;
import com.baeldung.web.PathPatternController;
import com.baeldung.Spring5Application;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Spring5Application.class)
public class PathPatternsUsingHandlerMethodTest {
private static WebTestClient client;
@BeforeClass
public static void setUp() {
client = WebTestClient.bindToController(new PathPatternController())
.build();
}
@Test
public void givenHandlerMethod_whenMultipleURIVariablePattern_then200() {
client.get()
.uri("/spring5/ab/cd")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/ab/cd");
}
@Test
public void givenHandlerMethod_whenURLWithWildcardTakingZeroOrMoreChar_then200() {
client.get()
.uri("/spring5/userid")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/spring5/*id");
}
@Test
public void givenHandlerMethod_whenURLWithWildcardTakingExactlyOneChar_then200() {
client.get()
.uri("/string5")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/s?ring5");
}
@Test
public void givenHandlerMethod_whenURLWithWildcardTakingZeroOrMorePathSegments_then200() {
client.get()
.uri("/resources/baeldung")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("/resources/**");
}
@Test
public void givenHandlerMethod_whenURLWithRegexInPathVariable_thenExpectedOutput() {
client.get()
.uri("/abc")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("abc");
client.get()
.uri("/123")
.exchange()
.expectStatus()
.is4xxClientError();
}
@Test
public void givenHandlerMethod_whenURLWithMultiplePathVariablesInSameSegment_then200() {
client.get()
.uri("/baeldung_tutorial")
.exchange()
.expectStatus()
.is2xxSuccessful()
.expectBody()
.equals("Two variables are var1=baeldung and var2=tutorial");
}
}