Erkundung des Spring 5 WebFlux URL Matching

Erkunden des WebFlux-URL-Abgleichs in Spring 5

1. Überblick

Feder 5 brachtea newPathPatternParser zum Parsen von URI-Vorlagenmustern. Dies ist eine Alternative zu den zuvor verwendetenAntPathMatcher.

AntPathMatcher war eine Implementierung des Pfadmustervergleichs im Ant-Stil. PathPatternParser unterteilt den Pfad in eine verknüpfte Liste vonPathElements. Diese Kette vonPathElements wird von der KlassePathPattern verwendet, um Muster schnell abzugleichen.

MitPathPatternParser wurde auch die Unterstützung einer neuen URI-Variablensyntax eingeführt.

In diesem Artikelwe’ll go through the new/updated URL pattern matchers introduced in Spring 5.0 WebFlux und auch diejenigen, die seit älteren Versionen von Spring vorhanden sind.

2. Neue URL-Muster-Matcher in Spring 5.0

In Spring 5.0 wurde eine sehr einfach zu verwendende URI-Variablensyntax hinzugefügt: \ {* foo}, um eine beliebige Anzahl von Pfadsegmenten am Ende des Musters zu erfassen.

2.1. URI-Variablensyntax \ {* foo} Verwenden einer Handler-Methode

Sehen wir uns ein Beispiel für das URI-Variablenmuster\{*foo}an, ein weiteres Beispiel mit@GetMapping und einer Handler-Methode. Was auch immer wir im Pfad nach“/spring5” angeben, wird in der Pfadvariablen "id" gespeichert:

@GetMapping("/spring5/{*id}")
public String URIVariableHandler(@PathVariable String id) {
    return id;
}
@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable() {

    client.get()
      .uri("/spring5/example/tutorial")
      .exchange()
      .expectStatus()
      .is2xxSuccessful()
      .expectBody()
      .equals("/example/tutorial");

    client.get()
      .uri("/spring5/example")
      .exchange()
      .expectStatus()
      .is2xxSuccessful()
      .expectBody()
      .equals("/example");
}

2.2. URI-Variablensyntax \ {* foo} Verwenden vonRouterFunction

Sehen wir uns ein Beispiel für das neue Pfadmuster für URI-Variablen mitRouterFunction an:

private RouterFunction routingFunction() {
    return route(GET("/test/{*id}"),
      serverRequest -> ok().body(fromObject(serverRequest.pathVariable("id"))));
}

In diesem Fall wird der Pfad, den wir nach "/ test" schreiben, in der Pfadvariablen "id" erfasst. Der Testfall dafür könnte also sein:

@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable()
  throws Exception {

    client.get()
      .uri("/test/ab/cd")
      .exchange()
      .expectStatus()
      .isOk()
      .expectBody(String.class)
      .isEqualTo("/ab/cd");
}

2.3. Verwendung der URI-Variablensyntax \ {* foo} für den Zugriff auf Ressourcen

Wenn wir auf Ressourcen zugreifen möchten, müssen wir das ähnliche Pfadmuster wie im vorherigen Beispiel schreiben.

Nehmen wir also an, unser Muster lautet:“/files/\{*filepaths}”. In diesem Fall lautet der Wert der Pfadvariablen“filepaths” "/hello.txt", wenn der Pfad/files/hello.txt, ist, während der Pfad "/hello.txt" ist /files/test/test.txt, ist der Wert von“filepaths” = "/test/test.txt".

Unsere Routing-Funktion für den Zugriff auf Dateiressourcen im Verzeichnis/files/:

private RouterFunction routingFunction() {
    return RouterFunctions.resources(
      "/files/{*filepaths}",
      new ClassPathResource("files/")));
}

Nehmen wir an, dass unsere Textdateienhello.txt undtest.txt“hello” bzw.“test” enthalten. Dies kann mit einem JUnit-Testfall demonstriert werden:

@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable()
  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");
}

3. Vorhandene URL-Muster aus früheren Versionen

Lassen Sie uns nun einen Blick auf alle anderen URL-Mustervergleiche werfen, die von älteren Versionen von Spring unterstützt wurden. Alle diese Muster funktionieren sowohl mitRouterFunction als auch mit Handler-Methoden mit@GetMapping.

3.1. ?? ' Entspricht genau einem Zeichen

Wenn wir das Pfadmuster wie folgt angeben:“/t?st _ “, _ entspricht dies Pfaden wie:“/test” und“/tast”,, jedoch nicht“/tst” und“/teest”.

