Zelfstudie: Een Java-webtoepassing bouwen met Behulp van Azure Cosmos DB en de API voor NoSQL

VAN TOEPASSING OP: NoSQL

In deze zelfstudie over Java-webtoepassingen wordt uitgelegd hoe u de Microsoft Azure Cosmos DB-service gebruikt voor het opslaan van en de toegang tot een Java-toepassing die wordt gehost in Azure App Service Web Apps. Zonder creditcard of azure-abonnement kunt u een gratis Probeer Azure Cosmos DB-account instellen. In dit artikel leert u het volgende:

  • Een eenvoudige JSP-toepassing (JavaServer Pages) maken in Eclipse.
  • Werken met de Azure Cosmos DB-service met behulp van de Azure Cosmos DB Java SDK.

In deze zelfstudie over het maken van een Java-toepassing wordt uitgelegd hoe u een webtoepassing voor taakbeheer maakt waarmee u taken kunt maken, ophalen en als voltooid kunt markeren, zoals in de volgende afbeelding. Alle taken in de ToDo-lijst worden als JSON-documenten opgeslagen in Azure Cosmos DB.

De Java-toepassing My ToDo List

Tip

In deze zelfstudie voor het ontwikkelen van toepassingen wordt ervan uitgegaan dat u ervaring met Java hebt. Als u niet bekend bent met Java of de vereiste hulpprogramma's, is het raadzaam het volledige todo-project via GitHub te downloaden. Vervolgens kunt u de instructies aan het eind van dit artikel gebruiken om het project op te bouwen. Zodra u klaar bent, kunt u het artikel lezen voor meer informatie over de code in de context van het project.

Vereisten voor deze zelfstudie over Java-webtoepassingen

Voordat u met deze zelfstudie over het ontwikkelen van toepassingen aan de slag gaat, moet u beschikken over het volgende:

Als u deze hulpprogramma's voor het eerst installeert, kunt u op coreservlets.com in de quickstart-sectie van het artikel Tutorial: Installing TomCat7 and Using it with Eclipse (Zelfstudie: TomCat7 installeren en gebruiken met Eclipse) een overzicht van het installatieproces vinden.

Maak een Azure Cosmos DB-account

Begin met het maken van een Azure Cosmos DB-account. Als u al een account hebt of de Azure Cosmos DB-emulator gebruikt voor deze zelfstudie, kunt u direct doorgaan naar Stap 2: De Java JSP-toepassing maken.

  1. Selecteer vanuit het menu van Azure Portal of op de startpagina de optie Een resource maken.

  2. Zoek naar Azure Cosmos DB. Selecteer Azure>Cosmos DB maken.

  3. Selecteer op de pagina Een Azure Cosmos DB-account maken de optie Maken in de sectie Azure Cosmos DB for NoSQL .

    Azure Cosmos DB biedt verschillende API's:

    • NoSQL voor documentgegevens
    • PostgreSQL
    • MongoDB, voor documentgegevens
    • Apache Cassandra
    • Tabel
    • Apache Gremlin voor grafiekgegevens

    Zie Welkom bij Azure Cosmos DB voor meer informatie over de API voor NoSQL.

  4. Voer op de pagina Azure Cosmos DB-account maken de basisinstellingen voor het nieuwe Azure Cosmos DB-account in.

    Instelling Waarde Beschrijving
    Abonnement Abonnementsnaam Selecteer het Azure-abonnement dat u voor dit Azure Cosmos DB-account wilt gebruiken.
    Resourcegroep Naam van de resourcegroep Selecteer een resourcegroep of selecteer Nieuwe maken en voer vervolgens een unieke naam in voor de nieuwe resourcegroep.
    Accountnaam Een unieke naam Voer een naam in om uw Azure Cosmos DB-account te identificeren. Gebruik een unieke naam omdat documents.azure.com is toegevoegd aan de naam die u hebt opgegeven om uw URI te maken. De naam mag alleen kleine letters, cijfers en het afbreekstreepje (-) bevatten. Deze moet 3-44 tekens bevatten.
    Locatie De regio het dichtst bij uw gebruikers Selecteer een geografische locatie waar u het Azure Cosmos DB-account wilt hosten. Gebruik de locatie die zich het dichtst bij uw gebruikers bevindt, zodat ze de snelst mogelijke toegang tot de gegevens hebben.
    Capaciteitsmodus Ingerichte doorvoer of serverloos Selecteer Ingerichte doorvoer om een account te maken in de modus Ingerichte doorvoer. Selecteer Serverloos om een account te maken in de modus serverloos.
    Niveaukorting op gratis laag van Azure Cosmos DB toepassen Toepassen of niet toepassen Met de gratis laag van Azure Cosmos DB krijgt u de eerste 1000 RU/s en 25 GB gratis opslagruimte in een account. Meer informatie over de gratis laag.
    Totale accountdoorvoer beperken Geselecteerd of niet Beperk de totale hoeveelheid doorvoer die voor dit account kan worden ingericht. Deze limiet voorkomt onverwachte kosten met betrekking tot ingerichte doorvoer. U kunt deze limiet bijwerken of verwijderen nadat uw account is gemaakt.

    U kunt maximaal één Azure Cosmos DB-account in de gratis laag per Azure-abonnement hebben en u moet zich aanmelden bij het maken van het account. Als u de optie voor het toepassen van de korting voor de gratis laag niet ziet, is een ander account in het abonnement al ingeschakeld met de gratis laag.

    Schermopname van de pagina Azure Cosmos DB-account maken.

    Notitie

    De volgende opties zijn niet beschikbaar als u Serverloos als Capaciteitsmodus selecteert:

    • Korting voor gratis lagen toepassen
    • Totale accountdoorvoer beperken
  5. Configureer op het tabblad Globale distributie de volgende details. U kunt de standaardwaarden voor deze quickstart laten staan:

    Instelling Waarde Beschrijving
    Georedundantie Uitschakelen Schakel globale distributie voor uw account in of uit door uw regio te koppelen met een koppelingsregio. U kunt later meer regio's aan uw account toevoegen.
    Schrijven voor meerdere regio's Uitschakelen Dankzij de mogelijkheid voor schrijfbewerkingen in meerdere regio's kunt over de hele wereld profiteren van de ingerichte doorvoer voor uw databases en containers.
    Beschikbaarheidszones Uitschakelen Met beschikbaarheidszones kunt u de beschikbaarheid en tolerantie van uw toepassing verder verbeteren.

    Notitie

    De volgende opties zijn niet beschikbaar als u Serverloos selecteert als capaciteitsmodus op de vorige pagina Basisbeginselen :

    • Geografische redundantie
    • Schrijven voor meerdere regio's
  6. U kunt desgewenst meer details configureren op de volgende tabbladen:

  7. Selecteer Controleren + maken.

  8. Controleer de accountinstellingen en selecteer vervolgens Maken. Het duurt een paar minuten om het account te maken. Wacht tot de portal-pagina Uw implementatie is voltooid weergeeft.

    Schermopname die laat zien dat uw implementatie is voltooid.

  9. Selecteer Ga naar resource om naar de Azure Cosmos DB-accountpagina te gaan.

    Schermopname van de azure Cosmos DB-accountpagina.

