Java

Recuperando cursor de uma procedure do Oracle no Java

Percebi que muitas pessoas acabam chegando aqui pesquisando uma forma de recuperar cursores através de procedures do Oracle, para estas pessoas eu coloco à disposição uma maneira de fazê-lo.

Para que o cursor possa ser retornado é preciso declara-lo como REF CURSOR no spec da Package.

  --Criando o tipo REF CURSOR que será o cursor
  type g_cursor is ref cursor;

Em ambos, spec e body, você precisa declarar uma variável out do tipo do REF CURSOR mencionado acima.

  procedure PRO_RETORNA_LISTA_CARROS(
    i_id     in     tbl_car.car_id%type,
    o_cursor in out g_cursor);

Para devolver o cursor com os resultados (caso haja), é necessário abri-lo no body da procedure, desta forma:

open o_cursor for
          select car_id, company, model, color, hp, price
          from tbl_car
          where car_id = i_id;

A Package completa ficará assim:

create or replace package PAC_CURSOR is
  --Criando o tipo REF CURSOR que será o cursor
  type g_cursor is ref cursor;

  --Procedure que retornará o cursor
  procedure PRO_RETORNA_LISTA_CARROS(
    i_id     in     tbl_car.car_id%type,
    o_cursor in out g_cursor); -- Nosso cursor

end PAC_CURSOR;
/

create or replace package body PAC_CURSOR is
  procedure PRO_RETORNA_LISTA_CARROS(
    i_id     in     tbl_car.car_id%type,
    o_cursor in out g_cursor) is

       begin
        --Abrindo o cursor para retornar os valores
        open o_cursor for
          select car_id, company, model, color, hp, price
          from tbl_car
          where car_id = i_id;

  end PRO_RETORNA_LISTA_CARROS;

end PAC_CURSOR;

Temos o lado do Oracle pronto, agora precisamos tratar a chamada no Java.

Como o cursor está sendo retornado por uma procedure, usaremos um java.sql.CallableStatement.

CallableStatement cs = conn.prepareCall("{call PAC_CURSOR.PRO_RETORNA_LISTA_CARROS(?,?)}");

O registerOutParameter receberá o tipo oracle.jdbc.OracleTypes.CURSOR e retornará um java.sql.ResultSet. Iteraremos o ResultSet do mesmo modo que iteramos um Iterator.
Cada coluna retornada pelo SELECT será representado como um mapa, usando o getter correpondente. Por exemplo, chamaremos o método getString(<nome coluna>) quando retornar um varchar, getDate(<nome coluna>) quando retornar um date e etc.

O código completo fica assim:

//Chamando o procedure
CallableStatement cs = conn.prepareCall("{call PAC_CURSOR.PRO_RETORNA_LISTA_CARROS(?,?)}");

//Definindo o tipo do retorno, no caso o cursor
cs.registerOutParameter("o_cursor", OracleTypes.CURSOR);
cs.setLong("i_id", id);

cs.execute();//Executando a chamada

//Recuperando o cursor como um Resultset
ResultSet rs = (ResultSet)cs.getObject("o_cursor");

//Iterando as linhas retornadas
while(rs.next()){
	//Obtendo o valor das colunas
	System.out.println("ID: " + rs.getLong("car_id"));
	System.out.println("Marca: " + rs.getString("company"));
	System.out.println("Modelo: " + rs.getString("model"));
	System.out.println("Cor: " + rs.getString("color"));
	System.out.println("HP: " + rs.getString("hp"));
	System.out.println("Preco: " + rs.getFloat("price"));
}

No final você conseguirá obter qualquer valor retornado em um SELECT.

Até a próxima!


Gerando ‘EXE’ para iniciar suas aplicações Java

Percebi que muitos desenvolvedores precisam, ou já precisaram, distribuir suas aplicações Java de forma que os usuários de Windows pudessem iniciá-las naturalmente, sem a necessidade de chamar o comando java -jar <arquivo jar> ou executar um arquivo .BAT.

