Estrutura do bean de apoio JSF (melhores práticas)

118

Espero que neste post eu possa obter a opinião das pessoas sobre as melhores práticas para a interface entre as páginas JSF e os beans de apoio.

Uma coisa que nunca consigo definir é a estrutura dos meus grãos de apoio. Além disso, nunca encontrei um bom artigo sobre o assunto.

Quais propriedades pertencem a quais grãos de apoio? Quando é apropriado adicionar mais propriedades a um determinado bean em vez de criar um novo bean e adicionar as propriedades a ele? Para aplicativos simples, faz sentido ter apenas um único bean de apoio para a página inteira, considerando a complexidade envolvida em injetar um bean em outro? O bean de apoio deve conter qualquer lógica de negócios real ou deve conter estritamente dados?

Sinta-se à vontade para responder a essas perguntas e a quaisquer outras que possam surgir.


Quanto à redução do acoplamento entre a página JSF e o backing bean, nunca permito que a página JSF acesse as propriedades de qualquer propriedade do backing bean. Por exemplo, nunca permito algo como:

<h:outputText value="#{myBean.anObject.anObjectProperty}" />

Sempre exijo algo como:

<h:outputText value="#{myBean.theObjectProperty}" />

com um valor de bean de apoio de:

public String getTheObjectProperty()
{
    return anObject.getAnObjectProperty();
}

Quando faço um loop em uma coleção, uso uma classe wrapper para evitar o detalhamento de um objeto em uma tabela de dados, por exemplo.

Em geral, essa abordagem parece "certa" para mim. Isso evita qualquer acoplamento entre a exibição e os dados. Por favor me corrija se eu estiver errado.

Zack Marrapese
fonte
Você pode dar um exemplo para: Quando faço um loop em uma coleção, uso uma classe wrapper para evitar o detalhamento de um objeto em uma tabela de dados, por exemplo.
Koray Tugay
2
Para obter mais informações, consulte a resposta de BalusC em stackoverflow.com/questions/7223055/…
Zack Marrapese

Respostas:

146

Você pode querer verificar isso: fazendo distinções entre diferentes tipos de beans gerenciados JSF .

Aqui está uma descrição dos diferentes tipos de feijão, conforme definido no artigo acima de Neil Griffin:

  • Model Managed-Bean : Normalmente, o escopo da sessão. Este tipo de bean gerenciado participa da preocupação de "Modelo" do padrão de design MVC. Quando você vir a palavra "modelo" - pense em DADOS. Um bean de modelo JSF deve ser um POJO que segue o padrão de design JavaBean com getters / setters encapsulando propriedades. O caso de uso mais comum para um bean de modelo é ser uma entidade de banco de dados ou simplesmente representar um conjunto de linhas do conjunto de resultados de uma consulta de banco de dados.
  • Backing Managed-Bean : normalmente solicita o escopo. Este tipo de bean gerenciado participa da preocupação "Visualização" do padrão de design MVC. O propósito de um backing-bean é oferecer suporte à lógica da IU e ter um relacionamento 1 :: 1 com uma visualização JSF ou um formulário JSF em uma composição de Facelet. Embora normalmente tenha propriedades de estilo JavaBean com getters / setters associados, essas são propriedades da Visualização - não do modelo de dados do aplicativo subjacente. Os backing-beans JSF também podem ter os métodos JSF actionListener e valueChangeListener.
  • Bean gerenciado pelo controlador : normalmente solicita o escopo. Este tipo de bean gerenciado participa da preocupação "Controlador" do padrão de design MVC. O objetivo de um bean de controlador é executar algum tipo de lógica de negócios e retornar um resultado de navegação para o manipulador de navegação JSF. Os beans do controlador JSF normalmente têm métodos de ação JSF (e não métodos actionListener).
  • Suporte para Managed-Bean : Normalmente sessão ou escopo de aplicativo. Este tipo de bean "suporta" uma ou mais visualizações na preocupação "Visualização" do padrão de projeto MVC. O caso de uso típico é fornecer uma ArrayList para as listas suspensas JSF h: selectOneMenu que aparecem em mais de uma exibição JSF. Se os dados nas listas suspensas forem específicos do usuário, o bean será mantido no escopo da sessão. No entanto, se os dados se aplicarem a todos os usuários (como listas suspensas de províncias), o bean será mantido no escopo do aplicativo, para que possa ser armazenado em cache para todos os usuários.
  • Utility Managed-Bean : Normalmente, escopo do aplicativo. Este tipo de bean fornece algum tipo de função de "utilidade" para uma ou mais visualizações JSF. Um bom exemplo disso pode ser um bean FileUpload que pode ser reutilizado em vários aplicativos da web.
cecemel
fonte
8
Este é um ótimo artigo. Eu nunca tinha visto isso antes e estou definitivamente feliz que você postou. Quem votou nisso é louco. Não é específico do iceFaces.
Zack Marrapese
2
O link para o artigo real parece ter desaparecido.
Bill Rosmus
Uma cópia pode ser encontrada aqui
ChrLipp
10
Ainda assim, não consigo concluir que esta resposta está atualmente com 71 votos positivos. Quem quer que tenha implementado seu aplicativo JSF de acordo com essas regras deve, sem dúvida, depois estar reclamando sobre o JSF ser um framework terrivelmente opaco e seus aplicativos JSF sendo uma grande bagunça de código e todos eles culpam o próprio JSF em vez de sua própria abordagem ruim com base nas lições erradas e assim chamados "melhores práticas" aprendidas.
BalusC
alguma lógica desses beans é executada no navegador em vez de no servidor?
eskalera
14

Ótima pergunta. Sofri muito com o mesmo dilema quando me mudei para o JSF. Realmente depende da sua aplicação. Sou do mundo Java EE, portanto, recomendo ter o mínimo possível de lógica de negócios em seus beans de apoio. Se a lógica estiver puramente relacionada à apresentação de sua página, não há problema em tê-la no bean de apoio.

Eu acredito que um dos (muitos) pontos fortes do JSF é realmente o fato de que você pode expor objetos de domínio diretamente nos beans gerenciados. Portanto, eu recomendaria fortemente a <:outputText value="#{myBean.anObject.anObjectProperty}" />abordagem, caso contrário, você acabaria fazendo muito trabalho para si mesmo ao expor manualmente cada propriedade. Além disso, seria um pouco complicado inserir ou atualizar dados se você encapsular todas as propriedades. Existem situações em que um único objeto de domínio pode não ser suficiente. Nesses casos, preparo um ValueObject antes de expô-lo no bean.

EDIT: Na verdade, se você vai encapsular todas as propriedades de objeto que deseja expor, eu recomendaria que você vinculasse os componentes da interface do usuário ao bean de apoio e injetasse o conteúdo diretamente no valor do componente.

Em termos de estrutura de bean, o ponto de virada para mim foi quando ignorei vigorosamente todas as coisas que sabia sobre a construção de aplicativos da web e comecei a tratá-lo como um aplicativo GUI. O JSF imita muito o Swing e, portanto, as melhores práticas para desenvolver aplicativos Swing também se aplicam principalmente à construção de aplicativos JSF.

Allan Lykke Christensen
fonte
Obrigado pelo seu insight. Eu nunca fiz muito em termos de aplicações de swing (além de projetos acadêmicos há muito tempo). Quais são alguns bons princípios de aplicações de swing? Além disso, por que é uma bagunça ao inserir e atualizar valores? parece o mesmo para mim?
Zack Marrapese
5

Acho que a coisa mais importante com seus grãos de apoio é separar suas lógicas. Se você tem uma página inicial para um sistema CMS, consideraria uma prática ruim colocar cada pedaço de código em um bean porque:

  1. O feijão se tornaria muito grande eventualmente
  2. É mais fácil para outras pessoas encontrarem o que procuram se estiverem solucionando problemas na página de login, se então puderem facilmente consultar o arquivo loginBean.java.
  3. Às vezes você tem pequenos pedaços de funcionalidade que são claramente distintos do resto do seu código, separando isso eu imagino que você tornaria mais fácil para você mesmo desenvolver / expandir este código em algo maior, quando você já tem um bom bean com bom estrutura.
  4. Ter 1 big bean, para fazer tudo, o tornará mais dependente da memória se / quando você tiver que fazer declarações como esta MyBigBean bigBean = new MyBigBean (); em vez de usar funksjonality que você realmente precisava fazendo LoginBean loginBean = new LoginBean (); (Me corrija se eu estiver errado aqui ???)
  5. Em minha opinião, separar seus grãos é como separar seus métodos. Você não quer um método grande que execute mais de 100 linhas, mas sim dividi-lo com novos métodos que lidam com suas tarefas específicas.
  6. Lembre-se, muito provavelmente outra pessoa além de você terá que trabalhar em seus projetos JSF também.


