Melhores práticas - JSF

Colegas,

Estou aprendendo JSF e gostaria de saber como vcs lidam com os seguintes casos:

Para um dado objeto, eu tenho um entity(com anotações) para persistir no banco usando o hibernate e o managed bean para o jsf. Ambos com seus getters and seters. Como vcs lidam com essa situação? Criam esses dois objetos ou existe outra estratégia?

As regras de negócios ficam no managed bean também?

Vc conhece algum material falando sobre essas práticas?

Muito obrigado,

Marques

Dae Marques.

Aqui usamos da seguinte forma, que considero uma boa prática:

  • uma classe para a entidade;
  • uma classe para ligação entre interface e negócio;
  • uma classe para gerenciamento (managed bean).

As entidades nunca são usadas nos MBeans. Nos MBeans são instanciadas apenas essas classes de ligação (chamamos de VO ou TO - de View Object e Transfer Object, respectivamente. Apesar de nomes diferentes, funcionam da mesma forma).

Por que fazemos isso? Simplesmente pra não misturar dados negociais, que são persistidos no banco de dados, com dados que são exibidos na tela, para o usuário. Dei esse exemplo num outro tópico: se você precisa cuidar de dados apenas na tela, como checkbox de exclusão, você precisa manter em algum lugar. Manter na entidade não tem sentido, já que isso não é persistido. Se você não tiver o VO ali no meio, terá que criar na entidade, misturando o que salva no banco de dados e o que aparece na tela, ou ainda colocando uma lista (nesse caso) de Booleans apenas pra controlar a lista de registros a ser excluído, enfim, dores de cabeça.

Pra usar é simples. O VO tem todos os dados da entidade que serão efetivamente usados na tela. Na entidade existe dois métodos, entity2VO e vo2Entity, que copia os dados da entidade para o VO, no primeiro caso, e do VO pra entidade, no segundo. O primeiro é realizado após uma consulta no banco (você recebe a entidade), transformando-o no VO. O segundo acontece quando você vai persistir os dados (precisa ser uma entidade pra ser persistido pelo hibernate). Nos VOs você também pode criar métodos pra configurar uma data num formato específico, por exemplo, coisa desnecessária de ficar na entidade.

Já no seu MBean, você seta apenas os VOs, nunca entidades. Acessa-os normalmente no jsp.

#{nome_do_bean.nome_objeto_VO.atributo

Lembrando que precisa de getter e setter tanto do VO no seu MBean quanto dos atributos dentro do VO.

Quanto à nomenclatura, usamos como padrão o seguinte:

  • para Management Beans: MBean[Nome]. e.g.: MBeanConsultaPlacasDiscosVoadores, MBeanCadastroEspinhas
  • para entidades: [Nome]. e.g.: PlacasDiscosVoadores, Espinhas
  • para VOs: [Nome_da_Entidade]VO. e.g.: PlacasDiscosVoadoresVO, EspinhasVO

Entendeu?

Abraço

k1tsune ,

Entendí e agradeço a tua resposta.
Mais uma dúvida: Todas as regras de negócios ficam no managed bean?

Muito obrigado,

Marques

Bom dia Marques,

Tente não deixar nenhuma regra de negócio no seu mbean, pois isso vai deixar seu código bem mais modular (ou seja, se você trocar seu bean, a parte de negócio fica intacta e vice-versa). Creia, acontece muito e é muito útil. Por exemplo, no seu MBean você faz uma pesquisa. Para isso, invoca o método pesquisar que está numa outra classe (na classe onde ficam os trechos de negócio, ou seja, que “conversam” com o banco de dados e mantém os requisitos do cliente). Se você precisar alterar algo na pesquisa, só esse arquivo precisa ser alterado, não mexendo no MBean.

Agora, imagine que esse método é usado por várias telas diferentes (por exemplo uma tela e uma popup, que faz a mesma pesquisa, as vezes com menos campos, enfim…). Seriam 2 lugares diferentes pra alterar caso a pesquisa estivesse dentro dos seus MBeans. A medida que seu projeto cresce, isso acontece com frequência, por isso é melhor haver essa separação.

Abraço

cara se nao for pedir muito voce poderia colocar trechos de codigo que voce jah fez de um caso de uso pequeno das 3 classes?

entidade, vo e mb?

Bom, vou escrever aqui rapidamente (não é de caso de uso verdadeiro, estou apenas dando exemplo, ok?)

