Dúvida: Fazendo CRUD com JSF

Olá!

Estou iniciando alguns testes em JSF, até o momento entendi boa parte de como funciona o framework, porém, pintou uma dúvida simples, veja, estou fazendo um CRUD, e na lista de um determinado cadastro denho a opção Editar para cada registro, quero fazer o simples, clicar sobre o botão e ser redirecionado ao formulário com os campos preenchidos devidamente.

Abaixo o código:

			<h:dataTable value="#{editora.listaEditora}" var="it">
				<h:column>
					<f:facet name="header"><h:outputText value="Cód."/></f:facet>
					<h:outputText value="#{it.id_editora}"/>
				</h:column>
	
				<h:column>
					<f:facet name="header"><h:outputText value="Editora"/></f:facet>
					<h:outputText value="#{it.nm_editora}"/>
				</h:column>
	
				<h:column>
					<f:facet name="header"><h:outputText value="Status"/></f:facet>
					<h:outputText value="#{it.fl_ativo}"/>
				</h:column>
				
				<h:column>
					<h:commandButton action="#{editora.editar}" value="Editar">
						<f:attribute name="id" value="#{editora.id_editora}" />
					</h:commandButton>
				</h:column>
				
			</h:dataTable>

No faces-config.xml tá assim:

...
 <navigation-rule>
  <display-name>editora_lista</display-name>
  <from-view-id>/editora_lista.jsp</from-view-id>
  <navigation-case>
   <to-view-id>/editora_novo.jsp</to-view-id>
  </navigation-case>
  <navigation-case>
   <from-outcome>edit</from-outcome>
   <to-view-id>/editora_editar.jsp</to-view-id>
  </navigation-case>
 </navigation-rule>
...

Alguma dica?

Já tentou usar o actionListener para chamar um método que carrega o list que vai preencher sua tela, quando clicar no botao editar?

Valeu pela dica, vou tentar!

Tentei fazer com o ActionEvent, mas pintou outra dúvida, como faço pra redirecionar para o formulário?

Veja bem, estou fazendo de maneira bem simples, não separei por camada de negócio, ou seja, o Bean que criei faz tudo! (Tosco não? Mas foi seguindo um tutorial aqui do GUJ mesmo) Pretento fazer de uma forma melhor, mas agora quero entender o mecanismo mesmo…

O ultimo método é o actionEvent.


public class Editora implements Serializable{
	private static final String SUCESS 		= "success";
	private static final String FAIL 		= "failure";
	private static final String DSNAME 		= "MySqlLuciano";	
	
	private int id_editora;
	private String nm_editora;
	private String fl_ativo;
	private List<Editora> listaEditora;

	public Editora(){
		listaEditora = new ArrayList<Editora>();		
	}

	public int getId_editora(){
		return id_editora;
	}

	public void setId_editora(int id_editora){
		this.id_editora = id_editora;
	}

	public String getNm_editora(){
		return nm_editora;
	}

	public void setNm_editora(String nm_editora){
		this.nm_editora = nm_editora;
	}

	public String getFl_ativo(){
		return fl_ativo;
	}

	public void setFl_ativo(String fl_ativo){
		this.fl_ativo = fl_ativo;
	}

	public List<Editora> getListaEditora(){
		findEditora();
		return listaEditora;
	}

	public void setListaEditora(List<Editora> listaEditora){
		this.listaEditora = listaEditora;
	}

	public String findEditora(){
		Connection conn = null;
		Statement stmt	= null;
		ResultSet rset 	= null;
		
		try {
			String sql 	= "select id_editora, nm_editora, fl_ativo from editora";
			conn 		= new ConnManager(DSNAME).getConn();		
			stmt 		= conn.createStatement();
			rset 		= stmt.executeQuery(sql);

			while( rset.next() ){
				Editora e = new Editora();
				e.setId_editora( rset.getInt(1) );
				e.setNm_editora( rset.getString(2) );
				e.setFl_ativo( rset.getString(3) );

				listaEditora.add( e );
			}// while

		}catch(SQLException e){
			e.printStackTrace();
			return FAIL;
		}
		return SUCESS;
	}
	
	public String gravarNovo(){
		Connection conn 		= null;
		PreparedStatement pstmt	= null;

		try {
			String sql 	= "insert into editora(nm_editora) values( ? )";
			conn 		= new ConnManager(DSNAME).getConn();	
			pstmt 		= conn.prepareStatement( sql );
			pstmt.setString(1, nm_editora);
			pstmt.execute();

		}catch(SQLException e){
			e.printStackTrace();
			return FAIL;
		}
		return SUCESS;
	}

