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

quarta-feira, 7 de dezembro de 2016

Hello World em JSF2 no Eclipse passo a passo

Usou-se eclipse neon.1 e tomcat 8 para a criação deste hello world.

1) Crie um Dynamic web project (File -> New -> Dynamic web project).

O nome do projeto será JSF2HelloWorld. Já selecione o "Apache Tomcat v8.0" em Target runtime. Vá dando next até não poder mais. Na última tela marque a checkbox "Generate web.xml deployment descriptor". Clique em finish e o projeto estará criado.

Outra forma de adiconar o tomcat seria clicando com o botão direito em cima do projeto, indo em "Properties" > "Java Build Path" > "Add Library" > Selecionar "Server Runtime" e dar next e, então selecionaria o Tomcat. Mas para que ele possa aparecer em "Server Runtime" é necessário que ele tenha antes sido baixado da internet, seja descompactado (não precisa instalá-lo) e que seja indicado o seu caminho na aba "Servers" do Eclipse Java EE.

2) Baixando e configurando o JSF2.

Clique com o botão direito do mouse sobre o projeto criado. Vá em "Properties" e depois em "Project facets". Marque o checkbox "JavaServer Faces". Irá aparece abaixo "Further configuration required...". Clique nele. Ao abrir a tela "Modify Faceted Project" clique no botão Download library que tem o desenho de um disquete. Faça o download da JSF Mojarra, que é o criado pela Oracle e que serve de referência para as demais. Feito o download, coloque no URL Mapping Patterns: *.jsf e clique em OK.

Perceba agora que em seu projeto foi criado um arquivo chamado "faces-config.xml" e o seu "web.xml" foi criado com o seguinte código:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>JSF2HelloWorld</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
  </servlet-mapping>
  <context-param>
    <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
  </context-param>
  <context-param>
    <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
    <param-value>resources.application</param-value>
  </context-param>
  <listener>
    <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
  </listener>
</web-app>


3) Criando um arquivo xhtml

O JSF2 é utilizado junto com xhtml. Por isso, vamos criar um "helloWorld.xhtml". Clique com o botão direito sobre "WebContent" > "New" > "HTML File". Ponha o nome do arquivo de "helloWorld.xhtml", dê um "next" e escolha um template "New XHTML File (1.0 strict)" e clique em finish. Cole no seu xhtml o código abaixo:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:c="http://java.sun.com/jsf/core"
      xmlns:ui = "http://java.sun.com/jsf/facelets"
      xmlns:h = "http://java.sun.com/jsf/html">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Insert title here</title>
</head>
<h:body>

    <h:outputLabel value="Hello World"></h:outputLabel>   

</h:body>
</html>


Para que esse seu "helloWorld.xhtml" seja a primeira página a aparecer ao executar o projeto é necessário fazer uma pequena modificação no seu arquivo web.xml. Basta modificar o conteúdo da sua tag welcome-file, como no código abaixo:

  <display-name>JSF2HelloWorld</display-name>
  <welcome-file-list>
    <welcome-file>helloWorld.xhtml</welcome-file>
  </welcome-file-list>


Rode a sua aplicação pelo servidor e então veja o seu resultado pelo link:
http://localhost:8080/JSF2HelloWorld/faces/helloWorld.xhtml

Se você tiver posto URL Mapping Patterns: *.jsf na hora de configurar o jsf, então o link será:
http://localhost:8080/JSF2HelloWorld/index.jsf

O hello world de JSF2 está feito. Mas, caso queira produzir algo mais elaborado é preciso ter em mente os seguinte pontos:

1) Criando as Beans

As classes do java que irão de comunicar com as páginas jsf (xhtml) deverão estar no padrão Java Bean, ou seja:

- Variáveis de instância devem ser private e só podem ser acessadas por getters e setters.
- Exemplo: se a classe tiver um variável "String nome", deve ser criado um getNome() e setNome(). Se for um boolean, deve ser usado "is" em vez de "get", como em "isLigada()" para um variável "boolean ligada", por exemplo. Seguir esse padrão Java Bean para o uso do JSF é imprescindível!
- Deve ser criado um construtor sem parâmetros.
- A classe deve implementar java.io.Serializable.

Beans gerenciados (Managed beans) são beans que pode ser acessados a partir de uma página JSF. Devem ter um nome e um escopo. Existem alguns escopos, como "@ApplicationSocoped", "@SessionScoped", "@RequestScoped", entre outros. O escopo determina o tempo de existência da instância do objeto, se a instância irá existir durante toda a aplicação, ou apenas durante a sessão ou apenas o tempo de duração de uma requisição.

2) Mapeando a classe Bean

Após criada, a classe Bean ainda não pode ser acessada, mesmo que tenha seguido todos os padrões de nomenclatura. Para isso é necessário mapeá-la. O mapeamento pode ser feito pelo arquivo "faces-config.xml" ou via anotações (annotations).

Uma opção de anotação é a @Named que pertence ao pacote javax.inject.Named. Veja o exemplo abaixo:

@Named("usuario")
public class UsuarioBean implements Serializable { ... }


Outra opção é a anotação @ManagedBean do pacote javax.faces.bean. Se nenhum parâmetro for informado, o nome utilizado será o mesmo da classe, porém com a 1ª letra minúscula. Também podemos utilizar o parâmetro name para especificar um nome qualquer, como no exemplo abaixo:

@ManagedBean(name="usuario")
public class UsuarioBean implements Serializable { ... }


Veja abaixo um exemplo:

@ManagedBean
@ViewScoped
public class UsuarioBean implements Serializable {
    private int idade;
   
    public UsuarioBean() { }
   
    public int getIdade() { return this.idade; }
    public void setIdade(int idade) { this.idade = idade; }
    public void incrementaIdade() { this.idade = this.idade + 1; }
}


<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h = "http://java.sun.com/jsf/html">
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Exemplo JSF</title>
</h:head>
<h:body>
    Idade: #{usuarioBean.idade}
    <h:form>
        <h:inputText value="#{usuarioBean.idade}" />
        <h:commandButton value="Altera" />
        <h:commandButton value="Incrementa" action="#{usuarioBean.incrementaIdade}" />   
    </h:form>
</h:body>
</html>


A expression language #{usuarioBean.idade} serve tanto para pegar o valor da idade, como para mudar. Portanto, é usado tanto como um set e um get dependendo da ação que é feita. Se for só mostrar, funciona como um get, se for para enviar um valor por meio de uma submissão de uma requisição, então funciona como um set.

A expression language #{usuarioBean.incrementaIdade} serve para utilizar o método incrementaIdade que existe no objeto.

That's all.

quinta-feira, 17 de novembro de 2016

Uso de Singleton e Application customizado

Suponha que você tenha criado uma classe Livro, com o título, descrição, nome do autor e etc. Após isso tenha criado uma classe LivroControl que possuirá um ArrayList de Livros e que conterá os métodos necessários para o controle dessa lista de livros. Acontece que você deseja que essa lista seja única e acessível para toda a aplicação. O que você faz?

Os dois caminhos mais comuns são:
1) Instanciar um objeto LivroControl no método onCreate da classe Application
2) Usar o padrão Singleton

Caso 1: Instanciando LivroControl no Application

Application existe em todo aplicativo Android. É criado na abertura do aplicativo e, também possui um ciclo de vida, que é diferente de uma Activity. Mas, como vou alterar o meu Application?

Para alterá-lo é preciso criar uma classe filha e depois, basta sobrescrever o método onCreate, como no exemplo abaixo:

public class CustomApplication extends Application{

    private LivroControl livroControl;

    @Override
    public void onCreate() {
        super.onCreate();
        livroControl = new LivroControl();
    }

    public LivroControl getLivroControl() {
        return livroControl;
    }
}


Para usar esse CustomApplication no lugar do Application é necessário alterar um atributo xml chamado 'name' que está dentro da tag <application> do AndroidManifest.xml. Segue um exemplo:

    <application
        android:name=".application.CustomApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".ui.activity.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>


Feito isso, é possível acessar a CustomApplication de qualquer lugar:

final CustomApplication customApplication = getCustomApplication();
List<Livro> listaLivros = customApplication.getLivroControl().retrieveLista();


Caso 2: Usando o padrão Singleton


