Início Rápido: Usar o Java para criar um aplicativo mostrando a contagem estrelas do GitHub com o Azure Functions e o Serviço do SignalR

Neste artigo, você usará o Serviço do Azure SignalR, o Azure Functions e o Java para criar um aplicativo sem servidor com a fim de difundir mensagens aos clientes.

Observação

O código deste artigo está disponível no GitHub.

Pré-requisitos

  • Um editor de códigos, como o Visual Studio Code

  • Uma conta do Azure com uma assinatura ativa. Se você ainda não tiver uma conta, crie uma conta gratuitamente.

  • Azure Functions Core Tools. Usado para executar os aplicativos de funções do Azure localmente.

    • Só há suporte para as associações do Serviço do SignalR necessárias em Java no Azure Functions Core Tools versão 2.4.419 (versão do host 2.0.12332) ou superior.
    • Para instalar extensões, o Azure Functions Core Tools exige o SDK do .NET Core instalado. No entanto, não é necessário nenhum conhecimento do .NET para criar aplicativos do Azure Functions no Java.
  • Java Developer Kit, versão 11

  • Apache Maven, versão 3.0 ou posterior.

Este início rápido pode ser executado no macOS, Windows ou Linux.

Criar uma instância do Serviço Azure SignalR

Nesta seção, você criará uma instância básica do Azure SignalR para usar em seu aplicativo. As etapas a seguir usam o portal do Azure para criar uma nova instância, mas você também pode usar a CLI do Azure. Para obter mais informações, consulte o comando az signalr create na referência da CLI do serviço do Azure SignalR.

  1. Entre no portal do Azure.
  2. No canto superior esquerdo da página, escolha + Criar um recurso.
  3. Na página Criar um recurso, na caixa de texto serviços Pesquisa e marketplace, insira signalr e, em seguida, selecione Serviço do SignalR na lista.
  4. Na página Serviço do SignalR, selecione Criar.
  5. Na guia Noções básicas, você inserirá as informações essenciais para sua nova instância do Serviço do SignalR. Insira os valores a seguir:
Campo Valor sugerido Descrição
Assinatura Escolha sua assinatura Selecione a assinatura que você deseja usar para criar uma nova instância do serviço do SignalR.
Grupo de recursos Criar um grupo de recursos chamado SignalRTestResources Selecione ou crie um grupo de recursos para seu recurso do SignalR. É útil criar um novo grupo de recursos para este tutorial em vez de usar um grupo de recursos existente. Para liberar recursos depois de concluir o tutorial, exclua o grupo de recursos.

A exclusão de um grupo de recursos também exclui todos os recursos que pertencem ao grupo. Essa ação não pode ser desfeita. Antes de excluir um grupo de recursos, certifique-se de que ele não contenha os recursos que você deseja manter.

Para obter mais informações, consulte Usando os grupos de recursos para gerenciar seus recursos do Azure.
Nome do recurso testsignalr Insira um nome exclusivo do recurso a ser usado para o recurso do SignalR. Se testsignalr já estiver sendo usado em sua região, adicione um dígito ou caractere até que o nome seja exclusivo.

O nome deve ser uma cadeia de caracteres com 1 a 63 caracteres, e deve conter somente números, letras e o hífen (-). O nome não pode começar nem terminar com o caractere hífen, e os caracteres hífen consecutivos não serão válidos.
Região Escolha a região Selecione a região apropriada para sua nova instância do serviço do SignalR.

O serviço do Azure SignalR não está disponível atualmente em todas as regiões. Para saber mais, confira Disponibilidade por região do serviço do Azure SignalR
Tipo de preços Selecione Alterar e, em seguida, escolha Gratuito (somente desenvolvimento/teste). Escolha Selecionar para confirmar sua escolha de tipo de preço. O serviço do Azure SignalR tem três tipos de preço: Gratuito, Standard e Premium. Os tutoriais usam o tipo Gratuito, a menos que indicado de outra forma nos pré-requisitos.

Para obter mais informações sobre as diferenças de funcionalidade entre tipos e preços, consulte preço do serviço do Azure SignalR
Modo de serviço Escolher o modo de serviço apropriado Use Padrão ao hospedar a lógica do hub do SignalR em seus aplicativos Web e usar o serviço SignalR como um proxy. Use Sem servidor ao usar tecnologias sem servidor, como o Azure Functions, para hospedar a lógica do hub do SignalR.