	public Editora getEditora(int id){
		Connection conn 		= null;
		PreparedStatement pstmt	= null;
		ResultSet rset 			= null;
		Editora e 				= null;

		try {
			String sql 	= "select id_editora, nm_editora, fl_ativo from editora where id_editora = ?";
			conn 		= new ConnManager(DSNAME).getConn();		
			pstmt 		= conn.prepareStatement(sql);
			pstmt.setInt(1, id);
			rset 		= pstmt.executeQuery();

			if( rset.next() ){
				e = new Editora();
				e.setId_editora( rset.getInt(1) );
				e.setNm_editora( rset.getString(2) );
				e.setFl_ativo( rset.getString(3) );
			}// if end

		}catch(SQLException ex){
			ex.printStackTrace();
		}
		return e;
	}

	public void selEditar(ActionEvent evento){
		UIParameter param = (UIParameter) evento.getComponent().findComponent("codEditora");
		Integer codE      = (Integer) param.getValue();
		/// ???? - Como faço para redirecionar para o formulário?!
	}
	
}

lusilva,

me desculpe, acho que não me fiz claro… é assim, você chama o action passando para ele o parametro “edit”, que o faces vai buscar lá no faces-config.xml e no actionListener voce passa o seu metodo do bean, o action vai cuidar do redirecionamento automaticamente, enquanto o seu action listener deverá se preocupar em popular o seu list para exibição dos dados, isso tudo no jsp… ficaria assim
<h:commandButton value=“Editar” action=“edit” actionListener="#{Editora.selEditar}" /> .

Quanto ao retorno, na hora de salvar as alterações, você chama um action , passando por exemplo <h:commandButton value=“Salvar” action="#{Editora.salvar}" /> agora o faces vai buscar o seu método que deverá retornar algum valor de algum tipo, se você retornar uma String, ele automaticamente buscará no faces-config a ação, por exemplo:

public String salvar(){
try{
String SUCCESS=“SUCCESS”;
String FAILURE=“FAILURE”;

   MeuBusiness.SalvaObjeto(meuList);
   return SUCCESS;
catch (Exception e){
     e.printStackTrace();
     return FAILURE;
}

}

e no seu faces-config:
<navigation-rule>
<display-name>editora_lista</display-name>
<from-view-id>/editora_lista.jsp</from-view-id>
<navigation-case>
<to-view-id>/editora_novo.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>edit</from-outcome>
<to-view-id>/editora_editar.jsp</to-view-id>
</navigation-case>

<from-view-id>/editora_editar.jsp</from-view-id>
<navigation-case>
<from-outcome>SUCCESS</from-outcome>
<to-view-id>/editora_sucesso.jsp</to-view-id>
</navigation-case>

</navigation-rule>

note que eu só coloquei o success, isso porque por padrão do faces, se ele não encontrar o map no faces-config.xml, ele vai ficar aonde está, logo em caso de falha, ele não encontraria o retorno FAILURE, o que faria com que ele ficasse na propria pagina “/editora_editar.jsp” aonde você poderia tratar o problema ou dar alguma mensagem, ou simplesmente redirecionar.

espero ter ajudado… qualquer coisa estamos ai!

Eu entendi a idéia, mas como eu passo o parametro (ID) para o método que vai popular o list? Se eu não passar o ID ele não saberá qual registro eu quero editar, correto?

					<h:commandButton action="edit" actionListener="#{editora.editar}" value="Editar">
						<f:attribute name="codEditora" value="#{editora.id_editora}" />
					</h:commandButton>

Esse código abaixo não funciona, tá recebendo um ActionEvent, não sei qual o type correto:

	public void editar(ActionEvent evento){
		UIParameter param = (UIParameter) evento.getComponent().findComponent("codEditora");
		Integer codE      = (Integer) param.getValue();
		/// ????
	}

O restante da configuração tá correto!
Valeu pela paciência e ajuda.

[]`s

na verdade você já está passando o parametro no JSP quando coloca lá <{#Editora.id_editora}>
se esse campo for oculto, deverá estar dentro de um hide e se você estiver postando, dê uma olhada no myfaces tomahawk
http://myfaces.apache.org/tomahawk/tlddoc/index.html
ele tem um objeto, o savestate para fazer o postback de seus objetos…

para acessálos em sua classe, basta dar um this.id_editora e pronto, já tem acesso ao objeto… não precisa pegá-los como em um servlet e joga-los aonde quer…

qualquer coisa posta o codigo todo para darmos uma olhada!

sem problemas :smiley:
pode perguntar q nao tem erro!

Olá!

Demorou um pouco pra entender, mas aprendi como usar o ActionListener, provavelmente apareçam novas dúvidas, mas essa tá resolvidoa.
Seguindo as orientações do thgdias fiz assim:

página jsp:

					<h:commandLink action="edit" actionListener="#{editora.editar}">
						<h:outputText value="Editar"/>
						<f:param id="editoraId" name="id_editora" value="#{it.id_editora}" />
					</h:commandLink>

o método para popular o bean:

	public void editar(ActionEvent evento){
		UIParameter param = (UIParameter) evento.getComponent().findComponent("editoraId");
		Integer codE      = Integer.parseInt( param.getValue().toString() );

		this.setEditora( getEditora(codE) );
	}

no faces-config.xml ficou assim:

<navigation-rule>
  <display-name>editora_lista</display-name>
  <from-view-id>/editora_lista.jsp</from-view-id>
  <navigation-case>
   <from-action>edit</from-action>
   <to-view-id>/editora_editar.jsp</to-view-id>
  </navigation-case>
  <navigation-case>
   <from-outcome>new</from-outcome>
   <to-view-id>/editora_novo.jsp</to-view-id>
  </navigation-case>
 </navigation-rule>

Thanks.

Acho que está faltando você entender como funciona a comunicação com JSF,

Abraços e boa sorte.

aproveitando o topico, fazendo algumas coisas com JSF acabei me enrolando com um CRUD
consigo criar,listar e exibir mais quando tento alterar, nao tenho sucesso.

faco algo do tipo
meu xhtml de listagem de mercadorias (mercadoriaList.xhtml) , vai ter algo como :

<h:column>
    <f:facet name="header">Nome</f:facet>
    <h:commandLink value="#{mercadoria.nome}" action="#{mercadoriaBean.obterMercadoria}">
	<f:param value="#{mercadoria.id}" name="id" />
    </h:commandLink>
</h:column>

no meu backbean tenha algo como:

public String obterMercadoria() {
    try {
           Integer id = obterIdParametro(); 
           Mercadoria mercadoria = new JpaUtil().getEntityManager().find(Mercadoria.class, id);
           setMercadoria(mercadoria);			
           return "obterSuccess"; // isso me leva a mercadoria.xhtml ( onde eu uso para cadastrar, editar e rem. )
     }catch (Exception e) {
	   e.printStackTrace();
	   return "error";
     }
}

apos fazer a execução do obterMercadoria os dados são exibidos corretamente no meu xhtml de mercadoria, mas ao tentar editar e salvar as alterações eu não consigo, não me é retornado nenhum erro, mais ao fazer um debug vi que as informações do tipo nome e codigo estão no objeto mercadoria mas o id está como null (por isso não consigo fazer merge).

public String atualizarMercadoria() {
    try {
        EntityManager em = new JpaUtil().getEntityManager();	
	em.merge(getMercadoria());
	return "success";
    } catch (Exception e) {
        e.printStackTrace();
	return "error";
    }
}

o meu mercadoria.xhtml eh algo basico, somente pro teste do crud mesmo, algo como

...
<ui:decorate template="/layout/edit.html">
    <ui:define name="label">Código:</ui:define>
    <h:inputText value="#{mercadoriaBean.mercadoria.codigo}"/>
</ui:decorate>
<ui:decorate template="/layout/edit.html">
    <ui:define name="label">Nome:</ui:define>
    <h:inputText value="#{mercadoriaBean.mercadoria.nome}"/>
</ui:decorate>
...
// atualizar e demais buttons!
<h:commandButton value="Atualizar" action="#{mercadoriaBean.atualizarMercadoria}">

na verdade estou em duvida se o problema eh algo que estou fazendo de errado no JSF ou com relacao a JPA.
se alguem tiver alguma sugestão, será bem vinda.

t+

alguem ja passou por isso ? acho que deve ser algo comum entre vcs, qualquer dica eh bem vinda ! :smiley: