Meu "FrameWork"

Ola pessoal do Guj venho aqui pedir um favor a vocês xD, recentemente eu fiz uma classe baseado numa classe de um amigo meu que ele tinha feito em PHP

basicamente é uma classe que faz a comunicação com o banco de dados MySql

e o que gostaria de pedir, era para você derem uma opinião sobre ele, como está, se pode melhor, uma nota, uma critica

Bem espero que gostem, tive um certo trabalho e tal para fazer mas achei que ficou interessante, por isso botei aqui, além disso eu sei que existe outros FrameWork que é melhor e mais completo, e talz, eu só queria saber o que vocês acharam do projeto, se ta legal ou não

“Copyright nos arquivos”

link para download https://www.dropbox.com/s/ypgauectv5n42ld/javaDB.tar.gz

bem acho melhor falar um pouco sobre ele e como usar

Obs : A classes que eu fiz aqui são para o tutorial, mas você podem encapsular os campo a vontade, fazer suas classes da forma que desejar, basta seguir os princípios ditos

[size=18]Básico[/size]

Classe principal do projeto é a “javaDB.model.Model” estenda a classe e coloque duas anotações primeiro a “@TableDB” e indique o nome da tabela dela
segundo a @FieldDB(isId = true) (OBS IMPORTANTE : é necessário ter pelo menos um campo declarado como ID), também sobrescreva o método getConnection

Obs: o nome da variável deve ser igual ao nome colocado no banco de dados caso não seja você deve declarar no @FieldDB o campo “name” contendo o nome da variável no banco

[code]
@TableDB(nome = “Tabela”)
class ClasseModel extends Model {

private Connection conn;
@FieldDB(isId = true)
long id;

public ClasseModel(Connection conn) {
    this.conn = conn;
}

@Override
public Connection getConnection() throws SQLException {
    return conn;
}

}[/code]

Ao fazer isso você terá seu modelo do banco de dados, agora imaginemos que estamos trabalhando com uma tabela chamada Imagem, e que ela tem duas colunas,
ID (Primary, int), e Arquivo (VarChar(150)) utilizando a base acima basta mudar o nome da tabela e adicionar o campo, assim

[code]
@TableDB(nome = “Imagem”)
class ImagemModel extends Model {

private Connection conn;
@FieldDB(isId = true)
long id;
@FieldDB
String Arquivo

public ImagemModel(Connection conn) {
    this.conn = conn;
}

@Override
public Connection getConnection() throws SQLException {
    return conn;
}

}[/code]

Blz agora digamos que queremos pegar do banco de dados a imagem cujo o ID seja 5 faça assim

ImagemModel model = new ImagemModel(Connection);
model.id = 5;
System.out.println(model.pesquisa());

Pronto esse código irá pegar no banco de dados a imagem com ID e popular a classe com seu valor

para fazer um Insert/Update e um Delete use :

ImagemModel model = new ImagemModel(Connection);
/**
   *seta os valores na instancia
   */

//salvar() faz um insert ou update dependendo do valor do campo ID se ele for igual a zero ele faz um insert se for diferente de zero ele faz um update
model.salvar();

//Deleta do banco de dados de acordo com o id
model.deleta();

[size=18]Nivel medio[/size]

É possível criar uma modelo que se referencia a outro modelo basta adicionar no campo que será a ForeignKey a anotação

@ForeignKey(Model = Model.class)” assim :

pressupomos que uma imagem possui uma referencia de quem criou ela e que criamos um modelo chamado “UsuarioModel” que deve seguir o modelo base citado lá em cima

[code]
@TableDB(nome = “Imagem”)
class ImagemModel extends Model {

private Connection conn;
@FieldDB(isId = true)
long id;
@FieldDB
String Arquivo


@FieldDB
@ForeignKey(Model = UsuarioModel.class)
long usuario_id;

UsuarioModel ModelRecursivo;

public ImagemModel(Connection conn) {
    this.conn = conn;
}

@Override
public Connection getConnection() throws SQLException {
    return conn;
}

}[/code]