Eu, que também já passei por isso, encontrei um solução fácil e com muitos recursos: JSmooth.

Este programinha possibilita que você “transforme” seu JAR em um executável (EXE), mas claro, ainda sim você precisará ter o JVM instalado no micro que rodará o executável.

Aqui só destacarei as configurações que considero relevantes, então vamos ao que interessa!


Baixe o JSmooth em http://sourceforge.net/projects/jsmooth/files/;

Após instalá-lo (ou descompactá-lo, depende do arquivo que você baixou) execute-o;

No menu lateral, clique em “Skeleton“;

1

No “Skeleton Selection” você informa como a aplicação será executada, aqui selecionaremos Window Wrapper.

No “Skeleton Properties” você define uma mensagem caso o usuário não tenha o JVM instalador (Message) e onde ele poderá baixá-lo (URL).

Launch java app in the exe process” indica se o JAR será executado no mesmo processo do EXE, aparecendo somente o executável no Gerenciador de Tarefas do Windows, caso contrário também será o processo javaw.exe.

Single Instance” define se você ser aberto mais de uma instância.

Debug Console” executa o EXE em uma janela do prompt de comando, exibindo os possíveis Stacktraces gerados pela aplicação.

Agora clique em “Executable

2

Em “Executable Settings” você informa onde o EXE será gerado (“Executable Binary“), o ícone do EXE (“Executable Icon“) e qual será o diretório de execução da aplicação.

Clique em “Application

3

Primeiro, clique no ícone 7 e selecione o JAR que contém a classe principal (que contém o método main).

Em seguida, selecione a classe no campo “Main Class” clicando no botão 8.

O campo “Application arguments” você passa os parâmetros necessário para a sua classe.

Embedded JAR” possibilita que você integre seu JAR no EXE, ou seja, não será necessário ter os dois arquivos, pois o EXE descompactará o JAR a cada execução.

Agora, clique em “JVM Selection“.

4

Aqui você pode definir qual versão, mínima (“Minimum JVM Version“) e máxima (“Maximum JVM Version“), da virtual machine  rodará sua aplicação.

O”JVM Search Sequence” indica a ordem de busca do arquivo javaw.exe, neste caso ele procurará primeiro no registro, depois no diretório informado na variável de ambiente “JAVA_HOME” e assim por diante.

E então clique em “JVM Configuration

5

Aqui você informa a quantidade máxima de memória que sua aplicação poderá usar (“Maximum Memory“), quanta memória será alocada para sua aplicação assim que ela iniciar (“Initial Memory Allocation“) e os argumentos que será passado à JVM para sua aplicação.

Até este ponto você somente configurou o JSmooth, mas ainda não temos o EXE. Para isso, clique no botão 6, caso você ainda não tenha salvo o projeto será aberta uma janela para escolher o local de salvamento do arquivo. Feito isso, o EXE será gerado no diretório indicado no campo “Executable Binary” da tela “Executable“.

Agora é só dar um duplo clique no arquivo EXE e aplicação iniciará!

Para mais informações acessem http://jsmooth.sourceforge.net/

Espero que tenham gostado, comentem à vontade!

Até mais! :)


Recuperando coleção de objetos de uma procedure Oracle

Como prometido há muito tempo atrás (e bota tempo nisso) no tópico “Passando Objetos Java para uma Procedure do Oracle“, mostrarei como recuperar objetos Java contendo uma coleção de outro objetos através de uma procedure do Oracle. Para quem não leu, é altamente recomendado ler o post anterior.

Para este tutorial, precisamos incluir a tabela TBL_CLASS e adicionar sua primary key como foreign key na TBL_USER.

--num class será a PK e o desc_class será a descrição
create table TBL_CLASS (num_class number, desc_class varchar(100));
alter table TBL_CLASS add primary key(num_class);

alter table TBL_USER add num_class number;
alter table TBL_USER add constraint FK_CLASS foreign key(num_class) references tbl_class(num_class);

Agora precisamos incluir os novos tipos:

create or replace type class_type as object (num_class number, desc_class varchar2(100), users arr_users);
/
create or replace type arr_class as table of class_type;
/

O tipo class_type será o objeto. Repare que na sua assinatura incluímos o tipo arr_users, que será nossa coleção de user_type (vide post anterior), o tipo arr_class será uma coleção de class_type.

Agora incluiremos a procedure responsável por retornar nossa coleção de class_type.

procedure pro_select_class(clas in class_type, class_return in out arr_class)is
  class_ref_cur ref_cur;
  --Coleção de classes
  classes arr_class := arr_class();

  begin
    open class_ref_cur for
      select cast(
                multiset(
                  select num_class,
                         desc_class,
                         (select cast(
                                  multiset(
                                    select user_name,
                                           height,
                                           b_date
                                    from tbl_user
                                    --Fazendo o JOIN com a TBL_USER
                                    where tbl_user.num_class = tbl_class.num_class
                                  ) as arr_users)
                          from dual) users
                  from tbl_class
                  --Usando o atributo num_class do parâmetro de entrada
                  where num_class = clas.num_class) as arr_class
      ) classes
    from dual;

    --incluindo ao retorno no array
    fetch class_ref_cur into classes;
    --passando o array para a variável out
    class_return := classes;
end pro_select_class;

Repare que a procedure recebe o tipo class_type como parâmetro in e retorna o tipo arr_class.

Separando trecho responsável por resgatar e montar nossos objetos teremos:

--Montará a coleção de retorno
select cast(
        multiset(

          --Retornará os objetos class_type e seus atributos
          select num_class,
                 desc_class,

                 --Populará a coleção com user_type
                 (select cast(
                          multiset(
                            select user_name,
                                   height,
                                   b_date
                            from tbl_user
                            where tbl_user.num_class = tbl_class.num_class
                          ) as arr_users)

                  from dual) users

          from tbl_class
          where num_class = clas.num_class) as arr_class
) classes
from dual;

Os objetos de banco estão prontos, agora para o Java!

Criaremos o objeto que será interpretado pelo Oracle. Vamos chamá-lo de TypeClass:

public class TypeClass implements SQLData{
	public static final String ORACLE_OBJECT_NAME = "CLASS_TYPE"; //Nome do tipo no Oracle
	public static final String ORACLE_CLASS_ARRAY_NAME = "ARR_CLASS"; //Nome do array no Oracle

        //campos criados na tabela TBL_CLASS
	private Long number;
	private String desc;
	private Array users; //Esta será a coleção de user_type (ou TypeUser no Java)

	public String getSQLTypeName() throws SQLException {
		return ORACLE_OBJECT_NAME;
	}

	public void readSQL(SQLInput stream, String typeName) throws SQLException {
		setNumber(stream.readLong());
		setDesc(stream.readString());
		setUsers(stream.readArray());//Usado pelo JDBC driver para ler a coleção
	}

	public void writeSQL(SQLOutput stream) throws SQLException {
		stream.writeLong(getNumber());
		stream.writeString(getDesc());
		stream.writeArray(getUsers());//Usado pelo JDBC driver para armazenar a coleção
	}
	//Getters e setters omitidos
}

Precisamos mapear os dois tipos já que ambos serão interpretados na requisição, desta forma:

Map> typeMaps = connection.getTypeMap();
typeMaps.put(TypeUser.ORACLE_OBJECT_NAME, TypeUser.class);
typeMaps.put(TypeClass.ORACLE_OBJECT_NAME, TypeClass.class);

Também precisaremos mapear os dois arrays:

typeMaps.put(TypeClass.ORACLE_CLASS_ARRAY_NAME, TypeClass[].class);//retornado pela procedure
typeMaps.put(TypeUser.ORACLE_USER_ARRAY_NAME, TypeUser[].class);//retornado pela coleção de class_type

Para a requisição faremos:

cs = conn.prepareCall("{call PAC_BEAN.PRO_SELECT_CLASS(?,?)}");
//registrando o tipo de saída, que será um array de TypeClass
cs.registerOutParameter("class_return", OracleTypes.ARRAY, TypeClass.ORACLE_CLASS_ARRAY_NAME);

