O blog da AWS
Criando relatórios com Lambda, RDS e JasperReports
Por Pedro Rates, Arquiteto de Soluções da AWS Brasil
A biblioteca JasperRerports é um motor de geração de relatórios amplamente utilizado na indústria, proporcionando aos usuários a capacidade de construir relatórios completos e bem estruturados de maneira fácil e rápida. A biblioteca é open source e pode ser embutida em uma aplicação Java, sendo capaz de se integrar a diversas fontes de dados e exportar documentos para uma série de formatos. Neste blog post, abordarei o deploy de uma função Lambda escrita em Java capaz de criar e disponibilizar um relatório do tipo JasperReports no formato PDF. A função Lambda buscará os dados que formarão o relatório em uma instância Amazon Relational Database Service (Amazon RDS) com o motor MySQL, e utilizará um template do JasperReports armazenado em bucket do Amazon Simple Storage Service (Amazon S3), no formato “.jrxml”. Esta solução elimina a necessidade de gerenciar instâncias para hospedar a aplicação geradora dos relatórios ao utilizar o AWS Lambda e permite utilizar o JasperReports através de um microsserviço desacoplado e independente.
Overview da solução
A solução que apresentamos neste blogpost consiste na arquitetura abaixo. Nela, utilizamos uma função Lambda para buscar um template do JasperReports em um bucket do Amazon S3, e geramos o relatório com base nos dados que obtemos de um banco de dados Amazon RDS. Para que a função Lambda possa acessar o banco de dados de forma segura, armazenamos as credenciais do banco na forma de um segredo no serviço AWS Secrets Manager, de modo que a função só acessa o segredo em tempo de execução.
Arquitetura da solução para geração de relatórios JasperReports utilizando Lambda e Amazon API Gateway. Nesta arquitetura, o Amazon RDS armazena os dados que compõe o relatório, o Amazon S3 armazena o template do relatório, e o AWS Secrets Manager armazena de forma segura as credenciais para conexão ao banco de dados.
Neste guia, seguiremos os seguintes passos para implementarmos a solução geradora de JasperReports:
- Execução do template do Cloudformation para criação de parte dos serviços que integram a solução;
- Criação da solução no AWS Lambda utilizando o AWS Toolkit for Eclipse;
- Associação da função Lambda à VPC criada pelo Cloudformation;
- Criação do segredo com as credencias do banco de dados no AWS Secrets Manager;
- Adição das variáveis de ambiente à função Lambda
- Criação de um API Gateway integrado à função Lambda
- Modificação as queries ao banco de dados e passagem dos parâmetros para a função
- Modificação do layout do relatório JasperReports
Pré-requisitos
Para seguir este guia, é necessário que você cumpra os seguintes pré-requisitos:
- Tenha uma conta AWS com permissão para criar e modificar recursos nos seguintes serviços: Cloudformation, Lambda, Amazon RDS, Secrets Manager, Amazon S3, VPC, API Gateway, IAM;
- Tenha o AWS CLI instalado e configurado com uma conta que possua os acessos mencionados acima;
- IDE Eclipse com o AWS Toolkit for Eclipse instalado;
- Conhecimento intermediário na linguagem de programação Java;
- Familiaridade com o AWS Management Console.
Setup Inicial
Em um diretório local, clone o seguinte repositório:
https://github.com/aws-samples/jasper-reports-with-lambda-rds
Neste repositório estão o template do Cloudformation responsável por criar parte dos recursos na sua conta AWS, o template do relatório JasperReports e o código em Java da função Lambda.
Parte 1 – Execução do template do Cloudformation
Para iniciar o guia, vamos executar um template do Cloudformation. Para isso, acesse o Cloudformation pelo Console da AWS e clique em “Create Stack” no canto superior direito. Selecione a opção “With new resources (standard)”.
Na tela de “Create Stack”, mantenha a opção “Template is ready” marcada, e selecione a opção “Upload a template file”. Clique então no botão “Choose file” e selecione o arquivo “jasper-lambda-architecture.json” localizado na raiz do projeto que você clonou para sua máquina. Clique em “Next”.
Na tela de “Specify Stack Details”, digite um nome para a stack, o usuário e a senha para a conta master do banco de dados. A senha deverá ter entre 8 e 41 caracteres, e pode incluir qualquer caractere imprimível ASCII com exceção de “@”, “””, e “/”. Anote o usuário e senha digitados pois serão utilizados em etapas futuras.
Clique em “Next”. Na tela de “Configure stack options”, deixe tudo como está e clique em “Next”. Na tela de “Review”, marque a caixa “I acknowledge that AWS CloudFormation might create IAM resources.” e clique em “Create Stack”.
A operação deve levar alguns minutos para completar. Depois de completa, acesse a aba “Outputs” da stack, e anote os valores de “IamRoleArn” e “JasperBucketName”.
Na raiz do projeto que você clonou para sua máquina, verifique a existência do arquivo “template.jrxml”. Abra o prompt de comando e execute o seguinte comando para fazer o upload deste arquivo para o bucket do S3 que foi criado pelo CloudFormation. Não se esqueça se substituir o “placeholder” pelo nome do seu bucket.
aws s3api put-object –-bucket placeholder –-key template.jrxml -–body template.jrxml
Parte 2 – Criação da função Lambda
Importe o projeto clonado do Github como um projeto Maven no Eclipse. O primeiro passo necessário é implementar o método que gera o relatório que desejamos, na classe “ReportGenerator.java”. Para isso, no método “generateReport”, substitua a exceção lançada na linha 63 pelo código que gerará o relatório.
Para que o código acima funcione corretamente, será necessário importar para o projeto a biblioteca JasperReports na versão 6.11.0, que pode ser encontrada no seguinte link:
https://community.jaspersoft.com/project/jasperreports-library
É possível também incluir esta biblioteca editando o arquivo “pom.xml”, localizado na raiz do projeto.
Após finalizar as modificações, clique com o botão direito no pacote “com.amazonaws.lambda.demo” e selecione a opção “Amazon Web Services -> Upload function to AWS Lambda…”. Na janela que abrir, garanta que a opção “Create a New Lambda function” esteja selecionada, escolha um nome para a função Lambda e clique em “Next”.
Na janela seguinte, selecione o IAM Role que foi criado pelo Cloudformation em “Function Role”. Na seção “S3 Bucket for Function Code”, selecione o bucket do S3 que foi criado pelo Cloudformation. Altere o Timeout para 300 e clique em “Finish”. Após a operação terminar, a função Lambda poderá ser vista no console da AWS.
3 – Associar a função Lambda à VPC na qual está o banco de dados Amazon RDS
No Console da AWS, acesse o serviço Lambda e selecione a função que acabamos de criar. Desça até a seção “VPC” e clique em “Editar”. Selecione a VPC que foi criada pelo Cloudformation (CIDR 173.0.0.0/24) e selecione apenas a subnet privada: a que tem o nome “subnet-privada”. Em SecurityGroups, selecione o “JasperLambdaSecurityGroup”. Clique em “Save”.
4 – Criação do segredo no Secrets Manager
Acesse o Secrets Manager pelo Console da AWS e clique em “Armazenar um novo segredo”. Selecione a opção “Credenciais para o banco de dados RDS”, e coloque o usuário e a senha que você utilizou na criação dos recursos pelo Cloudformation. Selecione a instância “jasperreportsdb” na seção “Selecione qual banco de dados RDS esse segredo vai acessar”.
Clique em “Next”. Em “Nome do segredo”, dê um nome ao segredo e clique em “Próximo”. Anote o nome que você deu para o segredo pois vamos utilizá-lo no próximo passo. Na próxima tela, mantenha a configuração padrão e clique em “Próximo”.
5 – Configuração das variáveis de ambiente do Lambda
Acesse novamente a função Lambda que editamos no passo 3. Na seção “Variáveis de ambiente” clique em “Editar”. Adicione os seguintes valores:
- RDS_DB_DRIVER: org.mariadb.jdbc.Driver
- SECRET_NAME: nome do secret criado no passo 4
- SECRET_REGION: us-east-1
- BUCKET_NAME: nome do bucket criado pelo template do cloudformation
Clique em “Salvar”.
6 – Criação do API Gateway
Acesse o serviço API Gateway no Console da AWS e clique no botão “Criar API” no canto superior direito. Selecione uma API do tipo “API REST” clicando em “Compilar” no card correspondente.
Mantenha a opção “API nova” selecionada, dê um nome e uma descrição para sua API e mantenha o “Tipo de endpoint” como “Regional”. Clique em “Criar API”.
Na tela da API criada, clique em “Ações” e depois em “Criar método”. Selecione o método “GET”.
Deixe selecionado “Função Lambda” como tipo de integração, marque a caixa “Usar a integração de proxy do Lambda” e selecione a função Lambda que foi criada no passo 2. Mantenha as outras opções como estão e clique em “Salvar”. Clique em “OK” na caixa que aparece.
No menu da API na parte esquerda da tela, clique em “Configurações”, acima de “Planos de uso”. Desça até o fim da tela para a seção “Tipos de mídia binários”, clique em “Adicionar tipo de mídia binário” e adicione um wildcard: “*/*”. Clique em “Salvar alterações”.
Volte para a seção “Recursos” no menu da API, clique em “Ações” e “Implantar API”. Crie um novo estágio de implantação, e insira um nome e opcionalmente uma descrição para o estágio e para a implantação. Clique em “Implante”.
Agora, na tela de “Estágios”, clique na url de “Invocar URL”, e uma nova abra deverá abrir. Depois de alguns segundos, aparecerá o relatório JasperReports em formato PDF para ser baixado para sua máquina. Faça o download do arquivo e abra-o com seu visualizador de PDF de preferência. O resultado deve ser como o seguinte:
7- Passando parâmetros para filtrar os resultados e customizando a consulta ao SQL
O API Gateway permite que o usuário passe dados para a função Lambda de diversas formas: através de headers, corpo da requisição, path parameters e query string parameters são alguns exemplos. Neste guia, utilizaremos os query parameters para que possamos filtrar a consulta no SQL, modificando o nosso relatório.
Na classe “LambdaFunctionHandler.java” desta solução, extraímos todos os query string parameters da requisição e armazenamos em um objeto JSON na variável “queryParameters”. Esta variável é passada como parâmetro para o método “getBeanList” da classe “RDSConnector.java”, responsável por buscar do banco os dados do relatório.
No método “getBeanList”, realizamos a query no banco Amazon RDS e buscamos os dados para o relatório, que, neste exemplo, é uma lista de colaboradores contendo o identificador, nome, e país de cada um. Neste método, buscamos pelo string parameter com o nome “country”, e utilizamos o seu valor na cláusula “where” da consulta ao banco. No nosso exemplo, caso não exista o string parameter “country” na URL da requisição, retornaremos todos os itens da tabela.
Para poder ver o uso do filtro via query string em ação, copie a URL de invocação da API gateway que utilizamos no passo anterior e adicione a query string “country” com o valor “Brazil”, como no exemplo abaixo:
Desta vez, o relatório gerado deve ser composto apenas dos colaboradores brasileiros:
Sinta-se à vontade para editar a query e modificar os query string parameters da forma que achar necessário.
8 – Modificando o layout do relatório
O layout dos relatórios do JasperReports são controlados pelo arquivo de template, que, no caso deste guia, é o arquivo “template.jrxml” que adicionamos no S3 no passo 1 deste guia. O JasperReports utiliza XML para configurar a exibição do relatório, e é possível alterar o template utilizando o editor de texto de sua preferência, ou o editor especializado JasperSoft Studios. Para que as alterações sejam refletidas no relatório, não se esqueça de, após atualizar o template, fazer novamente o upload dele pro S3, se atentando para manter o mesmo nome, caminho e bucket.
Limpando os recursos
Para evitar cobranças futuras, é importante que façamos a limpeza dos recursos que criamos durante este guia. O primeiro passo é excluir o API Gateway que criamos no passo 6. Para isso, vá ao menu de “Recursos”, clique em “Ações” e depois em “Excluir API”. Digite o nome da API na caixa de diálogo e confirme a exclusão do recurso.
Depois, vamos deletar a função Lambda criada no passo 2. No console do serviço Lambda, selecione a função criada anteriormente. Clique em “Ações -> Excluir função”, e depois em “Excluir” na caixa de diálogo para confirmar a exclusão.
Acesse o serviço Amazon S3 pelo console e localize o bucket criado pelo CloudFormation. Selecione o Bucket, clique em “Vazio”, digite “excluir permanentemente” e clique em “Vazio” para confirmar a exclusão. Clique em “Sair” para voltar à tela principal do S3. Com o bucket ainda selecionado, clique em “Excluir”, digite (ou cole) o nome do bucket, e clique em “Excluir bucket” para excluí-lo permanentemente.
Acesse o serviço “Secrets Manager” e clique no segredo criado no passo 4. Clique no botão “Ações” e depois em “Excluir segredo”. Ajuste o “período de espera” para 7 dias e clique em “Programar exclusão”. Segredos do Secrets Manager não podem ser excluídos imediatamente e necessitam que se agende a exclusão com uma antecedência de pelo menos 7 dias, período durante o qual o segredo não poderá ser acessado por outras aplicações.
Por último, acesse o Console do CloudFormation, selecione a stack que foi criada no passo 1 e clique em “Delete”. Depois de alguns minutos, todos os recursos serão deletados e a stack desaparecerá da lista.
É importante seguir a ordem das exclusões corretamente para garantir que todos os recursos sejam excluídos da sua conta e você não seja surpreendido com custos no futuro.
Conclusão
Neste blogpost aprendemos como gerar um relatório JasperReport simples e disponibilizá-lo para download no formato PDF utilizando Lambda, API Gateway e outros serviços. Você agora pode facilmente modificar o template “.jrxml” e o código da função Java para criar relatórios que atendam às suas necessidades particulares. A utilização de uma arquitetura Serverless permite que você pague apenas pelos relatórios que forem de fato gerados e disponibilizados para os seus clientes, sem a necessidade de se preocupar com o gerenciamento de servidores.
Sobre o autor
Pedro Rates é arquiteto de soluções na AWS e possui experiência em desenvolvimento de aplicações web. Atua atendendo clientes do segmento enterprise, guiando-os nas melhores práticas de arquitetura na cloud.