Ga naar de accountpagina van Azure Cosmos DB en selecteer Sleutels. Kopieer de waarden die moeten worden gebruikt in de webtoepassing die u hierna maakt.

Schermopname van Azure Portal waarin de knop Sleutels is gemarkeerd op de accountpagina van Azure Cosmos DB

De Java JSP-toepassing maken

De JSP-toepassing maken:

  1. Als eerste moet u een Java-project maken. Start Eclipse, selecteer vervolgens Bestand, selecteer Nieuw en selecteer vervolgens Dynamisch webproject. Als dynamisch webproject niet wordt weergegeven als een beschikbaar project, gaat u als volgt te werk: Selecteer Bestand, selecteer Nieuw, selecteer Project..., vouw Web uit, selecteer Dynamisch webproject en selecteer Volgende.

    JSP Java-toepassing ontwikkelen

  2. Voer een projectnaam in het vak Projectnaam in en selecteer in het vervolgkeuzemenu Doelruntime eventueel een waarde (bijvoorbeeld Apache Tomcat v7.0) en selecteer vervolgens Voltooien. Door een doelruntime te selecteren, kunt u het project lokaal via Eclipse uitvoeren.

  3. Vouw in de weergave Project Explorer (Projectverkenner) van Eclipse uw project uit. Klik met de rechtermuisknop op WebContent, selecteer Nieuw en selecteer vervolgens JSP-bestand.

  4. Geef in het dialoogvenster New JSP File (Nieuw JSP-bestand) de naam index.jsp voor het bestand op. Behoud de bovenliggende map als WebContent, zoals wordt weergegeven in de volgende afbeelding, en selecteer vervolgens Volgende.

    Een nieuw JSP-bestand maken - Zelfstudie Java-webtoepassing

  5. Selecteer in het dialoogvenster JSP-sjabloon selecteren voor deze zelfstudie De optie Nieuw JSP-bestand (html) en selecteer vervolgens Voltooien.

  6. Wanneer het bestand index.jsp wordt geopend in Eclipse, voegt u tekst toe om Hallo wereld! weer te geven binnen het bestaande <body> element. De bijgewerkte <body>-inhoud moet eruitzien als de volgende code:

    <body>
      <% out.println("Hello World!"); %>
    </body>
    
  7. Sla het bestand index.jsp op.

  8. Als u in stap 2 een doelruntime instelt, kunt u Project selecteren en vervolgens Uitvoeren om uw JSP-toepassing lokaal uit te voeren:

    Hello World: zelfstudie Java-toepassing

De SQL Java SDK installeren

De eenvoudigste manier om de SQL Java SDK en de bijbehorende afhankelijkheden op te halen, is via Apache Maven. Hiervoor moet u met behulp van de volgende stappen het project converteren naar een Maven-project:

  1. Klik met de rechtermuisknop op uw project in Projectverkenner, selecteer Configureren en selecteer Converteren naar Maven-project.

  2. Accepteer de standaardwaarden in het venster Nieuwe POM maken en selecteer Voltooien.

  3. Ga naar de Projectverkenner en open het bestand pom.xml.

  4. Selecteer op het tabblad Afhankelijkheden in het deelvenster Afhankelijkheden de optie Toevoegen.

  5. Ga in het venster Select Dependency (Afhankelijkheid selecteren) als volgt te werk:

    • Voer com.azure in het vak Groeps-id in.
    • Voer azure-cosmos in het vak Artefact-id in.
    • Voer 4.11.0 in het vak Versie in.

    Of voeg de afhankelijkheids-XML voor de groeps- en artefact-id rechtstreeks toe aan het bestand pom.xml:

    <dependency>
      <groupId>com.azure</groupId>
      <artifactId>azure-cosmos</artifactId>
      <version>4.11.0</version>
    </dependency>
    
  6. Selecteer OK . Maven installeert de SQL Java SDK of slaat het pom.xml-bestand op.

De Azure Cosmos DB-service in uw Java-toepassing gebruiken

U kunt nu de modellen, weergaven en controllers toevoegen aan uw webtoepassing.

Een model toevoegen

Eerst gaan we een model definiëren in een nieuw bestand TodoItem.java. Met de TodoItem-klasse wordt het schema van een item gedefinieerd, samen met de ophaal- en installatiemethoden:

package com.microsoft.azure.cosmos.sample.model;

//@Data
//@Builder
public class TodoItem {
    private String entityType;
    private String category;
    private boolean complete;
    private String id;
    private String name;

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getEntityType() {
        return entityType;
    }

    public void setEntityType(String entityType) {
        this.entityType = entityType;
    }

    public boolean isComplete() {
        return complete;
    }

    public void setComplete(boolean complete) {
        this.complete = complete;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    
}

De DAO-klassen (Data Access Object) toevoegen

Maak een Data Access-object (DAO) om de ToDo-items naar Azure Cosmos DB te abstraheren. De client moet weten welke database en verzameling moeten worden gebruikt (waarnaar wordt verwezen via self link-elementen) om de ToDo-items op te kunnen slaan naar een verzameling. Indien mogelijk slaat u de database en verzameling op in het cachegeheugen om extra retouren naar de database te voorkomen.

  1. Als u de Azure Cosmos DB-service wilt aanroepen, moet u een nieuw cosmosClient-object maken. Doorgaans kunt u het cosmosClient-object het best opnieuw gebruiken, zodat u het niet voor elke volgende aanvraag en nieuwe client hoeft te maken. U kunt de client opnieuw gebruiken door deze te definiëren in de cosmosClientFactory-klasse. Werk de HOST- en MASTER_KEY-waarden die u hebt opgeslagen in stap 1 bij. Vervang de HOST-variabele door uw URI en vervang de MASTER_KEY door uw PRIMAIRE SLEUTEL. Gebruik de volgende code om de CosmosClientFactory-klasse te maken in het bestand CosmosClientFactory.java:

    package com.microsoft.azure.cosmos.sample.dao;
    
    import com.azure.cosmos.ConsistencyLevel;
    import com.azure.cosmos.CosmosClient;
    import com.azure.cosmos.CosmosClientBuilder;
    
    public class CosmosClientFactory {
        private static final String HOST = "[ACCOUNT HOST NAME]";
        private static final String MASTER_KEY = "[ACCOUNT KEY]";
    
        private static CosmosClient cosmosClient = new CosmosClientBuilder()
                .endpoint(HOST)
                .key(MASTER_KEY)
                .consistencyLevel(ConsistencyLevel.EVENTUAL)
                .buildClient();
    
        public static CosmosClient getCosmosClient() {
            return cosmosClient;
        }
    
    }
    
  2. Maak een nieuw TodoDao.java-bestand en voeg de TodoDao-klasse toe om de TODO-items te maken, bij te werken, te lezen en te verwijderen:

    package com.microsoft.azure.cosmos.sample.dao;
    
    import java.util.List;
    
    import com.microsoft.azure.cosmos.sample.model.TodoItem;
    
    public interface TodoDao {
        /**
         * @return A list of TodoItems
         */
        public List<TodoItem> readTodoItems();
    
        /**
         * @param todoItem
         * @return whether the todoItem was persisted.
         */
        public TodoItem createTodoItem(TodoItem todoItem);
    
        /**
         * @param id
         * @return the TodoItem
         */
        public TodoItem readTodoItem(String id);
    
        /**
         * @param id
         * @return the TodoItem
         */
        public TodoItem updateTodoItem(String id, boolean isComplete);
    
        /**
         *
         * @param id
         * @return whether the delete was successful.
         */
        public boolean deleteTodoItem(String id);
    }
    
  3. Maak een nieuw MockDao.java-bestand en voeg de MockDao-klasse toe; met deze klasse wordt de TodoDao-klasse geïmplementeerd om CRUD-bewerkingen op de items uit te voeren:

    package com.microsoft.azure.cosmos.sample.dao;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import lombok.NonNull;
    
    import com.microsoft.azure.cosmos.sample.model.TodoItem;
    
    public class MockDao implements TodoDao {
        private final Map<String, TodoItem> todoItemMap;
    
        public MockDao() {
            todoItemMap = new HashMap<String, TodoItem>();
        }
    
        @Override
        public TodoItem createTodoItem(@NonNull TodoItem todoItem) {
            if (todoItem.getId() == null || todoItem.getId().isEmpty()) {
                todoItem.setId(generateId());
            }
            todoItemMap.put(todoItem.getId(), todoItem);
            return todoItem;
        }
    
        @Override
        public TodoItem readTodoItem(@NonNull String id) {
            return todoItemMap.get(id);
        }
    
        @Override
        public List<TodoItem> readTodoItems() {
            return new ArrayList<TodoItem>(todoItemMap.values());
        }
    
        @Override
        public TodoItem updateTodoItem(String id, boolean isComplete) {
            todoItemMap.get(id).setComplete(isComplete);
            return todoItemMap.get(id);
        }
    
        @Override
        public boolean deleteTodoItem(@NonNull String id) {
            todoItemMap.remove(id);
            return true;
        }
    
        private String generateId() {
            return new Integer(todoItemMap.size()).toString();
        }
    }
    
  4. Maak een nieuw DocDbDao.java-bestand en voeg de DocDbDao-klasse toe. In deze klasse wordt code gedefinieerd om de TodoItems in de container op te slaan, worden uw database en verzameling opgehaald, indien aanwezig, of wordt een nieuwe gemaakt als deze nog niet bestaat. In dit voorbeeld wordt Gson gebruikt om TodoItem POJO's (Plain Old Java Objects) naar JSON-documenten te serialiseren en te deserialiseren. De client moet weten welke database en verzameling moeten worden gebruikt (waarnaar wordt verwezen via self link-elementen) om de ToDo-items op te kunnen slaan naar een verzameling. In deze klasse wordt ook de Help-functie gedefinieerd om de documenten op te halen door een ander kenmerk (bijvoorbeeld id) in plaats van self link. U kunt de Help-methode gebruiken om een TodoItem JSON-document op te halen op basis van de id om het document vervolgens te deserialiseren naar een POJO.

