Explorando a correspondência de URL WebFlux do Spring 5

Explorando a correspondência de URL WebFlux do Spring 5

1. Visão geral

O Spring 5 trouxea newPathPatternParser para analisar os padrões de template URI. Esta é uma alternativa para oAntPathMatcher usado anteriormente.

OAntPathMatcher foi uma implementação de correspondência de padrões de caminho no estilo Ant. PathPatternParser divide o caminho em uma lista vinculada dePathElements. Esta cadeia dePathElements é usada pela classePathPattern para correspondência rápida de padrões.

Com oPathPatternParser, o suporte para uma nova sintaxe de variável URI também foi introduzido.

Neste artigo,we’ll go through the new/updated URL pattern matchers introduced in Spring 5.0 WebFlux e também aqueles que estão lá desde as versões anteriores do Spring.

2. Novos Matchers de Padrão de URL no Spring 5.0

A versão do Spring 5.0 adicionou uma sintaxe de variável URI muito fácil de usar: \ {* foo} para capturar qualquer número de segmentos de caminho no final do padrão.

2.1. Sintaxe da variável URI \ {* foo} usando um método de manipulador

Vejamos um exemplo do padrão de variável URI\{*foo} outro exemplo usando@GetMappinge um método manipulador. Tudo o que dermos no caminho após“/spring5” será armazenado na variável de caminho “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. Sintaxe da variável URI \ {* foo} usandoRouterFunction

Vejamos um exemplo do novo padrão de caminho de variável URI usandoRouterFunction:

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

Nesse caso, qualquer caminho que escrevermos após “/ test” será capturado na variável de caminho “id”. Portanto, o caso de teste pode ser:

@Test
public void whenMultipleURIVariablePattern_thenGotPathVariable()
  throws Exception {

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

2.3. Uso da sintaxe de variável URI \ {* foo} para acessar recursos

Se quisermos acessar recursos, precisaremos escrever o padrão de caminho semelhante ao que escrevemos no exemplo anterior.

Então, digamos que nosso padrão seja:“/files/\{*filepaths}”. Neste caso, se o caminho for/files/hello.txt,, o valor da variável de caminho“filepaths” será “/hello.txt”, enquanto, se o caminho for /files/test/test.txt, o valor de“filepaths” = “/teste/teste.txt”.

Nossa função de roteamento para acessar recursos de arquivo no diretório/files/:

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

Vamos supor que nossos arquivos de textohello.txtetest.txt contenham“hello”e“test” respectivamente. Isso pode ser demonstrado com um caso de teste 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. Padrões de URL existentes de versões anteriores

Vamos agora dar uma olhada em todos os outros matchers de padrão de URL que são suportados por versões anteriores do Spring. Todos esses padrões funcionam comRouterFunctione métodos Handler com@GetMapping.

3.1. '?' Corresponde exatamente a um personagem

Se especificarmos o padrão de caminho como:“/t?st _ “, _ isso corresponderá a caminhos como:“/test”e“/tast”,, mas não“/tst”e“/teest”.

O código de exemplo usandoRouterFunction e seu caso de teste 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. ‘ 'corresponde a 0 ou mais caracteres em um segmento de caminho *

Se especificarmos o padrão de caminho como:“/example/*Id”,, ele corresponderá aos padrões de caminholike:”/example/Id”, “/example/tutorialId”, “/ example / articleId”, etc:

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. ‘ * 'Corresponde a 0 ou mais segmentos de caminho até o final do caminho *

Nesse caso, a correspondência de padrões não se limita a um único segmento de caminho. Se especificarmos o padrão como“/resources/**”,, ele corresponderá todos os caminhos a qualquer número de segmentos de caminho após“/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]+}' Regex na variável de caminho

Também podemos especificar uma regex para o valor da variável de caminho. Portanto, se nosso padrão for como“/\{example:[a-z]+}”,, o valor da variável de caminho“example” será qualquer segmento de caminho que corresponda ao regex fornecido:

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} '_ Variáveis ​​de caminhos múltiplos no mesmo segmento de caminho

A Primavera 5 garantiu que várias variáveis ​​de caminho fossem permitidas em um único segmento de caminho somente quando separadas por um delimitador. Somente então o Spring pode distinguir entre as duas variáveis ​​de caminho diferentes:

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. Conclusão

Neste artigo, examinamos os novos correspondentes de URL no Spring 5, bem como os disponíveis em versões mais antigas do Spring.

Como sempre, a implementação de todos os exemplos que discutimos pode ser encontradaover on GitHub.