为什么我的bean验证消息没有被拾取?

问题描述:

我为后来的i18n定义了一些bean验证消息。 此消息应验证输入的类型是数/ BigDecimal的:为什么我的bean验证消息没有被拾取?

class Payment { 
    @Digits(message = "test error msg", fraction = 2, integer = 13) 
    private BigDecimal amount; 
} 

<p:inputText value="#{payment.amount}" /> 

不幸的是,如果我尝试输入文本,我没有得到我的定义味精,但:

'asd' must be a signed decimal number 

莫非有人解释为什么?或者说,我如何强制我的输入字段始终使用@Digits进行验证?

在JSF验证后转换发生。如果您在映射到backing bean中的BigDecimal的文本字段中输入的数字不是数字,JSF将尝试将其转换为BigDecimal,当然它会失败。所以Hibernate验证器不会真的有机会参与其中。您需要本地化JSF转换消息才能达到您想要的效果。

我不熟悉@Digits注解。但Hibernate Validator docs似乎表明它验证数字是否使用了预期的整数和小数位数。因此,不要在文本字段中输入文本,而是尝试输入与验证程序无法接受的格式相同的值(在您的情况下,fraction = 2,integer = 13)。所以请尝试输入值123.123120,看看你是否得到预期的消息。

下面是进入实体并在转换器中获取注释的黑客入侵。首先,你需要创建一些自定义的转换器(在这种情况下,BigDecimal)的:

@FacesConverter("MyBigDecimalConverter") 
public class MyBigDecimalConverter extends NumberConverter { 
@Override 
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) { 
    try { 
     HtmlInputText it = (HtmlInputText) arg1; 
     ValueExpression ve = it.getValueExpression("value"); 
     String expression = ve.getExpressionString(); 
     String field = expression.replaceAll("#\\{.*\\.", ""); 
     field = field.replace("}", ""); 
     String parent = expression.replace("." + field, ""); 
     ExpressionFactory expressionFactory = arg0.getApplication().getExpressionFactory(); 
     ValueExpression exp = expressionFactory.createValueExpression(arg0.getELContext(), parent, Object.class); 
     Object obj = exp.getValue(arg0.getELContext()); 

     Digits d = null;  
     Field f = obj.getClass().getDeclaredField(field); 
     d = f.getAnnotation(Digits.class); 
     return super.getAsObject(arg0, arg1, arg2); 
    } catch (ConverterException e) { 
     FacesMessage msg = new FacesMessage(d.message()); 
     msg.setSeverity(FacesMessage.SEVERITY_ERROR); 
     throw new ConverterException(msg); 
    } catch (Exception e) { 
     return super.getAsObject(arg0, arg1, arg2); 
    } 
} 

@Override 
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) { 
    return super.getAsString(arg0, arg1, arg2); 
} 

} 

而且你需要使用转换器在你的页面:

<h:outputText value="#{someBean.someEntity.nome}" /> 
    <h:form> 
     <p:inputText value="#{someBean.someEntity.someBigDecimal}" id="test"> 
      <f:converter converterId="MyBigDecimalConverter" /> 
     </p:inputText> 
     <h:message for="test"></h:message> 
     <p:commandButton value="teste" process="@form" update="@form"></p:commandButton> 
    </h:form> 

我在这里使用primeFaces组件,但你并不需要它们。

转换器到底在做什么?它正在获取bean中保存inputText引用的值和字段名称的对象。然后,它找到该字段的@Digits注释并读取其消息。它要求NumericConverter将字符串转换为数字。如果失败,它将使用@Digits注释中的消息来显示错误消息。

+0

是的,当我做了一个输入,通过jsf我得到相应的hib验证器味精。 – membersound 2012-02-28 16:02:09

+0

我想那回答你的问题呢?我很高兴能够提供帮助。干杯 – Andre 2012-02-28 16:25:58

+0

不是。我仍然试图强制验证休眠,并跳过jsf验证。如下所述,即使我完全删除标签,f:validateBean也不适用于我。 JSF似乎默认将映射验证为支持BigDecimal。而且我还没有找到任何可以禁用这个特定功能的东西。 – membersound 2012-02-28 17:11:14

您应该使用<f:validateBean />来验证委托给Bean验证API(JSR 303)

<p:inputText value="#{payment.amount}" > 
    <f:validateBean /> 
</p:inputText> 
+0

这很奇怪。我试过这个标签,但它不起作用。即使我完全删除验证标签,仍然会发生JSF验证。 – membersound 2012-02-28 16:02:35

不知道这<p:inputText>标签,但在香草JSF你可以只:

<h:inputText id="price" 
    value="#{movieController.movie.price}" redisplay="true" 
    converterMessage="Please input a decimal"> 
    <f:ajax event="blur" render="numberOfCopiesMessage" /> 
</h:inputText> 

通知的converterMessage属性。

虽然这可能看起来像违反DRY(因为您已经在实体中有消息),但它没有。您的模型与提交'asd'作为整数的用户无关 - 它确实是视图内容