ASP .NET - Gerando Relatórios PDF a partir de um banco de dados (VB .NET)


Neste artigo vou mostrar como gerar relatórios no formato PDF usando o iTextSharp a partir de registros de um banco de dados SQL Server em um projeto ASP .NET Web Forms.

Eu já publiquei alguns artigos sobre a geração de PDF usando a biblioteca iTextSharp (veja as referências). Lembrando que ela é gratuita e pode ser obtida no seguinte endereço: http://sourceforge.net/projects/itextsharp/.

Neste artigo meu objetivo é gerar relatórios dinâmicos com as informações obtidas a partir de um banco de dados SQL Server.

Vou usar como exemplo o banco de dados Northwind e a tabela Employees.  A estrutura desta tabela é vista a seguir:

Assim vamos acessar as informações dessa tabela e gerar um relatório no formato PDF para cada funcionário selecionado.

A seguir vemos o leiaute de um relatório gerado para um funcionário:

Para obter esse resultado vamos realizar as seguintes tarefas:

  1. Criar um projeto ASP .NET Web Forms

  2. Referenciar via Nuget a biblioteca iTextSharp

  3. Acessar a tabela Employees do banco de dados Northwind.mdf via ADO .NET

  4. Exibir em um GridView algumas informações da tabela como : ID, Sobrenome, Nome e Endereço

  5. Exibir em um controle DropDownlist os nomes dos funcionários

  6. Gerar um relatório PDF usando os recursos do iTextSharp para o funcionários selecionado

Com isso posto, vamos arregaçar as mangas e partir para o que interessa...

Recursos usados:

Nota: Baixe e use a versão Community 2015 do VS ela é grátis e é equivalente a versão Professional.

Criando o projeto ASP .NET Web Forms

Abra o VS Community 2015 e clique em New Project;

Selecione a linguagem Visual Basic -> ASP .NET Web Aplication, Informe o nome ASP_GerarPDF e clique no botão OK;

A seguir selecione o template Empty e marque Web Forms, sem autenticação nem hospedagem na nuvem e clique em OK;

Vamos incluir uma página web no projeto.

No menu Project clique em Add New Item;

Selecione o template Web e a seguir Web Form e informe o nome Default.aspx e clique em Add;

Incluindo a referência ao pacote iTextSharp no projeto via Nuget

Vamos incluir os pacotes do iTextSharp em nosso projeto.

No menu Tools clique em Nuget Package Manager -> Manage Nuget Packages for solution;

Digite itextsharp na caixa de busca e a seguir instale os pacotes iTextSharp no projeto:

Ao final você teremos a referência à biblioteca iTextSharp em nosso projeto.

Definindo as pastas contendo as imagens e a interface com o usuário na página Default.aspx

Vamos criar duas pastas em nosso projeto:

1- A pasta imagens onde vamos incluir o arquivo northwindlogo.gif que será exibido como o logo da empresa Northwind;
2- A pasta fotos onde iremos incluir arquivos de imagens referente a cada um dos funcionários da tabela Employees, onde cada arquivo será nomeado  com o respectivo código do funcionário na tabela;

Selecione o projeto e no menu Project clique em New Folder e informe o nome imagens; Repita o procedimento e cria a pasta fotos.

Para incluir as imagens nas pasta basta clicar com o botão direito do mouse sobre a pasta e a seguir em Add->Existing Item e selecionar imagem.

No final do artigo você têm o projeto completo com as imagens. Após isso vamos definir a interface com o usuário.

Na página Default.aspx vamos incluir os seguintes controles a partir da ToolBox:

Disponha os controles conforme o leiaute da figura abaixo:

O código gerado no pode ser visto abaixo:

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="ASP_SalvarPDF._Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Relatório PDF</title>
</head>
<body>
    <form id="form1" runat="server">
        <h2>Macoratti .net - Relatórios PDF</h2>
        <hr />
    <div>
      <div>
        <asp:GridView ID="Gv_Dados" runat="server" AutoGenerateColumns ="false" Height="193px" Width="506px" >
        <Columns>
        <asp:TemplateField HeaderText ="ID">
        <ItemTemplate>
        <asp:Label ID="lblId" Text='<%#Eval("EmployeeID")%>' runat ="server">
        </asp:Label>
        </ItemTemplate>
        </asp:TemplateField>
         <asp:TemplateField HeaderText ="SobreNome">
        <ItemTemplate>
        <%# Eval("LastName").ToString()%>       
        </ItemTemplate>
        </asp:TemplateField>
         <asp:TemplateField HeaderText ="Nome">
        <ItemTemplate>
        <asp:Label ID="lblLnome" Text='<%#Eval("FirstName")%>' runat ="server">
        </asp:Label>
        </ItemTemplate>       
        </asp:TemplateField>
        <asp:TemplateField HeaderText ="Endereço">
        <ItemTemplate>
        <asp:Label ID="lblEndereco" Text='<%#Eval("Address")%>' runat ="server">
        </asp:Label>
        </ItemTemplate>
        </asp:TemplateField>
        </Columns>
        </asp:GridView>
    </div>
    </div>
        <div>
        <asp:DropDownList ID="ddlEmployees" runat="server" Height="18px" Width="231px">
        </asp:DropDownList>
        <asp:Button ID="btnRelatorio" runat="server" Text="Gerar Relatório (PDF)" OnClick = "GerarRelatorio" Width="275px" />
        </div>
        <asp:Label ID="lblmsg" runat="server" Font-Bold="True" Font-Names="Segoe UI" ForeColor="#FF5050"></asp:Label>
    </form>
