Tutorial: Criar um aplicativo Web Java usando o Azure Cosmos DB e a API para NoSQL
APLICA-SE A: NoSQL
Este tutorial de aplicação Web do Java mostra-lhe como utilizar o serviço do Microsoft Azure Cosmos DB para armazenar e aceder a dados a partir de uma aplicação Java alojada em Aplicações Web do Serviço de Aplicações do Azure. Sem um cartão de crédito ou uma assinatura do Azure, você pode configurar uma conta gratuita Experimente o Azure Cosmos DB. Neste artigo, vai aprender:
- Como criar uma aplicação JSP (JavaServer Pages) básica no Eclipse.
- Como trabalhar com o serviço do Azure Cosmos DB com o SDK Java do Azure Cosmos DB.
Este tutorial de aplicação Java mostra-lhe como criar uma aplicação de gestão de tarefas baseada na Web que lhe permite criar, obter e marcar tarefas como concluídas, conforme mostrado na imagem que se segue. Cada uma das tarefas da lista ToDo é armazenada como documentos JSON no Azure Cosmos DB.
Gorjeta
Este tutorial do desenvolvimento de aplicações parte do princípio que tem experiência na utilização do Java. Se estiver familiarizado com o Java ou com as ferramentas dos pré-requisitos, recomendamos-lhe transferir todo o projeto todo a partir do GitHub e criá-lo utilizando as instruções no final deste artigo. Assim que o tiver criado, pode rever o artigo para obter conhecimentos aprofundados sobre o código no contexto do projeto.
Pré-requisitos para este tutorial de aplicação Web de Java
Antes de começar este tutorial de desenvolvimento de aplicação, tem de ter o seguinte:
Se você não tiver uma assinatura do Azure, sem um cartão de crédito ou uma assinatura do Azure, poderá configurar uma conta gratuita do Azure Cosmos DB.
Você pode experimentar o Azure Cosmos DB gratuitamente, sem uma assinatura do Azure e sem necessidade de compromisso. Como alternativa, você pode criar uma conta de camada gratuita do Azure Cosmos DB, com os primeiros 1000 RU/s e 25 GB de armazenamento gratuitamente. Você também pode usar o emulador do Azure Cosmos DB com um URI de
https://localhost:8081
. Para obter a chave a ser usada com o emulador, consulte Autenticando solicitações.
Se você estiver instalando essas ferramentas pela primeira vez, o coreservlets.com fornece um passo a passo do processo de instalação na seção de início rápido do artigo Tutorial: Instalando o TomCat7 e usando-o com o Eclipse .
Criar uma conta do Azure Cosmos DB
Comecemos por criar uma conta do Azure Cosmos DB. Se já tiver uma conta ou se estiver a utilizar o Emulador do Azure Cosmos DB para este tutorial, pode avançar para o Passo 2: Criar a aplicação Java JSP.
A partir do menu do portal do Azure ou a partir da Home page, selecione Criar um recurso.
Procure o Azure Cosmos DB. Selecione Criar>Azure Cosmos DB.
Na página Criar uma conta do Azure Cosmos DB, selecione a opção Criar na seção Azure Cosmos DB para NoSQL.
O Azure Cosmos DB fornece várias APIs:
- NoSQL, para dados de documentos
- PostgreSQL
- MongoDB, para dados de documentos
- Apache Cassandra
- Tabela
- Apache Gremlin, para dados gráficos
Para saber mais sobre a API para NoSQL, consulte Bem-vindo ao Azure Cosmos DB.
Na página Criar Conta do Azure Cosmos DB, insira as configurações básicas para a nova conta do Azure Cosmos DB.
Definição valor Description Subscrição Nome da subscrição Selecione a subscrição do Azure que pretende utilizar para esta conta do Azure Cosmos DB. Grupo de Recursos Nome do grupo de recursos Selecione um grupo de recursos ou selecione Criar novo e, em seguida, introduza um nome exclusivo para o novo grupo de recursos. Nome da Conta Um nome exclusivo Insira um nome para identificar sua conta do Azure Cosmos DB. Uma vez que documents.azure.com é anexado ao nome que indicar para criar o URI, utilize um nome exclusivo. O nome pode conter apenas letras minúsculas, números e o caractere hífen (-). Deve ter de 3 a 44 caracteres. Location A região mais próxima dos seus utilizadores Selecione a localização geográfica para alojar a sua conta do Azure Cosmos DB. Utilize a localização mais próxima dos utilizadores para lhes dar o acesso mais rápido aos dados. Modo de capacidade Taxa de transferência provisionada ou sem servidor Selecione Taxa de transferência provisionada para criar uma conta no modo de taxa de transferência provisionada. Selecione Serverless para criar uma conta no modo serverless . Aplicar desconto de nível gratuito do Azure Cosmos DB Candidatar-se ou Não aplicar Com o nível gratuito do Azure Cosmos DB, você obtém os primeiros 1000 RU/s e 25 GB de armazenamento gratuitamente em uma conta. Saiba mais sobre o nível gratuito. Limitar a taxa de transferência total da conta Selecionado ou não Limite a quantidade total de taxa de transferência que pode ser provisionada nessa conta. Esse limite evita cobranças inesperadas relacionadas à taxa de transferência provisionada. Você pode atualizar ou remover esse limite depois que sua conta for criada. Você pode ter até uma conta gratuita do Azure Cosmos DB por assinatura do Azure e deve optar por participar ao criar a conta. Se você não vir a opção de aplicar o desconto de nível gratuito, outra conta na assinatura já foi habilitada com o nível gratuito.
Nota
As seguintes opções não estarão disponíveis se você selecionar Serverless como o modo de Capacidade:
- Aplicar Desconto de Escalão Gratuito
- Limitar a taxa de transferência total da conta
Na guia Distribuição Global, configure os seguintes detalhes. Você pode deixar os valores padrão para este início rápido:
Definição valor Description Georredundância Desativar Habilite ou desative a distribuição global em sua conta emparelhando sua região com uma região par. Pode adicionar mais regiões à sua conta mais tarde. Escritas de várias regiões Desativar O recurso de gravação em várias regiões permite que você aproveite a taxa de transferência provisionada para seus bancos de dados e contêineres em todo o mundo. Zonas de Disponibilidade Desativar As zonas de disponibilidade ajudam a melhorar ainda mais a disponibilidade e a resiliência do seu aplicativo. Nota
As opções a seguir não estarão disponíveis se você selecionar Serverless como o modo de capacidade na página Noções básicas anterior:
- Georredundância
- Escritas de várias regiões
Opcionalmente, você pode configurar mais detalhes nas seguintes guias:
- Redes. Configure o acesso a partir de uma rede virtual.
- Política de backup. Configure a política de backup periódico ou contínuo .
- Encriptação. Use uma chave gerenciada pelo serviço ou uma chave gerenciada pelo cliente.
- Etiquetas. As etiquetas são pares nome/valor que permitem categorizar recursos e ver faturação consolidada aplicando a mesma etiqueta a múltiplos recursos e grupos de recursos.
Selecione Rever + criar.
Reveja as definições da conta e, em seguida, selecione Criar. A criação da conta demora alguns minutos. Aguarde até que a página do portal apresente A implementação está concluída.
Selecione Ir para recurso para aceder à página da conta do Azure Cosmos DB.
Vá para a página da conta do Azure Cosmos DB e selecione Chaves. Copie os valores a serem usados no aplicativo Web que você criar a seguir.
Criar o aplicativo Java JSP
Para criar a aplicação JSP:
Primeiro, começaremos criando um projeto Java. Inicie o Eclipse e, em seguida, selecione Arquivo, selecione Novo e, em seguida, selecione Projeto Web Dinâmico. Se você não vir o Projeto Web Dinâmico listado como um projeto disponível, faça o seguinte: Selecione Arquivo, selecione Novo, selecione Projeto..., expanda Web, selecione Projeto Web Dinâmico e selecione Avançar.
Insira um nome de projeto na caixa Nome do projeto e, no menu suspenso Target Runtime, selecione opcionalmente um valor (por exemplo, Apache Tomcat v7.0) e, em seguida, selecione Concluir. Selecionar um tempo de execução de destino permite-lhe executar o seu projeto localmente através do Eclipse.
No Eclipse, na vista do Explorador de Projeto, expanda o seu projeto. Clique com o botão direito do mouse em WebContent, selecione Novo e, em seguida, selecione Arquivo JSP.
Na caixa de diálogo Novo ficheiro JSP, atribua o nome index.jsp ao ficheiro. Mantenha a pasta pai como WebContent, conforme mostrado na ilustração a seguir, e selecione Avançar.
Na caixa de diálogo Selecionar Modelo JSP, para este tutorial, selecione Novo Arquivo JSP (html) e, em seguida, selecione Concluir.
Quando o arquivo index.jsp for aberto no Eclipse, adicione texto para exibir Hello World! dentro do elemento existente
<body>
. O conteúdo<body>
atualizado deverá ser semelhante ao seguinte código:<body> <% out.println("Hello World!"); %> </body>
Salve o arquivo index.jsp .
Se você definir um tempo de execução de destino na etapa 2, poderá selecionar Projeto e, em seguida , Executar para executar seu aplicativo JSP localmente:
Instalar o SQL Java SDK
A forma mais fácil para obter o SDK do SQL Java e as respetivas dependências é através do Apache Maven. Para fazer isso, você precisa converter seu projeto em um projeto Maven usando as seguintes etapas:
Clique com o botão direito do mouse em seu projeto no Explorador de Projetos, selecione Configurar, selecione Converter em Projeto Maven.
Na janela Criar novo POM, aceite os padrões e selecione Concluir.
No Explorador de Projeto, abra o ficheiro pom.xml.
Na guia Dependências, no painel Dependências, selecione Adicionar.
Na janela Selecionar Dependência, faça o seguinte:
- Na caixa ID do Grupo , digite
com.azure
. - Na caixa Id do artefato, digite
azure-cosmos
. - Na caixa Versão, digite
4.11.0
.
Ou, você pode adicionar o XML de dependência para ID de Grupo e ID de Artefato diretamente ao arquivo pom.xml :
<dependency> <groupId>com.azure</groupId> <artifactId>azure-cosmos</artifactId> <version>4.11.0</version> </dependency>
- Na caixa ID do Grupo , digite
Selecione OK e o Maven instalará o SQL Java SDK ou salvará o arquivo pom.xml.
Usar o serviço Azure Cosmos DB em seu aplicativo Java
Agora vamos adicionar os modelos, as visualizações e os controladores ao seu aplicativo Web.
Adicionar um modelo
Primeiro, vamos definir um modelo dentro de um novo arquivo TodoItem.java. A TodoItem
classe define o esquema de um item junto com os métodos getter e 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;
}
}
Adicionar as classes Data Access Object (DAO)
Crie um Data Access Object (DAO) para abstrair os itens ToDo persistentes para o Azure Cosmos DB. Para guardar os itens ToDo numa coleção, o cliente tem de saber qual a base de dados e a coleção a manter (conforme referenciado em auto-ligações). Em geral, é melhor colocar em cache a base de dados e a coleção sempre que possível, para evitar tempos de retorno adicionais para a base de dados.
Para invocar o serviço Azure Cosmos DB, você deve instanciar um novo
cosmosClient
objeto. Em geral, é melhor reutilizar ocosmosClient
objeto em vez de construir um novo cliente para cada solicitação subsequente. Você pode reutilizar o cliente definindo-o dentro dacosmosClientFactory
classe. Atualize os valores HOST e MASTER_KEY que você salvou na etapa 1. Substitua a variável HOST pelo URI e substitua o MASTER_KEY pela CHAVE PRIMÁRIA. Use o código a seguir para criar aCosmosClientFactory
classe dentro do arquivo 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; } }
Crie um novo arquivo TodoDao.java e adicione a
TodoDao
classe para criar, atualizar, ler e excluir os itens todo: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); }
Crie um novo arquivo MockDao.java e adicione a
MockDao
classe, essa classe implementa aTodoDao
classe para executar operações CRUD nos itens: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(); } }
Crie um novo arquivo de DocDbDao.java e adicione a
DocDbDao
classe. Essa classe define o código para persistir o TodoItems no contêiner, recupera seu banco de dados e coleção, se existir, ou cria um novo, se ele não existir. Este exemplo usa Gson para serializar e desserializar os POJOs (TodoItem Plain Old Java Objects) para documentos JSON. Para guardar os itens ToDo numa coleção, o cliente tem de saber qual a base de dados e a coleção a manter (conforme referenciado em auto-ligações). Esta classe também define a função auxiliar para recuperar os documentos por outro atributo (por exemplo, "ID") em vez de auto-link. Você pode usar o método auxiliar para recuperar um documento JSON TodoItem por ID e, em seguida, desserializá-lo para um POJO.Você também pode usar o
cosmosClient
objeto cliente para obter uma coleção ou lista de TodoItems usando uma consulta SQL. Finalmente, você define o método delete para excluir um TodoItem da sua lista. O código a seguir mostra o conteúdo daDocDbDao
classe: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; } } }
Em seguida, crie um novo arquivo de TodoDaoFactory.java e adicione a
TodoDaoFactory
classe que cria um novo objeto DocDbDao:package com.microsoft.azure.cosmos.sample.dao; public class TodoDaoFactory { private static TodoDao myTodoDao = new DocDbDao(); public static TodoDao getDao() { return myTodoDao; } }
Adicionar um controlador
Adicione o controlador TodoItemController ao seu aplicativo. Neste projeto, está a utilizar o Project Lombok para gerar o construtor, os getters, os setters e um construtor. Como alternativa, você pode escrever esse código manualmente ou fazer com que o IDE o gere:
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);
}
}
Criar um servlet
Em seguida, crie um servlet para rotear solicitações HTTP para o controlador. Crie o arquivo ApiServlet.java e defina o seguinte código sob ele:
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);
}
}
Conecte o restante do aplicativo Java
Agora que terminamos os bits divertidos, tudo o que resta é construir uma interface de usuário rápida e conectá-la ao seu DAO.
Você precisa de uma interface de usuário da Web para exibir ao usuário. Vamos reescrever o index.jsp que criamos anteriormente com o seguinte código:
<%@ 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>
Finalmente, escreva um JavaScript do lado do cliente para unir a interface do usuário da Web e o servlet:
/** * 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(); });
Agora, só falta testar a aplicação. Execute localmente a aplicação e adicione alguns itens Todo ao indicar o nome e a categoria do item. De seguida, clique em Adicionar Tarefa. Depois que o item for exibido, você poderá atualizar se ele está concluído alternando a caixa de seleção e clicando em Atualizar tarefas.
Implantar seu aplicativo Java em Sites do Azure
Os Sites do Azure tornam a implementação de aplicações Java tão simples como a exportação da sua aplicação com um ficheiro WAR e ao carregá-lo através do controlo de código fonte (por exemplo, Git) ou FTP.
Para exportar seu aplicativo como um arquivo WAR, clique com o botão direito do mouse em seu projeto no Project Explorer, selecione Exportar e, em seguida, selecione Arquivo WAR.
Na janela Exportar WAR, efetue o seguinte procedimento:
- Na caixa Projeto Web, insira azure-cosmos-java-sample.
- Na caixa Destino, selecione um destino para guardar o ficheiro WAR.
- Selecione Concluir.
Agora que tem um ficheiro WAR, pode simplesmente carregá-lo no diretório webapps do seu Site do Azure. Para obter instruções sobre o carregamento do ficheiro, veja Adicionar uma aplicação Java às Aplicações Web do Serviço de Aplicações do Azure. Depois que o arquivo WAR for carregado no diretório webapps, o ambiente de tempo de execução detetará que você o adicionou e o carregará automaticamente.
Para ver o seu produto concluído, navegue para
http://YOUR\_SITE\_NAME.azurewebsites.net/azure-cosmos-java-sample/
e comece a adicionar as suas tarefas!
Obter o projeto a partir do GitHub
Todos os exemplos deste tutorial estão incluídos no projeto todo no GitHub. Para importar o projeto todo para o Eclipse, certifique-se de que o software e os recursos estão listados na secção Pré-requisitos e, de seguida, efetue o seguinte procedimento:
Instalar Project Lombok. Lombok é utilizado para gerar construtores, getters e setters no projeto. Depois de ter transferido o ficheiro lombok.jar, faça duplo clique para instalá-lo ou instale-o a partir da linha de comandos.
Se o Eclipse estiver aberto, feche-o e reinicie-o para carregar o Lombok.
No Eclipse, no menu Arquivo , selecione Importar.
Na janela Importar, selecione Git, selecione Projetos do Git e selecione Avançar.
Na tela Selecionar origem do repositório, selecione Clonar URI.
Na tela Source Git Repository, na caixa URI, digite https://github.com/Azure-Samples/azure-cosmos-java-sql-api-todo-appe, em seguida, selecione Next.
No ecrã Seleção de Ramo, certifique-se de que a opção principal está selecionada e, em seguida, selecione Seguinte.
Na tela Destino Local, selecione Procurar para selecionar uma pasta onde o repositório pode ser copiado e, em seguida, selecione Avançar.
Na tela Selecione um assistente para usar para importar projetos, verifique se a opção Importar projetos existentes está selecionada e selecione Avançar.
Na tela Importar Projetos, desmarque o projeto do Banco de Dados de Documentos e selecione Concluir. O projeto do DocumentDB contém o SDK Java do Azure Cosmos DB, que iremos adicionar como uma dependência.
No Explorador de Projetos, navegue até azure-cosmos-java-sample\src\com.microsoft.azure.cosmos.sample.dao\DocumentClientFactory.java e substitua os valores HOST e MASTER_KEY pelo URI e pela CHAVE PRIMÁRIA da sua conta do Azure Cosmos DB e salve o arquivo. Para obter mais informações, consulte a Etapa 1. Crie uma conta de banco de dados do Azure Cosmos DB.
No Explorador de Projetos, clique com o botão direito do mouse no azure-cosmos-java-sample, selecione Caminho de Construção e, em seguida, selecione Configurar Caminho de Construção.
Na tela Java Build Path, no painel direito, selecione a guia Bibliotecas e, em seguida, selecione Adicionar JARs externos. Navegue até o local do arquivo lombok.jar e selecione Abrir e, em seguida, selecione OK.
Use a etapa 12 para abrir a janela Propriedades novamente e, no painel esquerdo, selecione Tempos de execução direcionados.
Na tela Targeted Runtimes, selecione New, Apache Tomcat v7.0 e OK.
Use a etapa 12 para abrir a janela Propriedades novamente e, no painel esquerdo, selecione Facetas do projeto.
Na tela Facetas do projeto, selecione Módulo Web dinâmico e Java e, em seguida, selecione OK.
Na guia Servidores na parte inferior da tela, clique com o botão direito do mouse em Tomcat v7.0 Server at localhost e selecione Adicionar e Remover.
Na janela Adicionar e Remover, mova azure-cosmos-java-sample para a caixa Configurado e selecione Concluir.
Na guia Servidores, clique com o botão direito do mouse em Tomcat v7.0 Server no localhost e selecione Reiniciar.
Num browser, navegue para
http://localhost:8080/azure-cosmos-java-sample/
e comece a adicionar à sua lista de tarefas. Tenha em atenção que se tiver alterado os valores de porta predefinidos, altere 8080 para o valor que selecionou.Para implantar seu projeto em um site do Azure, consulte Etapa 6. Implante seu aplicativo nos Sites do Azure.
Próximos passos
Tentando fazer o planejamento de capacidade para uma migração para o Azure Cosmos DB? Você pode usar informações sobre seu cluster de banco de dados existente para planejamento de capacidade.
- Se tudo o que você sabe é o número de vCores e servidores em seu cluster de banco de dados existente, leia sobre como estimar unidades de solicitação usando vCores ou vCPUs
- Se você souber as taxas de solicitação típicas para sua carga de trabalho de banco de dados atual, leia sobre como estimar unidades de solicitação usando o planejador de capacidade do Azure Cosmos DB