Pesquisar este blog

segunda-feira, 19 de outubro de 2015

Exemplo de cadastro de Usuários com o JSF

Como fazer um cadastro de usuários com o JSF?
Seguindo na sequência de como desenvolver um aplicativo web completo com Java e JSF
Todo o código referente a estes posts estão no github.

Estrutura do banco

Como dito anteriormente, o primeiro passo para se construir um sistema é a definição da estrutura do seu banco de dados, a estrutura escolhida para este passo do sistema está na Figura 1.
Figura1: Estrutura do banco de dados
A tabela de usuário só possui o nome do usuário e o email dele, note que neste caso o sistema só permite um email por usuário, se o seu sistema necessita de mais de um email por usuário, você deverá criar uma tabela específica para os emails do usuário.
Foi criada uma tabela separada para a senha do usuário afim de garantir uma maior segurança dos dados. Como a senha está isolada em uma outra tabela, ela só será pesquisada pelo sistema quando o usuário logar, ou quando houver alguma alteração da senha.
Caso a senha estivesse na mesma tabela do usuário, os dados da senha ficariam trafegando pelo aplicativo toda hora em que os dados do usuário fossem requisitados, o que aumenta a possibilidade de alguém coletar esta informação, e mesmo que criptografada, pode ser que esta senha seja descoberta.
Na parte do endereço do usuário, houve uma normalização dos dados de cidades, estados e ruas. Note que nem sempre esta normalização é necessária, poderíamos ter uma tabela de endereço com todos estes dados, mas a normalização deles nos traz a vantagem de não termos que repetir o cadastro de dados que já existam.
Todas estas tabelas estão ligadas a tabela CEP, para que com isso seja possível localizarmos estes dados pelo CEP, assim que o usuário digitar um CEP que já existe no sistema ele deve trazer os valores daqueles campos, facilitando o cadastro das informações do endereço.
Porém isto também levanta um alerta, e se o usuário estiver cadastrando um CEP e aquele valor já existir para uma certa Rua de um município? Bom alguns municípios pequenos possuem apenas um CEP, com isso todas as ruas deles estão em um mesmo valor do CEP, assim podemos ter dados de CEPs que só possuem o estado e a cidade.
Para tratarmos estes casos, devemos ter uma certa lógica de negócios ao utilizarmos o cadastro do CEP. Uma das atitudes que podem ser tomadas é nunca cadastrar todos os dados do CEP, quando ele tiver sendo inserido pela primeira vez em uma cidade. Se uma cidade nunca foi cadastrada no sistema, o CEP só vai conter os valores do estado e da Cidade, e quando houver um segundo cadastro, com a mesma rua, ai sim completa-se a informação do CEP. Mas fazer isso durante o cadastro do endereço do usuário não é uma boa opção, já que o sistema deve fazer algumas queries para realizar estas operações, entõa o ideal é deixar isto para um sistema de batch que rode de tempos em tempos.
E o que fazer quando duas ruas foram cadastradas para um CEP de uma cidade, mas esta cidade não possui CEP único? Neste caso, você pode tentar tratar pela maioria, ou mesmo fazer uma análise manual, isto vai depender da quantidade de dados que a sua base tem neste caso.

Validações e regras de negócio

Existem algumas validações que podemos e devemos fazer durante este cadastro, por exemplo se a senha possui no mínimo 6 caracteres e 2 dígitos. Para fazer este tipo de validação iremos usar uma classe validadora do JSF, para isso deve-se adicionar a tag validator no seu componente, como mostrado a seguir em destaque:
<h:inputSecret id="senha"
                        value="#{usuarioBean.usuarioSenha.password}"
                        validator="validadorDeSenha"
                        required="#{not empty param.includeInSalvar}"
                        pt:placeholder="Qual é a sua senha?" />
O código de validação será implementado em um bean que implementa a interface Validator do faces. O único método que esta interface define é o validate, como mostrado abaixo:
public void validate(FacesContext context, UIComponent iuComponent, Object valor)
            throws ValidatorException {
        if(!padraoSenha.matcher(valor.toString()).matches()){
            MessageFactory msg = new MessageFactory();
             throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR,
                            msg.getMessage("senhaInvalida"), null));             
        }
    }