//passando o objeto de parâmetros da query
cs.setObject("clas", classQry);

cs.execute();
//recuperando e iterando o array de TypeClass
Object[] array = (Object[])cs.getArray("class_return").getArray();

for(Object obj : array){
	TypeClass objClass = ((TypeClass)obj);

	System.out.println("Description: "+objClass.getDesc());

        //Aqui pegamos a coleção (ou array) de user_type(TypeUser) retornada pela query.
	Object[] userArray = (Object[])objClass.getUsers().getArray();
	for(Object user : userArray){
		System.out.println("\tName: " + ((TypeUser)user).getName());
		System.out.println("\tHeight: " + ((TypeUser)user).getHeight());
		System.out.println("\tBirth: " + sdf.format(((TypeUser)user).getBirth())+ "\r\n");
	}
}

O final você terá um TypeClass que contém um java.sql.Array de TypeUser no atributo getUsers().

E aqui cumpro minha promessa. Baixe o código fonte com o exemplo contendo este e o post anterior aqui.

Até a próxima!


Tirando Screen Shots com Java

Aqui mostrarei como fazer uma classe para tirar Screen shots .

Estava pensando com quão complexo seria fazer uma classe que tirasse screen shots do compulador local e o armazenasse em um arquivo. Perguntando ao tio “G” descobri a classe Robot, que possui o método createScreenCapture.

Agora mostrarei como implementar esta funcionalidade:

Robot robot = new Robot();
//Definindo o retângulo que será a área de captura da tela que, neste caso, será a tela inteira.
Rectangle rect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());

BufferedImage img = robot.createScreenCapture(rect);

Aqui definimos a área de captura e obtivemos um BufferedImage, que já é nossa imagem. Agora é só persisti-la no disco.

//Capturando o ImageWriter e ImageWriterParam
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
ImageWriteParam iwp = writer.getDefaultWriteParam();

//Definindo o modo de compressão e a qualidade
iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(1);

//Persistindo a imagem
writer.setOutput(new FileImageOutputStream(arquivo));

IIOImage iioimage = new IIOImage(img, null, null);

writer.write(null, iioimage, iwp);
writer.dispose();

Aqui capturamos o ImageWriter e ImageWriterParam para configurar o método de compressão e a qualidade da imagem.

Na linha 07 definimos a qualidade como 1, onde o valor varia de 0 (zero), maior compressão e menor qualidade, até 1 (um), menor compressão e maior qualidade. Em seguida persistimos o arquivo no HD.

Pronto! Simples, não?!.

Faça o download do exemplo aqui.

Até a próxima!

Neste caso será a tela inteira.

Limitando número máximo de caracteres em um JTextField

A implementação padrão do JTextField não permite definir um limite para inserção de caracteres. Para habilitar este recurso é necessário implementar um Document, onde será necessário sobrescrever o método insertString.

public class MaxLengthTextDocument extends PlainDocument {
	//Armazena o número máximo de caracteres para o texto.
	private int maxChars;

	@Override
	public void insertString(int offs, String str, AttributeSet a)
			throws BadLocationException {
		if(str != null && (getLength() + str.length() < maxChars)){
            		super.insertString(offs, str, a);
        	}
	}

	//getter e setter omitidos
}

Aqui definimos a classe MaxLengthTextDocument estendendo a PlainDocument. No atributo insertString inserimos uma regra onde só será inserido valor se comprimento não ultrapassar o valor máximo.

Depois é só inserir a implementação no JTextField, desta forma:

	...
	MaxLengthTextDocument maxLength = new MaxLengthTextDocument();
	maxLength.setMaxChars(50);//Limitamos para 50 caracteres

	jTextField.setDocument(maxLength);
	...

E voilá!

Até mais!


  • AdSense

  • Copyright © 1996-2010 André L. S.. All rights reserved.
    iDream theme by Templates Next | Powered by WordPress