Entidade:

	import seu_package.EmpresaVO;
	@Entity
	public class Empresa {
		
		@Id
		private Long id;

		@Column(nullable=false, length=100)
		private String nome;

		@Column(nullable=false, length=100)
		private String endereco;
	
		@Column(nullable=false, length=15)
		private String cnpj;

		public long getId() {
			return id;
		}

		public void setId(long id) {
			this.id = id;
		}

		public void setNome(String nome){
			this.nome = nome;
		}

		public String getNome(){
			return this.nome;
		}

		public void setEndereco(String endereco){
			this.endereco= endereco;
		}

		public String getEndereco(){
			return this.endereco;
		}

		public void setCnpj(String cnpj){
			this.cnpj= cnpj;
		}

		public String getCnpj(){
			return this.cnpj;
		}

		public EmpresaVO entity2VO(){
			EmpresaVO eVO = new EmpresaVO();
			eVO.setId(this.getId());
			eVO.setNome(this.getNome());
			eVO.setEndereco(this.getEndereco());
			eVO.setCnpj(this.getCnpj());
			return eVO;
		}


		public void vo2Entity(EmpresaVO eVO){
			this.setId(eVO.getId());
			this.setNome(eVO.getNome());
			this.setEndereco(eVO.getEndereco());
			this.setCnpj(eVO.getCnpj());
		}
	}

VO:


	public class EmpresaVO {
		
		private Long id;
		private String nome;
		private String endereco;
		private String cnpj;

		public long getId() {
			return id;
		}

		public void setId(long id) {
			this.id = id;
		}

		public void setNome(String nome){
			this.nome = nome;
		}

		public String getNome(){
			return this.nome;
		}

		public void setEndereco(String endereco){
			this.endereco= endereco;
		}

		public String getEndereco(){
			return this.endereco;
		}

		public void setCnpj(String cnpj){
			this.cnpj= cnpj;
		}

		public String getCnpj(){
			return this.cnpj;
		}
		
		/*
		 * Esse método trunca o nome da empresa em 50 caracteres (47 letras mais 3 reticências)
		 */
		public String getNomeTruncado(){
			String retorno = "";
			if (this.getNome().length() <= 47) {
				retorno = this.getNome(); 
			}
			else {
				retorno = this.getNome().substring(0, 47) + "...";
			}
		
			return retorno;
		}

Managed Bean

	import seu_package.EmpresaVO;

	public class MBeanCadastroEmpresa(){
		
		private EmpresaVO empresa;

		//.
		//. Os demais atributos e métodos da classe
		//.

		public void doSalvar(ActionEvent e){
			// Instanciar seu método que salva.Nesse seu método, deverá intanciar a entidade empresa, e invocar o método
			// vo2Entity, persistindo a entidade com os dados.
			seu_metodo.salvar(this.getEmpresa);
		}

		public EmpresaVO getEmpresa(){
			return this.empresa;
		}

		public void setEmpresa(EmpresaVO empresa){
			this.empresa = empresa;
		}
	}

É por aí. Seu método salvar tem que instanciar a entidade Empresa, e passar os dados do VO pra ela antes de persistir (já que só persiste a entidade, que tem as anotações, etc).

Os campos da empresaVO podem estar diretamente na tela, por exemplo:

	<h:inputText id="txtNomeEmpresa" value="#{mBeanCadastroEmpresa.empresa.nome}" maxlenght="100"/>
	<h:inputText id="txtEnderecoEmpresa" value="#{mBeanCadastroEmpresa.empresa.endereco}" maxlenght="100" />
	<h:inputText id="txtCnpjEmpresa" value="#{mBeanCadastroEmpresa.empresa.cnpj}" maxlenght="15"/>

O botão seria assim:

	<a4j:commandButton id="btnSalvar" actionListener="#{mBeanCadastroEmpresa.doSalvar}"/>

Ao clicar no botão Salvar, executará o método do ManagedBean doSalvar, e os dados colocados na tela já estarão populados (nome da empresa, endereço e cnpj).

Bom, acho que é isso.

Abraço

Cara
uma duvida

tenho um DTO

@Entity(name="PESSOA")
@SequenceGenerator(sequenceName="pessoa_jpa",name="pessoa_jpa", allocationSize = 1)   
public class Pessoa implements Serializable{

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(generator = "pessoa_jpa", strategy=GenerationType.SEQUENCE)
	@Column(name = "ID_PESSOA")
	private Long id;
	
	@Column(name = "NOME_PESSOA")
	private String nome;
	
	@Column(name = "IDADE")
	private int idade;

        gets / sets

e um VO

public class PessoaVO{

        private Long id;
	private String nome;
        private int idade;

        gets / sets

no meu Bean
tem um objeto PessoaVO
e nos meus JSF
eu acesso o bean.vo.propriedade…

agora uma coisa…
eu tenho lá meu metodo salvar

facade.salvar(pessoaVO).

eu mando meu objeto VO pro save ou o DTO ?
como eu passo os valores do VO pro DTO

vlw

Galera, aconselho dá uma olhada nesses links:

http://fragmental.com.br/wiki/index.php?title=Evitando_VOs_e_BOs
http://www.guj.com.br/posts/list/101563.java
http://www.guj.com.br/posts/list/81232.java