    U kunt ook het clientobject cosmosClient gebruiken om een verzameling of lijst met TodoItems op te halen via een SQL-query. Ten slotte definieert u de verwijderingsmethode voor het verwijderen van een TodoItem uit uw lijst. De volgende code toont de inhoud van de DocDbDao-klasse:

    package com.microsoft.azure.cosmos.sample.dao;
    
    import com.azure.cosmos.CosmosClient;
    import com.azure.cosmos.CosmosContainer;
    import com.azure.cosmos.CosmosDatabase;
    import com.azure.cosmos.CosmosException;
    import com.azure.cosmos.implementation.Utils;
    import com.azure.cosmos.models.CosmosContainerProperties;
    import com.azure.cosmos.models.CosmosContainerResponse;
    import com.azure.cosmos.models.CosmosDatabaseResponse;
    import com.azure.cosmos.models.CosmosItemRequestOptions;
    import com.azure.cosmos.models.CosmosQueryRequestOptions;
    import com.azure.cosmos.models.FeedResponse;
    import com.azure.cosmos.models.PartitionKey;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import com.google.gson.Gson;
    import com.microsoft.azure.cosmos.sample.model.TodoItem;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class DocDbDao implements TodoDao {
        // The name of our database.
        private static final String DATABASE_ID = "TestDB";
    
        // The name of our collection.
        private static final String CONTAINER_ID = "TestCollection";
    
        // We'll use Gson for POJO <=> JSON serialization for this example.
        private static Gson gson = new Gson();
    
        // The Cosmos DB Client
        private static CosmosClient cosmosClient = CosmosClientFactory
            .getCosmosClient();
    
        // The Cosmos DB database
        private static CosmosDatabase cosmosDatabase = null;
    
        // The Cosmos DB container
        private static CosmosContainer cosmosContainer = null;
    
        // For POJO/JsonNode interconversion
        private static final ObjectMapper OBJECT_MAPPER = Utils.getSimpleObjectMapper();
    
        @Override
        public TodoItem createTodoItem(TodoItem todoItem) {
            // Serialize the TodoItem as a JSON Document.
    
            JsonNode todoItemJson = OBJECT_MAPPER.valueToTree(todoItem);
    
            ((ObjectNode) todoItemJson).put("entityType", "todoItem");
    
            try {
                // Persist the document using the DocumentClient.
                todoItemJson =
                    getContainerCreateResourcesIfNotExist()
                        .createItem(todoItemJson)
                        .getItem();
            } catch (CosmosException e) {
                System.out.println("Error creating TODO item.\n");
                e.printStackTrace();
                return null;
            }
    
    
            try {
    
                return OBJECT_MAPPER.treeToValue(todoItemJson, TodoItem.class);
                //return todoItem;
            } catch (Exception e) {
                System.out.println("Error deserializing created TODO item.\n");
                e.printStackTrace();
    
                return null;
            }
    
        }
    
        @Override
        public TodoItem readTodoItem(String id) {
            // Retrieve the document by id using our helper method.
            JsonNode todoItemJson = getDocumentById(id);
    
            if (todoItemJson != null) {
                // De-serialize the document in to a TodoItem.
                try {
                    return OBJECT_MAPPER.treeToValue(todoItemJson, TodoItem.class);
                } catch (JsonProcessingException e) {
                    System.out.println("Error deserializing read TODO item.\n");
                    e.printStackTrace();
    
                    return null;
                }
            } else {
                return null;
            }
        }
    
        @Override
        public List<TodoItem> readTodoItems() {
    
            List<TodoItem> todoItems = new ArrayList<TodoItem>();
    
            String sql = "SELECT * FROM root r WHERE r.entityType = 'todoItem'";
            int maxItemCount = 1000;
            int maxDegreeOfParallelism = 1000;
            int maxBufferedItemCount = 100;
    
            CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
            options.setMaxBufferedItemCount(maxBufferedItemCount);
            options.setMaxDegreeOfParallelism(maxDegreeOfParallelism);
            options.setQueryMetricsEnabled(false);
    
            int error_count = 0;
            int error_limit = 10;
    
            String continuationToken = null;
            do {
    
                for (FeedResponse<JsonNode> pageResponse :
                    getContainerCreateResourcesIfNotExist()
                        .queryItems(sql, options, JsonNode.class)
                        .iterableByPage(continuationToken, maxItemCount)) {
    
                    continuationToken = pageResponse.getContinuationToken();
    
                    for (JsonNode item : pageResponse.getElements()) {
    
                        try {
                            todoItems.add(OBJECT_MAPPER.treeToValue(item, TodoItem.class));
                        } catch (JsonProcessingException e) {
                            if (error_count < error_limit) {
                                error_count++;
                                if (error_count >= error_limit) {
                                    System.out.println("\n...reached max error count.\n");
                                } else {
                                    System.out.println("Error deserializing TODO item JsonNode. " +
                                        "This item will not be returned.");
                                    e.printStackTrace();
                                }
                            }
                        }
    
                    }
                }
    
            } while (continuationToken != null);
    
            return todoItems;
        }
    
        @Override
        public TodoItem updateTodoItem(String id, boolean isComplete) {
            // Retrieve the document from the database
            JsonNode todoItemJson = getDocumentById(id);
    
            // You can update the document as a JSON document directly.
            // For more complex operations - you could de-serialize the document in
            // to a POJO, update the POJO, and then re-serialize the POJO back in to
            // a document.
            ((ObjectNode) todoItemJson).put("complete", isComplete);
    
            try {
                // Persist/replace the updated document.
                todoItemJson =
                    getContainerCreateResourcesIfNotExist()
                        .replaceItem(todoItemJson, id, new PartitionKey(id), new CosmosItemRequestOptions())
                        .getItem();
            } catch (CosmosException e) {
                System.out.println("Error updating TODO item.\n");
                e.printStackTrace();
                return null;
            }
    
            // De-serialize the document in to a TodoItem.
            try {
                return OBJECT_MAPPER.treeToValue(todoItemJson, TodoItem.class);
            } catch (JsonProcessingException e) {
                System.out.println("Error deserializing updated item.\n");
                e.printStackTrace();
    
                return null;
            }
        }
    
        @Override
        public boolean deleteTodoItem(String id) {
            // CosmosDB refers to documents by self link rather than id.
    
            // Query for the document to retrieve the self link.
            JsonNode todoItemJson = getDocumentById(id);
    
            try {
                // Delete the document by self link.
                getContainerCreateResourcesIfNotExist()
                    .deleteItem(id, new PartitionKey(id), new CosmosItemRequestOptions());
            } catch (CosmosException e) {
                System.out.println("Error deleting TODO item.\n");
                e.printStackTrace();
                return false;
            }
    
            return true;
        }
    
        /*
        
        private CosmosDatabase getTodoDatabase() {
            if (databaseCache == null) {
                // Get the database if it exists
                List<CosmosDatabase> databaseList = cosmosClient
                        .queryDatabases(
                                "SELECT * FROM root r WHERE r.id='" + DATABASE_ID
                                        + "'", null).getQueryIterable().toList();
    
                if (databaseList.size() > 0) {
                    // Cache the database object so we won't have to query for it
                    // later to retrieve the selfLink.
                    databaseCache = databaseList.get(0);
                } else {
                    // Create the database if it doesn't exist.
                    try {
                        CosmosDatabase databaseDefinition = new CosmosDatabase();
                        databaseDefinition.setId(DATABASE_ID);
    
                        databaseCache = cosmosClient.createDatabase(
                                databaseDefinition, null).getResource();
                    } catch (CosmosException e) {
                        // TODO: Something has gone terribly wrong - the app wasn't
                        // able to query or create the collection.
                        // Verify your connection, endpoint, and key.
                        e.printStackTrace();
                    }
                }
            }
    
            return databaseCache;
        }
    
        */
    
        private CosmosContainer getContainerCreateResourcesIfNotExist() {
    
            try {
    
                if (cosmosDatabase == null) {
                    CosmosDatabaseResponse cosmosDatabaseResponse = cosmosClient.createDatabaseIfNotExists(DATABASE_ID);
                    cosmosDatabase = cosmosClient.getDatabase(cosmosDatabaseResponse.getProperties().getId());
                }
    
            } catch (CosmosException e) {
                // TODO: Something has gone terribly wrong - the app wasn't
                // able to query or create the collection.
                // Verify your connection, endpoint, and key.
                System.out.println("Something has gone terribly wrong - " +
                    "the app wasn't able to create the Database.\n");
                e.printStackTrace();
            }
    
            try {
    
                if (cosmosContainer == null) {
                    CosmosContainerProperties properties = new CosmosContainerProperties(CONTAINER_ID, "/id");
                    CosmosContainerResponse cosmosContainerResponse = cosmosDatabase.createContainerIfNotExists(properties);
                    cosmosContainer = cosmosDatabase.getContainer(cosmosContainerResponse.getProperties().getId());
                }
    
            } catch (CosmosException e) {
                // TODO: Something has gone terribly wrong - the app wasn't
                // able to query or create the collection.
                // Verify your connection, endpoint, and key.
                System.out.println("Something has gone terribly wrong - " +
                    "the app wasn't able to create the Container.\n");
                e.printStackTrace();
            }
    
            return cosmosContainer;
        }
    
        private JsonNode getDocumentById(String id) {
    
            String sql = "SELECT * FROM root r WHERE r.id='" + id + "'";
            int maxItemCount = 1000;
            int maxDegreeOfParallelism = 1000;
            int maxBufferedItemCount = 100;
    
            CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
            options.setMaxBufferedItemCount(maxBufferedItemCount);
            options.setMaxDegreeOfParallelism(maxDegreeOfParallelism);
            options.setQueryMetricsEnabled(false);
    
            List<JsonNode> itemList = new ArrayList();
    
            String continuationToken = null;
            do {
                for (FeedResponse<JsonNode> pageResponse :
                    getContainerCreateResourcesIfNotExist()
                        .queryItems(sql, options, JsonNode.class)
                        .iterableByPage(continuationToken, maxItemCount)) {
    
                    continuationToken = pageResponse.getContinuationToken();
    
                    for (JsonNode item : pageResponse.getElements()) {
                        itemList.add(item);
                    }
                }
    
            } while (continuationToken != null);
    
            if (itemList.size() > 0) {
                return itemList.get(0);
            } else {
                return null;
            }
        }
    
    }
    
