terça-feira, 20 de dezembro de 2016

Fragments: o que são e para que servem?

Fragments são como "pedaços" de activities que podem ser reutilizados. Os fragments não funcionam sozinhos, pois precisam de uma activity para funcionar. Você pode montar uma activity com vários fragments. Para criar um Fragment basta criar uma classe que herde de Fragment, como no exemplo a seguir:

public class MeuFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View layout = inflater.inflate(R.layout.fragment_layout, container, false);

        return layout;
    }
}


Repare que foi necessário sobrescrever o método onCreateView, cujo retorno será uma view que foi inflada de um layout criado em xml. Pronto. Criamos nosso primeiro fragment, mas como iremos utilizá-lo em uma activity? Primeiramente, é necessário posicionar um FrameLayout no layout xml da activity:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <FrameLayout
        android:id="@+id/localDoFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"><FrameLayout>

</LinearLayout>


Agora temos que fazer com que o Fragment apareça nesse FrameLayout que foi criado. Dentro do método onCreate da activity, use um FragmentTransaction:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_layout);

    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.replace(R.id.localDoFragment, new MeuFragment());
    ft.commit();
}


Pronto! Conseguimos posicionar um fragment em uma activity. Usando o mesmo procedimento, é possível posicionais e reutilizar fragments. Isso se torna útil, por exemplo, quando precisamos fazer um layout diferente para uso em tablets, reaproveitando as telas que foram criadas para um celular.

quinta-feira, 15 de dezembro de 2016

Material Palette: Cores Padronizadas da Google

Você tem dúvidas com relação a quais cores usar em seu aplicativo? É um programador e não um designer? Seus problemas acabaram! A Google fornece um padrão de cores a serem usadas em seu aplicativos. Basta escolher uma cor primária e uma secundária no site Material Palette, depois faça o download em formato XML. Cole-o dentro de seu 'res/values'. Depois use essas cores no style.xml. Assim as cores padrão de seu app serão as do novo arquivo XML baixado.

Veja também:
Para fazer com que o seu app siga o padrão das cores baixadas, o seu arquivo style.xml deverá ficar parecido com o exemplo a seguir:

     <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/primary</item>
        <item name="colorPrimaryDark">@color/primary_dark</item>
        <item name="colorAccent">@color/accent</item>
        <item name="android:textColorPrimary">@color/primary_text</item>
        <item name="android:textColorSecondary">@color/secondary_text</item>
        <item name="android:icon">@color/icons</item>
        <item name="android:colorButtonNormal">@color/primary_dark</item>
        <item name="android:divider">@color/divider</item>
    </style>


That's all! ;)

segunda-feira, 12 de dezembro de 2016

Criando um Menu Suspenso (Menu de Contexto) no Android

Um menu suspenso ou menu de contexto, no Android, pode ser criado para aparecer ao se clicar em uma view vinculada a ele. Por exemplo, suponha que você deseje que, ao se clicar em um item de uma ListView, surja um menu sobre ela com algumas opções, como deletar um item. A ListView continuará parcialmente visível, pois um menu de opções ficará sobre ela. Para que isso seja feito, basta sobrescrever o método onCreateContextMenu que está na activity. As opções do menu podem ser criadas programaticamente (sem ter que ser via xml) como no código a seguir:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    menu.add("Primeira Opção do Menu");
    menu.add("Segunda Opção do Menu");
    menu.add("Deletar Item");

    super.onCreateContextMenu(menu, v, menuInfo);
}


Agora vai uma pergunta: como o menu suspenso saberá o momento de surgir? Em outras palavras, como eu faço a ligação de uma view com o menu suspenso? Basta registrá-la no menu, usando o método registerForContextMenu que deverá ser colocado dentro do onCreate() da activity:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_meu_laytout);

    registerForContextMenu(MinhaView);
}


O menu de contexto será acionado sempre que houver um clique longo na view com a qual está vinculado. Por isso, caso você já tenha implementado nessa view o método setOnItemLongClickListener, será necessário fazer com que seu retorno se torne 'false', para que não consuma sozinho o evento. Se deixar como 'true', o menu suspenso não será acionado. Caso coloque como 'false', ambos eventos serão acionados. Nesse último caso, os dois métodos podem ser utilizados em conjunto, como, por exemplo, o método setOnItemLongClickListener pode ser usado para pegar um item de uma ListView, armazenando em uma variável de instância, enquanto o menu suspenso pode se utilizar de informações desse item para fazer alguma ação, como deletá-lo, pois o menu não seria capaz de enxergar qual item da ListView é que foi clicado.