O modo Clássico é apenas para compatibilidade com versões anteriores e não é recomendável usar.

Para obter mais informações, confira Modo de serviço no serviço do Azure SignalR.

Você não precisa alterar as configurações nas guias Rede e Marcações para os tutoriais do SignalR.

  1. Selecione o botão Revisar + criar na parte inferior da guia Noções básicas.
  2. Na guia Revisar + Criar, revise os valores e, em seguida, selecione Criar. A implantação leva alguns momentos para ser concluída.
  3. Depois que a implantação estiver concluída, selecione o botão Ir para o recurso.
  4. Na tela de recursos do SignalR, selecione Chaves no menu à esquerda, em Configurações.
  5. Copie a Cadeia de conexão para a chave primária. Você precisará dessa cadeia de conexão para configurar seu aplicativo posteriormente neste tutorial.

Configurar e executar o aplicativo do Azure Functions

Verifique se o Azure Function Core Tools, Java (versão 11 no exemplo) e Maven estão instalados.

  1. Inicialize o projeto usando o Maven:

    mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DjavaVersion=11
    

    O Maven solicita os valores necessários para concluir a geração do projeto. Forneça os seguintes valores:

    Prompt Valor Descrição
    groupId com.signalr Um valor que identifica exclusivamente o projeto em todos os projetos, seguindo as regras de nomenclatura do pacote para Java.
    artifactId java Um valor que é o nome do jar, sem um número de versão.
    version 1.0-SNAPSHOT Escolha o valor padrão.
    package com.signalr Um valor que é o pacote Java para o código de função gerado. Use o padrão.
  2. Acesse a pasta src/main/java/com/signalr e copie os seguintes códigos para Function.java:

    package com.signalr;
    
    import com.google.gson.Gson;
    import com.microsoft.azure.functions.ExecutionContext;
    import com.microsoft.azure.functions.HttpMethod;
    import com.microsoft.azure.functions.HttpRequestMessage;
    import com.microsoft.azure.functions.HttpResponseMessage;
    import com.microsoft.azure.functions.HttpStatus;
    import com.microsoft.azure.functions.annotation.AuthorizationLevel;
    import com.microsoft.azure.functions.annotation.FunctionName;
    import com.microsoft.azure.functions.annotation.HttpTrigger;
    import com.microsoft.azure.functions.annotation.TimerTrigger;
    import com.microsoft.azure.functions.signalr.*;
    import com.microsoft.azure.functions.signalr.annotation.*;
    
    import org.apache.commons.io.IOUtils;
    
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.URI;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.net.http.HttpResponse.BodyHandlers;
    import java.nio.charset.StandardCharsets;
    import java.util.Optional;
    
    public class Function {
        private static String Etag = "";
        private static String StarCount;
    
        @FunctionName("index")
        public HttpResponseMessage run(
                @HttpTrigger(
                    name = "req",
                    methods = {HttpMethod.GET},
                    authLevel = AuthorizationLevel.ANONYMOUS)HttpRequestMessage<Optional<String>> request,
                final ExecutionContext context) throws IOException {
    
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("content/index.html");
            String text = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name());
            return request.createResponseBuilder(HttpStatus.OK).header("Content-Type", "text/html").body(text).build();
        }
    
        @FunctionName("negotiate")
        public SignalRConnectionInfo negotiate(
                @HttpTrigger(
                    name = "req",
                    methods = { HttpMethod.POST },
                    authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> req,
                @SignalRConnectionInfoInput(
                    name = "connectionInfo",
                    hubName = "serverless") SignalRConnectionInfo connectionInfo) {
    
            return connectionInfo;
        }
    
        @FunctionName("broadcast")
        @SignalROutput(name = "$return", hubName = "serverless")
        public SignalRMessage broadcast(
            @TimerTrigger(name = "timeTrigger", schedule = "*/5 * * * * *") String timerInfo) throws IOException, InterruptedException {
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest req = HttpRequest.newBuilder().uri(URI.create("https://api.github.com/repos/azure/azure-signalr")).header("User-Agent", "serverless").header("If-None-Match", Etag).build();
            HttpResponse<String> res = client.send(req, BodyHandlers.ofString());
            if (res.headers().firstValue("Etag").isPresent())
            {
                Etag = res.headers().firstValue("Etag").get();
            }
            if (res.statusCode() == 200)
            {
                Gson gson = new Gson();
                GitResult result = gson.fromJson(res.body(), GitResult.class);
                StarCount = result.stargazers_count;
            }
    
            return new SignalRMessage("newMessage", "Current start count of https://github.com/Azure/azure-signalr is:".concat(StarCount));
        }
    
        class GitResult {
            public String stargazers_count;
        }
    }
    
  3. Algumas dependências precisam ser adicionadas. Abra pom.xml e adicione as seguintes dependências usadas no código:

    <dependency>
        <groupId>com.microsoft.azure.functions</groupId>
        <artifactId>azure-functions-java-library-signalr</artifactId>
        <version>1.0.0</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.7</version>
    </dependency>
    
  4. A interface do cliente deste exemplo é uma página da Web. Lemos o conteúdo HTML do content/index.html na função index e, em seguida, criamos um arquivo content/index.html no diretório resources. A árvore do seu diretório deve estar semelhante ao seguinte:

        | - src
        | | - main
        | | | - java
        | | | | - com
        | | | | | - signalr
        | | | | | | - Function.java
        | | | - resources
        | | | | - content
        | | | | | - index.html
        | - pom.xml
        | - host.json
        | - local.settings.json
    
  5. Abra o index.html e copie o conteúdo a seguir:

    <html>
    
    <body>
        <h1>Azure SignalR Serverless Sample</h1>
        <div id="messages"></div>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.7/signalr.min.js"></script>
        <script>
        let messages = document.querySelector('#messages');
        const apiBaseUrl = window.location.origin;
        const connection = new signalR.HubConnectionBuilder()
            .withUrl(apiBaseUrl + '/api')
            .configureLogging(signalR.LogLevel.Information)
            .build();
            connection.on('newMessage', (message) => {
            document.getElementById("messages").innerHTML = message;
            });
    
            connection.start()
            .catch(console.error);
        </script>
    </body>
    
    </html>
    
  6. O Azure Functions exige uma conta de armazenamento para funcionar. Você pode instalar e executar o Emulador do Armazenamento do Azure.

  7. Você já está quase terminando. A última etapa é definir uma cadeia de conexão do Serviço do SignalR para as configurações do Azure Function.

    1. Pesquise a instância do Azure SignalR implantada anteriormente usando a caixa Pesquisar no portal do Azure. Selecione a instância para abri-la.

      Search for the SignalR Service instance

    2. Selecione Chaves para exibir as cadeias de conexão para a instância do SignalR Service.

      Screenshot that highlights the primary connection string.

    3. Copie a cadeia de conexão primária e execute o seguinte comando:

      func settings add AzureSignalRConnectionString "<signalr-connection-string>"
      # Also we need to set AzureWebJobsStorage as Azure Function's requirement
      func settings add AzureWebJobsStorage "UseDevelopmentStorage=true"
      
  8. Execute o Azure Function localmente:

    mvn clean package
    mvn azure-functions:run
    

    Depois que a Função do Azure estiver em execução localmente, acesse o http://localhost:7071/api/index e você verá a contagem de estrelas atual. Se você adicionar ou remover uma estrela no GitHub, obterá uma contagem de estrelas atualizada em intervalos de alguns segundos.

Limpar os recursos

Se você não pretende continuar a usar este aplicativo, exclua todos os recursos criados por esse início rápido com as seguintes etapas para não incorrer em alterações:

  1. No portal do Azure, selecione Grupos de recursos na extremidade esquerda, depois selecione o recurso de grupo que você criou. Como alternativa, você pode usar a caixa de pesquisa para localizar o grupo de recursos pelo nome.

  2. Na janela que se abre, selecione o grupo de recursos e clique em Excluir grupo de recursos.

  3. Na nova janela, digite o nome do grupo de recursos a ser excluído, depois clique em Excluir.

Está com problemas? Experimente o guia de solução de problemas ou fale conosco.

Próximas etapas

Neste início rápido, você criou e executou um aplicativo sem servidor em tempo real no host local. Depois, saiba mais sobre como se comunicar de forma bidirecional entre clientes e o Azure Functions com o Serviço do SignalR.