Pronto agora nosso modelo imagem, já pode fazer uma pesquisa recursiva basta fazer assim :


ImagemModel model = new ImagemModel(conn);

//Lembre de setar o valor do ID para procurar

//Informe que a pesquisa deve ser recursiva
model.setPesquisaRecursiva(true);

//pesquisa da mesma forma que antes
System.out.println(model.pesquisa());

[size=18]Nivel avançado[/size]

O “FrameWork” também possibilita usar tipos de dados alem dos primitivos como é o exemplo do BufferedImage, é comum usar um campo BLOB no banco para armazenar uma imagem, bem aki também é possível usar se utilizamos um recurso que chamei de “Carregador”

Uma carregador é uma classe abstrata que serve para tratar a informação antes de ir para o banco de dados, e depois de receber do bancos de dados, todo carregador contem dois metodos , o Salvar() e o Popular(), salvar é chamado quando irá adicionar aquele campo no banco de dados e o popular é chamado depois de pegar os valores do banco de dados, um exemplo de Carregador que criei foi o “BufferedImageCarregador”

Observe seus metodos

    @Override
    public void Salvar(PreparedStatement statement, int pos, Object typeToSave) {
       //O statement recebido será nele que deverá adicionar, junto vem o 
       //int pos que deve ser usado em conjuto com o statment para ele colocar na posisão correta na query
       // Ja o typeToSave é o objeto que irá ser salvo no banco de dados, em outras palavras é o valor atual do campo de sua model 
        try {
            ByteArrayOutputStream bytesImg = new ByteArrayOutputStream();
            ImageIO.write((BufferedImage) typeToSave, imgType, bytesImg);
            bytesImg.flush();
            statement.setBytes(pos, bytesImg.toByteArray());
        } catch (IOException | SQLException ex) {
            Logger.getLogger(BufferedImageCarregador.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    @Override
    public BufferedImage Popula(ModelInfo info, String columnName) {
        try {
              //ModelInfo é outra classe abstrata que serve para popular a model, isso permite que para popular a classe você possa passar valores que não nessesáriamente
              //seja do banco de dados
              //columName é o nome da colula deve ser usada junto com a ModelInfo para pegar o valor que veio do banco de dados
              //Observe que no caso pelo campo no banco de dadose ser um BLOB ele volta sendo um Byte array então por isso que eu passo como            
              //class byte[].class pois o objeto é um Byte array
            return ImageIO.read(new ByteArrayInputStream(info.getObject(columnName, byte[].class)));
        } catch (IOException ex) {
            Logger.getLogger(BufferedImageCarregador.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

Esse é o exemplo de um carregar aconselho a você ler a classe carregador pode tirar algumas duvidas

Mas vamos para de falar, como usa um Carregador? Basta você adicionar ele estaticamente na classe Model, assim :
no caso estou adicionando um carregador “BufferedImageCarregador” ele recebe um parâmetro que é para determinar o tipo da imagem, alem disso
ele recebe um segundo parâmetro, serve para indica qual classe a variável deve ter para se utilizar esse carregador, como no caso é para BufferedImagem.

Model.addCarregador(new BufferedImageCarregador("jpg"), BufferedImage.class);

Utilizando o carregador tem alguns exemplos de classes na raiz do projeto está no arquivo Teste.java, ele mostra o exemplo usando carregadores.

[code]
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.Serializable;
import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import javaDB.Anotations.FieldDB;
import javaDB.Anotations.TableDB;
import javaDB.Ultil.Carregador.BufferedImageCarregador;
import javaDB.Ultil.Carregador.SerializableCarregador;
import javaDB.model.Model;
import javax.imageio.ImageIO;

/**

  • Copyright © 2010-2013 Victor Lacerda.

  • Permission is hereby granted, free of charge, to any person obtaining a copy

  • of this software and associated documentation files (the “Software”), to deal

  • in the Software without restriction, including without limitation the rights

  • to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

  • copies of the Software, and to permit persons to whom the Software is

  • furnished to do so, subject to the following conditions:

  • The above copyright notice and this permission notice shall be included in

  • all copies or substantial portions of the Software.

  • THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

  • IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

  • FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

  • AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

  • LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

  • OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

  • THE SOFTWARE.

  • @author Victor Lacerda victorgerin@live.com
    */
    public class Teste {

    public static void main(String[] args) throws SQLException, IOException {
    Connection conn = DriverManager.getConnection(“jdbc:mysql://localhost/Banco”, “User”, “Senha”);

     //Teste BufferedImagem
     //Adiciona um carregador para tratar os arquivos que forem BufferedImagem
     Model.addCarregador(new BufferedImageCarregador("jpg"), BufferedImage.class);
     //Gera uma nova instancia da classe passando uma connection como parametro
     ClasseModelImagem instanciaDoModelo1 = new ClasseModelImagem(conn);
     //Gera uma BufferedImagem como qualquer outra
     instanciaDoModelo1.setImagem();
     //Salva a model no banco de dados se o ID não for zero então irá fazer um inser no DB
     instanciaDoModelo1.salvar();
     
     //Remove o carregador adicionado
     Model.getCarregador(BufferedImage.class);
     
     //Teste Serializable
     //Adicona um carregador para tratar as classes ClasseModelSerializable.ClasseSerializable
     Model.addCarregador(new SerializableCarregador(), ClasseModelSerializable.ClasseSerializable.class);
     //Gera uma nova instancia da classe passando uma connection como parametro
     ClasseModelSerializable instanciaDoModelo2 = new ClasseModelSerializable(conn);
     //Cria uma instancia da classe "ClasseSerializable" normalmente
     instanciaDoModelo2.setClass();
     //Salva a model no banco de dados se o ID não for zero então irá fazer um inser no DB
     instanciaDoModelo2.salvar();
    

    }
    }

@TableDB(nome = “Tabela”)
class ClasseModelImagem extends Model {

private Connection conn;
@FieldDB(isId = true)
private long id;
@FieldDB
private BufferedImage imagem;

public ClasseModelImagem(Connection conn) {
    this.conn = conn;
}

public void setImagem() throws IOException {
    imagem = ImageIO.read(new URL("http://rack.0.mshcdn.com/media/ZgkyMDEyLzEyLzA0L2I1L3doZXJlZG9nb29nLmJoTi5qcGcKcAl0aHVtYgk5NTB4NTM0IwplCWpwZw/4931e287/304/where-do-google-doodles-come-from--ff2932470c.jpg"));

}

public BufferedImage getImagem() {
    return imagem;
}

@Override
public Connection getConnection() throws SQLException {
    return conn;
}

}

@TableDB(nome = “Tabela”)
class ClasseModelSerializable extends Model {

private Connection conn;
@FieldDB(isId = true)
private long id;
@FieldDB
private ClasseSerializable CLASS;

public ClasseModelSerializable(Connection conn) {
    this.conn = conn;
}

public void setClass() {
    CLASS = new ClasseSerializable();
    CLASS.INTERGER = 20;
    CLASS.STRING = "String teste Serializable";
}

public ClasseSerializable getClase() {
    return CLASS;
}

@Override
public Connection getConnection() throws SQLException {
    return conn;
}

public class ClasseSerializable implements Serializable {
    int INTERGER;
    String STRING;
}

}[/code]

Achei legal o fato de você se dedicar a fazer isso, sendo que muitas pessoas não fariam.

Vamos à alguns pontos:
1 - Eu precisaria extender a classe Model… Isso não é muito legal, você força as pessoas a extenderem uma classe.
2 - A gente precisa implementar um método chamado “getConnection” que é a connection do banco de dados que precisou ser passada via construtor (ou setter, tanto faz). Percebe que o nosso modelo está fazendo uma coisa que não deveria?
3 - Os atributos têm que ser públicos? Isso fere o encapsulamento, se necessário… Com reflection vc consegue ler os atributos privados, é só usar o getDeclaredFields().
4 - Nós precisamos trabalhar com as connections em si. Isso também é um pouco chato, por exemplo: se eu quiser ter 2 formas de salvar uma entidade, uma em DB e outra em XML, eu preciso separar isso em duas formas completamente malucas e lembrar disso. Por isso, o legal é que quem estiver usando o seu framework não saiba nada sobre como ele faz aquilo… Assim você tem um encapsulamento decente…

Eu ainda indico você a ver como o Hibernate trabalha. Se quiser, ainda, olhe como o CoreData do iOS trabalha (esse é muito legal) e ai veja como o seu framework pode ser melhor e mais completo…

Boa sorte.

Blz xD Obrigado pela resposta.

1 - Mas só um detalhe, os campos podem ser privados sim, só fiz assim para mostra que não precisa dos métodos, só da existência deles, é auto suficiente.
2 - tenho que admitir que a conexão não foi a melhor coisa que eu fiz (alias eu não sabia direito o que fazer com ela), mas o que você acha devo criar um XML para conter as informação para a conexão?
3 - Infelizmente eu ainda não prevejo outros tipos de conexão alem do MySql, mas trabalhar com XML ? como DB ?
4 - Bem, não sei, posso está errado mas na minha visão faz sentido estender a Model, visto que tudo nela será usado pelas filhas que basicamente fica sendo Salvar, Deletar e Popular/Pesquisar, alem disso se não estender qual seria outra opção ? criar como sendo uma classe estática que os métodos Salvar, Deletar e Popular/Pesquisar recebam um objeto para ser populado ?

Detalhe, muito obrigado pela sua resposta, basicamente coloquei minha experiencia e estudos em cima dessa classe, sei que tem que amadurecer bastante e exatamente por isso que ela está aqui agora xD

vou dar uma pesquisada melhor no Hibernate para ver como funcina, mas obrigado pelas dicas

eu estava vendo sobre o Hibernate, achei algumas coisas legal, mas n gostei muito, como ele trabalhar com os Beans (e também percebi que eu n trabalho bem também, visto pelo fato que eu estendo a minha classe)

desconsiderando o bean no meu caso, não preciso criar uma factory, ou iniciar uma session (q talvez seja uma boa forma para optimizar múltiplas query), a minha ideia inicial é manter uma simplicidade para trabalhar o que pessoalmente não encontrei nos vídeos e leituras que acabei de fazer (ou talvez eu esperasse mais), mas en essência vale a pena criar um arquivo de configuração em XML, para tratar essa, parte

Vamos lá! hehehe…

Legal!

Não… Fuja de XML… As configurações do Hibernate eram antes feitas em XML e ai começou a ficar mto difícil arrumar essas configurações. Gerou um movimento chamado XML Hell… Por isso os frameworks webs estão tendendo a não ter mais xml de configurações… O nome é Convention Over Configuration (CoC). Ou seja, defina padrões e siga esses padrões, se a pessoa quiser algo diferente, ela configura…

Sim, eu posso querer salvar meus dados de qualquer forma, .txt, .csv, .xml…

É exatamente esse o problema, vamos supor a entidade Estado (UF)… Elas são fixas, eu não quero salvar novas, não quero deletar, só quero pesquisar… Quando extendemos uma classe, pegamos TODOS os comportamentos (métodos) dela, e pode ser que não queremos todos eles. Existe um Design Pattern chamado Composite. Ele diz que é melhor você compor a sua classe com outra classe a extender… Mas ainda assim, composite não seria uma boa saída, pois todos os modelos precisariam ter um atributo da class Model… O que também não é bom.

[quote=Victor Gerin]Detalhe, muito obrigado pela sua resposta, basicamente coloquei minha experiencia e estudos em cima dessa classe, sei que tem que amadurecer bastante e exatamente por isso que ela está aqui agora xD

vou dar uma pesquisada melhor no Hibernate para ver como funcina, mas obrigado pelas dicas

eu estava vendo sobre o Hibernate, achei algumas coisas legal, mas n gostei muito, como ele trabalhar com os Beans (e também percebi que eu n trabalho bem também, visto pelo fato que eu estendo a minha classe)

desconsiderando o bean no meu caso, não preciso criar uma factory, ou iniciar uma session (q talvez seja uma boa forma para optimizar múltiplas query), a minha ideia inicial é manter uma simplicidade para trabalhar o que pessoalmente não encontrei nos vídeos e leituras que acabei de fazer (ou talvez eu esperasse mais), mas en essência vale a pena criar um arquivo de configuração em XML, para tratar essa, parte[/quote]
Legal. Mas se você analisar, quando você faz Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/Banco", "User", "Senha"); você tem uma factory de Connection… Ou seja, lembra daquela historinha de que se vc não quer repetir o código em vários lugares, você cria uma classe e coloca isso lá e ela vai te entregar uma connection já configurada?
Pois bem, é exatamente esse o papel do SessionFactory…

O session do Hibernate é o connection encapsulado e melhorado, ou seja, eu não preciso criar prepared statements, não preciso me preocupar em escrever SQL.
A forma como ele trabalha com a session é a mesma como trabalhamos com a Connection.

Abrimos a session (pela factory) = Pegamos a connection (da factory)
Abrimos uma transaction = Abrimos uma transaction
Rodamos o SQL (encapsulado pelo hibernate) = Rodamos o SQL
Commitamos ou damos rollback = commitamos ou damos rollback
fechamos a session = fechamos a connection.

O hibernate ainda tem um trabalho bem legal de integração com os Pools de Connections, ou seja, ele consegue criar connections ANTES de você precisar e te entrega quando você precisa…

E, mais uma vez, fuja de XML…

Blz, a solução que tomei para com a conexão foi criar uma classe config esta terá as configurações para gerar a Connection, nela implementei dois métodos para salvar em um arquivo e carregar de um arquivo; não usei XML, usei no caso JSON, mas o detalhe é que esse arquivo não é obrigatório, na verdade ele só é para guardar se quiser, a ideia principal é usar a instancia da classe Configs. Detalhe importante é ja que estou usando JSON fica nessesário uma depedencia Json-Simple mas ela só será necessário se você quiser gravar e carregar o arquivo de Configs

Alem disse fiz as mudanças para criar uma especie de Session que nem o Hibernate, ela agora conterá os métodos Salvar, Deletar e Popular/Pesquisar, mas diferente do hibernate ao usar esses métodos, a operação ocorre na hora da execução, ou seja eu não crio uma fila antes de salvar.

Feito isso agora os modelos não precisarão estender a Model basta usa-los com a session

OBS : ainda é nessesário as anotações
OBS²: Download foi atualizado se quiser baixar para ver como ficou
OBS³: Como a classe Model basicamente virou Session ela pode receber os Carregadores também mas não de forma estatica

[quote=Rafael Guerreiro]

Sim, eu posso querer salvar meus dados de qualquer forma, .txt, .csv, .xml…[/quote]

Bem não sou nenhum DBA como eu faria esse tipo de coisa ? já existe bibliotecas para isso (isso = trabalhar com arquivos normais .txt, .xsv, .xml) que trabalham com SQL ? poderia me passar algumas delas para eu testa ?

obrigado xD

public class NovoTeste {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        
        //Esse Configs fica assim( "jdbc:mysql://127.0.0.1:3306/DataBase?user=root&password=SenhaHue" )
        Configs conf = new Configs("DataBase", "root", "SenhaHue");
        Session sec = new Session(conf);
        
        imagem imagem = new imagem();
        imagem.setId(1);
        sec.pesquisa(imagem);
        
        System.out.println(Session.toString(imagem));
    }
}
@TableDB(nome = "teste")
class imagem  {

    @FieldDB(isId = true)
    private long id;
    @FieldDB
    private String nome;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getNome() {
        return nome;
    }

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