No padrão Singleton, o construtor de LivroControl deverá ser privado. Portanto, não poderá ser instanciado por alguém fora da classe. Quem fará a única instanciação será um método chamado getInstance, que instanciará o LivroControl apenas uma única vez. O método getInstance deve ser estático e thread-safe. Segue o código de exemplo:

public final class LivroControl {
    private final List<Livro> listaLivro = new ArrayList<>();
    private static ItemControl INSTANCE;

    private ItemControl() { }

    public static synchronized ItemControl getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new ItemControl();
        }
        return INSTANCE;
    }
}


Também é possível fazer esse mesmo Singleton usando Enumerações. Basta jogar todos os métodos de LivroControl para dentro de uma Enum e os métodos do LivroControl apenas acessarão os métodos do Enum. Veja o exemplo baixo:

public final class LivroControl {
    public void adicionarLivro(Livro livro) {
        ListaLivros.INSTANCE.adicionarLivro(livro);       
    }

    public enum ListaLivros {
        INSTANCE;

        private static List<Livro> listaLivro;
        static {
            listaLivro = new ArrayList<>();
        }

        private ListaLivros() { }

        public void adicionarLivro(Livro livro) {
            listaLivro.add(livro);
        }
    }
}


Recomendo a leitura desta discussão caso queira se aprofundar no uso de Enumerações em Singletons:
What is an efficient way to implement a singleton pattern in Java?

sexta-feira, 7 de outubro de 2016

Aprendendo Collections Framework

Para entender como as principais estruturas de dados já implementadas na API Java funcionam, escrevi o seguinte código:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

public class Colecoes {
    //Método que remove strings duplicadas de uma Lista de Strings
    public static List<String> removeDuplicates(List<String> lista) {
        List<String> listaCopy = new ArrayList<String>();
        List<String> posicoesCopy = new ArrayList<String>();
       
        for(int i = 0; i < lista.size(); i++) {
            listaCopy.add(lista.get(i));
        }
       
        for(int i = 0; i < lista.size(); i++) {
            for(int j = 0; j < listaCopy.size(); j++) {
                if(lista.get(i).equals(listaCopy.get(j)) && j > i) posicoesCopy.add(String.valueOf(j));
            }
        }
       
        for(int i = 0; i < posicoesCopy.size(); i++) {
            lista.remove(Integer.parseInt(posicoesCopy.get(i)));
        }
       
        return lista;
    }

    public static void main(String[] args) {
        List<String> frutaArrayList = new ArrayList<String>();
        Set<String> frutaTreeSet = new TreeSet<String>();
        HashMap<String, String> frutaHashMap = new HashMap<String, String>();
        List<String> frutaLinkedList = new LinkedList<String>();
        Set<String> frutaHashSet = new HashSet<String>();
        LinkedHashMap<String, String> frutaLinkedHashMap = new LinkedHashMap<String, String>();
       
        String[] frutas = {"banana", "morango", "abacaxi", "damasco",
                "abacaxi", "banana", "abacate"
        };
       
        for(int i = 0; i < frutas.length; i++) {
            frutaArrayList.add(frutas[i]);
            frutaTreeSet.add(frutas[i]);
            frutaHashMap.put(String.valueOf(i), frutas[i]);
            frutaLinkedList.add(frutas[i]);
            frutaHashSet.add(frutas[i]);
            frutaLinkedHashMap.put(String.valueOf(i), frutas[i]);
        }
       
        System.out.println("ArrayList: "+frutaArrayList);
        System.out.println("TreeSet: "+frutaTreeSet);
        System.out.println("HashMap: "+frutaHashMap);
        System.out.println("LinkedList: "+frutaLinkedList);
        System.out.println("HashSet: "+frutaHashSet);
        System.out.println("LinkedHashMap: "+frutaLinkedHashMap);
       
        System.out.println("\nRemovendo duplicadas da ArrayList: ");
        System.out.println(removeDuplicates(frutaArrayList));
    }
}

Como resultado da execução do código acima, obtive a seguinte saída:

ArrayList: [banana, morango, abacaxi, damasco, abacaxi, banana, abacate]
TreeSet: [abacate, abacaxi, banana, damasco, morango]
HashMap: {0=banana, 1=morango, 2=abacaxi, 3=damasco, 4=abacaxi, 5=banana, 6=abacate}
LinkedList: [banana, morango, abacaxi, damasco, abacaxi, banana, abacate]
HashSet: [banana, morango, abacaxi, abacate, damasco]
LinkedHashMap: {0=banana, 1=morango, 2=abacaxi, 3=damasco, 4=abacaxi, 5=banana, 6=abacate}

Removendo duplicadas da ArrayList:
[banana, morango, abacaxi, damasco, abacate]

Com isso, pude aprender que as estruturas do tipo 'Set' eliminam as palavras duplicadas automaticamente, sendo que a TreeSet, além de fazer isso, já põe em ordem alfabética. Também aprendi que não se pode percorrer uma estrutura do tipo 'Set', pois ela não possui um método get(). A HashSet trocou de posição as palavras 'abacate' e 'damasco', o que demonstra que estruturas do tipo 'Set' não respeitam a ordem de adição, organizando os objetos de qualquer maneira ou em ordem alfabética, no caso da TreeSet.

É possível ainda melhorar o método "removeDuplicates", pois a lista está sendo percorrida várias vezes desnecessariamente. Assim, se essa lista fosse muito grande, isso causaria lentidão no processamento. Uma maneira de melhoria pode ser vista logo abaixo:

public static List<String> removeDuplicates(List<String> lista) {
        List<String> result = new ArrayList<String>();
        Set<String> itemsSet = new HashSet<>();
   
        for(int i = 0; i < lista.size(); i++) {
            String s = lista.get(i);
            if (!itemsSet.contains(s)) {
                itemsSet.add(s);
                result.add(s);
            }
        }
        return result;
}

O segredo está no uso de um 'Set', no caso, o HashSet itemsSet, pois, com ele, não é preciso percorrer a lista para encontrar o que se quer. Ele vai diretamente ao ponto por meio de uma tabela hash e verifica com o método contains se existe ou não determinado elemento. Isso evita aquele aninhamento desnecessário de loops. Além disso, impede-se que elementos duplicados sejam adicionados a nova lista (result), pois a adição só ocorre se não existir o item analisado dentro de itemsSet. 

quarta-feira, 28 de setembro de 2016

Fatorial e Fibonacci com Recursividade em Java

Para treinar recursividade em Java, fiz dois programinhas. O primeiro calcula o fatorial de um número digitado pelo usuário e o segundo imprime a sequência de Fibonacci do tamanho solicitado também pelo usuário. Seguem os códigos logo abaixo.

//Desenvolva um algoritmo que calcule o fatorial de um número n.
import java.util.Scanner;

public class FatorialRecursivo {
   
    //Método que calcula fatorial de forma recursiva
    static int Fatorial(int numero) {
        if(numero > 1)
            return (numero * Fatorial(numero - 1));
        else
            return numero;
    }

    //Testando o método Fatorial()
    public static void main(String[] args) {
        Scanner leitor = new Scanner(System.in);
        System.out.print("Digite um número inteiro cujo fatorial deseje calcular: ");
        int numero = leitor.nextInt();
        System.out.println(numero+"! = "+Fatorial(numero));
        leitor.close();
    }
}



/***************************************************
 * Desenvolva um algoritmo que calcule o n-ésimo termo de uma série de fibonacci.
 * Série de fibonacci: 1, 1, 2, 3, 5, 8, 13, 21, 34 . . .
 * OBS.: O n-ésimo termo é obtido a partir dos dois anteriores.
***************************************************/


import java.util.Scanner;

public class FibonacciRecursivo {
   
    //Método que imprime sequência de Fibonacci recursivamente   
    static int Fibonacci(int quantidade, int i, int j) {
        if(quantidade > 0) {
            System.out.print(j+" ");
            return Fibonacci(quantidade - 1, j, i+j);
        } else {
            return 1;
        }
    }

    public static void main(String[] args) {
        Scanner leitor = new Scanner(System.in);
        System.out.print("Quantidade de número na sequência de Fibonacci: ");
        Fibonacci(leitor.nextInt(), 0, 1);
        leitor.close();
    }
}