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 een creditcard of een Azure-abonnement kunt u een gratis 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.
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 geen Azure-abonnement hebt, zonder creditcard of een Azure-abonnement, kunt u een gratis Azure Cosmos DB-account instellen.
U kunt Azure Cosmos DB gratis proberen, zonder een Azure-abonnement en zonder toezegging. U kunt ook een gratis Azure Cosmos DB-account maken met de eerste 1000 RU/s en 25 GB opslagruimte. U kunt ook de Azure Cosmos DB-emulator gebruiken met een URI van
https://localhost:8081
. Zie Aanvragen verifiëren voor de sleutel die u nodig hebt voor de emulator.Een Azure-website met een Java-runtimeomgeving (bijvoorbeeld Tomcat of Jetty) ingeschakeld.
Als u deze hulpprogramma's voor de eerste keer installeert, biedt coreservlets.com een overzicht van het installatieproces in de snelstartsectie van hun zelfstudie: TomCat7 installeren en gebruiken met Eclipse-artikel .
Een Azure Cosmos DB-account maken
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.
Selecteer vanuit het menu van Azure Portal of op de startpagina de optie Een resource maken.
Zoek naar Azure Cosmos DB. Selecteer Azure Cosmos DB maken>.
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.
Voer op de pagina Azure Cosmos DB-account maken de basisinstellingen voor het nieuwe Azure Cosmos DB-account in.
Instelling Weergegeven als Beschrijving Abonnement Naam van het abonnement Selecteer het Azure-abonnement dat u wilt gebruiken voor dit Azure Cosmos DB-account. 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. Het moet 3-44 tekens zijn. 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 opslagruimte gratis 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 gratis Azure Cosmos DB-account 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 op de gratis laag niet ziet, is er al een ander account in het abonnement ingeschakeld met de gratis laag.
Notitie
De volgende opties zijn niet beschikbaar als u Serverloos als Capaciteitsmodus selecteert:
- Korting voor gratis laag toepassen
- Totale accountdoorvoer beperken
Configureer op het tabblad Globale distributie de volgende details. U kunt de standaardwaarden voor deze quickstart behouden:
Instelling Weergegeven als 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
U kunt desgewenst meer details configureren op de volgende tabbladen:
- Netwerken. Toegang configureren vanuit een virtueel netwerk.
- Back-upbeleid. Configureer periodiek of doorlopend back-upbeleid.
- Versleuteling. Gebruik een door de service beheerde sleutel of een door de klant beheerde sleutel.
- Tags. Tags zijn naam/waarde-paren waarmee u resources kunt categoriseren en een geconsolideerde facturering kunt weergeven. Hiervoor past u dezelfde tag toe op meerdere resources en resourcegroepen.
Selecteer Controleren + maken.
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.
Selecteer Ga naar resource om naar de Azure Cosmos DB-accountpagina te gaan.
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.
De Java JSP-toepassing maken
De JSP-toepassing maken:
Als eerste moet u een Java-project maken. Start Eclipse en selecteer Vervolgens Bestand, Nieuw en selecteer vervolgens Dynamic Web Project. Als dynamische 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.
Voer een projectnaam in het vak Projectnaam in en selecteer eventueel een waarde (bijvoorbeeld Apache Tomcat v7.0) in de vervolgkeuzelijst Doelruntime en selecteer Voltooien. Door een doelruntime te selecteren, kunt u het project lokaal via Eclipse uitvoeren.
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.
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.
Selecteer in het dialoogvenster JSP-sjabloon selecteren voor deze zelfstudie het nieuwe JSP-bestand (html) en selecteer Voltooien.
Wanneer het bestand index.jsp in Eclipse wordt geopend, 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>
Sla het bestand index.jsp op.
Als u een doelruntime in stap 2 instelt, kunt u Project selecteren en vervolgens uitvoeren om uw JSP-toepassing lokaal uit te voeren:
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:
Klik met de rechtermuisknop op uw project in projectverkenner, selecteer Configureren, converteren naar Maven-project.
Accepteer in het venster Nieuwe POM maken de standaardwaarden en selecteer Voltooien.
Ga naar de Projectverkenner en open het bestand pom.xml.
Selecteer Toevoegen op het tabblad Afhankelijkheden in het deelvenster Afhankelijkheden.
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>
- Voer
Selecteer OK en 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.
Als u de Azure Cosmos DB-service wilt aanroepen, moet u een nieuw
cosmosClient
-object maken. Doorgaans kunt u hetcosmosClient
-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 decosmosClientFactory
-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 deCosmosClientFactory
-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; } }
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); }
Maak een nieuw MockDao.java-bestand en voeg de
MockDao
-klasse toe; met deze klasse wordt deTodoDao
-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(); } }
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. Deze klasse definieert ook de helperfunctie om de documenten op te halen door een ander kenmerk (bijvoorbeeld 'ID') in plaats van zelfkoppeling. 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 deDocDbDao
-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; } } }
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 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.
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>
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(); });
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.
Uw 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.
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 WAR-bestand.
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 Voltooien.
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.
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:
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.
Als Eclipse is geopend, sluit en opent u Eclipse opnieuw om Lombok te laden.
Selecteer Importeren in Eclipse in het menu Bestand.
Selecteer Git in het venster Importeren, selecteer Projecten in Git en selecteer vervolgens Volgende.
Selecteer in het scherm Opslagplaatsbron selecteren de optie URI Klonen.
Voer in het URI-vak in het scherm Git-bronopslagplaats de optie https://github.com/Azure-Samples/azure-cosmos-java-sql-api-todo-appVolgende in en selecteer vervolgens Volgende.
Controleer in het scherm Vertakkingsselectie of de hoofdmap is geselecteerd en selecteer vervolgens Volgende.
Selecteer In het scherm Lokaal doel bladeren om een map te selecteren waarin de opslagplaats kan worden gekopieerd en selecteer vervolgens Volgende.
Zorg ervoor dat bestaande projecten importeren is geselecteerd in het scherm Selecteer een wizard die u wilt gebruiken voor het importeren van projecten en selecteer vervolgens Volgende.
Schakel in het scherm Projecten importeren de selectie van het DocumentDB-project uit en selecteer Voltooien. Het DocumentDB-project bevat de Azure Cosmos DB Java SDK die we in plaats daarvan als een afhankelijkheid zullen toevoegen.
Navigeer in Projectverkenner naar azure-cosmos-java-sample\src\com.microsoft.azure.cosmos.sample.dao\DocumentClientFactory.java en 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.
Klik in Projectverkenner met de rechtermuisknop op het azure-cosmos-java-sample, selecteer BuildPad en selecteer vervolgens Buildpad configureren.
Selecteer in het scherm Java Build Path in het rechterdeelvenster het tabblad Bibliotheken en selecteer vervolgens Externe JAR's toevoegen. Navigeer naar de locatie van het lombok.jar-bestand en selecteer Openen en selecteer vervolgens OK.
Gebruik stap 12 om het venster Eigenschappen opnieuw te openen en selecteer vervolgens Targeted Runtimes in het linkerdeelvenster.
Selecteer Nieuw in het scherm Targeted Runtimes, selecteer Apache Tomcat v7.0 en selecteer VERVOLGENS OK.
Gebruik stap 12 om het venster Eigenschappen opnieuw te openen en selecteer vervolgens in het linkerdeelvenster Project Facets.
Selecteer in het scherm Project Facets de optie Dynamische webmodule en Java en selecteer vervolgens OK.
Klik op het tabblad Servers onder aan het scherm met de rechtermuisknop op Tomcat v7.0 Server op localhost en selecteer vervolgens Toevoegen en verwijderen.
Verplaats in het venster Toevoegen en verwijderen azure-cosmos-java-sample naar het vak Geconfigureerd en selecteer Voltooien.
Klik op het tabblad Servers met de rechtermuisknop op Tomcat v7.0 Server op localhost en selecteer Opnieuw opstarten.
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.
Volgende stappen
Wilt u capaciteitsplanning uitvoeren voor een migratie naar Azure Cosmos DB? U kunt informatie over uw bestaande databasecluster gebruiken voor capaciteitsplanning.
- Als alles wat u weet het aantal vCores en servers in uw bestaande databasecluster is, leest u meer over het schatten van aanvraageenheden met behulp van vCores of vCPU's
- Als u typische aanvraagtarieven voor uw huidige databaseworkload kent, leest u meer over het schatten van aanvraageenheden met behulp van azure Cosmos DB-capaciteitsplanner