  5. Maak vervolgens een nieuw TodoDaoFactory.java-bestand en voeg de TodoDaoFactory-klasse toe, waarmee een nieuw DocDbDao-object wordt gemaakt:

    package com.microsoft.azure.cosmos.sample.dao;
    
    public class TodoDaoFactory {
        private static TodoDao myTodoDao = new DocDbDao();
    
        public static TodoDao getDao() {
            return myTodoDao;
        }
    }
    

Een controller toevoegen

Voeg de TodoItemController-controller toe aan uw toepassing. In dit project, gebruikt u Project Lombok om de constructor, getters, setters en een opbouwfunctie te genereren. U kunt deze code ook handmatig schrijven of door de IDE laten genereren:

package com.microsoft.azure.cosmos.sample.controller;

import java.util.List;
import java.util.UUID;

import lombok.NonNull;

import com.microsoft.azure.cosmos.sample.dao.TodoDao;
import com.microsoft.azure.cosmos.sample.dao.TodoDaoFactory;
import com.microsoft.azure.cosmos.sample.model.TodoItem;

public class TodoItemController {
    public static TodoItemController getInstance() {
        if (todoItemController == null) {
            todoItemController = new TodoItemController(TodoDaoFactory.getDao());
        }
        return todoItemController;
    }

    private static TodoItemController todoItemController;

    private final TodoDao todoDao;

    TodoItemController(TodoDao todoDao) {
        this.todoDao = todoDao;
    }

    public TodoItem createTodoItem(@NonNull String name,
            @NonNull String category, boolean isComplete) {
        TodoItem todoItem = new TodoItem();
        
        todoItem.setName(name);
        todoItem.setCategory(category);
        todoItem.setComplete(isComplete);
        todoItem.setId(UUID.randomUUID().toString());

        return todoDao.createTodoItem(todoItem);
    }

    public boolean deleteTodoItem(@NonNull String id) {
        return todoDao.deleteTodoItem(id);
    }

    public TodoItem getTodoItemById(@NonNull String id) {
        return todoDao.readTodoItem(id);
    }

    public List<TodoItem> getTodoItems() {
        return todoDao.readTodoItems();
    }

    public TodoItem updateTodoItem(@NonNull String id, boolean isComplete) {
        return todoDao.updateTodoItem(id, isComplete);
    }
}

Een servlet maken

Maak vervolgens een servlet om HTTP-aanvragen naar de controller te sturen. Maak het bestand ApiServlet. java en definieer hieronder de volgende code:

package com.microsoft.azure.cosmos.sample;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.gson.Gson;
import com.microsoft.azure.cosmos.sample.controller.TodoItemController;

/**
 * API Frontend Servlet
 */
@WebServlet("/api")
public class ApiServlet extends HttpServlet {
    // API Keys
    public static final String API_METHOD = "method";

    // API Methods
    public static final String CREATE_TODO_ITEM = "createTodoItem";
    public static final String GET_TODO_ITEMS = "getTodoItems";
    public static final String UPDATE_TODO_ITEM = "updateTodoItem";

    // API Parameters
    public static final String TODO_ITEM_ID = "todoItemId";
    public static final String TODO_ITEM_NAME = "todoItemName";
    public static final String TODO_ITEM_CATEGORY = "todoItemCategory";
    public static final String TODO_ITEM_COMPLETE = "todoItemComplete";

    public static final String MESSAGE_ERROR_INVALID_METHOD = "{'error': 'Invalid method'}";

    private static final long serialVersionUID = 1L;
    private static final Gson gson = new Gson();

    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {

        String apiResponse = MESSAGE_ERROR_INVALID_METHOD;

        TodoItemController todoItemController = TodoItemController
                .getInstance();

        String id = request.getParameter(TODO_ITEM_ID);
        String name = request.getParameter(TODO_ITEM_NAME);
        String category = request.getParameter(TODO_ITEM_CATEGORY);
        String itemComplete = request.getParameter(TODO_ITEM_COMPLETE);
        boolean isComplete = itemComplete!= null && itemComplete.equalsIgnoreCase("true");

        switch (request.getParameter(API_METHOD)) {
        case CREATE_TODO_ITEM:
            apiResponse = gson.toJson(todoItemController.createTodoItem(name,
                    category, isComplete));
            break;
        case GET_TODO_ITEMS:
            apiResponse = gson.toJson(todoItemController.getTodoItems());
            break;
        case UPDATE_TODO_ITEM:
            apiResponse = gson.toJson(todoItemController.updateTodoItem(id,
                    isComplete));
            break;
        default:
            break;
        }

        response.setCharacterEncoding("UTF-8");
        response.getWriter().println(apiResponse);
    }

    @Override
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

De rest van de Java-app aan elkaar koppelen

Nu het merendeel van het werk is voltooid, hoeven we alleen nog maar een gebruikersinterface te maken en deze te verbinden met uw DAO.

  1. U hebt een online gebruikersinterface nodig die voor de gebruiker kan worden weergegeven. Laten we het bestand index.jsp dat we eerder hebben gemaakt, herschrijven met de volgende code:

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge;" />
      <title>Azure Cosmos Java Sample</title>
    
      <!-- Bootstrap -->
      <link href="//ajax.aspnetcdn.com/ajax/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
    
      <style>
        /* Add padding to body for fixed nav bar */
        body {
          padding-top: 50px;
        }
      </style>
    </head>
    <body>
      <!-- Nav Bar -->
      <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
        <div class="container">
          <div class="navbar-header">
            <a class="navbar-brand" href="#">My Tasks</a>
          </div>
        </div>
      </div>
    
      <!-- Body -->
      <div class="container">
        <h1>My ToDo List</h1>
    
        <hr/>
    
        <!-- The ToDo List -->
        <div class = "todoList">
          <table class="table table-bordered table-striped" id="todoItems">
            <thead>
              <tr>
                <th>Name</th>
                <th>Category</th>
                <th>Complete</th>
              </tr>
            </thead>
            <tbody>
            </tbody>
          </table>
    
          <!-- Update Button -->
          <div class="todoUpdatePanel">
            <form class="form-horizontal" role="form">
              <button type="button" class="btn btn-primary">Update Tasks</button>
            </form>
          </div>
    
        </div>
    
        <hr/>
    
        <!-- Item Input Form -->
        <div class="todoForm">
          <form class="form-horizontal" role="form">
            <div class="form-group">
              <label for="inputItemName" class="col-sm-2">Task Name</label>
              <div class="col-sm-10">
                <input type="text" class="form-control" id="inputItemName" placeholder="Enter name">
              </div>
            </div>
    
            <div class="form-group">
              <label for="inputItemCategory" class="col-sm-2">Task Category</label>
              <div class="col-sm-10">
                <input type="text" class="form-control" id="inputItemCategory" placeholder="Enter category">
              </div>
            </div>
    
            <button type="button" class="btn btn-primary">Add Task</button>
          </form>
        </div>
    
      </div>
    
      <!-- Placed at the end of the document so the pages load faster -->
      <script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.1.min.js"></script>
      <script src="//ajax.aspnetcdn.com/ajax/bootstrap/3.2.0/bootstrap.min.js"></script>
      <script src="assets/todo.js"></script>
    </body>
    </html>
    
  2. Schrijf tot slot wat JavaScript aan de clientzijde om de onlinegebruikersinterface en de servlet te koppelen:

    /**
     * ToDo App
     */
    
    var todoApp = {
      /*
       * API methods to call Java backend.
       */
      apiEndpoint: "api",
    
      createTodoItem: function(name, category, isComplete) {
        $.post(todoApp.apiEndpoint, {
            "method": "createTodoItem",
            "todoItemName": name,
            "todoItemCategory": category,
            "todoItemComplete": isComplete
          },
          function(data) {
            var todoItem = data;
            todoApp.addTodoItemToTable(todoItem.id, todoItem.name, todoItem.category, todoItem.complete);
          },
          "json");
      },
    
      getTodoItems: function() {
        $.post(todoApp.apiEndpoint, {
            "method": "getTodoItems"
          },
          function(data) {
            var todoItemArr = data;
            $.each(todoItemArr, function(index, value) {
              todoApp.addTodoItemToTable(value.id, value.name, value.category, value.complete);
            });
          },
          "json");
      },
    
      updateTodoItem: function(id, isComplete) {
        $.post(todoApp.apiEndpoint, {
            "method": "updateTodoItem",
            "todoItemId": id,
            "todoItemComplete": isComplete
          },
          function(data) {},
          "json");
      },
    
      /*
       * UI Methods
       */
      addTodoItemToTable: function(id, name, category, isComplete) {
        var rowColor = isComplete ? "active" : "warning";
    
        todoApp.ui_table().append($("<tr>")
          .append($("<td>").text(name))
          .append($("<td>").text(category))
          .append($("<td>")
            .append($("<input>")
              .attr("type", "checkbox")
              .attr("id", id)
              .attr("checked", isComplete)
              .attr("class", "isComplete")
            ))
          .addClass(rowColor)
        );
      },
    
      /*
       * UI Bindings
       */
      bindCreateButton: function() {
        todoApp.ui_createButton().click(function() {
          todoApp.createTodoItem(todoApp.ui_createNameInput().val(), todoApp.ui_createCategoryInput().val(), false);
          todoApp.ui_createNameInput().val("");
          todoApp.ui_createCategoryInput().val("");
        });
      },
    
      bindUpdateButton: function() {
        todoApp.ui_updateButton().click(function() {
          // Disable button temporarily.
          var myButton = $(this);
          var originalText = myButton.text();
          $(this).text("Updating...");
          $(this).prop("disabled", true);
    
          // Call api to update todo items.
          $.each(todoApp.ui_updateId(), function(index, value) {
            todoApp.updateTodoItem(value.name, value.value);
            $(value).remove();
          });
    
          // Re-enable button.
          setTimeout(function() {
            myButton.prop("disabled", false);
            myButton.text(originalText);
          }, 500);
        });
      },
    
      bindUpdateCheckboxes: function() {
        todoApp.ui_table().on("click", ".isComplete", function(event) {
          var checkboxElement = $(event.currentTarget);
          var rowElement = $(event.currentTarget).parents('tr');
          var id = checkboxElement.attr('id');
          var isComplete = checkboxElement.is(':checked');
    
          // Togle table row color
          if (isComplete) {
            rowElement.addClass("active");
            rowElement.removeClass("warning");
          } else {
            rowElement.removeClass("active");
            rowElement.addClass("warning");
          }
    
          // Update hidden inputs for update panel.
          todoApp.ui_updateForm().children("input[name='" + id + "']").remove();
    
          todoApp.ui_updateForm().append($("<input>")
            .attr("type", "hidden")
            .attr("class", "updateComplete")
            .attr("name", id)
            .attr("value", isComplete));
    
        });
      },
    
      /*
       * UI Elements
       */
      ui_createNameInput: function() {
        return $(".todoForm #inputItemName");
      },
    
      ui_createCategoryInput: function() {
        return $(".todoForm #inputItemCategory");
      },
    
      ui_createButton: function() {
        return $(".todoForm button");
      },
    
      ui_table: function() {
        return $(".todoList table tbody");
      },
    
      ui_updateButton: function() {
        return $(".todoUpdatePanel button");
      },
    
      ui_updateForm: function() {
        return $(".todoUpdatePanel form");
      },
    
      ui_updateId: function() {
        return $(".todoUpdatePanel .updateComplete");
      },
    
      /*
       * Install the TodoApp
       */
      install: function() {
        todoApp.bindCreateButton();
        todoApp.bindUpdateButton();
        todoApp.bindUpdateCheckboxes();
    
        todoApp.getTodoItems();
      }
    };
    
    $(document).ready(function() {
      todoApp.install();
    });
    
  3. Nu hoeft de toepassing alleen nog maar te worden getest. Voer de toepassing lokaal uit en voeg enkele Todo-items toe door de itemnaam en categorie in te vullen en op Taak toevoegen te klikken. Wanneer het item wordt weergegeven, kunt u bijwerken of het item is voltooid door het selectievakje in of uit te schakelen en op Taken bijwerken te klikken.

De Java-toepassing implementeren op Azure Web Sites

Met Azure Web Sites kunt u heel eenvoudig, alsof u de toepassing als een WAR-bestand exporteert, Java-toepassingen implementeren en uploaden via broncodebeheer (bijvoorbeeld Git) of FTP.