</body>
</html>

Vamos definir agora no arquivo code-behind o código que irá acessar a tabela Employees e preencher o GridView e o DropDownList.

Abra o arquivo Default.aspx.vb e inclua no início os namespaces usados:

Imports System.Data.SqlClient
Imports System.IO
Imports iTextSharp.text
Imports iTextSharp.text.pdf
Imports System.Drawing

No evento Load da página Default.aspx.vb inclua código abaixo:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Not IsPostBack Then
            VinculaDados()
        End If
  End Sub

O código do método VinculadDados() é visto a seguir:

 Protected Sub VinculaDados()

        Dim con As New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("conexaoBD").ConnectionString)
        Dim cmd As New SqlCommand("SELECT EmployeeID, LastName, FirstName, Address, City  FROM Employees ORDER BY LastName ASC", con)
        Dim da As New SqlDataAdapter(cmd)
        Dim ds As New DataSet()
        da.Fill(ds)
        Gv_Dados.DataSource = ds.Tables(0)
        Gv_Dados.DataBind()
        ddlEmployees.DataSource = GetDados("SELECT EmployeeId, (FirstName + ' ' + LastName) Name FROM Employees")
        ddlEmployees.DataTextField = "Name"
        ddlEmployees.DataValueField = "EmployeeId"
        ddlEmployees.DataBind()
 End Sub

No código acima acessamos a string de conexão a partir do arquivo web.config e usando uma instrução SQL SELECT obtemos os dados da tabela Employees.

A seguir criamos um DataSet e vinculamos no GridView e depois chamamos o método GetDados() para preencher o DropDownList.

A string de conexão com o banco de dados Northwind.mdf esta definida no arquivo Web.Config :

...
<connectionStrings>
  <add name="conexaoBD" connectionString="Data Source=.\sqlexpress;Initial Catalog=Northwind;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
...

O código do método GetDados() é o seguinte:

 Private Function GetDados(query As String) As DataTable
        Dim conString As String = ConfigurationManager.ConnectionStrings("conexaoBD").ConnectionString
        Dim cmd As New SqlCommand(query)
        Using con As New SqlConnection(conString)
            Using sda As New SqlDataAdapter()
                cmd.Connection = con
                sda.SelectCommand = cmd
                Using dt As New DataTable()
                    sda.Fill(dt)
                    Return dt
                End Using
            End Using
        End Using
    End Function

Este método recebe uma string representando a instrução SQL e retorna um DataTable.

Para concluir vamos definir o código associando ao evento OnClick do botão de comando que irá chamar o método GerarRelatorio() :

