title | description | author | ms.author | ms.date | ms.topic | ms.service | ms.devlang | ms.custom |
---|---|---|---|---|---|---|---|---|
Use Java to create a chat room with Azure Functions and SignalR Service |
A quickstart for using Azure SignalR Service and Azure Functions to create an App showing GitHub star count using Java. |
vicancy |
lianwei |
04/04/2022 |
quickstart |
azure-signalr-service |
java |
devx-track-java, mode-api, devx-track-extended-java |
Quickstart: Use Java to create an App showing GitHub star count with Azure Functions and SignalR Service
In this article, you'll use Azure SignalR Service, Azure Functions, and Java to build a serverless application to broadcast messages to clients.
Note
The code in this article is available on GitHub.
-
A code editor, such as Visual Studio Code
-
An Azure account with an active subscription. If you don't already have an account, create an account for free.
-
Azure Functions Core Tools. Used to run Azure Function apps locally.
- The required SignalR Service bindings in Java are only supported in Azure Function Core Tools version 2.4.419 (host version 2.0.12332) or above.
- To install extensions, Azure Functions Core Tools requires the .NET Core SDK installed. However, no knowledge of .NET is required to build Java Azure Function apps.
-
Java Developer Kit, version 11
-
Apache Maven, version 3.0 or above.
This quickstart can be run on macOS, Windows, or Linux.
[!INCLUDE Create instance]
Make sure you have Azure Function Core Tools, Java (version 11 in the sample), and Maven installed.
-
Initialize the project using Maven:
mvn archetype:generate -DarchetypeGroupId=com.microsoft.azure -DarchetypeArtifactId=azure-functions-archetype -DjavaVersion=11
Maven asks you for values needed to finish generating the project. Provide the following values:
Prompt Value Description groupId com.signalr
A value that uniquely identifies your project across all projects, following the package naming rules for Java. artifactId java
A value that is the name of the jar, without a version number. version 1.0-SNAPSHOT
Choose the default value. package com.signalr
A value that is the Java package for the generated function code. Use the default. -
Go to the folder
src/main/java/com/signalr
and copy the following code to 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; } }
-
Some dependencies need to be added. Open pom.xml and add the following dependencies used in the code:
<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>
-
The client interface for this sample is a web page. We read HTML content from content/index.html in the
index
function, and then create a new file content/index.html in theresources
directory. Your directory tree should look like this:| - src | | - main | | | - java | | | | - com | | | | | - signalr | | | | | | - Function.java | | | - resources | | | | - content | | | | | - index.html | - pom.xml | - host.json | - local.settings.json
-
Open index.html and copy the following content:
<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>
-
Azure Functions requires a storage account to work. You can install and run the Azure Storage Emulator.
-
You're almost done now. The last step is to set a connection string of the SignalR Service to Azure Function settings.
-
Search for the Azure SignalR instance you deployed earlier using the Search box in Azure portal. Select the instance to open it.
-
Select Keys to view the connection strings for the SignalR Service instance.
-
Copy the primary connection string, and then run the following command:
func settings add AzureSignalRConnectionString "<signalr-connection-string>" # Also we need to set AzureWebJobsStorage as Azure Function's requirement func settings add AzureWebJobsStorage "UseDevelopmentStorage=true"
-
-
Run the Azure Function in local:
mvn clean package mvn azure-functions:run
After Azure Function is running locally, go to
http://localhost:7071/api/index
and you'll see the current star count. If you star or "unstar" in the GitHub, you'll get a star count refreshing every few seconds.
[!INCLUDE Cleanup]
Having issues? Try the troubleshooting guide or let us know.
In this quickstart, you built and ran a real-time serverless application in the local host. Next, learn more about how to bi-directional communicating between clients and Azure Function with SignalR Service.
[!div class="nextstepaction"] SignalR Service bindings for Azure Functions
[!div class="nextstepaction"] Bi-directional communicating in Serverless
[!div class="nextstepaction"] Create your first function with Java and Maven