Quanto ao acoplamento, não vejo como um problema para permitir que suas páginas JSF acessem também as propriedades dos objetos em seu backingbean. Este é o suporte embutido no JSF, e realmente torna mais fácil ler e construir o imo. Você já está separando estritamente a lógica MVC. Ao fazer isso, você economiza toneladas de linhas com getters e setters em seu backingbean. Por exemplo, eu tenho um objeto realmente enorme que me foi fornecido pelos serviços da web, onde preciso usar algumas propriedades na minha apresentação. Se eu fizesse um getter / setter para cada propriedade, meu bean se expandiria com pelo menos mais 100 linhas de variáveis ​​e métodos para obter as propriedades. Usando a funcionalidade JSF integrada, meu tempo e preciosas linhas de código são poupados.

Apenas meus 2 centavos em relação a isso, mesmo com a pergunta já marcada como respondida.

Chris Dale
fonte
1
entretanto, se você tem um objeto enorme que está em seu bean, e você tem - digamos - 15 funções EL cavando aquele objeto a partir da página JSF, você agora está amarrado não apenas ao bean, mas àquele objeto. Portanto, será difícil remover esse objeto sem quebrar a IU.
Zack Marrapese,
1
Mas seu bean de apoio também não será amarrado a esse objeto? E sua IU ligada ao bean de apoio? Quando você tiver que modificá-lo, terá que alterar todos os seus getters / setters na IU e no bean.
Chris Dale,
4

Posso não responder a todas as suas perguntas, porque poucas parecem bastante dependentes de caso para caso.

  • Não há problema em ter uma lógica de negócios em seu bean de apoio. Depende de onde você vem. Se você estiver praticando design orientado por domínio, ficará tentado a incluir a lógica de negócios no bean de apoio ou pode ser a lógica de persistência também. Eles argumentam que por que objeto tão estúpido. O objeto deve conter não apenas o estado, mas também o comportamento. Por outro lado, se você considerar a maneira tradicional Java EE de fazer as coisas, pode estar com vontade de ter dados em seu bean de apoio, que também pode ser seu bean de entidade e outra lógica de negócios e persistência em algum bean de sessão ou algo assim. Isso também está bom.

  • É perfeitamente normal ter um único bean de apoio para a página inteira. Eu não vejo nenhum problema com isso sozinho. Isso pode não parecer certo, mas depende do caso.

  • Sua outra pergunta depende muito mais do caso que você está tendo em mãos. Eu preferiria seguir pelo domínio aqui, pode ser apropriado adicionar propriedades ao existente ou criar um novo bean para isso. O que sempre se adapta melhor. Não acho que haja solução para isso.

  • Quais propriedades pertencem a qual bean de apoio. Bem, não depende do objeto de domínio? Ou pode ser que a questão não seja tão clara.

Além disso, em seu exemplo de código fornecido, não estou vendo nenhum benefício enorme.

Adeel Ansari
fonte
se - por exemplo - mudássemos do uso de POJOs caseiros criados com consultas JDBC para entidades do Hibernate que tinham nomes de campo ligeiramente diferentes, teríamos que mudar não apenas o bean de apoio. Teríamos que mudar a página JSF também. Não é assim com meu exemplo de código. Basta trocar o feijão.
Zack Marrapese
Nesse caso, você pode fazer seus beans de apoio, entidades. então você só precisa mudar as páginas JSF. Ou depende de por que você mudaria o nome das propriedades de qualquer maneira? isso só faria sentido quando você renomeie o campo para corresponder ao nome da coluna do banco de dados. Mas esse é um caso totalmente diferente.
Adeel Ansari
4

Não seria necessário manter apenas um bean de apoio por página. Depende da funcionalidade, mas na maioria das vezes eu tinha um bean por página, já que a maioria de uma página lida com uma funcionalidade. Por exemplo, em uma página eu tenho um link de registro (irei linkar com RegisterBean) e um link de carrinho de compras (ShoopingBasketBean).

Eu uso este <: outputText value = "# {myBean.anObject.anObjectProperty}" /> porque normalmente continuo apoiando beans como action beans que contêm objetos de dados. Não quero escrever um wrapper em meu backing bean para acessar as propriedades de meus objetos de dados.

Bhushan Bhangale
fonte
0

Eu gosto de testar o código de negócios sem View, então considero BackingBeans como interfaces de View para Model. Nunca coloquei nenhuma regra ou processo em um BackingBean. Esse código vai para serviços ou ajudantes, permitindo a reutilização.

Se você usar validadores, coloque-os fora de seu BackingBean e faça referência a eles em seu método de validação.

Se você acessar DAOs para preencher Selects, Radios, Checkboxes, faça isso sempre fora de um BackingBean.

Acredite em mim!. Você pode injetar um JavaBean em um BackingBean, mas tente injetar um BackingBean em outro. Você logo estará em um pesadelo de manutenção e compreensão do código.

Jjruiz
fonte