Självstudie: Skapa ett Java-webbprogram med Hjälp av Azure Cosmos DB och API:et för NoSQL
GÄLLER FÖR: NoSQL
Den här självstudiekursen om webbprogram i Java beskriver hur du kan använda tjänsten Microsoft Azure Cosmos DB för att lagra och komma åt data från ett Java-program i Azure App Service Web Apps. Utan ett kreditkort eller en Azure-prenumeration kan du konfigurera ett kostnadsfritt Prova Azure Cosmos DB-konto. I den här artikeln lär du dig att:
- Skapa ett enkelt JSP-program (JavaServer Pages) i Eclipse.
- Arbeta med Azure Cosmos DB-tjänsten med hjälp av Azure Cosmos DB Java SDK.
I den här självstudien om Java visar vi hur du skapar en webbaserad aktivitetshanteringsapp där du kan skapa, hämta och markera aktiviteter som slutförda, enligt bilden nedan. Alla aktiviteter i att göra-listan lagras som JSON-dokument i Azure Cosmos DB.
Dricks
Den här självstudien om apputveckling förutsätter att du har tidigare erfarenhet av Java. Om du inte har använt Java eller verktygen som krävs tidigare, rekommenderar vi att du hämtar det fullständiga todo-projektet från GitHub och skapar det enligt anvisningarna i slutet av artikeln. När du har skapat det kan du läsa den här artikeln för information om koden i projektets sammanhang.
Förhandskrav för den här självstudien för Java-webbprogram
Innan du påbörjar den här självstudien om apputveckling måste du ha följande:
Om du inte har en Azure-prenumeration, utan ett kreditkort eller en Azure-prenumeration, kan du konfigurera ett kostnadsfritt Prova Azure Cosmos DB-konto.
Du kan prova Azure Cosmos DB kostnadsfritt, utan en Azure-prenumeration och utan något åtagande. Du kan också skapa ett kostnadsfritt Azure Cosmos DB-konto med de första 1 000 RU/s och 25 GB lagringsutrymme utan kostnad. Du kan också använda Azure Cosmos DB-emulatorn med en URI för
https://localhost:8081
. Den nyckel som ska användas med emulatorn finns i Autentisera begäranden.En Azure-webbplats med en Java-körningsmiljö (till exempel Tomcat eller Jetty) aktiverad.
Om du installerar dessa verktyg för första gången ger coreservlets.com en genomgång av installationsprocessen i snabbstartsavsnittet i artikeln Självstudie: Installera TomCat7 och Använda det med Eclipse .
Skapa ett Azure Cosmos DB-konto
Vi ska börja med att skapa ett Azure Cosmos DB-konto. Om du redan har ett konto eller om du använder Azure Cosmos DB-emulatorn för den här kursen kan du gå vidare till Steg 2: Skapa Java JSP-programmet.
I menyn i Azure-portalen eller på sidan Start väljer du Skapa en resurs.
Sök efter Azure Cosmos DB. Välj Skapa>Azure Cosmos DB.
På sidan Skapa ett Azure Cosmos DB-konto väljer du alternativet Skapa i avsnittet Azure Cosmos DB för NoSQL .
Azure Cosmos DB innehåller flera API:er:
- NoSQL för dokumentdata
- PostgreSQL
- MongoDB, för dokumentdata
- Apache Cassandra
- Register
- Apache Gremlin, för grafdata
Mer information om API:et för NoSQL finns i Välkommen till Azure Cosmos DB.
På sidan Skapa Azure Cosmos DB-konto anger du de grundläggande inställningarna för det nya Azure Cosmos DB-kontot.
Inställning Värde beskrivning Prenumeration Prenumerationsnamn Välj den Azure-prenumeration som du vill använda för det här Azure Cosmos DB-kontot. Resursgrupp Namn på resursgrupp Välj en resursgrupp eller välj Skapa ny och ange sedan ett unikt namn för den nya resursgruppen. Kontonamn Ett unikt namn Ange ett namn för att identifiera ditt Azure Cosmos DB-konto. Eftersomdocuments.azure.com läggs till det namn du anger för att skapa din URI måste du använda ett unikt namn. Namnet får bara innehålla gemener, siffror och bindestreck (-). Det måste vara 3–44 tecken. Plats Den region som är närmast dina användare Välj en geografisk plats som värd för ditt Azure Cosmos DB-konto. Använd den plats som är närmast dina användare för att ge dem så snabb åtkomst till data som möjligt. Kapacitetsläge Etablerat dataflöde eller serverlöst Välj Etablerat dataflöde för att skapa ett konto i etablerat dataflödesläge . Välj Serverlös för att skapa ett konto i serverlöst läge. Tillämpa rabatt på den kostnadsfria Azure Cosmos DB-nivån Tillämpa eller tillämpa inte Med den kostnadsfria Azure Cosmos DB-nivån får du de första 1 000 RU/s och 25 GB lagringsutrymme kostnadsfritt på ett konto. Lär dig mer om kostnadsfri nivå. Begränsa det totala kontots dataflöde Markerad eller inte Begränsa den totala mängden dataflöde som kan etableras för det här kontot. Den här gränsen förhindrar oväntade avgifter relaterade till etablerat dataflöde. Du kan uppdatera eller ta bort den här gränsen när ditt konto har skapats. Du kan ha upp till ett Azure Cosmos DB-konto på en kostnadsfri nivå per Azure-prenumeration och måste anmäla dig när du skapar kontot. Om du inte ser alternativet att tillämpa rabatten på den kostnadsfria nivån har ett annat konto i prenumerationen redan aktiverats med den kostnadsfria nivån.
Kommentar
Följande alternativ är inte tillgängliga om du väljer Serverlös som kapacitetsläge:
- Tillämpa rabatt för kostnadsfri nivå
- Begränsa det totala kontots dataflöde
På fliken Global distribution konfigurerar du följande information. Du kan lämna standardvärdena för den här snabbstarten:
Inställning Värde beskrivning Geo-redundans Inaktivera Aktivera eller inaktivera global distribution på ditt konto genom att para ihop din region med en parregion. Du kan lägga till fler regioner i ditt konto senare. Skrivåtgärder för flera regioner Inaktivera Med skrivfunktioner i flera regioner kan du dra nytta av det etablerade dataflödet för dina databaser och containrar över hela världen. Tillgänglighetszoner Inaktivera Tillgänglighetszoner hjälper dig att ytterligare förbättra programmets tillgänglighet och återhämtning. Kommentar
Följande alternativ är inte tillgängliga om du väljer Serverlös som kapacitetsläge på föregående grundläggande sida:
- Geo-redundans
- Skrivåtgärder för flera regioner
Du kan också konfigurera mer information på följande flikar:
- Nätverk. Konfigurera åtkomst från ett virtuellt nätverk.
- Säkerhetskopieringsprincip. Konfigurera antingen regelbunden eller kontinuerlig säkerhetskopieringsprincip.
- Kryptering. Använd antingen tjänsthanterad nyckel eller en kundhanterad nyckel.
- Taggar. Taggar är namn/värde-par som gör att du kan kategorisera resurser och visa sammanställd faktureringsinformation genom att tillämpa samma tagg på flera resurser och resursgrupper.
Välj Granska + skapa.
Granska kontoinställningarna och välj sedan Skapa. Det tar några minuter att skapa kontot. Vänta tills portalsidan visar meddelandet Distributionen är klar.
Välj Gå till resurs för att gå till sidan för Azure Cosmos DB-kontot.
Gå till azure Cosmos DB-kontosidan och välj Nycklar. Kopiera de värden som ska användas i webbprogrammet som du skapar härnäst.
Skapa Java JSP-programmet
Så här skapar du JSP-appen:
Först börjar vi med att skapa ett Java-projekt. Starta Eclipse, välj sedan Arkiv, välj Nytt och välj sedan Dynamiskt webbprojekt. Om du inte ser Dynamiskt webbprojekt i listan som ett tillgängligt projekt gör du följande: Välj Fil, välj Nytt, välj Projekt..., expandera Webben, välj Dynamiskt webbprojekt och välj Nästa.
Ange ett projektnamn i rutan Projektnamn och i listrutan Målkörning väljer du ett värde (t.ex. Apache Tomcat v7.0) och väljer sedan Slutför. När du väljer ett mål för körning kan du köra projektet lokalt genom Eclipse.
Expandera projektet i Eclipse i vyn Projektutforskaren. Högerklicka på WebContent, välj Ny och välj sedan JSP-fil.
I dialogrutan Ny JSP-fil namnger du filen index.jsp. Behåll den överordnade mappen som WebContent, som du ser i följande bild, och välj sedan Nästa.
I dialogrutan Välj JSP-mall väljer du Ny JSP-fil (html) i den här självstudien och väljer sedan Slutför.
När filen index.jsp öppnas i Eclipse lägger du till text för att visa Hello World! i det befintliga
<body>
elementet. Det uppdaterade<body>
-innehållet bör likna följande kod:<body> <% out.println("Hello World!"); %> </body>
Spara filen index.jsp .
Om du anger en målkörning i steg 2 kan du välja Projekt och sedan Köra för att köra JSP-programmet lokalt:
Installera SQL Java SDK
Det enklaste sättet att hämta SQL Java SDK och dess beroenden är via Apache Maven. För att göra detta måste du konvertera projektet till ett Maven-projekt med hjälp av följande steg:
Högerklicka på projektet i Projektutforskaren, välj Konfigurera, välj Konvertera till Maven-projekt.
I fönstret Skapa ny POM accepterar du standardvärdena och väljer Slutför.
Öppna filen pom.xml i Projektutforskaren.
På fliken Beroenden går du till fönstret Beroenden och väljer Lägg till.
I fönstret Välj beroende gör du följande:
- I rutan Grupp-ID anger du
com.azure
. - I rutan Artefakt-ID anger du
azure-cosmos
. - I rutan Version anger du
4.11.0
.
Eller så kan du lägga till beroende-XML för grupp-ID och artefakt-ID direkt i filen pom.xml :
<dependency> <groupId>com.azure</groupId> <artifactId>azure-cosmos</artifactId> <version>4.11.0</version> </dependency>
- I rutan Grupp-ID anger du
Välj OK så installerar Maven SQL Java SDK eller sparar filen pom.xml.
Använda Azure Cosmos DB-tjänsten i ditt Java-program
Nu ska vi lägga till modellerna, vyerna och kontrollanterna i webbappen.
Lägg till modell
Först ska vi definiera en modell i en ny fil TodoItem.java. Klassen TodoItem
definierar schemat för ett objekt tillsammans med metoderna getter och setter:
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;
}
}
Lägg till DAO-klasserna (Data Access Object)
Skapa ett dataåtkomstobjekt (DAO) för att abstrahera kvarstående ToDo-objekt till Azure Cosmos DB. För att kunna spara ToDo-objekt till en samling måste klienten veta vilken databas och samling de ska sparas i (refererade med självlänkar). Det är vanligen bäst att cachelagra databasen och samlingen när det är möjligt, för att undvika ytterligare rundor till databasen.
Om du vill anropa Azure Cosmos DB-tjänsten måste du instansiera ett nytt
cosmosClient
objekt. I allmänhet är det bäst att återanvändacosmosClient
objektet i stället för att skapa en ny klient för varje efterföljande begäran. Du kan återanvända klienten genom att definiera den icosmosClientFactory
klassen. Uppdatera värden och MASTER_KEY värden som du sparade i steg 1. Ersätt HOST-variabeln med din URI och ersätt MASTER_KEY med primärnyckeln. Använd följande kod för att skapaCosmosClientFactory
klassen i filen 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; } }
Skapa en ny TodoDao.java fil och lägg till
TodoDao
klassen för att skapa, uppdatera, läsa och ta bort att göra-objekten: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); }
Skapa en ny MockDao.java fil och lägg till
MockDao
klassen, den här klassen implementerarTodoDao
klassen för att utföra CRUD-åtgärder på objekten: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(); } }
Skapa en ny DocDbDao.java fil och lägg till
DocDbDao
klassen. Den här klassen definierar kod för att spara TodoItems i containern, hämtar databasen och samlingen, om den finns eller skapar en ny om den inte finns. I det här exemplet används Gson för att serialisera och av-serialisera TodoItem Plain Old Java Objects (POJO) till JSON-dokument. För att kunna spara ToDo-objekt till en samling måste klienten veta vilken databas och samling de ska sparas i (refererade med självlänkar). Den här klassen definierar även hjälpfunktionen för att hämta dokumenten med ett annat attribut (t.ex. "ID") i stället för självlänk. Du kan använda hjälpmetoden för att hämta ett TodoItem JSON-dokument med ID och sedan deserialisera det till en POJO.Du kan också använda klientobjektet
cosmosClient
för att hämta en samling eller lista över TodoItems med hjälp av en SQL-fråga. Slutligen definierar du borttagningsmetoden för att ta bort en TodoItem från listan. Följande kod visar innehållet iDocDbDao
klassen: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; } } }
Skapa sedan en ny TodoDaoFactory.java-fil och lägg till klassen
TodoDaoFactory
som skapar ett nytt DocDbDao-objekt:package com.microsoft.azure.cosmos.sample.dao; public class TodoDaoFactory { private static TodoDao myTodoDao = new DocDbDao(); public static TodoDao getDao() { return myTodoDao; } }
Lägga till en kontrollant
Lägg till TodoItemController-styrenheten i ditt program. I det här projektet generar vi konstruktorn, get-metoder, set-metoder och ett verktyg via Project Lombok. Du kan också skriva den här koden manuellt eller låta IDE generera den:
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);
}
}
Skapa en servlet
Skapa sedan en servlet för att dirigera HTTP-begäranden till kontrollanten. Skapa ApiServlet.java-filen och definiera följande kod under den:
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);
}
}
Koppla ihop resten av Java-appen
Nu när vi har slutfört de roliga bitarna är allt som återstår att skapa ett snabbt användargränssnitt och koppla det till din DAO.
Du behöver ett webbanvändargränssnitt som ska visas för användaren. Nu skriver vi om index.jsp vi skapade tidigare med följande kod:
<%@ 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>
Skriv slutligen javascript på klientsidan för att koppla samman webbanvändargränssnittet och servleten:
/** * 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 återstår bara att testa appen. Kör appen lokalt och lägg till några Todo-objekt genom att fylla i namn och kategori och klicka på Lägg till aktivitet. När objektet visas kan du uppdatera om det är klart genom att växla kryssrutan och klicka på Uppdatera uppgifter.
Distribuera Java-programmet till Azure Web Sites
Med Azure Web Sites är det enkelt att distribuera Java-appar. Allt du behöver göra är att exportera appen som en WAR-fil och antingen ladda upp den via källkontrollen (t.ex. Git) eller FTP.
Om du vill exportera programmet som en WAR-fil högerklickar du på projektet i Project Explorer, väljer Exportera och väljer sedan WAR-fil.
I fönstret WAR-export gör du så här:
- I rutan Webbprojekt anger du azure-cosmos-java-sample.
- Välj en plats där WAR-filen ska sparas i rutan Destination.
- Välj Slutför.
Nu när du har en WAR-fil laddar du bara upp den till katalogen Webbappar på Azure Web Sites. Anvisningar som beskriver hur du laddar upp filen finns i Add a Java application to Azure App Service Web Apps (Lägga till ett Java-program i Azure App Service Web Apps). När WAR-filen har laddats upp till katalogen webapps identifierar körningsmiljön att du har lagt till den och läser in den automatiskt.
Du kan visa den färdiga produkten genom att gå till
http://YOUR\_SITE\_NAME.azurewebsites.net/azure-cosmos-java-sample/
och börja lägga till aktiviteter!
Hämta projektet från GitHub
Alla exempel i den här självstudien finns i projektet Todo på GitHub. Om du vill importera Todo-projektet till Eclipse ska du se till att du har de program och resurser som anges i avsnittet Förutsättningar och sedan göra följande:
Installera Project Lombok. Lombok används för att generera konstruktorer, get-metoder och set-metoder i projektet. När du har laddat ned filen lombok.jar installerar du den genom att dubbelklicka på filen eller från kommandoraden.
Om Eclipse är öppet startar du om det för att läsa in Lombok.
I Eclipse går du till Arkiv-menyn och väljer Importera.
I fönstret Importera väljer du Git, projekt från Git och sedan Nästa.
På skärmen Välj lagringsplatskälla väljer du Klona URI.
På skärmen Git-källlagringsplats i rutan URI anger du https://github.com/Azure-Samples/azure-cosmos-java-sql-api-todo-appoch väljer sedan Nästa.
På skärmen Förgreningsval kontrollerar du att huvud är markerat och väljer sedan Nästa.
På skärmen Lokalt mål väljer du Bläddra för att välja en mapp där lagringsplatsen kan kopieras och väljer sedan Nästa.
På skärmen Välj en guide som ska användas för att importera projekt kontrollerar du att Importera befintliga projekt är markerat och väljer sedan Nästa.
På skärmen Importera projekt avmarkerar du DocumentDB-projektet och väljer sedan Slutför. Azure DocumentDB-projektet innehåller Azure Cosmos DB Java SDK, som vi ska lägga till som ett beroende i stället.
I Project Explorer navigerar du till azure-cosmos-java-sample\src\com.microsoft.azure.cosmos.sample.dao\DocumentClientFactory.java och ersätter värdena HOST och MASTER_KEY med URI och PRIMÄRNYCKEL för ditt Azure Cosmos DB-konto och sparar sedan filen. Mer information finns i Steg 1. Skapa ett Azure Cosmos DB-databaskonto.
Högerklicka på azure-cosmos-java-sample i Project Explorer, välj Skapa sökväg och välj sedan Konfigurera byggsökväg.
På skärmen Java Build Path (Java Build Path) i den högra rutan väljer du fliken Bibliotek och väljer sedan Lägg till externa JAR:er. Gå till platsen för filen lombok.jar och välj Öppna och välj sedan OK.
Använd steg 12 för att öppna fönstret Egenskaper igen och välj sedan Riktade körningar i den vänstra rutan.
På skärmen Riktade körningar väljer du Ny, Apache Tomcat v7.0 och sedan OK.
Använd steg 12 för att öppna fönstret Egenskaper igen och välj sedan Projektfasetter i den vänstra rutan.
På skärmen Projektfasetter väljer du Dynamisk webbmodul och Java och sedan OK.
På fliken Servrar längst ned på skärmen högerklickar du på Tomcat v7.0 Server på localhost och väljer sedan Lägg till och Ta bort.
I fönstret Lägg till och ta bort flyttar du azure-cosmos-java-sample till rutan Konfigurerad och väljer sedan Slutför.
På fliken Servrar högerklickar du på Tomcat v7.0 Server på localhost och väljer sedan Starta om.
Gå till
http://localhost:8080/azure-cosmos-java-sample/
i en webbläsare och börja lägga till aktiviteter. Om du har ändrat portarnas standardvärden ändrar du 8080 till värdet du har valt.Information om hur du distribuerar projektet till en Azure-webbplats finns i Steg 6. Distribuera ditt program till Azure-webbplatser.
Nästa steg
Försöker du planera kapacitet för en migrering till Azure Cosmos DB? Du kan använda information om ditt befintliga databaskluster för kapacitetsplanering.
- Om allt du vet är antalet virtuella kärnor och servrar i ditt befintliga databaskluster läser du om att uppskatta enheter för begäranden med virtuella kärnor eller virtuella kärnor
- Om du känner till vanliga begärandefrekvenser för din aktuella databasarbetsbelastning kan du läsa om att uppskatta enheter för begäranden med azure Cosmos DB-kapacitetshanteraren