<h:message> e internacionalização

5 respostas
robson_vs

estou com uma duvida referente as mensagem e internacionalização.

Bom é o seguinte quando colocamos a tag <h:message for=“tal campo”> validamos aquele campo e quando queremos validar uma ação?

tipo o campo foi preenchido mais gostaria de retornar uma mensagem na mesma página tipo “usuário já cadastrado” algo do genero?

segue o exemplo de como eu estou fazendo

<form jsfc="h:form" id="formLogin">
            <table width="100%">
                <tr>
                    <td width="20%" align="right">#{msgs.labelLogin}</td>
                    <td width="30%" align="left">
                        <input id="login" type="text" name="id" value="#{UserMBean.user.id}" jsfc="h:inputText" required="true" label="#{msgs.labelLogin}"/>
                    </td>
                    <td width="50%" align="left">
                        <label class="error" for="login" jsfc="h:message"/>
                    </td>
                </tr>
                <tr>
                    <td width="20%" align="right">#{msgs.labelPasswor}</td>
                    <td width="30%" align="left">
                        <input id="senha" type="password" name="password" value="#{UserMBean.user.password}" jsfc="h:inputSecret" required="true" label="#{msgs.labelPasswor}"/>
                    </td>
                    <td width="50%" align="left">
                        <label class="error" for="senha" jsfc="h:message"/>
                    </td>
                </tr>
                <tr>
                    <td>&nbsp;</td>
                    <td>
                        <input type="submit" value="#{msgs.buttonLogar}" jsfc="h:commandButton" id="logarPortal" action="#{UserMBean.logar}" />
                    </td>
                    <td><label class="error" for="logarPortal" jsfc="h:messages"/></td>
                </tr>
                <tr>
                    <td colspan="3">
                        <label class="error" jsfc="h:message" >
                            #{msgs.messageLoginError}
                        </label>
                    </td>
                </tr>
            </table>
        </form>

gostaria de retornar algo par o usuário caso o login ñ possa ser realizado

5 Respostas

Leozin

Seria interessante você carregar o teu ResourceBundle no teu código, criar uma chave nele com o erro que pode acontecer, por exemplo:

primeiro o tio vai lá e clica pra salvar um usuário

public String salvarUsuario() {
  try {
    salvarUmCertoUsuario( usuario );
  }
  catch( MinhaExcessaoDeNegocioException ex) {
    String mensagemInternacionalizada = getMessageResourceString( ex.getMessage(), ex.getParams() );
    algumMétodoQueCriaAsMessages( mensagemInternacionalizada );
  }
}
daí lá no teu método de salvarUmCertoUsuario ele pode jogar uma exception. Nessa exception, tu bota só a chave e os parametros
public void salvarUmCertoUsuario(Usuario usuario)  throws MinhaExcessaoDeNegocioException {
  if( usuarioDAO.listarPorNome( usuario.getNome() ).size() > 0 )
    throw new MinhaExcessaoDeNegocioException( "erros.usuario.existente", usuario.getNome() );
  usuarioDAO.salvar( usuario );
}

A tua exception poderia ser assim (olha que legal!)

public MinhaExcessaoDeNegocioException  extends Exception {
  private String key;
  private Object[] args;
  public MinhaExcessaoDeNegocioException( String key, Object... args ) {
    this.args = args;
    this.key = key;
  }
  // getters e setters
}
no teu ResourceBundle poderia ter a seguinte chave/valor:
erros.usuario.existente=Já existe um usuário com o nome {0}

há outras maneiras de se fazer um acesso ao resource bundle, mas eu fiz da seguinte maneira:

/**
	 * Obtém o ClassLoader de um objeto específico
	 * @param defaultObject O objeto cujo qual deseja-se adquirir o ClassLoader 
	 * @return O {@link ClassLoader} do objeto em questão
	 */
	private ClassLoader getCurrentClassLoader(Object defaultObject){
		
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		
		if(loader == null){
			loader = defaultObject.getClass().getClassLoader();
		}
		
		return loader;
	}

	/**
	 * Pega uma mensagem convertida para o Locale atual. Por exemplo, se a aplicação está rodando em
	 * inglês, o retorno será o valor que está no MessageBundle_en
	 * @param key Chave do valor. Ex.: pessoa (chave) person (retorno)
	 * @param params Parâmetros que complementam a mensagem. Seguem a ordem que foram inserida
	 * @return A mensagem convertida para o Locale Desejado
	 */
	public String getMessageResourceString( String key,	Object... params ) {

        String retorno;
        
        FacesContext ctx = FacesContext.getCurrentInstance();
        Locale locale = ctx.getViewRoot().getLocale();
        Application app = ctx.getApplication();
        
        ResourceBundle bundle = ResourceBundle.getBundle( 
        			app.getMessageBundle(), locale, getCurrentClassLoader( params ) );
        
        try{
        	retorno = bundle.getString(key);
        } catch(MissingResourceException e){
        	retorno = "????????????????? - " + key;
        }
        
        if(params != null){
            MessageFormat mf = new MessageFormat(retorno, locale );
            retorno = mf.format(params, new StringBuffer(), null).toString();
        }
        
        return retorno;
        }

