Oktatóanyag: Java-webalkalmazás létrehozása az Azure Cosmos DB és a NoSQL API használatával
A KÖVETKEZŐRE VONATKOZIK: NoSQL
Ez a Java-webalkalmazásokra vonatkozó oktatóanyag bemutatja, hogyan tárolhatja és érheti el az Azure App Service Web Appsben tárolt Java-alkalmazás adatait a Microsoft Azure Cosmos DB szolgáltatással. Hitelkártya vagy Azure-előfizetés nélkül beállíthat egy ingyenes Azure Cosmos DB-fiókot. Ebben a cikkben a következőkkel ismerkedhet meg:
- Alapszintű JavaServer Pages- (JSP-) alkalmazás létrehozása az Eclipse-ben.
- Az Azure Cosmos DB szolgáltatás használata az Azure Cosmos DB Java SDK-val.
Ez a Java-alkalmazásokra vonatkozó oktatóanyag bemutatja, hogyan hozhat létre egy webalapú feladatkezelő alkalmazást, amellyel feladatokat hozhat létre, kérhet le, valamint „kész” jelöléssel láthatja el azokat, ahogyan azt az alábbi illusztráció is mutatja. A rendszer a teendőlistában szereplő összes feladatot JSON-dokumentumként tárolja az Azure Cosmos DB-ben.
Tipp.
Ez az alkalmazásfejlesztési oktatóanyag feltételezi, hogy rendelkezik korábbi tapasztalattal a Java használatát illetően. Ha még nem ismeri a Javát vagy az előfeltételt jelentő eszközöket, ajánlott letölteni a teljes teendők projektet a GitHubról, majd lefordítani azt a jelen cikk végén található utasítások segítségével. A projekt lefordítása után a cikk áttekintésével betekintést nyerhet a kódba a projekt környezetében.
A jelen Java-webalkalmazásokra vonatkozó oktatóanyag előfeltételei
Az alkalmazásfejlesztési oktatóanyag elkezdéséhez az alábbiakkal kell rendelkeznie:
Ha nem rendelkezik Azure-előfizetéssel hitelkártya vagy Azure-előfizetés nélkül, beállíthat egy ingyenes Azure Cosmos DB-fiókot.
Az Azure Cosmos DB ingyenesen, Azure-előfizetés nélkül és kötelezettségvállalás nélkül is kipróbálható. Másik lehetőségként létrehozhat egy ingyenes szintű Azure Cosmos DB-fiókot, amely az első 1000 RU/s és 25 GB tárterülettel rendelkezik ingyenesen. Az Azure Cosmos DB emulátort az URI-val is használhatja
https://localhost:8081
. Az emulátorhoz használandó kulcsról a kérelmek hitelesítése című témakörben olvashat.Egy Java-futtatókörnyezettel (például Tomcat vagy Jetty) rendelkező Azure-webhely.
Ha először telepíti ezeket az eszközöket, a coreservlets.com bemutatja a telepítési folyamatot a TomCat7 telepítése és az Eclipse-cikkük rövid útmutatójában.
Azure Cosmos DB-fiók létrehozása
Először hozzon létre egy Azure Cosmos DB-fiókot. Ha már rendelkezik fiókkal vagy az oktatóanyagban az Azure Cosmos DB Emulatort használja, továbbléphet a 2. lépés: Új Java JSP-alkalmazás létrehozása című lépésre.
Az Azure Portal menüjében vagy a Kezdőlapon válassza az Erőforrás létrehozása elemet.
Keresse meg az Azure Cosmos DB-t. Válassza az Azure Cosmos DB létrehozása lehetőséget.>
Az Azure Cosmos DB-fiók létrehozása lapon válassza a Létrehozás lehetőséget az Azure Cosmos DB for NoSQL szakaszban.
Az Azure Cosmos DB számos API-t biztosít:
- NoSQL, dokumentumadatokhoz
- PostgreSQL
- MongoDB, dokumentumadatokhoz
- Apache Cassandra
- Tábla
- Apache Gremlin, gráfadatokhoz
A NoSQL API-val kapcsolatos további információkért lásd : Üdvözli az Azure Cosmos DB.
Az Azure Cosmos DB-fiók létrehozása lapon adja meg az új Azure Cosmos DB-fiók alapbeállításait.
Beállítás Érték Leírás Előfizetés Előfizetés neve: Válassza ki az Azure Cosmos DB-fiókhoz használni kívánt Azure-előfizetést. Erőforráscsoport Erőforráscsoport neve Válasszon ki egy erőforráscsoportot, vagy válassza az Új létrehozása lehetőséget, majd adja meg az új erőforráscsoport egyedi nevét. Fiók neve Egyedi név Adjon meg egy nevet az Azure Cosmos DB-fiók azonosításához. A rendszer a documents.azure.com utótaggal egészíti ki a megadott nevet az URI létrehozásához, ezért válasszon egyedi nevet. A név csak kisbetűket, számokat és kötőjelet (-) tartalmazhat. 3–44 karakter hosszúságúnak kell lennie. Hely A felhasználókhoz legközelebb eső régió Válassza ki az Azure Cosmos DB-fiókot üzemeltetéséhez használni kívánt földrajzi helyet. Használja a felhasználókhoz legközelebb lévő helyet, hogy a lehető leggyorsabb hozzáférést biztosítsa az adatokhoz. Kapacitásmód Kiosztott átviteli sebesség vagy kiszolgáló nélküli A kiosztott átviteli sebesség kiválasztásával hozzon létre egy fiókot kiosztott átviteli módban. A Kiszolgáló nélküli lehetőséget választva kiszolgáló nélküli módban hozhat létre fiókot. Ingyenes Azure Cosmos DB-kedvezmény alkalmazása Alkalmazás vagy nem alkalmazható Az Ingyenes Azure Cosmos DB-szinttel az első 1000 RU/s és 25 GB tárterület ingyenesen elérhető egy fiókban. További információk az ingyenes szintről. A fiók teljes átviteli sebességének korlátozása Kijelölve vagy nem Korlátozza az ezen a fiókon kiosztható átviteli sebesség teljes mennyiségét. Ez a korlát megakadályozza a kiosztott átviteli sebességhez kapcsolódó váratlan díjakat. A fiók létrehozása után frissítheti vagy eltávolíthatja ezt a korlátot. Azure-előfizetésenként legfeljebb egy ingyenes szintű Azure Cosmos DB-fiókkal rendelkezhet, és a fiók létrehozásakor be kell jelentkeznie. Ha nem látja az ingyenes szint kedvezményének alkalmazását, az előfizetés egy másik fiókja már engedélyezve van az ingyenes szinttel.
Feljegyzés
A következő beállítások nem érhetők el, ha a Kiszolgáló nélküli lehetőséget választja kapacitás módként:
- Ingyenes szintű kedvezmény alkalmazása
- A fiók teljes átviteli sebességének korlátozása
A Globális terjesztés lapon konfigurálja az alábbi adatokat. A rövid útmutató alapértelmezett értékeit a következő módon hagyhatja meg:
Beállítás Érték Leírás Georedundancia Letiltás Engedélyezze vagy tiltsa le a globális terjesztést a fiókjában, ha párosítja a régiót egy párrégióval. Később további régiókat is hozzáadhat a fiókjához. Többrégiós írások Letiltás A többrégiós írási képesség lehetővé teszi, hogy kihasználja az adatbázisok és tárolók kiosztott átviteli sebességét világszerte. Rendelkezésre állási zónák Letiltás A rendelkezésre állási zónák segítségével tovább javíthatja az alkalmazás rendelkezésre állását és rugalmasságát. Feljegyzés
Az alábbi beállítások nem érhetők el, ha a Kiszolgáló nélküli lehetőséget választja kapacitás módként az előző Alapszintű beállítások lapon:
- Georedundancia
- Többrégiós írások
Igény szerint további részleteket is konfigurálhat az alábbi lapokban:
- Hálózatkezelés. Virtuális hálózatról való hozzáférés konfigurálása.
- Biztonsági mentési szabályzat. Konfiguráljon rendszeres vagy folyamatos biztonsági mentési szabályzatot.
- Titkosítás. Használjon szolgáltatás által felügyelt vagy ügyfél által felügyelt kulcsot.
- Címkék. A címkék olyan név/érték párok, amelyek segítségével kategóriákba sorolhatja az erőforrásokat, és ha ugyanazt a címkét több erőforrásra és erőforráscsoportra is alkalmazza, ezzel együtt jelenítheti meg és kezelheti azok összesített számlázási adatait.
Válassza az Áttekintés + létrehozás lehetőséget.
Ellenőrizze a fiók beállításait, majd válassza a Létrehozás lehetőséget. A fiók létrehozása néhány percet vesz igénybe. Várja meg, hogy a portálon megjelenjen Az üzembe helyezés befejeződött üzenet.
Válassza az Ugrás az erőforrásra lehetőséget, és lépjen az Azure Cosmos DB-fiók oldalára.
Lépjen az Azure Cosmos DB-fiók lapjára, és válassza a Kulcsok lehetőséget. Másolja ki a következő webalkalmazásban használni kívánt értékeket.
A Java JSP-alkalmazás létrehozása
JSP-alkalmazás létrehozása:
Először egy Java-projekt létrehozásával kezdjük. Indítsa el az Eclipse-t, majd válassza a Fájl, az Új, majd a Dinamikus webprojekt lehetőséget. Ha nem látható a Dinamikus webes projekt elérhető projektként, tegye a következőket: Válassza a Fájl lehetőséget, válassza az Új, a Projekt..., a Web kibontása, a Dinamikus webes projekt, majd a Tovább lehetőséget.
Adjon meg egy projektnevet a Projektnév mezőbe, majd a Cél futtatókörnyezet legördülő menüben válasszon ki egy értéket (például Apache Tomcat v7.0), majd válassza a Befejezés lehetőséget. A tervezett futásidő megadása lehetővé teszi, hogy helyileg, az Eclipse-ben is futtathassa projektjét.
Az Eclipse Project Explorer (Projektböngésző) nézetében bontsa ki a projektet. Kattintson a jobb gombbal a WebContent elemre, válassza az Új, majd a JSP-fájl lehetőséget.
A New JSP File (Új JSP-fájl) párbeszédablakban nevezze el a fájlt az alábbi módon: index.jsp. Tartsa a szülőmappát WebContentként az alábbi ábrán látható módon, majd válassza a Tovább gombot.
A JSP-sablon kiválasztása párbeszédpanelen az oktatóanyag céljára válassza az Új JSP-fájl (html) lehetőséget, majd válassza a Befejezés lehetőséget.
Amikor megnyílik a index.jsp fájl az Eclipse-ben, adjon hozzá szöveget a meglévő
<body>
elemen belüli „Helló világ!” alkalmazás! megjelenítéséhez. A frissített<body>
tartalomnak az alábbi kódhoz kell hasonlítania:<body> <% out.println("Hello World!"); %> </body>
Mentse a index.jsp fájlt.
Ha a 2. lépésben beállít egy cél futtatókörnyezetet, válassza a Project , majd a Futtatás lehetőséget a JSP-alkalmazás helyi futtatásához:
Az SQL Java SDK telepítése
Az SQL Java SDK, valamint annak függőségei a legegyszerűbben az Apache Maven használatával kérhetők le. Ehhez az alábbi lépések végrehajtásával át kell alakítania a projektet Maven-projektté:
Kattintson a jobb gombbal a projektre a Projektkezelőben, válassza a Konfigurálás, majd a Konvertálás Maven-projektté lehetőséget.
Az Új POM létrehozása ablakban fogadja el az alapértelmezett beállításokat, és válassza a Befejezés lehetőséget.
A Project Explorer (Projektböngésző) nézetben nyissa meg a pom.xml fájlt.
A Függőségek lap Függőségek ablaktábláján válassza a Hozzáadás lehetőséget.
A Select Dependency (Függőség kiválasztása) ablakban tegye a következőket:
- A Csoportazonosító mezőbe írja be a következőt
com.azure
: - Az Összetevő azonosítója mezőbe írja be a következőt
azure-cosmos
: - A Verzió mezőbe írja be a következőt
4.11.0
:
Vagy közvetlenül a pom.xml fájlhoz is hozzáadhatja a csoportazonosítóhoz és az összetevő-azonosítóhoz tartozó függőségi XML-fájlt:
<dependency> <groupId>com.azure</groupId> <artifactId>azure-cosmos</artifactId> <version>4.11.0</version> </dependency>
- A Csoportazonosító mezőbe írja be a következőt
Válassza az OK gombot , és a Maven telepíti az SQL Java SDK-t, vagy menti a pom.xml fájlt.
Az Azure Cosmos DB szolgáltatás használata a Java-alkalmazásban
Most vegyük fel a modelleket, a nézeteket és a vezérlőket a webalkalmazásba.
Modell hozzáadása
Először határozzunk meg egy modellt egy új fájlban TodoItem.java. Az TodoItem
osztály meghatározza egy elem sémáját a getter és a setter metódusokkal együtt:
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;
}
}
Az Adatelérési objektum (DAO) osztályainak hozzáadása
Hozzon létre egy adatelérési objektumot (DAO) a ToDo-elemek Azure Cosmos DB-ben való megőrzésének absztrakt megőrzéséhez. Ha menteni szeretné a teendőket egy gyűjteménybe, az ügyfélnek tudnia kell, melyik adatbázisban és gyűjteményben kívánja azt megőrizni (ahogy erre az önhivatkozások is hivatkoznak). Általában érdemes gyorsítótárazni az adatbázist és a gyűjteményt, amennyiben ez lehetséges, így elkerülhető az adatbázissal való fölösleges üzenetváltás.
Az Azure Cosmos DB szolgáltatás meghívásához új
cosmosClient
objektumot kell létrehoznia. Általában a legjobb, ha az objektumot újra felhasználja ahelyettcosmosClient
, hogy minden további kéréshez új ügyfelet hoz létre. Az ügyfelet újra felhasználhatja az osztályon belülicosmosClientFactory
definiálásával. Frissítse a HOST-t, és MASTER_KEY az 1. lépésben mentett értékeket. Cserélje le a HOST változót az URI-ra, és cserélje le a MASTER_KEY az ELSŐDLEGES KULCSra. A következő kóddal hozza létre az osztályt aCosmosClientFactory
CosmosClientFactory.java fájlban: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; } }
Hozzon létre egy új TodoDao.java fájlt, és adja hozzá az
TodoDao
osztályt a teendőelemek létrehozásához, frissítéséhez, olvasásához és törléséhez: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); }
Hozzon létre egy új MockDao.java fájlt, és adja hozzá az
MockDao
osztályt. Ez az osztály implementálja az osztályt aTodoDao
CRUD-műveletek végrehajtásához az elemeken: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(); } }
Hozzon létre egy új DocDbDao.java fájlt, és adja hozzá az osztályt
DocDbDao
. Ez az osztály definiálja a todoItemek tárolóban való megőrzéséhez, az adatbázis és a gyűjtemény lekéréséhez, ha létezik, vagy létrehoz egy újat, ha nem létezik. Ez a példa a Gson használatával szerializálja és deszerializálja a TodoItem Egyszerű régi Java-objektumokat (POJOs-okat) A JSON-dokumentumokba. Ha menteni szeretné a teendőket egy gyűjteménybe, az ügyfélnek tudnia kell, melyik adatbázisban és gyűjteményben kívánja azt megőrizni (ahogy erre az önhivatkozások is hivatkoznak). Ez az osztály a segédfüggvényt is definiálja a dokumentumok egy másik attribútum (például "AZONOSÍTÓ") általi lekéréséhez az önhivatkozás helyett. A segédmetódussal azonosító alapján lekérhet egy TodoItem JSON-dokumentumot, majd deszerializálhatja azt egy POJO-ba.Az ügyfélobjektummal
cosmosClient
sql-lekérdezéssel is lekérheti a TodoItemek gyűjteményét vagy listáját. Végül meg kell határoznia a törlési módszert egy TodoItem törléséhez a listából. A következő kód az osztály tartalmátDocDbDao
mutatja be: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; } } }
Ezután hozzon létre egy új TodoDaoFactory.java fájlt, és adja hozzá az
TodoDaoFactory
új DocDbDao objektumot létrehozó osztályt:package com.microsoft.azure.cosmos.sample.dao; public class TodoDaoFactory { private static TodoDao myTodoDao = new DocDbDao(); public static TodoDao getDao() { return myTodoDao; } }
Vezérlő hozzáadása
Adja hozzá a TodoItemController vezérlőt az alkalmazáshoz. Ebben a projektben a Project Lombok nevű projekt használatával hozzuk létre a konstruktort, a beolvasókat, a beállítókat és a felépítőt. Másik lehetőségként manuálisan is megírhatja ezt a kódot, vagy létrehozhatja az IDE-t:
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);
}
}
Servlet létrehozása
Ezután hozzon létre egy servletet, amely a HTTP-kéréseket a vezérlőhöz irányítja. Hozza létre a ApiServlet.java fájlt, és definiálja alatta a következő kódot:
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);
}
}
A Java-alkalmazás többi részének összekapcsolása
Most, hogy befejeztük a szórakoztató biteket, már csak egy gyors felhasználói felület létrehozása és a DAO-hoz való csatlakoztatása maradt hátra.
A felhasználónak egy webes felhasználói felületre van szüksége. Írjuk újra a korábban létrehozott index.jsp a következő kóddal:
<%@ 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>
Végül írjon néhány ügyféloldali JavaScriptet a webes felhasználói felület és a servlet összekapcsolásához:
/** * 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(); });
Most már csak le kell tesztelni az alkalmazást. Futtassa az alkalmazást helyileg, és adjon hozzá néhány teendőt. Ehhez adja meg az elemek nevét és kategóriáját, majd kattintson az Add Task (Feladat hozzáadása) elemre. Miután az elem megjelent, frissítheti, hogy befejeződött-e, ha bejelöli a jelölőnégyzetet, és a Tevékenységek frissítése gombra kattint.
Java-alkalmazás üzembe helyezése az Azure-webhelyeken
Az Azure Websites megkönnyíti a Java-alkalmazások telepítését. Nincs más dolga, mint exportálni az alkalmazást WAR-fájlként, majd feltölteni azt egy forráskezelő rendszer (pl. Git) vagy FTP segítségével.
Ha WAR-fájlként szeretné exportálni az alkalmazást, kattintson a jobb gombbal a projektre a Project Explorerben, válassza az Exportálás lehetőséget, majd válassza a WAR-fájl lehetőséget.
A WAR Export (WAR-fájl exportálása) ablakban tegye a következőket:
- A Webes projekt mezőbe írja be az azure-cosmos-java-sample nevet.
- A Destination (Cél) mezőben válassza ki, hova szeretné menteni a WAR-fájlt.
- Válassza a Befejezés lehetőséget.
Most, hogy megvan a WAR-fájl, egyszerűen töltse fel az Azure Websites webapps könyvtárába. A fájl feltöltésével kapcsolatos további információkért lásd a Java-alkalmazások az Azure App Service Web Appshoz való hozzáadását ismertető cikket. Miután a WAR-fájlt feltöltötte a webapps könyvtárba, a futtatókörnyezet észleli, hogy hozzáadta, és automatikusan betölti.
A kész termék megtekintéséhez lépjen a
http://YOUR\_SITE\_NAME.azurewebsites.net/azure-cosmos-java-sample/
webhelyre, és kezdje meg a feladatok hozzáadását.
A projekt beszerzése a GitHubról
A jelen oktatóanyag minden példáját megtalálhatja a GitHubról elérhető todo (teendők) projektben. A teendők projekt Eclipse-be történő importálásához győződjön meg arról, hogy rendelkezik az Előfeltételek szakaszban ismertetett szoftverekkel és erőforrásokkal, majd tegye a következőket:
Telepítse a Project Lombok nevű projektet. A projekt konstruktorainak, beolvasóinak, beállítóinak létrehozása a Lombok használatával történik. A lombok.jar fájl letöltése után kattintson rá duplán annak telepítéséhez, vagy telepítse azt a parancssorból.
Ha az Eclipse meg van nyitva, zárja be, és indítsa el újra a Lombok betöltéséhez.
Az Eclipse Fájl menüjében válassza az Importálás lehetőséget.
Az Importálás ablakban válassza a Git, a Projektek a Gitből, majd a Tovább lehetőséget.
Az Adattár forrásának kiválasztása képernyőn válassza az URI klónozása lehetőséget.
A Forrás Git-adattár képernyőjén az URI mezőbe írja be a következőthttps://github.com/Azure-Samples/azure-cosmos-java-sql-api-todo-app, majd válassza a Tovább gombot.
Az Ágkijelölés képernyőn győződjön meg arról, hogy a fő elem ki van jelölve, majd válassza a Tovább gombot.
A Helyi cél képernyőn válassza a Tallózás lehetőséget egy olyan mappa kijelöléséhez, amelybe az adattár másolható, majd válassza a Tovább gombot.
A Projektek importálásához használandó varázslóban győződjön meg arról, hogy a Meglévő projektek importálása lehetőség van kiválasztva, majd válassza a Tovább gombot.
A Projektek importálása képernyőn törölje a DocumentDB-projekt kijelölését, majd válassza a Befejezés lehetőséget. A DocumentDB-projekt tartalmazza az Azure Cosmos DB Java SDK-t, amelyet inkább függőségként adunk hozzá.
A Project Explorerben lépjen az azure-cosmos-java-sample\src\com.microsoft.azure.cosmos.sample.dao\DocumentClientFactory.java, és cserélje le a HOST és MASTER_KEY értékeket az Azure Cosmos DB-fiók URI- és ELSŐDLEGES KULCSára, majd mentse a fájlt. További információ: 1. lépés. Hozzon létre egy Azure Cosmos DB-adatbázisfiókot.
A Project Explorerben kattintson a jobb gombbal az azure-cosmos-java-mintára, válassza a Build Path lehetőséget, majd válassza a Build Elérési út konfigurálása lehetőséget.
A Java Build Path képernyőjén, a jobb oldali panelen válassza a Kódtárak lapot, majd a Külső JAR-ek hozzáadása lehetőséget. Lépjen a lombok.jar fájl helyére, és válassza a Megnyitás, majd az OK gombot.
A 12. lépésben nyissa meg ismét a Tulajdonságok ablakot, majd a bal oldali panelen válassza a Célzott futtatókörnyezetek lehetőséget.
A Célzott futtatókörnyezetek képernyőn válassza az Új, az Apache Tomcat 7.0-s verziót, majd az OK gombot.
A 12. lépésben nyissa meg újra a Tulajdonságok ablakot, majd a bal oldali panelen válassza a Project Facets lehetőséget.
A Project Facets képernyőn válassza a Dinamikus webmodul és a Java lehetőséget, majd kattintson az OK gombra.
A képernyő alján található Kiszolgálók lapon kattintson a jobb gombbal a Tomcat v7.0 Server elemre a localhost webhelyen, majd válassza a Hozzáadás és eltávolítás lehetőséget.
A Hozzáadás és eltávolítás ablakban helyezze át az azure-cosmos-java-mintát a Konfigurált mezőbe, majd válassza a Befejezés lehetőséget.
A Kiszolgálók lapon kattintson a jobb gombbal a Tomcat v7.0-kiszolgálóra a localhost webhelyen, majd válassza az Újraindítás lehetőséget.
Egy böngészőből lépjen a
http://localhost:8080/azure-cosmos-java-sample/
címre, és kezdje el hozzáadni a feladatait a listához. Ügyeljen arra, hogy ha módosította a portok alapértelmezett értékét, akkor a 8080 értéket módosítsa a választott értékre.Ha a projektet egy Azure-webhelyen szeretné üzembe helyezni, tekintse meg a 6. lépést. Az alkalmazás üzembe helyezése az Azure-webhelyeken.
Következő lépések
Kapacitástervezést szeretne végezni az Azure Cosmos DB-be való migráláshoz? A kapacitástervezéshez használhatja a meglévő adatbázisfürt adatait.
- Ha csak annyit tud, hogy hány virtuális mag és kiszolgáló található a meglévő adatbázisfürtben, olvassa el a kérelemegységek becslését virtuális magok vagy vCPU-k használatával
- Ha ismeri az aktuális adatbázis számítási feladataira vonatkozó tipikus kérési arányokat, olvassa el a kérelemegységek becslését az Azure Cosmos DB kapacitástervezővel