Protected Sub GerarRelatorio(sender As Object, e As EventArgs) Handles btnRelatorio.Click
        Try
            Dim dr As DataRow = GetDados("SELECT * FROM Employees where EmployeeId = " + ddlEmployees.SelectedItem.Value).Rows(0)
            'cria um documento definindo o tamanho da página
            Dim document As New Document(PageSize.A4, 88.0F, 88.0F, 10.0F, 10.0F)

            'define a fonte
            Dim NormalFont As iTextSharp.text.Font = FontFactory.GetFont("Verdana", 12, iTextSharp.text.Font.NORMAL)

            Using memoryStream As New System.IO.MemoryStream()

                Dim writer As PdfWriter = PdfWriter.GetInstance(document, memoryStream)
                Dim phrase As Phrase = Nothing
                Dim cell As PdfPCell = Nothing
                Dim table As PdfPTable = Nothing

                'abre o documento
                document.Open()
                'Cabeçalho da tabela
                table = New PdfPTable(2)
                table.TotalWidth = 500.0F
                table.LockedWidth = True
                table.SetWidths(New Single() {0.300000012F, 0.699999988F})
                'Logotipo
                cell = imagemCelula("~/imagens/northwindlogo.gif", 30.0F, PdfPCell.ALIGN_CENTER)
                table.AddCell(cell)
                'Nome da empresa e endereço
                phrase = New Phrase()
                phrase.Add(New Chunk("Microsoft Northwind Traders Company" & vbLf & vbLf, FontFactory.GetFont("Arial", 16, iTextSharp.text.Font.BOLD)))
                phrase.Add(New Chunk("107, Park site," & vbLf, FontFactory.GetFont("Arial", 12, iTextSharp.text.Font.NORMAL)))
                phrase.Add(New Chunk("Salt Lake Road," & vbLf, FontFactory.GetFont("Arial", 12, iTextSharp.text.Font.NORMAL)))
                phrase.Add(New Chunk("Seattle, USA", FontFactory.GetFont("Arial", 12, iTextSharp.text.Font.NORMAL)))
                cell = FraseCelula(phrase, PdfPCell.ALIGN_LEFT)
                cell.VerticalAlignment = PdfPCell.ALIGN_TOP
                table.AddCell(cell)
                'Linha separador
                DesenhaLinha(writer, 25.0F, document.Top - 79.0F, document.PageSize.Width - 25.0F, document.Top - 79.0F, Color.Black)
                DesenhaLinha(writer, 25.0F, document.Top - 80.0F, document.PageSize.Width - 25.0F, document.Top - 80.0F, Color.Black)
                document.Add(table)
                 'define uma tabela com alinhamento centralizado
                table = New PdfPTable(2)
                table.HorizontalAlignment = Element.ALIGN_CENTER
                table.SetWidths(New Single() {0.300000012F, 1.0F})
                table.SpacingBefore = 20.0F
                'Detalhes do funcionario
                cell = FraseCelula(New Phrase("Registro do Funcionário", FontFactory.GetFont("Arial", 12, iTextSharp.text.Font.UNDERLINE)), PdfPCell.ALIGN_CENTER)
                cell.Colspan = 2
                table.AddCell(cell)
                cell = FraseCelula(New Phrase(), PdfPCell.ALIGN_CENTER)
                cell.Colspan = 2
                cell.PaddingBottom = 30.0F
                table.AddCell(cell)
                'Obtém a Foto a partir da pasta fotos com base no ID do funcionário
                cell = imagemCelula(String.Format("~/fotos/{0}.jpg", dr("EmployeeId")), 25.0F, PdfPCell.ALIGN_CENTER)
                table.AddCell(cell)
                'Nome
                phrase = New Phrase()
                phrase.Add(New Chunk(dr("TitleOfCourtesy").ToString & " " + dr("FirstName").ToString & " " + dr("LastName").ToString, FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.BOLD)))
                phrase.Add(New Chunk("(" + dr("Title").ToString() + ")", FontFactory.GetFont("Arial", 8, iTextSharp.text.Font.BOLD)))
                cell = FraseCelula(phrase, PdfPCell.ALIGN_LEFT)
                cell.VerticalAlignment = PdfPCell.ALIGN_MIDDLE
                table.AddCell(cell)
                document.Add(table)
                'DesenhaLinha(writer, 160.0F, 80.0F, 160.0F, 690.0F, Color.Black)
                ' DesenhaLinha(writer, 115.0F, document.Top - 200.0F, document.PageSize.Width - 100.0F, document.Top - 200.0F, Color.Black)
                table = New PdfPTable(2)
                table.SetWidths(New Single() {0.5F, 2.0F})
                table.TotalWidth = 340.0F
                table.LockedWidth = True
                table.SpacingBefore = 10.0F
                table.HorizontalAlignment = Element.ALIGN_CENTER
                'Código do Funci (ID)
                table.AddCell(FraseCelula(New Phrase("Código :", FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.BOLD)), PdfPCell.ALIGN_LEFT))
                table.AddCell(FraseCelula(New Phrase("000" + dr("EmployeeId"), FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.NORMAL)), PdfPCell.ALIGN_LEFT))
                cell = FraseCelula(New Phrase(), PdfPCell.ALIGN_CENTER)
                cell.Colspan = 2
                cell.PaddingBottom = 10.0F
                table.AddCell(cell)
                'Endereço
                table.AddCell(FraseCelula(New Phrase("Endereço:", FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.BOLD)), PdfPCell.ALIGN_LEFT))
                phrase = New Phrase(New Chunk(dr("Address").ToString, FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.NORMAL)))
                phrase.Add(New Chunk(dr("City").ToString + vbLf, FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.NORMAL)))
                phrase.Add(New Chunk(dr("Region").ToString + " " + dr("Country").ToString + " " + dr("PostalCode").ToString, FontFactory.GetFont("Arial", 8, iTextSharp.text.Font.NORMAL)))
                table.AddCell(FraseCelula(phrase, PdfPCell.ALIGN_LEFT))
                cell = FraseCelula(New Phrase(), PdfPCell.ALIGN_CENTER)
                cell.Colspan = 2
                cell.PaddingBottom = 10.0F
                table.AddCell(cell)
                'Data de nascimento
                table.AddCell(FraseCelula(New Phrase("Data de nascimento :", FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.BOLD)), PdfPCell.ALIGN_LEFT))
                table.AddCell(FraseCelula(New Phrase(Convert.ToDateTime(dr("BirthDate")).ToString("dd MMMM, yyyy"), FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.NORMAL)), PdfPCell.ALIGN_LEFT))
                cell = FraseCelula(New Phrase(), PdfPCell.ALIGN_CENTER)
                cell.Colspan = 2
                cell.PaddingBottom = 10.0F
                table.AddCell(cell)
                'telefone
                table.AddCell(FraseCelula(New Phrase("Telefone :", FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.BOLD)), PdfPCell.ALIGN_LEFT))
                table.AddCell(FraseCelula(New Phrase(dr("HomePhone") + " Ext: " + dr("Extension"), FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.NORMAL)), PdfPCell.ALIGN_LEFT))
                cell = FraseCelula(New Phrase(), PdfPCell.ALIGN_CENTER)
                cell.Colspan = 2
                cell.PaddingBottom = 10.0F
                table.AddCell(cell)
                'Informações
                table.AddCell(FraseCelula(New Phrase("Informações Adicionais :", FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.BOLD)), PdfPCell.ALIGN_LEFT))
                table.AddCell(FraseCelula(New Phrase(dr("Notes").ToString(), FontFactory.GetFont("Arial", 10, iTextSharp.text.Font.NORMAL)), PdfPCell.ALIGN_JUSTIFIED))
                document.Add(table)
                document.Close()
                Dim bytes As Byte() = memoryStream.ToArray()
                memoryStream.Close()
                Response.Clear()
                'define o formato e salva o arquivo com o nome do funcionario selecionado
                Response.ContentType = "application/pdf"
                Response.AddHeader("Content-Disposition", "attachment; filename=" & ddlEmployees.SelectedItem.Text)
                Response.ContentType = "application/pdf"
                Response.Buffer = True
                Response.Cache.SetCacheability(HttpCacheability.NoCache)
                Response.BinaryWrite(bytes)
                Response.End()
                Response.Close()
            End Using
        Catch ex As Exception
            lblmsg.Text = " Erro : " & ex.Message
        End Try
    End Sub

