Mostrando postagens com marcador JavaSE. Mostrar todas as postagens
Mostrando postagens com marcador JavaSE. Mostrar todas as postagens

10 de junho de 2011

XStream: Criando e lendo arquivos XML

Caso ainda não tenha precisado criar ou ler arquivos XML em Java, pelo menos já parou pra pensar como fazer isso? Criar uma String gigante concatenando valores e tags? Hoje em dia não há necessidade de se utilizar métodos tão "complexos" assim. Existe uma biblioteca chamada de XStream, onde objetos podem ser transformados em XML, e vice versa.
Obs: o XStream gera uma String em formato de XML, e não o arquivo XML propriamente dito, mas este é gerado com a ajuda do FileOutputStream do Java.
Então para fazer este exemplo vamos precisar de dois .jar, um é do próprio XStream e o outro é o Dom4J. Para baixar os dois juntos, clique aqui.

Estrutura do projeto
Nosso projeto irá ficar com essa estrutura:


Depois de muito tempo venho editar esta postagem sobre XStream...
Dentro do pacote model temos duas classes, um é o Endereco e a outra é Pessoa.
Classe Endereco:
@XStreamAlias("endereco")
public class Endereco {

    private String rua;
    private String cidade;

    //gettters e setters
}
A anotação @XStreamAlias é necessária quando vai fazer a leitura de uma String XML.
A Classe Pessoa:
public class Pessoa {

    private String nome;
    private String cpf;
    private List<Endereco> enderecos;
  
    //getters e setters
}

Bom agora vamos ver o que desejamos fazer e como fazer... Vamos começar pelo mais simples, caso queira gerar um XML de um endereço que está dessa forma:
<endereco>
  <rua>Rua das araras</rua>
  <cidade>Primavera do Leste</cidade>
</endereco>