O método add do menu retorna um MenuItem cuja referência pode ser armazenada em uma variável de mesmo tipo e, assim, podemos setar nele uma ação que ocorrerá após ser clicado ou mesmo ligá-lo a uma intent. No código abaixo, conecta-se o menu a uma intent, que é executada sem precisar usar o método startActivity. O exemplo a seguir mostra como isso é usado para enviar um sms:

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    MenuItem menuSMS = menu.add("Enviar SMS");
    Intent intentSMS = new Intent(Intent.ACTION_VIEW);
    intentSMS.setData(Uri.parse("sms:" + meuContato.getTelefone()));
    menuSMS.setIntent(intentSMS);

    super.onCreateContextMenu(menu, v, menuInfo);
}


No caso de um sms, não é necessário adicionar uma permissão no manifest, pois é outro aplicativo do celular que usuará o recurso de envio de sms.

Como já foi dito, posso adicionar um evento de clique no MenuItem, como se fosse um botão. No exemplo a seguir, faço isso com o objetivo de fazer uma ligação do celular.

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {

    MenuItem menuLigar = menu.add("Fazer chamada");
    menuLigar.setOnMenuItemClickListener(new MenuItem.setOnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
           

            if(ActivityCompat.checkSelfPermission(NomeActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {

                ActivityCompat.requestPermission(NomeActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 1);

            } else {
                Intent intentLigar = new Intent(Intent.ACTION_CALL);
                intentLigar.setData(Uri.parse("tel:" + meuContato.getTelefone()));

                startActivity(intentLigar);
            }

            return false;
        }
    });
   
    super.onCreateContextMenu(menu, v, menuInfo);
}


É necessário pedir para o dono do celular que ele permita o uso dessa funcionalidade do aparelho. Por isso, faz-se necessário adicionar no manifest a permissão:

<uses-permission android:name="android.permission.CALL_PHONE"/>

O código anterior apenas verifica se possui permissão para fazer uma ligação. Caso não possua, o aplicativo solicita uma permissão do usuário. Caso já tenha permissão, então executa uma intent implícita, que busca um recurso de chamada do celular.

sábado, 10 de dezembro de 2016

Usando SQLite e padrão DAO para persistir dados

Uma das formas de persistir os dados em um aplicativo nativo Android é por meio do SQLite. Ele é um mini-SGBD que vai acoplado junto a sua aplicação. Para usá-lo, você pode criar uma classe padrão DAO (Data Access Object), utilizada para manipulação de dados, que irá gerenciar os dados conjuntamente com o SQLite. Para exemplificar, vamos utilizar um model Usuario que possui um id do tipo long, um nome do tipo String e um e-mail do tipo String como variáveis de instância. Então, vamos criar um UsuarioDAO, que irá criar o banco de dados, uma tabela de usuários e cuidará da manipulação e recuperação de usuarios do banco da dados.

Para isso, crie uma classe UsuarioDAO e faça com que ela herde de SQLiteOpenHelper. Depois sobrescreva os métodos onCreate e onUpgrade. O método onCreate é executado sempre que a aplicação é instalada e utilizada pela primeira vez. O método onUpgrade é executado sempre que ocorre uma mudança de versão do banco de dados. Tendo em vista essa características, vamos criar a tabela de Usuarios no onCreate. O código abaixo servirá para exemplificar o que foi dito até aqui:

public class UsuarioDAO extends SQLiteOpenHelper {
    private static final String DATABASE = "appExemplo";
    private static final String TABELA = "Usuarios";
    private static final int VERSAO = 1;

    public UsuarioDAO(Context context) {
        super(context, DATABASE, null, VERSAO);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "CREATE TABLE " + TABLE + " ("
            + COL_ID + " INTEGER PRIMARY KEY, "
            + COL_NOME + " TEXT UNIQUE NOT NULL, "
            + COL_EMAIL + " TEXT"
            + ");";
       
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        String sql = "DROP TABLE IF EXISTS " + TABLE;

        db.execSQL(sql);
        onCreate(db);
    }
}


É preciso tomar muito cuidado com o uso da versão. Ela deve começar com o valor 1 e sempre que ocorrer qualquer mudança na estrutura do banco de dados, ela deve ser alterada sempre acrescentando um valor a mais. Ou seja, inicia-se com 1, caso seja acrescentado um atributo novo como telefone, ou um atributo do banco tenha tido seu nome alterado, então, a próxima versão deve ter o valor 2 e depois 3, 4 e assim por diante. Para o programador isso não fará muita diferença, mas, para o cliente que comprou o seu aplicativo fará muita diferença, pois uma mudança de versão da maneira incorreta poderá fazer com que o cliente perca todos os dados que ele já possuía. Portanto, cuidado!

