Encaminhando aplicativos In Play em Java

Encaminhando aplicativos In Play em Java

1. Visão geral

O roteamento é um conceito comum que aparece na maioria das estruturas de desenvolvimento da web, incluindoSpring MVC.

Uma rota é um padrão de URL que é mapeado para um manipulador. O manipulador pode ser um arquivo físico, como um ativo para download no aplicativo Web ou uma classe que processa a solicitação, como um controlador em um aplicativo MVC.

Neste tutorial, exploraremos o aspecto de roteamento no desenvolvimento de aplicativos da web comPlay Framework.

2. Configuração

Primeiro, precisamos criar um aplicativo Java Play. Os detalhes sobre como configurar o Play Framework em uma máquina estão disponíveis em nossointroductory article.

No final da configuração, devemos ter um aplicativo Play funcional que possamos acessar a partir de um navegador.

3. Roteamento HTTP

Então, como o Play sabe qual controlador consultar sempre que enviamos uma solicitação HTTP? A resposta a esta pergunta está no arquivo de configuraçãoapp/conf/routes.

O roteador do Play traduz as solicitações HTTP em chamadas de ação. HTTP requests are considered to be events in MVC architecturee o roteador reage a eles consultando o arquivoroutes para qual controlador e qual ação naquele controlador executar.

Cada um desses eventos fornece a um roteador dois parâmetros: um caminho de solicitação com sua string de consulta e o método HTTP da solicitação.

4. Roteamento básico com jogo

Para que o roteador faça seu trabalho, o arquivoconf/routes deve definir mapeamentos de métodos HTTP e padrões de URI para ações de controlador apropriadas:

GET     /     controllers.HomeController.index
GET     /     assets/*file controllers.Assets.versioned(path="/public", file: Asset)

Todos os arquivos de rotas também devem mapear os recursos estáticos na pastaplay-routing/public disponível para o cliente no endpoint/assets. Observe a sintaxe de definição de rotas HTTP e a ação do controlador do método HTTPspace URI patternspace.

5. Padrões URI

Nesta seção, explicaremos um pouco os padrões de URI.

5.1. Padrões de URI estáticos

Os três primeiros padrões de URI acima são estáticos. Isso significa que o mapeamento dos URLs para recursos ocorre sem nenhum processamento adicional nas ações do controlador.

Desde que um método do controlador seja chamado, ele retorna um recurso estático cujo conteúdo é determinado antes da solicitação.

5.2. Padrões de URI Dinâmicos

O último padrão de URI acima é dinâmico. Isso significa que a ação do controlador que atende a uma solicitação nesses URIs precisa de algumas informações da solicitação para determinar a resposta. No caso acima, ele espera um nome de arquivo.

A sequência normal de eventos é que o roteador recebe um evento, escolhe o caminho da URL, decodifica seus segmentos e os passa para o controlador.

Os parâmetros de caminho e consulta são injetados na ação do controlador como parâmetros. Vamos demonstrar isso com um exemplo nas próximas seções.

6. Encaminhamento avançado com jogo

Nesta seção, discutiremos as opções avançadas de roteamento usando padrões de URI dinâmicos em detalhes.

6.1. Parâmetros de caminho simples

Parâmetros de caminho simples são parâmetros sem nome em uma URL de solicitação que aparecem após o host e a porta e são analisados ​​em ordem de aparência.

Dentro deplay-routing/app/HomeController.java, vamos criar uma nova ação:

public Result greet(String name) {
    return ok("Hello " + name);
}

Queremos poder escolher um parâmetro de caminho da URL de solicitação e mapeá-lo para o nome da variável.

O roteador obterá esses valores de uma configuração de rota.

Então, vamos abrirplay-routing/conf/routes e criar um mapeamento para esta nova ação:

GET     /greet/:name     controllers.HomeController.greet(name: String)

Observe como informamos a um roteador que esse nome é um segmento de caminho dinâmico com a sintaxe de dois pontos e, em seguida, passa-o como um parâmetro para a chamada de ação greet.

Agora, vamos carregarhttp://locahost:9000/greet/john no navegador e seremos recebidos pelo nome:

Hello john

Acontece queif our action parameter is of string type, we may pass it during the action call without specifying the parameter type, embora não seja o mesmo para os outros tipos.

Vamos incrementar nosso endpoint/greet com informações de idade.

De volta à ação de saudação deHomeController, vamos alterá-la para:

public Result greet(String name, int age) {
    return ok("Hello " + name + ", you are " + age + " years old");
}

E a rota para:

GET     /greet/:name/:age               controllers.HomeController.greet(name: String, age: Integer)

Observe também a sintaxe Scala para declarar uma variável,age: Integer. Em Java, usaríamos a sintaxeInteger age. O Play Framework é construído em Scala. Conseqüentemente, há muita sintaxe do scala.

Hello john, you are 26 years old

6.2. Caracteres curinga em parâmetros de caminho

Em nosso arquivo de configuração de rotas, o último mapeamento é:

GET     /assets/*file  controllers.Assets.versioned(path="/public", file: Asset)

Usamos um curinga na parte dinâmica do caminho. O que estamos dizendo ao Play é que qualquer valor que substitua*file na solicitação real deve ser analisado como um todo e não decodificado como em outros casos de parâmetros de caminho.

Neste exemplo, o controlador é embutido,Assets, que permite ao cliente baixar arquivos da pastaplay-routing/public. Quando carregamoshttp://localhost:9000/assets/images/favicon.png, devemos ver a imagem do favicon do Play no navegador, pois ele está presente na pasta/public/images.

Vamos criar nossa própria ação de exemplo emHomeController.java:

public Result introduceMe(String data) {
    String[] clientData = data.split(",");
    return ok("Your name is " + clientData[0] + ", you are " + clientData[1] + " years old");
}

Observe que nesta ação, recebemos um parâmetro String e aplicamos nossa lógica para decodificá-lo. Nesse caso, a lógica é dividir umString delimitado por vírgulas em uma matriz. Anteriormente, dependíamos de um roteador para decodificar esses dados para nós.

Com curingas, estamos por nossa conta. Esperamos que o cliente obtenha nossa sintaxe correta ao passar esses dados. Idealmente,we should validate the incoming String before using it.

Vamos criar uma rota para esta ação:

GET   /*data   controllers.HomeController.introduceMe(data)

Agora carregue a URLhttp://localhost:9000/john,26. Isso imprimirá:

Your name is john, you are 26 years old

6.3. Regex em parâmetros de caminho

Assim como curingas, podemos usar expressões regulares para a parte dinâmica. Vamos adicionar uma ação que recebe um número e retorna seu quadrado:

public Result squareMe(Long num) {
    return ok(num + " Squared is " + (num * num));
}

Agora vamos adicionar sua rota:

GET   /square/$num<[0-9]+>   controllers.HomeController.squareMe(num:Long)

Vamos colocar essa rota abaixo da rotaintroduceMe para apresentar um novo conceito. Só podemos manipular rotas em que a parte regex é um número inteiro positivo com essa configuração de roteamento.

Agora, se colocamos a rota como instruído no parágrafo anterior, e carregamoshttp://localhost:9000/square/2, devemos ser saudados com umArrayIndexOutOfBoundsException:

image

Se verificarmos os logs de erro no console do servidor, perceberemos que a chamada de ação foi realmente executada na açãointroduceMe em vez da açãosquareMe. Como dito anteriormente sobre curingas, estamos sozinhos e não validamos os dados recebidos.

Em vez de uma string delimitada por vírgulas, o métodointroduceMe foi chamado com a string “square/2“. Consequentemente, após dividi-lo, obtivemos uma matriz de tamanho um. Tentando alcançar o índice, então gerou a exceção.

Naturalmente, esperaríamos que a chamada fosse roteada para o métodosquareMe. Por que ele foi roteado paraintroduceMe? O motivo é um recurso do Play que abordaremos em seguida, chamadoRouting Priority.

7. Prioridade de roteamento

Se houver um conflito entre as rotas, assim como entresquareMe eintroduceMe, entãoPlay picks the first route in declaration order.

Por que existe um conflito? Devido ao contexto de curinga, o caminho/data corresponde a qualquer URL de solicitação, exceto o caminho base/. Portanto, * cada rota cujo padrão de URI usa curingas deve aparecer por último na ordem.

Agora vamos alterar a ordem de declaração das rotas de modo que a rotaintroduceMe venha depois desquareMee recarregar:

2 Squared is 4

Para testar o poder das expressões regulares em uma rota, tente carregarhttp://locahost:9000/square/-1, um roteador não corresponderá à rotasquareMe. Em vez disso, ele corresponderá aintroduceMe, e obteremos oArrayIndexOutOfBoundsException novamente.

Isso ocorre porque-1 não corresponde à expressão regular fornecida, nem qualquer caractere alfabético.

8. Parâmetros

Até este ponto, cobrimos a sintaxe para declarar tipos de parâmetros no arquivo de rotas.

Nesta seção, veremos mais opções disponíveis para nós ao lidar com parâmetros em rotas.

8.1. Parâmetros com valores fixos

Às vezes, queremos usar um valor fixo para um parâmetro. Esta é a nossa maneira de dizer ao Play para usar o parâmetro de caminho fornecido ou, se o contexto da solicitação for o caminho/, use um determinado valor fixo.

Outra maneira de ver é ter dois pontos de extremidade ou caminhos de contexto que levam à mesma ação do controlador - com um ponto de extremidade exigindo um parâmetro da URL de solicitação e padronizando para o outro caso o referido parâmetro esteja ausente.

Para demonstrar isso, vamos adicionar uma açãowriter() aoHomeController:

public Result writer() {
    return ok("Routing in Play by example");
}

Presumindo que nem sempre queremos que nossa API retorne umString:

Routing in Play by example

Queremos controlá-lo enviando o nome de um autor do artigo junto com a solicitação, padronizando para o valor fixoexample apenas se a solicitação não tiver o parâmetroauthor.

Então, vamos alterar a açãowriter adicionando um parâmetro:

public Result writer(String author) {
    return ok("REST API with Play by " + author);
}

Vejamos também como adicionar um parâmetro de valor fixo à rota:

GET     /writer           controllers.HomeController.writer(author = "example")
GET     /writer/:author   controllers.HomeController.writer(author: String)

Observe como agora temos duas rotas separadas, todas levando à açãoHomeController.index em vez de uma.

Quando agora carregamoshttp://localhost:9000/writer do navegador, obtemos:

Routing in Play by example

E quando carregamoshttp://localhost:9000/writer/john, obtemos:

Routing in Play by john

8.2. Parâmetros com valores padrão

Além de ter valores fixos, os parâmetros também podem ter valores padrão. Ambos fornecem valores de fallback para os parâmetros de ação do controlador, caso a solicitação não forneça os valores necessários.

A diferença entre os dois é quefixed values are used as a fallback for path parameters while default values are used as a fallback for query parameters.

Os parâmetros de caminho são do formatohttp://localhost:9000/param1/param2 e os parâmetros de consulta são do formatohttp://localhost:9000/?param1=value1¶m2=value2.

A segunda diferença está na sintaxe de declarar os dois em uma rota. Os parâmetros de valor fixo usam o operador de atribuição como em:

author = "example"

Enquanto os valores padrão usam um tipo diferente de atribuição:

author ?= "example"

Usamos o operador?= que atribui condicionalmenteexample aauthor no caso deauthor não conter nenhum valor.

Para ter uma demonstração completa, vamos criar a açãoHomeController.writer. Digamos que, além do nome do autor, que é um parâmetro de caminho, também queremos passar o autorid como um parâmetro de consulta, que deve ser1 se não for passado na solicitação.

Mudaremos a ação dewriter para:

public Result writer(String author, int id) {
    return ok("Routing in Play by: " + author + " ID: " + id);
}

e as rotaswriter para:

GET     /writer           controllers.HomeController.writer(author="example", id: Int ?= 1)
GET     /writer/:author   controllers.HomeController.writer(author: String, id: Int ?= 1)

Agora carregandohttp://localhost:9000/writer vemos:

Routing in Play by: example ID: 1
Routing in Play by: example ID: 10
Routing in Play by: john ID: 1
Routing in Play by: john ID: 5

9. Conclusão

Neste artigo, exploramos a noção de roteamento em aplicativos Play. Também temos um artigo sobrebuilding a RESTful API with Play Framework onde os conceitos de roteamento neste tutorial são aplicados em um exemplo prático.

Como de costume, o código-fonte deste tutorial está disponívelover on GitHub.