O código acima usa os recursos do iTextSharp para montar o relatório e gerar o arquivo PDF. Este código usa os seguintes métodos :

Private Shared Sub DesenhaLinha(writer As PdfWriter, x1 As Single, y1 As Single, x2 As Single, y2 As Single, color As Color)
        Dim contentByte As PdfContentByte = writer.DirectContent
        contentByte.MoveTo(x1, y1)
        contentByte.LineTo(x2, y2)
        contentByte.Stroke()
    End Sub

    Private Function FraseCelula(phrase As Phrase, align As Integer) As PdfPCell
        Dim cell As New PdfPCell(phrase)
        cell.VerticalAlignment = PdfPCell.ALIGN_TOP
        cell.HorizontalAlignment = align
        cell.PaddingBottom = 2.0F
        cell.PaddingTop = 0.0F
        Return cell
    End Function
    Private Function imagemCelula(path As String, scale As Single, align As Integer) As PdfPCell
        Dim image As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(HttpContext.Current.Server.MapPath(path))
        image.ScalePercent(scale)
        Dim cell As New PdfPCell(image)
        cell.BorderColor = Color.White
        cell.VerticalAlignment = PdfPCell.ALIGN_TOP
        cell.HorizontalAlignment = align
        cell.PaddingBottom = 0.0F
        cell.PaddingTop = 0.0F
        Return cell
   End Function

Executando o projeto e selecionando um funcionário iremos obter o seguinte resultado:

Clicando no botão - Gerar Relatório (PDF) - e abrindo o relatório no visualizador PDF teremos:

Fique a vontade para melhorar o leiaute do relatório e incluir outros recursos.

Pegue o projeto completo aqui :   ASP_SalvarPDF.zip (sem as referências)

Porque há um só Deus, e um só Mediador entre Deus e os homens, Jesus Cristo homem.
1 Timóteo 2:5

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ?

 

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

 

Referências:


José Carlos Macoratti