Temos a nossa tabela de usuário e agora precisamos inserir e recuperar usuários do banco de dados. Para inserir, não podemos usar o método execSQL para executar o código SQL diretamente, pois isso é muito perigoso. Caso fique utilizando execução direta de SQL, pode ser que alguém se aproveite disso para fazer uma injeção de SQL (SQL Injection), causando danos a sua base da dados. Por isso, devemos inserir usuários por meio de um objeto ContentValues que funciona como um HashMap. Após colocar os dados de um usuário em um ContentValues, basta inseri-lo passando-o como parâmetro de um getWritableDatabase().insert(). Veja o exemplo a seguir:

    public void inserir(Usuario usuario) {
        ContentValues values = new ContentValues();

        values.put(COL_NOME, usuario.getNome());
        values.put(COL_EMAIL, usuario.getEmail());

        getWritableDatabase().insert(TABELA, null, values);
    }


Inserimos o usuário e agora temos que recuperá-lo. Temos que posicionar um cursor para o local em que gostaríamos de recuperar os dados, então você usa um SELECT para pegar os dados que você quer, depois use o método moveToNext() para movimentar o cursor que irá se posicionar na próxima linha da tabela. Então, é só fazer um loop que irá percorrer todas as linhas da tabela. Vá colocando todos os dados em uma lista e, então, retorne-a. Veja o exemplo a seguir:

    public List<Usuario> getLista() {
        List<Usuario> lista = new ArrayList<>();

        String sql = "SELECT * FROM " + TABELA + ";";
        Cursor c = getReadableDatabase().rawQuery(sql, null);

        Usuario usuario = null;

        while(c.moveToNext()) {
            usuario = new Usuario();

            usuario.setId(c.getString(c.getColumnIndex(COL_ID)));
            usuario.setNome(c.getString(c.getColumnIndex(COL_NOME)));
            usuario.setEmail(c.getString(c.getColumnIndex(COL_EMAIL)));

            lista.add(usuario);
        }

        return lista;
    }


Além de inserir um usuário, é preciso deletar algum quando necessário. Por isso, também precisamos criar um método deletar que receba um usuário como parâmetro e o exclua do banco por meio da checagem de seu id. Vamos utilizar o método getWritableDatabase().delete para evitarmos uma sql injection. Ele receberá como parâmetro um array de strings. Neste caso, iremos passar o id do usuário para informar qual usuário é que deve ser excluído. Um exemplo de código pode ser visto a seguir:

    public void deletar(Usuario usuario) {
        String[] argumentos = {usuario.getId().toString()};
        getWritableDatabase().delete(TABELA, COL_ID + "=?", argumentos);
    }


Já inserimos, recuperamos e excluímos usuários do banco. Agora precisamos alterar ou dar um update no conteúdo de um determinado usuário que se encontra no banco. Para isso, precisamos novamente receber um usuário como parâmetro de um método alterar, que conterá todas as novas informações a serem alteradas em um usuário já inserido. A seguir segue um exemplo de código:

    public void alterar(Usuario usuario) {
        ContentValues values = new ContentValues();
        values.put(COL_NOME, usuario.getNome());
        values.put(COL_EMAIL, usuario.getEmail());

        String[] argumentos = {usuario.getId().toString()};
        getWritableDatabase().update(TABELA, values, COL_ID + "=?", argumentos);
    }


Pronto, agora a nossa classe já está bem funcional e pode ser utilizada em uma activity:

UsuarioDAO dao = new UsuarioDAO(MinhaActivity.this);
List<Usuario> usuarios = dao.getLista();


Suponha agora que você tenha que alterar a estrutura de banco de dados, aumentando mais um campo, que neste exemplo será o endereço do usuário. Para isso, precisamos adicionar o novo campo no onCreate para aqueles que irão instalar o aplicativo pela primeira vez e precisamos apenas atualizar a nova estrutura do banco no celular daqueles que já possuem o aplicativo instalado. No segundo caso, é preciso modificar o método onUpgrade(). Além disso, é imprescindível trocar a versão, que atualmente está 1, para o valor 2. Então, o onCreate ficará assim:

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "CREATE TABLE " + TABLE + " ("
            + COL_ID + " INTEGER PRIMARY KEY, "
            + COL_NOME + " TEXT UNIQUE NOT NULL, "
            + COL_EMAIL + " TEXT, "
            + COL_ENDERECO + " TEXT"
            + ");";
       
        db.execSQL(sql);
    }