Eu preciso do seguinte código:
private static void gravaEndereco() {
        Endereco endereco = new Endereco();
        endereco.setCidade("Primavera do Leste");
        endereco.setRua("Rua das araras");

        XStream xStream = new XStream();
        xStream.alias("endereco", Endereco.class);
       
        File arquivo = new File("endereco.xml");
        FileOutputStream gravar;
        try {
            gravar = new FileOutputStream(arquivo);
            gravar.write(xStream.toXML(endereco).getBytes());
            gravar.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

Lembrando que a parte de gravar o arquivo não é do XStream, a String é gerada pelo seguinte código: xStream.toXML(endereco), o mesmo vale para os próximos métodos...

Agora caso queira gravar uma lista de endereços em XML, que fique dessa forma:
<enderecos>
  <endereco>
    <rua>Rua abc</rua>
    <cidade>Cuiaba</cidade>
  </endereco>
  <endereco>
    <rua>Avenida São João</rua>
    <cidade>Primavera do Leste</cidade>
  </endereco>
</enderecos>

É necessário o seguinte método:
private static void gravaListaEndereco() {
        List<Endereco> enderecos = new ArrayList<Endereco>();

        Endereco e1 = new Endereco();
        e1.setCidade("Cuiaba");
        e1.setRua("Rua abc");
        enderecos.add(e1);

        Endereco e2 = new Endereco();
        e2.setCidade("Primavera do Leste");
        e2.setRua("Avenida São João");
        enderecos.add(e2);

        XStream xStream = new XStream();
        xStream.alias("enderecos", List.class);
        xStream.alias("endereco", Endereco.class);

        File arquivo = new File("enderecos.xml");
        FileOutputStream gravar;
        try {
            gravar = new FileOutputStream(arquivo);
            gravar.write(xStream.toXML(enderecos).getBytes());
            gravar.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

Agora vamos ver algo mais complicado, que é gravar objetos que contenham listas dentro dele... ou seja vamos criar um XML que represente uma lista de pessoas (nosso model lá do início):
<pessoas>
  <pessoa>
    <nome>Andii</nome>
    <cpf>123.123.123-34</cpf>
    <enderecos>
      <endereco>
        <rua>Rua 123</rua>
        <cidade>Primavera do Leste</cidade>
      </endereco>
    </enderecos>
  </pessoa>
  <pessoa>
    <nome>Maria</nome>
    <cpf>345.656.235-98</cpf>
    <enderecos>
      <endereco>
        <rua>Avenida das flores</rua>
        <cidade>Cuiabá</cidade>
      </endereco>
      <endereco>
        <rua>Rua das abelhas</rua>
        <cidade>Cuiabá</cidade>
      </endereco>
    </enderecos>
  </pessoa>
</pessoas>
Para gerar esta estrutura precisamos o seguinte método:
private static void gravaListaCompleta() {
        Pessoa pessoa1 = new Pessoa();
        pessoa1.setNome("Andii");
        pessoa1.setCpf("123.123.123-34");

        Endereco endereco1 = new Endereco();
        endereco1.setCidade("Primavera do Leste");
        endereco1.setRua("Rua 123");

        List<Endereco> enderecos1 = new ArrayList<Endereco>();
        enderecos1.add(endereco1);
        pessoa1.setEnderecos(enderecos1);

        Pessoa pessoa2 = new Pessoa();
        pessoa2.setNome("Maria");
        pessoa2.setCpf("345.656.235-98");

        Endereco endereco2 = new Endereco();
        endereco2.setCidade("Cuiabá");
        endereco2.setRua("Avenida das flores");

        Endereco endereco3 = new Endereco();
        endereco3.setCidade("Cuiabá");
        endereco3.setRua("Rua das abelhas");

        List<Endereco> enderecos2 = new ArrayList<Endereco>();
        enderecos2.add(endereco2);
        enderecos2.add(endereco3);
        pessoa2.setEnderecos(enderecos2);

        List<Pessoa> pessoas = new ArrayList<Pessoa>();
        pessoas.add(pessoa1);
        pessoas.add(pessoa2);

        XStream xStream = new XStream();

        xStream.alias("pessoas", List.class);
        xStream.alias("pessoa", Pessoa.class);
        xStream.alias("endereco", Endereco.class);

        File arquivo = new File("pessoas.xml");
        FileOutputStream gravar;
        try {
            gravar = new FileOutputStream(arquivo);
            gravar.write(xStream.toXML(pessoas).getBytes());
            gravar.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
E enfim para lermos uma String XML, precisamos do método abaixo, para o exemplo de leitura eu estarei utilizando o arquivo gerado em um dos métodos acima, aquele que gera uma lista de endereços:
private static void lerXML() {
        try {
            XStream xStream = new XStream(new Dom4JDriver());
            xStream.alias("enderecos", ArrayList.class);
            xStream.processAnnotations(Endereco.class);

            BufferedReader input = new BufferedReader(new FileReader("enderecos.xml"));
            ArrayList<Endereco> enderecos = (ArrayList) xStream.fromXML(input);
            input.close();

            for (Endereco endereco : enderecos) {
                System.out.println("Endereço: " + endereco.getRua() + " - " + endereco.getCidade());
            }

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
Veja que eu leio o arquivo utilizando BufferedReader e tendo esse arquivo "carregado" utilizo do XStream para gerar uma lista para mim... Lembrando que dessa vez eu preciso da anotação lá na classe Endereco, o resultado da leitura do método acima é:
Endereço: Rua abc - Cuiaba
Endereço: Avenida São João - Primavera do Leste
Bom... peço desculpas pela demora a fazer as explicações do XStream... Mas está aí :)

Observação final: como vocês podem ver, eu não coloquei um endereço fixo de onde armazenar meus arquivos, era apenas new file("endereco.xml") ... para quem não sabe isso gera o arquivo dentro da pasta do projeto.

4 de junho de 2011

JasperReports 4.0.1: Utilizando Subreports e parâmetros

Para esta não ser uma postagem muito extensa, irei utilizar o mesmo projeto e o mesmo relatório criado na postagem: agrupando de dados com JasperReports. Para completar esse projeto, logo abaixo do agrupamento eu vou listar os dados dos cliente, ou seja, terei um relatório de clientes embutido no relatório de pedidos (claro que pode ser feito outras coisas, este é apenas um exemplo)

Começando...
Então lá no projeto Pedidos (link acima), dentro do pacote pedidos.dao, vamos criar uma classe Java como o nome de ClienteDAO, seguindo a mesma linha da classe PedidoDAO, temos:
public class ClienteDAO {

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("PedidosPU");
    EntityManager em = emf.createEntityManager();

    public List<Cliente> listarClientes() {
        List<Cliente> clientes = null;
        try {
            Query query = em.createQuery("Select c from Cliente c order by c.nome");
            clientes = query.getResultList();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            em.close();
        }
        return clientes;
    }
}

No iReport, vamos editar o relatório pedidos.jrxml, criando também no link da postagem acima.
Para começar no relatório vamos adicionar a band Summary:


Precisamos criar um parâmetro que será enviado pelo projeto, para isso no Report Inspector, clique com o botão direito em Parameters, e em Adicionar Parameter:


Selecione o parameter1 e vá nas propriedades para configurá-lo, altere o nome para listaClientes e o Parameter class para java.util.List, pois passaremos por parâmetro uma lista de clientes:


Na paleta procure pelo elemento Subreport, arraste-o para a band Summary, a partir de agora siga as imagens abaixo:


Clique em próximo, na janela abaixo selecione o tipo Blank A4:


Clique em próximo novamente, como estamos usando JavaBean datasource, e não utilizamos datasource, configure como na imagem:


Avance de novo:


Mais uma vez:


Na janela abaixo informe o nome do Subreport, nesse caso será chamado de pedidos_subreport:


No passo 7, habilite a opção "Use a JRDatasource expression", e clique no botão do lado da caixa de texto, a seguinte janela aparecerá, nela nós convertemos a listaClientes em um JRBeanCollectionDataSource :


Ao clicar em Apply voltamos para a seguinte janela:



E aqui basta finalizar...
No relatório que foi criado, deixe apenas as bands - Title, Column Header e Detail 1:


Como será uma lista de clientes, precisamos pegar da classe Cliente os seguintes fields - codigo, nome e limiteCredito... para isso em Report Query, na aba JavaBean Datasource:

Feito isso...
Como visto em postagens anteriores, estruture o relatório para que fique assim:


Ah, lembre-se de nas propriedades do relatório alterar a linguagem para Java, já que estamos usando JavaBean datasource:


Depois disto basta compilar nosso subreport, para poder gerar o pedidos_subreport.jasper 

Voltamos ao pedidos.jrxml, e vamos fazer umas ultimas configurações, temos este resultado:

Precisamos criar mais um parâmetro que será uma String com o caminho de onde encontrar o pedidos_subreport.jasper, repita o mesmo passo que foi feito para criar o listaClientes, mas dessa vez use as seguintes propriedades:


Agora precisamos setá-lo no lugar certo... para isso: veja que na band Summary tem um elemento que representa o subreport, clique nele e vá nas propriedades, procure por Subreport Expression, e configure-o assim:


Feito todos esses passos, pode compilar novamente o relatório principal (pedidos)...
Caso não ocorra nenhum erro, voltamos ao projeto Pedidos no NetBeans.

No projeto..
No pacote pedidos,controle.relatorios, substitua o pedidos,jasper pelo que foi compilado agora, e adicione o pedidos_subreport.jasper, ficando assim:

Para finalizar de vez, precisamos fazer algumas alterações no método gerarRelatorio() da classe PedidoControle.java:
public void gerarRelatorio() {
     String arquivo = "src/pedidos/controle/relatorios/pedidos.jasper";

     pedidoDAO = new PedidoDAO();
     clienteDAO = new ClienteDAO();

     Map parametros = new HashMap();
     parametros.put("localizacaoPedidosSubreport", "src/pedidos/controle/relatorios/pedidos_subreport.jasper");
     parametros.put("listaClientes", clienteDAO.listarClientes());

     JRDataSource jrds = new JRBeanCollectionDataSource(pedidoDAO.listarPedidos());
    gerarRelatorioDesktop(jrds, parametros, arquivo);
}

No começo da classe lembre-se de adicionar a declaração do ClienteDAO, assim como foi feito para PedidoDAO...
Vamos ver o que foi alterado no método...
Primeiro, depois de declarado o atributo clienteDAO no inicio da classe, na linha 5 estamos inicializando-o.
Da linha 7 a 9, criamos um Map, com os parâmetros que criamos lá no iReport... e por fim... na linha 12, passávamos o parâmetro como null, agora este é substituído e passamos o Map parametros por parâmetro.

Assim podemos executar nosso projeto e ver o seguinte resultado:


Por aqui ficamos... admito que tive alguns probleminhas ao conseguir utilizar o JavaBean datasource no subreport, o que me levou a pedir um help no Twitter onde o @altitdb me ajudou! por isso deixo os devidos créditos à ele :)

Créditos da postagem: Altieres de Matos, pois ele salvou minha aula sobre Subrepot hehe (pois é, tive problemas ao usar Subreport com JavaBean datasource)

JasperReports 4.0.1: Agrupando dados

Na postagem de hoje vamos agrupar os pedidos por cliente, assim:


Para este exemplo eu vou utilizar o JPA (visto em postagens anteriores), em um projeto Desktop, só para ser mais rápido, o foco da postagem será o agrupamento então para outros detalhes colocarei apenas os links com exemplos.

Banco de dados
Antes de começar vamos ver qual será as tabelas utilizadas no banco de dados:


Criando o projeto..
Inicialmente vamos no NetBeans criar um novo Aplicativo Java(Desktop) com o nome de Pedidos. Dentro do pacote pedidos(criado por padrão) crie um pacote com o nome de model, ficando assim: pedidos.model, as classes do model serão criadas pelo JPA, ou seja serão geradas a partir do banco, caso não saiba como fazer, veja aqui. Quando geradas o projeto ficará com essa estrutura:

Por eu estar utilizando o MySQL preciso incluir a biblioteca do mesmo dentro do projeto... então em Bibliotecas adicione a biblioteca MySQL JDBC Driver que já tem no NetBeans, caso contrário é facilmente encontrado na Internet.

Novamente dentro do pacote pedidos, crie um novo pacote com o nome de dao, ficando como: pedidos.dao, e dentro dele crie uma nova classe Java com o nome de PedidoDAO.java:
public class PedidoDAO {

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("PedidosPU");
    EntityManager em = emf.createEntityManager();

    public List<Pedido> listarPedidos() {
        List<Pedido> pedidos = null;
        try {
            Query query = em.createQuery(
                    "Select p from Pedido p order by p.cliente.nome");
            pedidos = query.getResultList();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            em.close();
        }
        return pedidos;
    }
}
OBS: ao criar o EntityManagerFactory veja que passo por parâmetro  a String PedidosPU, este valor é  o nome da Persistence Unit, que é encontrado no persistence.xml, por isso confirme se é este o nome que aparece no seu persistence.
Outro detalhe é quanto a consulta... essa parte é de extrema importância: para eu poder agrupar os dados, eu preciso mandar as informações ordenadas de acordo pelo o que eu quero agrupar, neste caso eu quero agrupar por cliente, então dou um order by pelo nome do cliente.
Até agora esse é o nosso projeto:


Depois de ter feito isso, no NetBeans clique em Limpar e Construir, para que ele gere o nosso .jar
Agora vamos dar uma pausa no projeto e vamos criar nosso .jasper...

No iReport
Como vamos utilizar o datasource do tipo JavaBean datasource, aconselho ver esta postagem antes de continuar, caso contrário não será possível entender o que está sendo feito.
No iReport aberto, crie um novo relatório do tipo Blank A4, para mais informações de como criar um relatório veja aqui, e coloque o nome do mesmo como pedidos... depois de criado, nas propriedades do report troque a Language para Java:


Agora antes de continuar, lembre-se de setar no classpath do iReport (ver na postagem sobre JavaBean datasource) o .jar criado do projeto acima...Depois de feito isso, vamos deixar no nosso relatório apenas as seguintes bands: Title, Column Header e Detail 1, quanto as outras pode removê-las, ficando assim:


Agora vamos pegar os fields que vamos precisar para fazer o relatório... então em Report Query vamos selecionar os atributos da classe Pedido... para isso, faça como na imagem abaixo:


No Report Inspector, confirme se os fields foram criados, caso sim, ainda no Report Inspector, na raiz (pedidos) clique com o botão direito e vá em Add report group, coloque o nome de pedido:


Ao clicar em próximo, aparece a seguinte tela, onde pode deixar marcado apenas a opção de Add the group header, pois o group footer não iremos utilizar, e por fim clique em Finalizar:


O nosso relatório passa a ter as seguintes bands:


Agora vamos estruturar nosso relatório, deixando-o assim (abaixo da imagem digo o que tem em cada band), aconselho clicar na imagem para ampliar e ver corretamente as bands:


Primeiramente na band Title, foi colocado apenas um static text como título do relatório. Logo abaixo no Column Header, tem mais um static text informando o "Nome do Cliente"... agora no pedido Group Header 1  que é onde a coisa acontece eu coloquei um text field com o field que pega o nome do cliente, e ainda na mesma band, logo abaixo do text field eu adicionei dois static text: um para código e outro para o valor do pedido. Por fim na band Detail 1, é colocado dois text fields referentes ao código e ao valor (lembrar de alterar os expression class dos text fields de acordo com o tipo dos fields)
Feito tudo isso vamos compilar o nosso relatório para gerar o .jasper (no botão que parece um martelinho) caso não dê nenhum problema podemos continuar no projeto agora.

Voltando ao projeto...
Novamente no pacote pedidos vamos criar agora nosso pacote controle, ficando assim: pedidos.controle e dentro dele crie uma classe Java com o nome de PedidoControle.java, antes de fazermos a codificação dela, vamos dentro do pacote controle, criar um pacote relatorios onde iremos armazenar nosso .jasper, ficando dessa forma: pedidos.controle.relatorios e dentro dele jogue o .jasper gerado ao compilar o relatório:

Antes que esqueçamos, precisamos jogar as bibliotecas do JasperReports dentro do projeto, caso não as tenha ainda, pode consegui-las nesta postagem. Agora sim vamos editar a classe PedidoControle:
public class PedidoControle {

    private PedidoDAO pedidoDAO;

    private void gerarRelatorioDesktop(JRDataSource jrds, Map<Object, Object> parametros, String arquivo) {
        try {
            JasperPrint print = JasperFillManager.fillReport(arquivo, parametros, jrds);
            JasperViewer.viewReport(print, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void gerarRelatorio() {
        String arquivo = "src/pedidos/controle/relatorios/pedidos.jasper";

        pedidoDAO = new PedidoDAO();

        JRDataSource jrds = new JRBeanCollectionDataSource(pedidoDAO.listarPedidos());
        gerarRelatorioDesktop(jrds, null, arquivo);
    }
}

Como já foi visto em outras postagens não irei explicar novamente o que acontece neste código.
Para finalizar, vamos chamar nosso método gerarRelatorio() na classe Main.java:
public class Main {

    public static void main(String[] args) {
        PedidoControle controle = new PedidoControle();
        controle.gerarRelatorio();
    }
}

Bom... ao executar o projeto, se tudo ocorrer bem, abrirá a janela no JasperViewer, o resultado será:


E por aqui ficamos com mais uma postagem sobre JasperReports... =)

25 de maio de 2011

JasperReports 4.0.1: JDBC datasource - abrir relatório em projeto desktop

Depois de vermos como chamar um relatório feito no JasperReports utilizando JDBC datasource em um projeto Web, nessa postagem vamos usar o mesmo relatório mas em um projeto Java Desktop!
Reveja algumas postagens:

Começando...
Para começar, no NetBeans crie um novo Aplicativo Java com o nome de RelatorioJDBC. A estrutura final será esta aqui:


Feito isso, vamos começar a estruturar nosso projeto para usarmos .jasper (criado na postagem do link). Como estamos usando JDBC, precisamos ter uma conexão com o banco de dados, então em pacotes de código-fonte já existirá um pacote com o nome de relatoriojdbc, dentro dele crie um novo pacote com o nome de dao, dentro desse pacote crie a classe Java com o nome de Conexao (já foi utilizada em outras postagem que não utilizava JPA), segue o código-fonte:
public class Conexao {
    private String driver = "com.mysql.jdbc.Driver";
    private String URL = "jdbc:mysql://localhost/5tads";
    private String USER = "root";
    private String SENHA = "admin";
    private Connection conn;

    public Conexao() {
        try {
            Class.forName(driver);
            conn = (Connection) DriverManager.getConnection(URL, USER, SENHA);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Connection getConn() {
        return conn;
    }

    public void fecharConexao() {
        try {
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
Obs: só lembrando que na URL, o 5tads corresponde à minha database.
Como nosso foco não é a conexão com o banco de dados, vamos prosseguir... agora no mesmo pacote relatoriojdbc.dao, vamos criar mais uma classe Java com o nome de ClienteDAO:
public class ClienteDAO {

    private Conexao conexao;
    private Statement stmt;

    public ClienteDAO() {
        conexao = new Conexao();
        try {
            stmt = (Statement) conexao.getConn().createStatement();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    public ResultSet clientesResultSet() {
        ResultSet rs = null;
        try {
            rs = stmt.executeQuery("SELECT * FROM cliente ORDER BY nome");
        } catch (Exception e) {
            e.printStackTrace();
        } 

        return rs;
    }
}
Veja que o nosso método clientesResultSet, retorna um ResultSet mesmo e não uma lista de clientes, ao usarmos a metodologia de JDBC datasource, é isto que precisamos passar para o .jasper, e não uma lista como na JavaBean datasource.

Agora precisamos de um lugar para guardar nosso .jasper, para isso crie a seguinte estrutura de pacotes:
relatoriojdbc.controle.relatorios, e dentro dele, coloque o arquivo .jasper (no meu caso relatorioJDBC .jasper):


Agora precisamos colocar as bibliotecas no projeto, caso não tenha baixado as bibliotecas do JasperReports, baixe por aqui.
De todas as bibliotecas disponibilizadas no link, para este tipo de relatório iremos usar apenas algumas delas, acabei filtrando e chegando as que realmente precisavam, então adicione ao projeto as seguintes bibliotecas:

* quanto a biblioteca do MySQL é do próprio NetBeans (mas pode ser encontrada facilmente no Google).

Agora que já temos nosso dao pronto, e como já criamos um pacote relatoriojdbc.controle.relatorios, já temos um pacote controle, e então dentro dele teremos uma classe Java com o nome de ClienteControle:
public class ClienteControle {

    private ClienteDAO dao;

    public void gerarRelatorio() {
        String arquivo = "src/relatoriojdbc/controle/relatorios/relatorioJDBC.jasper";

        dao = new ClienteDAO();
        JRDataSource jrds = new JRResultSetDataSource(dao.clientesResultSet());
        gerarRelatorioDesktop(jrds, null, arquivo);
    }

    private void gerarRelatorioDesktop(JRDataSource jrds, Map<Object, Object> parametros, String arquivo) {
        try {
            JasperPrint print = JasperFillManager.fillReport(arquivo, parametros, jrds);
            JasperViewer.viewReport(print, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Vamos ver o que esses métodos fazem: 

public void gerarRelatorio()
Inicialmente este método será chamado pela nossa classe Main (que foi criada por padrão no projeto), nesse método nós precisamos pegar o caminho exato do nosso arquivo .jasper, que lá no começo da postagem colocamos dentro do pacote relatoriojdbc.controle.relatorios para isso precisamos indicar o caminho corretamente.
Quanto ao jrRS: por termos utilizado JDBC datasource para gerar nosso .jasper, nos precisamos passar para nosso relatório um JRDataSource, que é formado por um Result Set  que é retornado pelo nosso método lá do ClienteDAO.
Ao chamar o gerarRelatorioDesktop, estamos passando um parâmetro null, esse corresponderia a uma Map, que serviria para passarmos parâmetros(que vai ficar pra outra postagem) para o nosso relatório...
Agora vamos ver o que acontece no:
gerarRelatorioDesktop(JRDataSource jrRS, Map<Object, Object> parametros, String arquivo)
Dentro de um try-catch(para capturar possíveis exceções) nós temos o método principal que é o responsável por gerar o que vai ser o nosso relatório, que é essa linha aqui:
JasperFillManager.fillReport... 
esse método não cria um arquivo .pdf fisicamente no computador, apenas gera ele como se fosse um arquivo temporário, e quem decide se quer salvar o relatório ou não é o usuário, depois disso, chamamos o JasperViewer que é o que eu chamo de "visualizador de relatórios" do próprio JasperReports (ao final eu mostro visualmente este visualizador)...
Depois de vermos a principal classe do projeto, vamos ver a classe Main.java (dentro do pacote relatoriojdbc) que vai ser a responsável por mostrar uma telinha em Swing que tem um jButton, e que quando clicar nele ele vai chamar nosso método gerarRelatorio() da nossa classe ClienteControle, veja o código da classe Main abaixo:
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        JFrame frame = new JFrame("Meu relatorio!");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JButton botao = new JButton("Chamar meu relatório!");
        botao.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                ClienteControle controle = new ClienteControle();
                controle.gerarRelatorio();
            }
        });

        frame.getContentPane().add(botao);
        frame.pack();
        frame.setVisible(true);

    }
}

Ao executar o projeto (F6) temos a seguinte tela (é bem essa grande tela aí abaixo):


Ao clicar no botão "Chamar meu relatório!", ele irá fazer o que o próprio nome dele já diz: Chamar o nosso relatório =) ... assim, aparece a seguinte tela do JasperViewer:


Por aqui finalizamos a visualização de relatórios feito no JasperReports utilizando JDBC datasource. =)

22 de maio de 2011

JasperReports 4.0.1: JavaBean datasource - abrir relatório em projeto desktop

Depois de vermos como chamar um relatório feito no JasperReports utilizando JavaBean, nessa postagem vamos usar o mesmo relatório mas em um projeto Java Desktop!
Reveja algumas postagens:

Começando...
Caso tenha seguido a postagem Utilizando JavaBean datasource(link acima) pule essa parte de criar um projeto, a classe Java e tals, pode-se utilizar o mesmo projeto feito lá. Caso contrário, vamos ver o que precisa ser feito:
Para começar, no NetBeans crie um novo Aplicativo Java com o nome de PrimeiroRelatorio.
Feito isso, vamos criar a estrutura que usamos para gerar o .jasper, então em Pacotes de código-fonte já existirá um pacote com o nome de primeirorelatorio e dentro dele crie um pacote model, dentro desse pacote crie a classe Produto (lembrando que tem que ser idêntica à aquela usada no .jar para gerar o relatório), ficando com esta estrutura:

Relembrando a classe Produto:
public class Produto {
    private int codigo;
    private String nome;
    private BigDecimal valor;

    //gerar getters e setters
}

Agora precisamos de um lugar para guardar nosso .jasper, para isso crie a seguinte estrutura de pacotes:
primeirorelatorio.controle.relatorios, e dentro dele, coloque o arquivo .jasper (no meu caso PrimeiroRelatorio.jasper):


Caso não tenha baixado as bibliotecas do JasperReports, baixe por aqui.
De todas as bibliotecas disponibilizadas no link, para este tipo de relatório iremos usar apenas algumas delas, acabei filtrando e chegando as que realmente precisavam, então adicione ao projeto as seguintes bibliotecas:


Como já criamos um pacote primeirorelatorio.controle.relatorios, já temos um pacote controle, e então dentro dele teremos uma classe Java com o nome de RelatorioControle:


O código fonte dessa classe será esse (abaixo do código eu explico ela):
package primeirorelatorio.controle;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.view.JasperViewer;
import primeirorelatorio.model.Produto;

/**
 *
 * @author andii
 */

public class RelatorioControle {

    public void gerarRelatorio() {
        String arquivo = "src/primeirorelatorio/controle/relatorios/PrimeiroRelatorio.jasper";

        JRDataSource jrds = new JRBeanCollectionDataSource(listarProdutos());

        gerarRelatorioDesktop(jrds, null, arquivo);
    }

    private void gerarRelatorioDesktop(JRDataSource jrds, Map<Object, Object> parametros, String arquivo) {
        try {
            JasperPrint print = JasperFillManager.fillReport(arquivo, parametros, jrds);
            JasperViewer.viewReport(print, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private List<Produto> listarProdutos() {
        List<Produto> produtos = new ArrayList<Produto>();
        Produto p1 = new Produto();
        p1.setCodigo(1);
        p1.setNome("Produto 1");
        p1.setValor(new BigDecimal(1.99));
        produtos.add(p1);

        Produto p2 = new Produto();
        p2.setCodigo(2);
        p2.setNome("Produto 2");
        p2.setValor(new BigDecimal(3000.50));
        produtos.add(p2);

        Produto p3 = new Produto();
        p3.setCodigo(3);
        p3.setNome("Produto 3");
        p3.setValor(new BigDecimal(500.00));
        produtos.add(p3);
        return produtos;
    }
}

Vamos ver o que esses métodos fazem: 

public void gerarRelatorio()
Inicialmente este método será chamado pela nossa classe Main (que foi criada por padrão no projeto), nesse método nós precisamos pegar o caminho exato do nosso arquivo .jasper, que lá no começo da postagem colocamos dentro do pacote primeirorelatorio.controle.relatorios para isso precisamos indicar o caminho corretamente.
Quanto ao jrds: por termos utilizado uma classe Java para gerar nosso .jasper, precisamos passar para nosso relatório um JRDataSource, que é formado por uma lista de Produto (pois o método listarProdutos(), retorna uma lista de produtos que poderia muito bem estar vindo de um banco de dados).
Ao chamar o gerarRelatorioDesktop, estamos passando um parâmetro null, esse corresponderia a uma Map, que serviria para passarmos parâmetros(que vai ficar pra outra postagem) para o nosso relatório...
Agora vamos ver o que acontece no:
gerarRelatorioDesktop(JRDataSource jrds, Map<Object, Object> parametros, String arquivo)
Dentro de um try-catch(para capturar possíveis exceções) nós temos o método principal que é o responsável por gerar o que vai ser o nosso relatório, que é essa linha aqui:
JasperFillManager.fillReport... 
esse método não cria um arquivo .pdf fisicamente no computador, apenas gera ele como se fosse um arquivo temporário, e quem decide se quer salvar o relatório ou não é o usuário, depois disso, chamamos o JasperViewer que é o que eu chamo de "visualizador de relatórios" do próprio JasperReports (ao final eu mostro visualmente este visualizador)...
Depois de vermos a principal classe do projeto, vamos ver a classe Main.java(dentro do pacote primeirorelatorio) que vai ser a responsável por mostrar uma telinha em Swing que tem um jButton, e que quando clicar nele ele vai chamar nosso método gerarRelatorio() da nossa classe RelatorioControle, veja o código da classe Main abaixo:
package primeirorelatorio;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import primeirorelatorio.controle.RelatorioControle;

/**
 *
 * @author andii
 */
public class Main {

    public static void main(String[] args) {
        JFrame frame = new JFrame("Meu relatorio!");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JButton botao = new JButton("Chamar meu relatório!");
        botao.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                RelatorioControle controle = new RelatorioControle();
                controle.gerarRelatorio();
            }
        });

        frame.getContentPane().add(botao);
        frame.pack();
        frame.setVisible(true);

    }
}
Ao executar o projeto (F6) temos a seguinte tela (é bem essa grande tela aí abaixo):


Ao clicar no botão "Chamar meu relatório!", ele irá fazer o que o próprio nome dele já diz: Chamar o nosso relatório =) ... assim, aparece a seguinte tela do JasperViewer:


Por aqui finalizamos a visualização de relatórios feito no JasperReports utilizando JavaBean. =)

24 de agosto de 2010

Swing: Preenchendo um JComboBox

Nesse post iremos preencher um JComboBox com objetos, para isso vamos precisar de uma java.util.List.
Para exemplo vamos usar uma categoria. Então... precisamos de uma classe chamada Categoria.java

public class Categoria {

    private int codigo;
    private String nome;

    public int getCodigo() {
        return codigo;
    }

    public void setCodigo(int codigo) {
        this.codigo = codigo;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    @Override
    public String toString() {
        return this.nome;
    }

}
Perceba que o método toString() foi sobreescrito, isso é necessário para que ao mostrar os objetos no JComboBox, apareça o nome da categoria como referência no combo... para entender a importância disso, faça um teste: retire o método toString() e veja o resultado!

Continuando...
Crie um Formulário JFrame com o nome de ExemploCombo.java, e arraste para a tela, um JComboBox (cmbCategoria) e um JButton (btnEnviar) para testarmos.
A janela deverá ficar como a imagem abaixo:

No código-fonte crie um método carregaCombo(), com o seguinte código:
private void carregaCombo(){
        //assim como é feito numa JTable, temos o DefaultComboBoxModel que é o model do JComboBox
        DefaultComboBoxModel comboModel = (DefaultComboBoxModel) cmbCategoria.getModel();
        //removendo todos os elementos do combo
        comboModel.removeAllElements();
        //cria a lista: java.util.List
        List<Categoria> categorias = new ArrayList<Categoria>();
        //adicionando valores aleatorios a lista
        Categoria c1 = new Categoria();
        c1.setCodigo(1);
        c1.setNome("Compra");
        categorias.add(c1);

        Categoria c2 = new Categoria();
        c2.setCodigo(2);
        c2.setNome("Venda");
        categorias.add(c2);
        //percorrendo a lista para inserir os valores no combo
        for (int linha = 0; linha < categorias.size(); linha++)
        {
            //pegando a categoria da lista
            Categoria categoria = categorias.get(linha);
            //adicionando a categoria no combo
            comboModel.addElement(categoria);
        }
    }
Os comentários no código explicam o que acontece em cada linha.
Agora é necessário chamar este método no construtor da classe, logo depois de iniciar os componentes:
public ExemploCombo() {
        initComponents();
        carregaCombo();
    }

E para pegar o valor, vamos utilizar o evento do btnEnviar, para isso dê dois cliques no botão para abrir o evento:
private void btnEnviarActionPerformed(java.awt.event.ActionEvent evt) {                                         
        //pegando o objeto selecionado no combo
        Categoria categoria = (Categoria) cmbCategoria.getSelectedItem();
        //mostrando o nome da categoria em um dialogo
        JOptionPane.showMessageDialog(this, categoria.getNome());
    }

Para setar um objeto por padrão em um combo, segue o exemplo:
cmbCategoria.setSelectedItem(categoria);
Essa categoria que está sendo passada por parâmetro, seria uma categoria por exemplo pega de uma lista, ou de um outro objeto que possua uma categoria.

=)

18 de agosto de 2010

JavaSE: Converter java.util.Date para String e vice-versa

Converter String para java.util.Date
Para converter uma String em java.util.Date, é necessário utilizar a classe java.text.SimpleDateFormat, passado uma String por parâmetro que se refere ao formato em que se encontra a String que será convertida:
SimpleDateFormat formataData = new SimpleDateFormat("dd/MM/yyyy");
Date dataEntrada = null;
try { 
    dataEntrada = formataData.parse("21/09/2010");
} catch (ParseException ex) {
    ex.printStackTrace();
}

Converter java.util.Date para String
Quando se tem um Date e quer transformar em String é só utilizar o mesmo SimpleDateFormat. O 'new Date()' pega a data atual do sistema, a String passada por parâmetro para SimpleDateFormat é o formato em que se deseja que a String seja formatada:
Date dataHoje = new Date();
SimpleDateFormat formataData = new SimpleDateFormat("dd/MM/yyyy");
String data = formataData.format(dataHoje);

Por se tratar de uma formatação onde não há riscos de ocorrer erros, não é necessário colocar a formatação dentro de um bloco 'try catch' como a conversão anterior.

15 de agosto de 2010

JavaSE: CRUD em Swing

Neste post, iremos implementar parte do projeto do Hotel  da postagem: UML: Trabalhando com a diagramação . Este sistema será implementado em Java SE (para Desktop), com armazenamento em estruturas de dados (mais especificamente em java.util.List).
O sistema final terá a seguinte estrutura:
Obs: as classes do pacote model são as mesmas criadas na aula citada no link acima.
Mas, neste post será criado apenas o cadastro de Aposentos... então vamos lá!

Criando o projeto...
Neste projeto será utilizado o NetBeans, neste crie um novo projeto: Arquivo -  Novo Projeto - Java -  Aplicativo Java, e coloque o nome do projeto como: Hotel.

Criando o banco de dados...
Considerando que o pacote model já esteja implementado, vamos começar criando nossa classe que servirá de banco de dados, então dentro do pacote hotel, crie uma nova classe java chamada de BancoDados.java, com o seguinte codigo:
public class BancoDados {

    private static List<Aposento> aposentos = new ArrayList<Aposento>();
 
    /*
     * Aposentos
     */

    public static List<Aposento> getAposentos() {
        return aposentos;
    }

    public static void addAposento(Aposento aposento){
        aposentos.add(aposento);
    }

    public static void atualizaAposento(int linhaSelecionada, Aposento aposento){
        aposentos.set(linhaSelecionada, aposento);
    }

    public static void removeAposento(Aposento aposento){
        aposentos.remove(aposento);
    }
}
Perceba que nossos métodos são static, pois como instanciaremos apenas uma única vez nosso BancoDados, os mesmos precisarão ser acessados mas sem instanciar um novo BancoDados, isso será entendido melhor mais pra frente...

Tela inicial...
Ainda dentro do pacote hotel, crie um Formulário JFrame, chamado de Principal.java, este será nossa tela inicial do sistema. Por ser um JFrame o NetBeans dá a opção de criar a tela arrastando os componentes, então arraste um botão (JButton) para o formulário, este ficará com a seguinte aparência:

Chamando nossa tela principal...
Na classe Main.java que foi criada juntamente com o projeto, insira o seguinte codigo:
public class Main {

    public static void main(String[] args) {
       new BancoDados();

       JFrame principal = new Principal();
       principal.setVisible(true);
    }
}
perceba que nosso BancoDados está sendo instanciado, isso garante que ele seja inicializado junto com o sistema. E após ele, está sendo instanciado nosso formulário JFrame Principal.java, que é a tela inicial do sistema.
Para visualizar a aplicação, basta apertar a tecla F6 (padrão do NetBeans para executar a aplicação).

Criando a tela principal de aposentos
Agora crie um pacote chamado aposento, dentro do pacote hotel, naquele crie um novo formulário JFrame chamado Aposentos.java, arraste para a tela três botões (JButton) e uma tabela (JTable). Altere o nome das variáveis dos botões para: btnNovo, btnAlterar e btnRemover.

Para alterar os campos da tabela, clique nela com o botão direito e clique em conteúdo da tabela e vá na aba colunas, e edite as mesmas. Depois, clique novamente na tabela e vá em propriedades - aba código, e altere os modificadores de variáveis, o mesmo deve ficar como private static. Isso precisa ser feito para criamos um método estático de atualização da tabela, pois é o mesmo caso do BancoDados, mais pra frente precisaremos chamar este método sem instanciar um novo objeto Aposentos(). Então, no código fonte de Aposentos.java, insira o seguinte método(deve ficar dentro da classe):
public static void atualizaTabela(){
        DefaultTableModel tTabela = (DefaultTableModel) jTable1.getModel();
        tTabela.setNumRows(0);

        List<Aposento> aposentos = BancoDados.getAposentos();

        for (int linha = 0; linha < aposentos.size(); linha++)
        {
            Aposento aposento = aposentos.get(linha);

            tTabela.addRow(new Object[]{1});

            jTable1.setValueAt(aposento.getCodigo(), linha, 0);
            jTable1.setValueAt(aposento.getNumero(), linha, 1);
            jTable1.setValueAt(aposento.getDescricao(), linha, 2);
            jTable1.setValueAt(aposento.getValor(), linha, 3);
        }

    }
jTable1 é a minha tabela, caso esteja dando erro, verifique o nome da sua tabela.
Para que nossa tabela inicie atualizada, vamos chamar o método atualizaTabela() no construtor da classe Aposentos.java, ficando como o código abaixo:
public Aposentos() {
        initComponents();
        atualizaTabela();
    }

Agora iremos chamara tela de aposentos ao clicar no botão "Aposentos" na tela do frame Principal.java: então, em Principal.java de um duplo clique no botão "Aposentos" para que ele vá para o método do clique, onde será inserido o código para instanciar nosso frame Aposentos.java:
private void btnAposentosActionPerformed(java.awt.event.ActionEvent evt) {                                             
        JFrame aposentos = new Aposentos();
        aposentos.setVisible(true);
}    
No meu caso, eu alterei o nome da variável do meu botão para btnAposentos, por isso o nome do método inicia dessa forma.(isso vai ser de acordo com o nome dado ao botão aposentos)
Até este momento nossa aplicação já está abrindo a janela de aposentos ao clicar no botão "Aposentos" da tela inicial.

Tela de inserir aposento...
Dentro do pacote hotel.aposento crie um novo formulário JFrame com o nome de InserirAposento.java, crie a seguinte estrutura: quatro rótulos(JLabel), quatro campos de texto(JTextField) e dois botões (JButton)

Renomeie os nomes das variáveis dos campos de texto para: txtCodigo, txtNumero, txtDescricao, txtValor. E os botões para: btnOk, e btnCancelar.
Dê dois cliques no botão "Ok" para que ele vá para o método do clique do botão, e insira este codigo:
private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {                                         
        int iCodigo = Integer.parseInt(txtCodigo.getText());
        int iNumero = Integer.parseInt(txtNumero.getText());
        String sDescricao = txtDescricao.getText();
        double dValor = Double.parseDouble(txtValor.getText());
        Aposento aposento = new Aposento();
        aposento.setCodigo(iCodigo);
        aposento.setNumero(iNumero);
        aposento.setDescricao(sDescricao);
        aposento.setValor(dValor);

        BancoDados.addAposento(aposento);
        Aposentos.atualizaTabela();
        this.dispose();
    } 

Este método pega os valores dos campos, seta no objeto Aposento, e insere no nosso BancoDados, veja que não foi instanciado nenhum BancoDados aqui, lembre que se instancia apenas no Main.java. Depois que ele inserir, ele atualizará a tabela de aposentos pelo codigo Aposentos.atualizaTabela() que é o mesmo caso do BancoDados, e depois disto ele fecha a janela com o código this.dispose().
Agora dê um duplo clique no botão de cancelar:
private void btnCancelarActionPerformed(java.awt.event.ActionEvent evt) {                                         
    this.dispose();
}
Observe que o botão de cancelar, apenas fechará nossa janela.
Agora, iremos no Aposentos.java para chamar o InserirAposento. Então, vá em Aposentos.java e dê um duplo clique no botão "Novo":
private void btnNovoActionPerformed(java.awt.event.ActionEvent evt) {                                         
    JFrame janela = new InserirAposento();
    janela.setVisible(true);
}

Assim, nossa aplicação já está inserindo e listando os aposentos!

Alterando um aposento...
Para facilitar nossa implementação, ao invés de criar um novo JFrame para alterar o aposento, vamos copiar o InserirAposento.java e colar no mesmo pacote em que este se encontra, renomeando ele para AlterarAposento.java (ele vai pedir pra refatorar, então refatore!)
Vá para o código fonte do AlterarAposento.java e lá nas declarações dos atributos, declare os seguintes:
private Aposento aposento;
private int linhaSelecionada;
Logo abaixo do construtor do AlterarAposento.java, crie um novo construtor, passando um int por paramêtro, este int será a linha selecionada da tabela de Aposentos, que corresponde ao índice do aposento que foi selecionado na lista.
public AlterarAposento(int linhaSelecionada){
    initComponents();

    this.linhaSelecionada = linhaSelecionada;
    aposento = BancoDados.getAposentos().get(linhaSelecionada);
    codigo.setText(String.valueOf(aposento.getCodigo()));
    numero.setText(String.valueOf(aposento.getNumero()));
    descricao.setText(aposento.getDescricao());
    valor.setText(String.valueOf(aposento.getValor()));
}
Veja que estou setando a linhaSelecionada recebida por parâmetro na linhaSelecionada declarada na classe, pois esta será utilizada para setar o índice do objeto que será alterado na lista. A próxima linha: busca na lista do BancoDados o objeto Aposento daquela determinada linha. E quanto ao restante do código, estes setam os valores nos campos, para que ao abrir a janela, os campos estejam com os valores.
Agora dê um duplo clique no botão de Ok de AlterarAposento, perceba que este já está implementado pois foi copiado do inserir, então substitua o código pelo código a seguir:
private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {                                         
    int iCodigo = Integer.parseInt(codigo.getText());
    int iNumero = Integer.parseInt(numero.getText());
    String sDescricao = descricao.getText();
    double dValor = Double.parseDouble(valor.getText());
    aposento.setCodigo(iCodigo);
    aposento.setNumero(iNumero);
    aposento.setDescricao(sDescricao);
    aposento.setValor(dValor);

    BancoDados.atualizaAposento(linhaSelecionada, aposento);
    Aposentos.atualizaTabela();
    this.dispose();
}
Deixe a implementação do botão "Cancelar" como ele está.
Vá para o JFrame Aposentos.java e dê um duplo clique no botão "Alterar", implemente o mesmo da seguinte forma:
private void btnAlterarActionPerformed(java.awt.event.ActionEvent evt) {                                         
    int linhaSelecionada = jTable1.getSelectedRow();

    if (linhaSelecionada >= 0){
        JFrame janelaAlterar = new AlterarAposento(linhaSelecionada);
        janelaAlterar.setVisible(true);
    }
    else{
        JOptionPane.showMessageDialog(this, "É necessário selecionar um aposento", "Aposento", JOptionPane.INFORMATION_MESSAGE);
    }        
}     
Analisando o código: nosso int linhaSelecionada está recebendo o valor da linha selecionada da tabela. Aí esta linha é verificada, para não ocorrer de abrir a janela de alterar aposento sem ter uma linha selecionada na tabela, por isso do if e else, caso a linhaSelecionada seja maior ou igual a 0, significa que tem uma linha selecionada na tabela, então será aberto a janela de AlterarAposento passando por parâmetro o valor desta linha, senão, abre uma janela dizendo que é necessário selecionar um aposento para alterar!

Removendo um aposento...
Para o remover aposento não será necessário um novo JFrame, iremos criar um JOptionPane. Então dê um duplo clique no botão "Remover" e insira o seguinte código:
private void btnRemoverActionPerformed(java.awt.event.ActionEvent evt) {                                         
    int linhaSelecionada = jTable1.getSelectedRow();

    if (linhaSelecionada >= 0){
        int resposta = JOptionPane.showConfirmDialog(this, "Deseja excluir o aposento?");
        if (resposta == JOptionPane.YES_OPTION){
            Aposento aposento = BancoDados.getAposentos().get(linhaSelecionada);
            BancoDados.removeAposento(aposento);

            atualizaTabela();
        }
    }
    else{
        JOptionPane.showMessageDialog(this, "É necessário selecionar um aposento", "Aposento", JOptionPane.INFORMATION_MESSAGE);
    }
}
Analisando  o código: Veja que parte do código é bem parecida com o evento do botão "Alterar", mas ao invés de chamar um novo JFrame, é criada uma janela de diálogo, que recebe um valor inteiro que em seguida é verificado, caso tenha clicado em Yes, o código para a remoção do aposento é executado!
E assim termina nosso cadastro de aposento =)