Der Beispielcode mitRouterFunction und seinem JUnit-Testfall:

private RouterFunction routingFunction() {
    return route(GET("/t?st"),
      serverRequest -> ok().body(fromObject("Path /t?st is accessed")));
}

@Test
public void whenGetPathWithSingleCharWildcard_thenGotPathPattern()
  throws Exception {

      client.get()
        .uri("/test")
        .exchange()
        .expectStatus()
        .isOk()
        .expectBody(String.class)
        .isEqualTo("Path /t?st is accessed");
}

3.2. ‘ 'Entspricht 0 oder mehr Zeichen innerhalb eines Pfadsegments *

Wenn wir das Pfadmuster wie folgt angeben:“/example/*Id”, entspricht dies den Pfadmusternlike:”/example/Id”, “/example/tutorialId”, "/ example / articleId" usw.:

private RouterFunction routingFunction() {
    returnroute(
      GET("/example/*Id"),
      serverRequest -> ok().body(fromObject("/example/*Id path was accessed"))); }

@Test
public void whenGetMultipleCharWildcard_thenGotPathPattern()
  throws Exception {
      client.get()
        .uri("/example/tutorialId")
        .exchange()
        .expectStatus()
        .isOk()
        .expectBody(String.class)
        .isEqualTo("/example/*Id path was accessed");
}

3.3. ‘ * 'Entspricht 0 oder mehr Pfadsegmenten bis zum Ende des Pfads *

In diesem Fall ist der Mustervergleich nicht auf ein einzelnes Pfadsegment beschränkt. Wenn wir das Muster als“/resources/**”, angeben, werden alle Pfade nach“/resources/”: mit einer beliebigen Anzahl von Pfadsegmenten abgeglichen

private RouterFunction routingFunction() {
    return RouterFunctions.resources(
      "/resources/**",
      new ClassPathResource("resources/")));
}

@Test
public void whenAccess_thenGot() throws Exception {
    client.get()
      .uri("/resources/test/test.txt")
      .exchange()
      .expectStatus()
      .isOk()
      .expectBody(String.class)
      .isEqualTo("content of file test.txt");
}

3.4. ‘\{example:[a-z]+}' Regex in der Pfadvariablen

Wir können auch einen regulären Ausdruck für den Wert der Pfadvariablen angeben. Wenn unser Muster also wie“/\{example:[a-z]+}”, ist, ist der Wert der Pfadvariablen“example” ein beliebiges Pfadsegment, das mit dem angegebenen regulären Ausdruck übereinstimmt:

private RouterFunction routingFunction() {
    return route(GET("/{example:[a-z]+}"),
      serverRequest ->  ok()
        .body(fromObject("/{example:[a-z]+} was accessed and "
        + "example=" + serverRequest.pathVariable("example"))));
}

@Test
public void whenGetRegexInPathVarible_thenGotPathVariable()
  throws Exception {

      client.get()
        .uri("/abcd")
        .exchange()
        .expectStatus()
        .isOk()
        .expectBody(String.class)
        .isEqualTo("/{example:[a-z]+} was accessed and "
          + "example=abcd");
}

3.5. ‘/{var1} {var2} '_ Mehrere Pfadvariablen im gleichen Pfadsegment

Spring 5 hat sichergestellt, dass mehrere Pfadvariablen in einem einzelnen Pfadsegment nur zulässig sind, wenn sie durch ein Trennzeichen getrennt sind. Nur dann kann Spring zwischen den beiden verschiedenen Pfadvariablen unterscheiden:

private RouterFunction routingFunction() {

    return route(
      GET("/{var1}_{var2}"),
      serverRequest -> ok()
        .body(fromObject( serverRequest.pathVariable("var1") + " , "
        + serverRequest.pathVariable("var2"))));
 }

@Test
public void whenGetMultiplePathVaribleInSameSegment_thenGotPathVariables()
  throws Exception {
      client.get()
        .uri("/example_tutorial")
        .exchange()
        .expectStatus()
        .isOk()
        .expectBody(String.class)
        .isEqualTo("example , tutorial");
}

4. Fazit

In diesem Artikel wurden die neuen URL-Matcher in Spring 5 sowie die in älteren Versionen von Spring verfügbaren URL-Matcher vorgestellt.

Wie immer kann die Implementierung aller von uns diskutierten Beispiele inover on GitHub gefunden werden.