Dúvida >> JSF e h:message

Bom dia galera.

Estou quebrando a cabeça aqui e não acho solução. Tenho um sistea de vendas e na página de produtos tenho que validar se o valor a ser vendido do produto é menor que o valor mínimo.
Caso seja tenho que apresentar uma mensagem dizendo que não é possível efetuar a venda pois o valor está abaixo do valor mínimo.

Tenho a página: (trecho)

<h:outputText value="#{msg.novo_item_campo_quantidade}" /><br />
                        <h:inputText id="qtde" value="#{pedidoHandler.item.qtde}" size="10" >
                            <f:validator validatorId="QuantidadeValidator" />
                        </h:inputText><br />
                        <h:message for="qtde" style="color:red; display:block;" />

                        <h:outputText value="#{msg.novo_item_campo_preco_sugerido}" /><br />
                        <h:inputText id="preco" value="#{pedidoHandler.item.precoSugerido}" readonly="#{true}" size="10" >
                            <f:convertNumber type="currency" />
                        </h:inputText><br />

                        <h:outputText value="#{msg.novo_item_campo_preco_praticado}" /><br />
                        <h:inputText id="valor_prat" value="#{pedidoHandler.item.precoPraticado}" size="10" >
                            <f:converter converterId="MoedaConverter" />
                        </h:inputText><br />
                        <h:message for="valor_prat" style="color:red; display:block;" />

                        <h:commandButton id="add" value="#{msg.novo_item_botao_adicionar}" action="#{pedidoHandler.adicionarItem}" />

e o método do managed ban que eu chamo como ação do botão:

 public String adicionarItem() {
        if (item.getPrecoPraticado() <= item.getPrecoMinimo()) {
            FacesContext.getCurrentInstance().addMessage("valor_prat", new FacesMessage(FacesMessage.SEVERITY_ERROR, "Valor praticado menor que valor mínimo", null));
            return "";
        } else {
            pedido.adicionaItem(item);
            item = new Item();
            return "adiciona_item";
        }
    }

Isso não é possível pois o ID do inputtext que deveria ser “valor_prat” vem como “j_id_jsp_738430882_1:valor_prat” dai eu não encontro o componente e a mensagem não é exibida.

Alguém sabe como resolver isso ou tem outra solução??

Você está explicitando o id do form?
Lembrando que, em JSF, o id de um componente é composto por: [id do form]:[id componente] (repare os “:” entre os ids).
Deve ser isso.

Bom dia Tchello.

Cara, consegui resolver com isso. Coloquei um id para o form e na hora de passar uma mensagem para o componente, coloquei o nome id do form com : e o nome do componente. Assim:

FacesContext.getCurrentInstance().addMessage("form:valor_prat", new FacesMessage(FacesMessage.SEVERITY_ERROR, "Valor praticado menor que valor mínimo", null));

Resolvido.

Agora estou com outro problema na mesma página, porém com outro componente.

<h:outputText value="#{msg.novo_item_campo_quantidade}" /><br />
<h:inputText id="qtde" value="#{pedidoHandler.item.qtde}" size="10" >
  <f:validator validatorId="QuantidadeValidator" />
</h:inputText><br />
<h:message for="qtde" style="color:red; display:block;" />

Esse daqui é um campo comum que deve ser inserido um valor inteiro para a quantidade. Eu criei um validador para checar se foi inserido a informação correta:

public void validate(FacesContext context, UIComponent component, Object value)
            throws ValidatorException {

        int x;

        try {
            x = Integer.parseInt(value.toString());
        } catch (NumberFormatException ex) {
            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Quantidade deve ser um valor inteiro", null);
            throw new ValidatorException(message);
        }

        if (x <= 0) {
            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Quantidade deve ser um valor positivo", null);
            throw new ValidatorException(message);
        }
    }

Quando eu digito um valor negativo aparece normalmente a mensagem: “Quantidade deve ser um valor positivo”, mas quando eu digito uma String qualquer (“lalala”, por exemplo) aparece a seguinte mensagem:

                  "form:qtde: 'lalala' must be a number between -2147483648 and 2147483647 Example: 9346"

É como se o JSF fizesse uma validação desse campo antes de mim, ou seja, meu validador nem foi chamado!!

Obs: estou vinculando esse campo a um atributo do tipo inteiro no meu ManagedBean!!

Você deveria ter um conversor para Integer declarado nesse input.
Ele fará o trabalho de conversão pra você (descartando o Integer.parseInt()) e você pode simplesmente fazer um cast no value para Integer (uma verificação com instanceof antes seria bom).
Assim você simplesmente altera a mensagem no faces-messages em vez de ficar lançando suas próprias exceções!

Guilherme.

O conversor seria só para verificar se eu informei um valor correto ou caso eu insira uma String qualquer esse conversor converteria minha String para inteiro??