Espero ter ajudado

abraço

robson_vs

No primeiro exemplo com a parte de exception fica mais elegante correto?

mais como ficaria a chamanda destas mensagens no meu view?

Leozin

no teu view você não faz nada, você simplesmente colocaria algo assim:

<h:messages />

porque você colocaria a mensagem pelo teu backing bean

FacesMessage mensagem = new FacesMessage( sumario, detalhe ); FacesContext.getCurrentInstance().addMessage( null, mensagem );

robson_vs

hum legal vou fazer uns teste para ver como fica qualquer coisa eu posto ai novamente.

por enquanto muito obrigado pela força

robson_vs
Leozin:
Seria interessante você carregar o teu ResourceBundle no teu código, criar uma chave nele com o erro que pode acontecer, por exemplo:

primeiro o tio vai lá e clica pra salvar um usuário

public String salvarUsuario() {
  try {
    salvarUmCertoUsuario( usuario );
  }
  catch( MinhaExcessaoDeNegocioException ex) {
    String mensagemInternacionalizada = getMessageResourceString( ex.getMessage(), ex.getParams() );
    algumMétodoQueCriaAsMessages( mensagemInternacionalizada );
  }
}
daí lá no teu método de salvarUmCertoUsuario ele pode jogar uma exception. Nessa exception, tu bota só a chave e os parametros
public void salvarUmCertoUsuario(Usuario usuario)  throws MinhaExcessaoDeNegocioException {
  if( usuarioDAO.listarPorNome( usuario.getNome() ).size() > 0 )
    throw new MinhaExcessaoDeNegocioException( "erros.usuario.existente", usuario.getNome() );
  usuarioDAO.salvar( usuario );
}

A tua exception poderia ser assim (olha que legal!)

public MinhaExcessaoDeNegocioException  extends Exception {
  private String key;
  private Object[] args;
  public MinhaExcessaoDeNegocioException( String key, Object... args ) {
    this.args = args;
    this.key = key;
  }
  // getters e setters
}
no teu ResourceBundle poderia ter a seguinte chave/valor:
erros.usuario.existente=Já existe um usuário com o nome {0}

há outras maneiras de se fazer um acesso ao resource bundle, mas eu fiz da seguinte maneira:

/**
	 * Obtém o ClassLoader de um objeto específico
	 * @param defaultObject O objeto cujo qual deseja-se adquirir o ClassLoader 
	 * @return O {@link ClassLoader} do objeto em questão
	 */
	private ClassLoader getCurrentClassLoader(Object defaultObject){
		
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		
		if(loader == null){
			loader = defaultObject.getClass().getClassLoader();
		}
		
		return loader;
	}

	/**
	 * Pega uma mensagem convertida para o Locale atual. Por exemplo, se a aplicação está rodando em
	 * inglês, o retorno será o valor que está no MessageBundle_en
	 * @param key Chave do valor. Ex.: pessoa (chave) person (retorno)
	 * @param params Parâmetros que complementam a mensagem. Seguem a ordem que foram inserida
	 * @return A mensagem convertida para o Locale Desejado
	 */
	public String getMessageResourceString( String key,	Object... params ) {

        String retorno;
        
        FacesContext ctx = FacesContext.getCurrentInstance();
        Locale locale = ctx.getViewRoot().getLocale();
        Application app = ctx.getApplication();
        
        ResourceBundle bundle = ResourceBundle.getBundle( 
        			app.getMessageBundle(), locale, getCurrentClassLoader( params ) );
        
        try{
        	retorno = bundle.getString(key);
        } catch(MissingResourceException e){
        	retorno = "????????????????? - " + key;
        }
        
        if(params != null){
            MessageFormat mf = new MessageFormat(retorno, locale );
            retorno = mf.format(params, new StringBuffer(), null).toString();
        }
        
        return retorno;
        }