  1. Als u uw toepassing wilt exporteren als een WAR-bestand, klikt u met de rechtermuisknop op uw project in Projectverkenner, selecteert u Exporteren en selecteert u vervolgens WAR-bestand.

  2. Ga in het venster WAR exporteren als volgt te werk:

    • Voer in het vak Webproject azure-cosmos-java-sample in.
    • Kies in het vak Doel de bestemming waarnaar u het WAR-bestand wilt opslaan.
    • Selecteer Finish.
  3. Nu u over een WAR-bestand beschikt, kunt u dit uploaden naar de map webapps voor Azure Web Sites. Zie Een Java-toepassing aan Azure App Service Web Apps toevoegen voor instructies over het uploaden van het bestand. Wanneer het WAR-bestand is geüpload naar de map webapps, detecteert de runtime-omgeving dat u het bestand hebt toegevoegd en wordt het bestand automatisch geladen.

  4. Als u het voltooide product wilt bekijken, gaat u naar http://YOUR\_SITE\_NAME.azurewebsites.net/azure-cosmos-java-sample/ en begint u met het toevoegen van uw taken.

Het project ophalen van GitHub

Alle voorbeelden in deze zelfstudie zijn opgenomen in het todo-project op GitHub. Als u het todo-project wilt importeren in Eclipse, moet u over de software en resources beschikken die worden vermeld in de sectie Vereisten en gaat u als volgt te werk:

  1. Installeer Project Lombok. Lombok wordt gebruikt om de constructors, getters, setters in het project te genereren. Zodra u het bestand lombok.jar hebt gedownload, dubbelklikt u op het bestand om het te installeren of installeert u het bestand vanaf de opdrachtregel.

  2. Als Eclipse is geopend, sluit en opent u Eclipse opnieuw om Lombok te laden.

  3. Selecteer in Eclipse in het menu Bestand de optie Importeren.

  4. Selecteer git in het venster Importeren, selecteer Projecten van Git en selecteer vervolgens Volgende.

  5. Selecteer in het scherm Opslagplaatsbron selecteren de optie URI klonen.

  6. Voer https://github.com/Azure-Samples/azure-cosmos-java-sql-api-todo-appin het scherm Git-bronopslagplaats in het vak URI in en selecteer volgende.

  7. Controleer in het scherm Vertakkingsselectie of hoofd is geselecteerd en selecteer vervolgens Volgende.

  8. Selecteer bladeren in het scherm Lokale bestemming om een map te selecteren waarin de opslagplaats kan worden gekopieerd en selecteer vervolgens Volgende.

  9. Controleer in het scherm Selecteer een wizard voor het importeren van projecten of Bestaande projecten importeren is geselecteerd en selecteer vervolgens Volgende.

  10. Hef in het scherm Projecten importeren de selectie van het DocumentDB-project op en selecteer Voltooien. Het DocumentDB-project bevat de Azure Cosmos DB Java SDK die we in plaats daarvan als een afhankelijkheid zullen toevoegen.

  11. Navigeer in Projectverkenner naar azure-cosmos-java-sample\src\com.microsoft.azure.cosmos.sample.dao\DocumentClientFactory.java, vervang de waarden host en MASTER_KEY door de URI en PRIMAIRE SLEUTEL voor uw Azure Cosmos DB-account en sla het bestand op. Zie stap 1 voor meer informatie . Maak een Azure Cosmos DB-databaseaccount.

  12. Klik in Projectverkenner met de rechtermuisknop op de azure-cosmos-java-sample, selecteer Build Path en selecteer vervolgens Build Path configureren.

  13. Selecteer op het scherm Java Build Path in het rechterdeelvenster het tabblad Bibliotheken en selecteer vervolgens Externe JAR's toevoegen. Ga naar de locatie van het bestand lombok.jar, selecteer Openen en selecteer vervolgens OK.

  14. Gebruik stap 12 om het venster Eigenschappen opnieuw te openen en selecteer vervolgens targeted runtimes in het linkerdeelvenster.

  15. Selecteer in het scherm Targeted Runtimesde optie Nieuw, selecteer Apache Tomcat v7.0 en selecteer vervolgens OK.

  16. Gebruik stap 12 om het venster Eigenschappen opnieuw te openen en selecteer vervolgens Project facets in het linkerdeelvenster.

  17. Selecteer in het scherm Project Facetsde optie Dynamic Web Module en Java en selecteer vervolgens OK.

  18. Klik op het tabblad Servers onder aan het scherm met de rechtermuisknop op Tomcat v7.0 Server at localhost en selecteer toevoegen en verwijderen.

  19. Verplaats in het venster Toevoegen en verwijderenazure-cosmos-java-sample naar het vak Geconfigureerd en selecteer vervolgens Voltooien.

  20. Klik op het tabblad Servers met de rechtermuisknop op Tomcat v7.0 Server op localhost en selecteer vervolgens Opnieuw opstarten.

  21. Ga in een browser naar http://localhost:8080/azure-cosmos-java-sample/ en begin met het toevoegen van taken aan uw takenlijst. Als u de standaardpoortwaarden hebt gewijzigd, wijzigt u 8080 in de waarde die u hebt geselecteerd.

  22. Zie Stap 6: Uw toepassing implementeren op Azure Web Sites.

Volgende stappen

Probeert u capaciteitsplanning uit te voeren voor een migratie naar Azure Cosmos DB? U kunt informatie over uw bestaande databasecluster gebruiken voor capaciteitsplanning.