Enquanto que o onUpgrade não apenas mais derrubará a tabela e a criará novamente. Ele agora será utilizado para alterar a tabela antiga, acrescentando mais uma coluna:

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        String sql = "ALTER TABLE " + TABLE + " ADD COLUMN " + COL_ENDERECO + " TEXT;";

        db.execSQL(sql);
    }


Lembre-se também de adicionar o novo campo nos métodos inserir, getLista e alterar.

E se, por acaso, decidirmos alterar novamente o banco de dados? O banco irá para a versão 3, mas o que acontece com aqueles que instalaram o aplicativo e estão ainda com versões anteriores? Além de atulizar o método onCreate e alterar o inserir, getLista e alterar, é preciso tomar cuidado com o método onUpgrade. Ele ficará responsável para progressivamente realizar todas as atualizações desde a que está instalada no celular até chegar na atualização atual.

Suponha então que vamos adicionar o telefone do usuário. O onUpgrade ficaria assim:

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        String sql;

        switch(oldVersion) {
            case 1:
                sql = "ALTER TABLE " + TABLE + " ADD COLUMN " + COL_ENDERECO + " TEXT;";
                db.execSQL(sql);
            case 2:
                sql = "ALTER TABLE " + TABLE + " ADD COLUMN " + COL_TELEFONE + " TEXT;";
                db.execSQL(sql);
        }
    }


Assim, se a versão antiga instalada for a 2, será feita a atualização do banco executando o que está no case 2. Se a versão antiga instalada for a 1, será feita a atualização do banco executando o que está tanto no case 1 quanto no case 2. Repare que eu não usei o break!

O código completo de nosso UsuarioDAO pode ser visto logo a seguir:

public class UsuarioDAO extends SQLiteOpenHelper {
    private static final String DATABASE = "appExemplo";
    private static final String TABELA = "Usuarios";
    private static final int VERSAO = 3;
    private static final String COL_ID = "id";
    private static final String COL_NOME = "nome";
    private static final String COL_EMAIL = "email";
    private static final String COL_ENDERECO = "endereco";
    private static final String COL_ENDERECO = "endereco";

    public UsuarioDAO(Context context) {
        super(context, DATABASE, null, VERSAO);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "CREATE TABLE " + TABLE + " ("
            + COL_ID + " INTEGER PRIMARY KEY, "
            + COL_NOME + " TEXT UNIQUE NOT NULL, "
            + COL_EMAIL + " TEXT, "
            + COL_ENDERECO + " TEXT, "
            + COL_TELEFONE + " TEXT"
            + ");";
      
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        String sql;

        switch(oldVersion) {
            case 1:
                sql = "ALTER TABLE " + TABLE + " ADD COLUMN " + COL_ENDERECO + " TEXT;";
                db.execSQL(sql);
            case 2:
                sql = "ALTER TABLE " + TABLE + " ADD COLUMN " + COL_TELEFONE + " TEXT;";
                db.execSQL(sql);
        }
    }

    public void inserir(Usuario usuario) {
        ContentValues values = new ContentValues();

        values.put(COL_NOME, usuario.getNome());
        values.put(COL_EMAIL, usuario.getEmail());
        values.put(COL_ENDERECO, usuario.getEndereco());
        values.put(COL_TELEFONE, usuario.getTelefone());

        getWritableDatabase().insert(TABELA, null, values);
    }

    public List<Usuario> getLista() {
        List<Usuario> lista = new ArrayList<>();

        String sql = "SELECT * FROM " + TABELA + ";";
        Cursor c = getReadableDatabase().rawQuery(sql, null);

        Usuario usuario = null;

        while(c.moveToNext()) {
            usuario = new Usuario();

            usuario.setId(c.getString(c.getColumnIndex(COL_ID)));
            usuario.setNome(c.getString(c.getColumnIndex(COL_NOME)));
            usuario.setEmail(c.getString(c.getColumnIndex(COL_EMAIL)));
            usuario.setEndereco(c.getString(c.getColumnIndex(COL_ENDERECO)));
            usuario.setTelefone(c.getString(c.getColumnIndex(COL_TELEFONE)));

            lista.add(usuario);
        }

        return lista;
    }

    public void deletar(Usuario usuario) {
        String[] argumentos = {usuario.getId().toString()};
        getWritableDatabase().delete(TABELA, COL_ID + "=?", argumentos);
    }

    public void alterar(Usuario usuario) {
        ContentValues values = new ContentValues();
        values.put(COL_NOME, usuario.getNome());
        values.put(COL_EMAIL, usuario.getEmail());
        alues.put(COL_TELEFONE, usuario.getTelefone());

        String[] argumentos = {usuario.getId().toString()};
        getWritableDatabase().update(TABELA, values, COL_ID + "=?", argumentos);
    }
}


That's all! ^^

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.