Spring 5のWebFlux URLマッチングの調査

Spring 5 WebFlux URLマッチングの調査

1. 概要

Spring 5では、URIテンプレートパターンを解析するためにa newPathPatternParserが導入されました。.これは、以前に使用されていたAntPathMatcherの代替手段です。

AntPathMatcherは、Antスタイルのパスパターンマッチングの実装でした。 PathPatternParserは、パスをPathElementsのリンクリストに分割します。 このPathElementsのチェーンは、パターンの迅速なマッチングのためにPathPatternクラスによって取得されます。

PathPatternParserでは、新しいURI変数構文のサポートも導入されました。

この記事では、we’ll go through the new/updated URL pattern matchers introduced in Spring 5.0 WebFluxと、古いバージョンのSpring以降に存在しているものについて説明します。

2. Spring5.0の新しいURLパターンマッチャー

Spring 5.0リリースでは、非常に使いやすいURI変数構文:\ {* foo}が追加され、パターンの最後に任意の数のパスセグメントをキャプチャしました。

2.1. URI変数構文\ {* foo}ハンドラーメソッドの使用

URI変数パターン\{*foo}の例を見てみましょう。@GetMappingとハンドラーメソッドを使用した別の例です。 “/spring5”の後にパスに指定したものはすべて、パス変数「id」に格納されます。

@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変数構文\ {* foo}RouterFunctionの使用

RouterFunctionを使用した新しいURI変数パスパターンの例を見てみましょう。

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

この場合、「/ test」の後に記述するパスはすべて、パス変数「id」にキャプチャされます。 そのため、テストケースは次のようになります。

@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable()
  throws Exception {

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

2.3. リソースにアクセスするためのURI変数構文\ {* foo}の使用

リソースにアクセスする場合は、前の例で記述したのと同様のパスパターンを記述する必要があります。

したがって、パターンが次のようになっているとします。“/files/\{*filepaths}”.この場合、パスが/files/hello.txt,の場合、パス変数“filepaths”の値は「/hello.txt」になりますが、パスが/files/test/test.txt,“filepaths” =“ /test/test.txt”の値。

/files/ディレクトリの下のファイルリソースにアクセスするためのルーティング関数:

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

テキストファイルhello.txttest.txtにそれぞれ“hello”“test”が含まれていると仮定しましょう。 これは、JUnitテストケースで実証できます。

@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. 以前のバージョンの既存のURLパターン

それでは、古いバージョンのSpringでサポートされている他のすべてのURLパターンマッチャーを見てみましょう。 これらのパターンはすべて、RouterFunctionメソッドと@GetMappingのHandlerメソッドの両方で機能します。

3.1. 「?」完全に1文字に一致

パスパターンを次のように指定した場合:“/t?st _“、_これは、“/test”“/tast”,のようなパスに一致しますが、“/tst”“/teest”.には一致しません

RouterFunctionとそのJUnitテストケースを使用したサンプルコード:

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. ‘ 'はパスセグメント内の0個以上の文字に一致します*

パスパターンを:“/example/*Id”,として指定すると、これはパスパターンlike:”/example/Id”, “/example/tutorialId”,“ / example / articleId”などと一致します。

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. ‘ * 'は、パスの終わりまで0個以上のパスセグメントに一致します*

この場合、パターンマッチングは単一のパスセグメントに限定されません。 パターンを“/resources/**”,として指定すると、“/resources/”:以降の任意の数のパスセグメントにすべてのパスが一致します。

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]+}'正規表現

パス変数の値に正規表現を指定することもできます。 したがって、パターンが“/\{example:[a-z]+}”,のような場合、パス変数“example”の値は、指定された正規表現に一致する任意のパスセグメントになります。

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} '_同じパスセグメント内の複数のパス変数

Spring 5では、区切り文字で区切られた場合にのみ、単一のパスセグメントで複数のパス変数が許可されるようになりました。 そうして初めて、Springは2つの異なるパス変数を区別できます。

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. 結論

この記事では、Spring 5の新しいURLマッチャーと、古いバージョンのSpringで使用可能なURLマッチャーについて説明しました。

いつものように、私たちが議論したすべての例の実装はover on GitHubで見つけることができます。