FacesContext é o contexto faces e podemos usar ele para, por exemplo redirecionar o usuário para uma outra página de erro. O componente é o objeto referente ao componente da tela que está sendo validado e finalmente o Objeto será o valor digitado pelo usuário.
Neste caso estamos apenas validando o valor digitado, usando REGEX (regular expression), nossa REGEX de validação de senha verifica se os valores digitados estão entre 6 e 20 caracteres de tamanho, e se ela contém pelo menos 2 letras e pelo menos 2 números, abaixo segue a implementação do REGEX:
((?=.{2,}\\d)(?=.{2,}[a-zA-Z]).{6,20})
(
   (?=.{2,}\\d) verifica se contém pelo menos 2 ({2,}) dígitos \\d
   (?=.{2,}[a-zA-Z]) verifica se contém pelo menos 2 ({2,})   letras(a-zA-Z) de a a z minúsculo e A a Z maiúsculo
   .{6,20} verificacao de tamanho;
)
Repare que para o regex a definição de números é dada por \d mas como \ no java é um caracter especial, devemos utilizar o caracter de escape que também é uma \, por isso temos \\d.
Para utilizar o regex em java usa-se a classe chamada Pattern:
private Pattern padraoSenha=  Pattern.compile("((?=.{2,}\\d)(?=.{2,}[a-zA-Z]).{6,20})");
Regex é um tema muito amplo que não cabe ao escopo deste post, por isso não vamos discutí-lo aqui.package br.unip.dsd.bean.validador;
Basicamente a classe validadora segue os mesmos princípios do ManagedBean e para definirmos ele, usamos a anotação @FacesValidator sobre a classe. Com isso ele poderá ser acessado nas suas páginas usando o nome da classe, no mesmo padrão dos beans, primeira letra minúscula e demais de acordo com o nome da classe.
Quando o usuário digitar uma senha que não atende aos padrões do nosso regex, uma mensagem de erro será mostrada para ele ao lado do componente.
Porém esta ação de validação acontece nas ações da tela, por exemplo, quando o usuário clicar no botão de salvar.
Quando a validação falha uma exceção do tipo ValidatorException é disparada, e este é o comportamento padrão dos validadores. Repare que nada deverá ser feito se o valor digitado pelo usuário estiver correto.
Lembre-se que cada pacote de beans adicionado ao projeto, deverá ser adicionado a propriedade basePackages, da anotação @ComponentScan, na classe de configuração, que no nosso caso é a JPAConfig.

Usando enums internacionalizados para os dados tipados

É comum o uso de enumerations para dados tipados, que raramente terão os valores alterados. Os enums basicamente são uma lista de valores introduzidos no código e que são gravados em um campo. Para gravarmos os valores dos enums em um campo existem duas possibilidades:
  1. usar um id no enum, valor numérico
  2. usar o toString do enum
Abaixo segue um exemplo de como usar um enum no modo string:
        public List<SelectItem> getEstadoCivil() {
           List<SelectItem> estadoCivil = new ArrayList<SelectItem>();
           MessageFactory msg = new MessageFactory();
       
           estadoCivil.add(new SelectItem(EstadoCivil.CASADO.toString(), msg.getMessage("casado")));   
           estadoCivil.add(new SelectItem( EstadoCivil.SOLTEIRO.toString(), msg.getMessage("solteiro")));
           estadoCivil.add(new SelectItem(EstadoCivil.DIVORCIADO.toString(), msg.getMessage("divorciado")));
           estadoCivil.add(new SelectItem(EstadoCivil.VIUVO.toString(), msg.getMessage("viuvo")));
           return estadoCivil;
    }
O código é bem simples, o primeiro ponto a observar é a utilização de um MessageFactory, que está sendo usado aqui para a internacionalização dos valores do enumeration.
SelectItem é um objeto utilizado para mostrarmos dados como uma lista, em uma combobox, para que o usuário selecione o valor desejado.
Através do SelectItem são enviados dois valores de String para a tela, primeiro o valor do enum internacionalizado, que irá aparecer na lista para o usuário. Depois o valor do enum transformado em String, que será usado para gravarmos no banco.

Amarrando os dados 

No próximo post será explicado como evitar exceções ao usar o jpa e hibernate.

Nenhum comentário:

Postar um comentário