Espero ter ajudado

abraço

Então cara estou meio atrapalhado por aqui gostaria de saber se pode me dar um help usando seu exemplo eu fiz as seguintes classes
public class Messages {

    /**  
     * Obtém o ClassLoader de um objeto específico  
     * @param defaultObject O objeto cujo qual deseja-se adquirir o ClassLoader  
     * @return O {@link ClassLoader} do objeto em questão  
     */   
    private ClassLoader getCurrentClassLoader(Object defaultObject){   
           
        ClassLoader loader = Thread.currentThread().getContextClassLoader();   
           
        if(loader == null){   
            loader = defaultObject.getClass().getClassLoader();   
        }   
           
        return loader;   
    }   
  
    /**  
     * Pega uma mensagem convertida para o Locale atual. Por exemplo, se a aplicação está rodando em  
     * inglês, o retorno será o valor que está no MessageBundle_en  
     * @param key Chave do valor. Ex.: pessoa (chave) person (retorno)  
     * @param params Parâmetros que complementam a mensagem. Seguem a ordem que foram inserida  
     * @return A mensagem convertida para o Locale Desejado  
     */   
    public String getMessageResourceString( String key, Object... params ) {   
  
        String retorno;   
           
        FacesContext ctx = FacesContext.getCurrentInstance();   
        Locale locale = ctx.getViewRoot().getLocale();   
        Application app = ctx.getApplication();   
           
        ResourceBundle bundle = ResourceBundle.getBundle(   
                    app.getMessageBundle(), locale, getCurrentClassLoader( params ) );   
           
        try{   
            retorno = bundle.getString(key);   
        } catch(MissingResourceException e){   
            retorno = "????????????????? - " + key;   
        }   
           
        if(params != null){   
            MessageFormat mf = new MessageFormat(retorno, locale );   
            retorno = mf.format(params, new StringBuffer(), null).toString();   
        }   
           
        return retorno;   
    }  
}
public class ViewException extends Exception {

    private String key;
    private Object[] msgs;
    
    /**
     * Creates a new instance of <code>ViewException</code> without detail message.
     */
    public ViewException() {
    }


    /**
     * Constructs an instance of <code>ViewException</code> with the specified detail message.
     * @param msg the detail message.
     */
    public ViewException(String key, Object... msgs) {
        this.key = key;
        this.msgs = msgs;
    }

    /** Methodos Getters e Setters para os atributos */
    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public Object[] getMsgs() {
        return msgs;
    }

    public void setMsgs(Object[] msgs) {
        this.msgs = msgs;
    }
}
mais estou me atrapalhando na parte do mbean na hora de chamar os metodos, fique meio em duvida de como deveria chamar os metodos de uma olhada de como estou fazendo
public class UserMBean {

    private User user = new User();
    private Messages messages = new Messages();
    
    /** Cria uma nova instancia de UserMBean */
    public UserMBean() {
    }

    /** Methodo para efetuar o login no portal */
    public String logar(){
        
        String retorno = null;
        try{
            login(user); 
            retorno = "success";
        }catch(ViewException ex) {   
            retorno = "failure";
            logout();
            String mensagem = messages.getMessageResourceString(ex.getKey(), ex.getMsgs());
            getMessages(mensagem);
        } 
        return retorno;
    }
    public void login(User user)throws ViewException{
        String usuario = user.getId();
        String senha =user.getPassword();
        
        UserDao dao =  new UserDao();
        User userDB = dao.find(usuario);
        if(userDB!=null){
            if(userDB.getId().equals(usuario) && userDB.getPassword().equals(senha)){

                HttpServletRequest request = (HttpServletRequest) FacesContext
                                                            .getCurrentInstance().getExternalContext()
                                                            .getRequest();
                HttpSession session = request.getSession();
                session.setAttribute("usuario", usuario);

                usuario = (String) session.getAttribute("usuario");
                System.out.print("login efetudado com sucesso para: " + usuario + " com senha: " + senha);
                user = new User();
            }else{
                throw new ViewException("messageLoginError", usuario);
            }
        }
    }
    private void getMessages(String message) {
        
    }
}
no momento esta me retornando na linha 20 da classe UserMBean
Caused by: java.lang.NullPointerException
Criado 20 de fevereiro de 2008
Ultima resposta 26 de fev. de 2008
Respostas 5
Participantes 2