Baixe o app para aproveitar ainda mais
Prévia do material em texto
Desenvolvimento de Software para WEB JSF (JavaServer Faces) – Parte 3 Prof. Regis Pires Magalhães regispires@lia.ufc.br Agradecimentos • Agradecemos ao Prof. Fábio Dias (UFC Quixadá) por ter gentilmente cedido seus slides para adaptação e uso nesta disciplina. Melhor visualização dos erros • Project Stage • Existem no JSF configurações que podem auxiliar durante o desenvolvimento ou até mesmo em produção. ▫ Chamadas de “estágios”. ▫ “Development”, “UnitTest”, “SystemTest”, “Production” (default). ▫ Modo development Mostra erros e outros detalhes da aplicação de forma mais detalhada no próprio browser. Melhor visualização dos erros • Configurar o estágio atual da aplicação no web.xml: <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> Cuidado com a NullPointerException • Erro comum: ▫ Esquecer de instanciar o objeto logo no atributo ou no construtor do Managed Bean. ▫ Quando o formulário for submetido, o JSF recupera a referência para aquele objeto, através do getter, porém, ele estaria nulo. Cuidado com a NullPointerException @ManagedBean public class AutomovelBean { private Automovel automovel = new Automovel(); // getter e setter public void salva() { System.out.println("Marca: " + automovel.getMarca()); } } Árvore de componentes • JSF lê arquivo .xhtml e monta uma árvore de componentes em memória. <h:form> <h:panelGrid columns="2"> Marca: <h:inputText value="#{marcaBean.marca.nome}" required="true"/> </h:panelGrid> <br/> Árvore de componentes • Depois passa essa árvore para um renderizador para escrever o HTML a cada nó que passar. • JSF guarda na memória qual foi a árvore usada para gerar determinada tela. • Compara cada atributo da requisição com os campos que estavam disponíveis para o usuário. • Com as opções na mão, JSF valida se os dados enviados são compatíveis com os disponíveis. • Framework stateful conhece todo o estado da tela e guarda isso através das requisições. Cliclo de vida das requisições no JSF 6 Fases Fase 1 – Criar ou restaurar a árvore de componentes da tela • Restore View. • Lê o xhtml e cria a árvore de componentes em memória. • JSF faz um cache de árvores, guardando no cliente ou no servidor, o estado das telas acessadas por último. <context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>client</param-value> <!-- valor padrão: server --> </context-param> Fase 2 – Aplicar valores da requisição na árvore de componentes • Apply Request Values • Buscar os valores informados pelo usuário e colocá-los nos seus respectivos componentes. • Seta os valores que o usuário digitou, sem se preocupar se ele é válido ou não. HtmlInputText nome = ... // JSF já conhece o componente nome.setSubmittedValue("Fulano"); HtmlInputText idade = ... idade.setSubmittedValue("28"); Fase 3 – Converter e Validar • Validate. • Fase mais perceptível. • 2 partes: converter e validar. • JSF tem conversores prontos para tipos basicos como Integer, Long, java.util.Date, entre outros. • Para converter tipos específicos é preciso criar e usar um conversor personalizado. • Depois de convertido, o valor informado será validado por um validador: ▫ RequiredValidator, LongRangeValidator, etc. Fase 4 – Atualizar o modelo • Update Model. • Colocar esses valores válidos dentro do nosso modelo. • No final, temos nosso modelo com os valores corretos. HtmlInputText inputNome = ... // já convertido e validado HtmlInputText inputIdade = ... // já convertido e validado Pessoa pessoa = jsfAvaliaExpressionLanguage("#{pessoa}"); pessoa.setNome(inputNome.getValue()); pessoa.setIdade(inputIdade.getValue()); Fase 5 – Invocar ação da aplicação • Invoke Application. • Nessa fase ocorre a lógica da aplicação. • Exemplo: ▫ Um sistema de universidade, em que para efetuar uma matrícula precisamos verificar: Primeiro se não existe mensalidade em aberto; Ou se já não existe um acordo sendo cumprido em relação às possíveis mensalidades em aberto. Fase 5 – Invocar ação da aplicação • Exemplo: public void efetuaMatricula(PropostaMatricula proposta){ try{ servicoFinanceiro.validaSituacaoAluno(proposta.getAluno()); // efetuaMatricula } catch(MensalidadesEmAbertoException e){ // exibe mensagem para o usuário e aborta o a matrícula } } Fase 6 – Renderizar a resposta • Render Response. • Última fase do ciclo de vida do JSF. • Chegamos nela se nas fases anteriores tudo ocorreu bem ou depois de um erro em fase intermediária. • Se ocorrer erro de conversão ou validação (fase 3), as fases 4 e 5 são puladas e vamos direto para a fase 6 para mostrar novamente o formulário para que ele possa corrigi-lo, já com as devidas mensagens de erro. ▫ Fase 1 Fase 2 Fase 3 Fase 6 Fase 6 – Renderizar a resposta • Outra possibilidade: ▫ Quando o usuário pede a página pela primeira vez, o JSF monta a árvore e já manda para a fase 6. ▫ Na primeira requisição à aplicação, não haverá formulário sendo submetido, nem ação para ser invocada. Fase 1 Fase 6 Cliclo de vida das requisições no JSF 6 Fases PhaseListener • Utilizamos um PhaseListener praticamente nas mesmas situações em que usaríamos um javax.servlet.Filter. • Mas em vez de envolver a requisição inteira, seremos notificados antes e depois de cada fase, o que faz com que tenhamos um acesso mais granular. • O método getPhaseId() devolve qual fase do JSF nosso listener irá escutar. Ou podemos devolver • PhaseId.ANY_PHASE para indicar que queremos ser notificados antes e depois de todas as fases. • Temos um método que e chamado antes do processamento da fase, beforePhase, e outro que e chamado depois, afterPhase. PhaseListener public class AutenticacaoPhaseListener implements PhaseListener { private static final String RESTRICTION_PATTERN = "^/restrito/.*"; public PhaseId getPhaseId() { return PhaseId.RESTORE_VIEW; } public void beforePhase(PhaseEvent event) { } public void afterPhase(PhaseEvent event) { FacesContext context = event.getFacesContext(); String viewId = context.getViewRoot().getViewId(); boolean urlProtegida = Pattern.matches(RESTRICTION_PATTERN, viewId); Object usuario = context.getExternalContext().getSessionMap(). get("usuarioLogado"); if(urlProtegida && usuario == null){ NavigationHandler navigator = context.getApplication() .getNavigationHandler(); navigator.handleNavigation(context, null, "login"); } } } PhaseListener no faces-config.xml <navigation-rule> <navigation-case> <from-outcome>login</from-outcome> <to-view-id>/login.xhtml</to-view-id> </navigation-case> </navigation-rule> <lifecycle> <phase-listener> facesmotors.AutenticacaoPhaseListener </phase-listener> </lifecycle> • Existem 4 escopos a partir do JSF 2: ▫ @RequestScoped: os beans gerenciáveis de escopo request são instanciados e permanecem disponíveis durante uma mesma requisição HTTP. ▫ @ViewScoped: os beans gerenciáveis de escopo view permanecem disponíveis enquanto o usuário permanecer em uma mesma página de uma aplicação. ▫ @SessionScoped: os beans gerenciáveis de escopo session são salvos na sessão HTTP de um usuário. ▫ @ApplicationScoped: os beans gerenciáveis de escopo application permanecem disponíveis enquanto a aplicação estiver no ar, e podemser acessados por todos os usuários da aplicação. Escopos do Managed-Bean Flash • Conceito originário do framework Ruby on Rails. • Fornece um meio de passar objetos entre as visões de usuário. • Um objeto que use flash poderá ser acessado na próxima visão, mesmo após um redirect. • Permite preservar mensagens definidas no managed bean, mesmo após um redirect. Flash @ManagedBean public class AutomovelBean { ... public String insere() { ... Flash flash = FacesContext.getCurrentInstance(). getExternalContext().getFlash(); flash.setKeepMessages(true); FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Automóvel inserido com sucesso.", null)); return "/automovel/lista?faces-redirect=true"; } ... } Action e ActionListener • Action ▫ Usado para executar a lógica da aplicação. • ActionListener ▫ Serve para observarmos eventos de tela. ▫ Escutar as ações do usuário, mas sem objetivo de negócio. ▫ Associado a método público e void. ▫ Há opção de ter parâmetro ou não receber um javax.faces.event.ActionEvent. Action e ActionListener <h:commandButton id="botaoSalvar" value="Salvar" actionListener="#{automovelBean.listener}“ action="#{automovelBean.salvar(automovel)}"/> public void listener(ActionEvent event){ UIComponent source = event.getComponent(); System.out.println("Ação executada no componente " + source.getId()); } Action e ActionListener • Outra forma de associar uma ActionListener com a ação: ▫ Através da tag f:actionListener. ▫ Permite especificar mais de um listener. ▫ Serão executados na ordem especificada. ▫ Vincula a ação com classes que implementam a interface ActionListener. ▫ Uma mesma ação pode ter vários listeners. <h:commandButton id="botaoSalvar" value="Salvar" action="#{automovelBean.salvar(automovel)}"> <f:actionListener type="facesmotors.LoggerActionListener"/> <f:actionListener type="..."/> </h:commandButton> Action e ActionListener <h:commandButton id="botaoSalvar" value="Salvar" action="#{automovelBean.salvar(automovel)}"> <f:actionListener type="facesmotors.LoggerActionListener"/> <f:actionListener type="..."/> </h:commandButton> public class LoggerActionListener implements ActionListener{ @Override public void processAction(ActionEvent event) throws AbortProcessingException { UIComponent source = event.getComponent(); System.out.println("Ação executada no componente " + source.getId()); } } Action e ActionListener • Usar ActionListener para executar algo antes da ação de negócio, como: ▫ Logar algo ▫ setar alguma propriedade via <f:setPropertyActionListener>. ▫ Acessar o componente que chamou a ação (disponível no parâmetro ActionEvent). • ActionListerner não permite navegação após sua execução (retorno void). • ActionListener sempre ocorre antes de Action. Action e ActionListener • ActionListener sempre ocorre antes de Action: <h:commandLink value="submit" actionListener="#{bean.listener1}" action="#{bean.submit}"> <f:actionListener type="com.example.SomeActionListener" /> <f:setPropertyActionListener target="#{bean.property}" value="some"/> </h:commandLink> Ordem de execução: 1. Bean#listener1() 2. SomeActionListener#processAction() 3. Bean#setProperty() 4. Bean#submit() setPropertyActionListener Normalmente <f:setPropertyActionListener ...> é usado para enviar uma variável associada a uma linha de uma dataTable como em: ... <h:dataTable value="#{produtoBean.produtos}" var="produto"> <h:column> <h:outputText value="#{produto.descricao}" /> </h:column> <h:column> <h:outputText value="#{produto.valor}" /> </h:column> <p:commandButton value="Detalhes" actionListener="#{produtoBean.detalhar}"> <f:setPropertyActionListener target="#{produtoBean.produto}" value="#{produto}"/> </p:commandButton> </h:dataTable> ... Substituir construções assim: <h:commandLink value="Próxima página" action="#{bean.proxPagina}" /> public String proxPagina() { return "prox_pagina"; } Por: <h:commandLink value="Próxima página" action="prox_pagina" /> Melhor ainda seria evitar a “navegação através de POST” assim: <h:link value="Próxima página" outcome="prox_pagina" /> Facelets • Facelets é um framework de criação de templates de páginas JSF. É um projeto open source. • O Facelets permite criar uma página-modelo (template), que será base estrutural e visual para as demais páginas JSF do sistema. • Essa página-modelo (template) é uma página normal em XHTML, com algumas tags específicas do Facelets. • Boa prática: ▫ Criar templates na pasta: /WEB-INF/templates Introdução a Facelets • Já vem embutido a partir do JSF 2.0. • Apenas adicione nas páginas: Facelets <?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> <title>Template de Pagina JSF</title> </h:head> <h:body> </h:body> </html> Template usada por várias páginas • Na figura abaixo temos um template de página: Introdução a Facelets Criando uma template: ui:insert • Utilizado para posicionar os trechos dinâmicos. • O atributo name desse componente é utilizado para nomear os trechos dinâmicos. <div id="pagina"> <div id="cabecalho"> <ui:insert name=“cabecalho" > </ui:insert> </div> <div id="menu"> <ui:insert name=“menu" > </ui:insert> </div> <div id="conteudo"> <ui:insert name=“conteudo" > </ui:insert> </div> <div id="rodape"> <ui:insert name=“rodape" > </ui:insert> </div> </div> Criando uma template Usando a Template – ui:composition <ui:composition template="/WEB-INF/templates/template.xhtml"> </ui:composition> • Quando criamos uma página que irá usar uma template precisamos especificar qual será o arquivo que possui o template, para isto iremos utilizar a tag composition. • Todo conteúdo não contido na tag <ui:composition> será descartado pelo JSF no processo de construção da tela. Usando a Template – ui:define <ui:composition template="/WEB-INF/templates/template.xhtml"> <ui:define name="conteudo"> <h1>Cadastro de Aluno</h1> </ui:define> </ui:composition> • O conteúdo de um trecho dinâmico pode ser definido através do componente <ui:define>. • Ele possui o atributo name que é utilizado para indicar qual trecho dinâmico do template queremos definir. • Se o conteúdo de um trecho dinâmico não for definido, o JSF utilizará o conteúdo existente no corpo da tag <ui:insert> definido no template. Aviso Importante • Quando utilizamos um template não há necessidade de especificar novamente as tags h:head, h:body ou qualquer outra tag que já tem no template, pois está página agora terá as mesmas tags do template para montar seu layout. Template usada por várias páginas <ui:insert name="x"> <ui:composition> <ui:define name="x"> </ui:composition> Modularização • Trechos estáticos ou dinâmicos definidos em um template possuemposição fixa. • Em determinadas situações, é necessário tornar flexível o posicionamento de um determinado trecho. • Exemplo: ▫ Formulário de contato deve ser exibido em posições diferentes nas telas da aplicação. ▫ Em algumas telas o formulário aparecerá no topo e em outras ele aparecerá no centro. Modularização Fragmento de página a ser inserida com ui:composition • A melhor abordagem é definir o formulário de contato, separadamente, em um arquivo XHTML. • O código XHTML que define o formulário de contato deve ser inserido no corpo da tag <ui:composition>. Fragmento de página a ser inserida com ui:composition Adicionar fragmento com ui:include ... <ui:include src="/formulario-de-contato.xhtml"/> ... Usando parâmetros no fragmento a ser inserido Enviando parâmetros para o fragmento de página a ser adicionado ... <ui:include src ="/lista-livros.xhtml"> <ui:param name="livros" value="#{livrosBean.livrosMaisVend}"/> </ui:include > ... Modularização <ui:composition> <ui:include> <ui:param> </ui:include> Exercício • Altere o último trabalho para que ele use facelets.
Compartilhar