快速入門:使用 Java 建立應用程式,其中顯示 Azure Functions 和 SignalR Service 的 GitHub 星號計數

在本文中,您將使用 Azure SignalR Service、Azure Functions 和 Java 來建置無伺服器應用程式,以將訊息廣播至用戶端。

注意

本文中的程式代碼可在 GitHub取得。

必要條件

  • 程式碼編輯器,例如 Visual Studio Code

  • 具有有效訂用帳戶的 Azure 帳戶。 如果您還沒有帳戶, 請免費建立帳戶。

  • Azure Functions Core Tools。 用來在本機執行 Azure Function 應用程式。

    • 只有 Azure Function Core Tools 2.4.419 版(主機版本 2.0.12332)或更新版本才支援 Java 中所需的 SignalR Service 系結。
    • 若要安裝擴充功能,Azure Functions Core Tools 需要 安裝 .NET Core SDK 。 不過,建置 Java Azure Function 應用程式不需要具備 .NET 的知識。
  • Java Developer Kit 第 11 版

  • Apache Maven 3.0 版或更新版本。

本快速入門可以在 macOS、Windows 或 Linux 上執行。

建立 Azure SignalR 服務實例

在本節中,您會建立要用於應用程式的基本 Azure SignalR 實例。 下列步驟會使用 Azure 入口網站 來建立新的實例,但您也可以使用 Azure CLI。 如需詳細資訊,請參閱 Azure SignalR Service CLI 參考中的 az signalr create 命令。

  1. 登入 Azure 入口網站
  2. 在頁面左上角,選取 [+ 建立資源]。
  3. 在 [建立資源] 頁面上的 [搜尋服務 和市集] 文本框中,輸入 signalr,然後從列表中選取 SignalR Service
  4. 在 [ SignalR 服務] 頁面上,選取 [ 建立]。
  5. 在 [ 基本] 索引 標籤上,輸入新 SignalR Service 實例的基本資訊。 輸入下列值:
欄位 建議的值 描述
訂用帳戶 選擇您的訂用帳戶 選取您想要用來建立新 SignalR Service 實例的訂用帳戶。
資源群組 建立名為 SignalRTestResources 的資源群組 選取或建立 SignalR 資源的資源群組。 為本教學課程建立新的資源群組,而不是使用現有的資源群組會很有用。 若要在完成本教學課程之後釋放資源,請刪除資源群組。

刪除資源群組也會刪除屬於群組的所有資源。 此動作無法復原。 刪除資源群組之前,請確定它不包含您想要保留的資源。

如需詳細資訊,請參閱 使用資源群組來管理您的 Azure 資源
資源名稱 testsignalr 輸入要用於 SignalR 資源的唯一資源名稱。 如果您的 區域中已經採用testignalr ,請新增數位或字元,直到名稱是唯一的。

名稱必須是 1 到 63 個字元的字串,且只包含數位、字母和連字元 (-) 字元。 名稱不能以連字元字元開頭或結尾,且連續連字元字元無效。
區域 選擇您的區域 為新的 SignalR 服務實例選取適當的區域。

Azure SignalR Service 目前無法在所有區域中使用。 如需詳細資訊,請參閱 Azure SignalR 服務區域可用性
定價層 選取 [變更],然後選擇 [免費](僅限開發/測試)。 選擇 [ 選取 ] 以確認您選擇的定價層。 Azure SignalR Service 有三個定價層:免費、標準和 進階版。 除非必要條件另有說明,否則教學課程會使用 免費 層。

如需階層與定價之間功能差異的詳細資訊,請參閱 Azure SignalR 服務定價
服務模式 選擇適當的服務模式 當您在 Web 應用程式中裝載 SignalR 中樞邏輯,並使用 SignalR 服務作為 Proxy 時,請使用預設值。 當您使用無伺服器技術,例如 Azure Functions 來裝載 SignalR 中樞邏輯時,請使用 伺服器。

傳統 模式僅供回溯相容性使用,不建議使用。

如需詳細資訊,請參閱 Azure SignalR Service 中的服務模式。

您不需要變更 SignalR 教學課程之 [網络標籤 ] 索引標籤上的設定。

  1. 選取 [基本] 索引標籤底部的 [檢閱 + 建立] 按鈕。
  2. 在 [ 檢閱 + 建立] 索引卷標上,檢閱值,然後選取 [ 建立]。 部署需要一些時間才能完成。
  3. 部署完成時,選取 [移至資源 ] 按鈕。
  4. 在 [SignalR 資源] 頁面上,從左側功能表中選取 [密鑰],在 [設定]。
  5. 複製主鍵的 連線 字串。 在本教學課程稍後,您需要此 連接字串 來設定您的應用程式。

設定和執行 Azure 函式應用程式

請確定您已安裝 Azure Function Core Tools、Java(範例中的第 11 版),以及 Maven。

  1. 使用 Maven 初始化專案:

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

    Maven 會要求您提供完成產生專案所需的值。 提供下列值:

    提示 Description
    groupId com.signalr 值,可針對所有專案唯一識別您的專案,並遵循 Java 的套件命名規則
    artifactId java 值,這個值是 jar 的名稱,不含版本號碼。
    version 1.0-SNAPSHOT 選擇預設值。
    com.signalr 值,這是所產生函式程序代碼的 Java 套件。 使用預設值。
  2. 移至資料夾 src/main/java/com/signalr ,並將下列程式代碼 複製到 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. 需要新增一些相依性。 開啟 pom.xml ,並新增程式代碼中使用的下列相依性:

    <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. 此範例的用戶端介面是網頁。 我們會從函式中的 index content/index.html 讀取 HTML 內容,然後在 目錄中建立新的檔案 content/index.htmlresources。 您的目錄樹狀結構看起來應該像這樣:

        | - src
        | | - main
        | | | - java
        | | | | - com
        | | | | | - signalr
        | | | | | | - Function.java
        | | | - resources
        | | | | - content
        | | | | | - index.html
        | - pom.xml
        | - host.json
        | - local.settings.json
    
  5. 開啟 index.html 並複製下列內容:

    <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. Azure Functions 需要記憶體帳戶才能運作。 您可以安裝並執行 Azure 儲存體 模擬器

  7. 你現在幾乎完成了。 最後一個步驟是將 SignalR Service 的 連接字串 設定為 Azure 函式設定。

    1. 使用 Azure 入口網站 中的 [搜尋] 方塊,搜尋您稍早部署的 Azure SignalR 實例。 選取 實例以開啟它。

      Search for the SignalR Service instance

    2. 選取 [金鑰] 以檢視 SignalR Service 實例的 連接字串。

      Screenshot that highlights the primary connection string.

    3. 複製主要 連接字串,然後執行下列命令:

      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. 在本機執行 Azure 函式:

    mvn clean package
    mvn azure-functions:run
    

    在 Azure 函式在本機執行之後,請移至 http://localhost:7071/api/index ,您會看到目前的星號計數。 如果您在 GitHub 中以星號或「取消星號」顯示,您就會每隔幾秒鐘重新整理一次星號計數。

清除資源

如果您不打算繼續使用此應用程式,請使用下列步驟刪除本快速入門所建立的所有資源,因此不會產生任何費用:

  1. 在 Azure 入口網站中選取最左側的 [資源群組],然後選取您所建立的資源群組。 或者,您可以使用搜尋方塊依其名稱尋找資源群組。

  2. 在開啟的視窗中,選取資源群組,然後按兩下 [ 刪除資源群組]。

  3. 在新視窗中輸入要刪除之資源群組的名稱,然後按一下 [刪除]

發生問題嗎? 請嘗試疑難解答指南,或讓我們知道

下一步

在本快速入門中,您已在本機主機中建置並執行即時無伺服器應用程式。 接下來,深入瞭解如何使用 SignalR Service 在用戶端與 Azure 函式之間進行雙向通訊。