Eu gostaria apenas de informar para o usuário de que o valor que ele inseriu não se adequa ao esperado no campo!!

Pq vc diz que seria melhor fazer um conversor do que um validador?? O conversor tem prioridade sobre o validador??

Desculpe tantas dúvidas, é que trabalho com JSF a pouco tempo e ainda não tenho todas as manhas!!

Tudo que vem da pagina (na requisicao) vem na forma de Strings. Por isso dos conversores, que transformam essas Strings em Integers, Shorts, etc (ou até classes próprias suas!!!).

Esse é o trabalho do conversor, você não deveria ter que fazer isso num validador. O validador serve pra verificar se o dado está correto. No seu caso, verificar se o dado é um inteiro positivo.
Você até pode deixar do jeito que está, se for trabalhar com String, mas não acredito que seja o caso ^^

Da uma olhada em faces messages e como customiza-las, para arrumar a mensagem de erro que você estava reclamando.

Resolvi da seguinte maneira:

no componente apenas adicionei um converterMessage com a mensagem: “Quantidade deve ser um valor inteiro”. Pois quando o valor digitado não é um inteiro, como esperado, o próprio jsf tenta fazer a conversão, sem precisar de eu criar um novo converter, e me manda essa mensagem!!

Valeu Guilherme.

Não vale a pena colocar também algumas máscaras JavaScript?
Se quiser tenho umas aqui com ER que funcionam muito bem!

Abraços.

Tchello, se você puder me mandar ou postar aqui seria muito bom. Me ajudaria também!!

Obrigado!

Achei tudo no google e mesmo assim deu trabalho pra encontrar.
Tem uma alteraçãozinha minha bem gambiarrenta, fiz quando não manjava nadinha de ER.
A vantagem de usar ER é que além de ficar um código BEM enxuto (contra um codigo gigantesco que era usado anterior) ele não permite NADA mais além do que você deixou, impedir caracteres especiais era uma dor de cabeça antes dessas máscaras:

function Mascara(o,f){
    v_obj=o
    v_fun=f
    setTimeout("execmascara()",1)
}
function execmascara(){ 
    v_obj.value=v_fun(v_obj.value)
}
function Data(v){
    v=v.replace(/\D/g,"")
    v=v.replace(/(\d{2})(\d)/,"$1/$2")
    v=v.replace(/(\d{2})(\d)/,"$1/$2")
    return v
}
function Integer(v){
    return v.replace(/\D/g,"")
}
function Valor(v){
    v = v.replace(/\D/g,"") //Remove tudo o que não é dígito
    v = v.replace(/^([0-9]{3}\.?){3}-[0-9]{2}$/,"$1.$2");
    //v=v.replace(/(\d{3})(\d)/g,"$1,$2")
    v = v.replace(/(\d)(\d{2})$/,"$1.$2") //Coloca ponto antes dos 2 últimos digitos
    
    if(v.value.length == 0 ){
        v.value = "0";
    }
    if(v.value.length == 1){
        v.value = "0.0"+v.value;
    }
    if(v.value.length == 2){
        v.value = "0."+v.value;
    }
    return v
}
function Cep(v){
    v=v.replace(/D/g,"")
    v=v.replace(/^(\d{5})(\d)/,"$1-$2")
    return v
}
function Cnpj(v){
    v=v.replace(/\D/g,"")
    v=v.replace(/^(\d{2})(\d)/,"$1.$2")
    v=v.replace(/^(\d{2})\.(\d{3})(\d)/,"$1.$2.$3")
    v=v.replace(/\.(\d{3})(\d)/,".$1/$2")
    v=v.replace(/(\d{4})(\d)/,"$1-$2")
    return v
}
function Cpf(v){
    v=v.replace(/\D/g,"")
    v=v.replace(/(\d{3})(\d)/,"$1.$2")
    v=v.replace(/(\d{3})(\d)/,"$1.$2")

    v=v.replace(/(\d{3})(\d{1,2})$/,"$1-$2")
    return v
}
function Telefone(v){
    v=v.replace(/\D/g,"")
    v=v.replace(/^(\d\d)(\d)/g,"($1) $2")
    v=v.replace(/(\d{4})(\d)/,"$1-$2")
    return v
}
function Hora(v){
    v=v.replace(/\D/g,"")
    v=v.replace(/(\d{2})(\d)/,"$1:$2")
    return v
}

Não precisa usar dessa forma, mas fique a vontade.

Tchello, muito obrigado!!

Vai ser muito útil também!!
Valeu!

Você também pode acrescentar o seguinte parâmetro no form: prependId=“false”
Assim, o id do input não será prefixado pelo id do form. Mais detalhes: http://www.rponte.com.br/2008/07/01/jsf-e-naming-container/