转换器:
@FacesConverter("bigDecimalConverter")
public class BigDecimalConverter implements Converter {
private static final int SCALE = 2;
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
return new BigDecimal(value);
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "Message"), e);
}
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return "";
}
BigDecimal newValue;
if (value instanceof Long) {
newValue = BigDecimal.valueOf((Long) value);
} else if (value instanceof Double) {
newValue = BigDecimal.valueOf((Double) value);
} else if (!(value instanceof BigDecimal)) {
throw new ConverterException("Message");
} else {
newValue = (BigDecimal) value;
}
DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance();
formatter.setGroupingUsed(false);
formatter.setMinimumFractionDigits(SCALE);
formatter.setMaximumFractionDigits(SCALE);
return formatter.format(newValue);
}
}
列表:
<p:selectOneMenu id="list" value="#{bean.value}">
<f:selectItems var="row" value="#{bean.list}" itemLabel="#{row}" itemValue="#{row}"/>
<f:converter converterId="bigDecimalConverter"/>
</p:selectOneMenu>
<p:message id="msg" for="list"/>
<p:commandButton value="Submit" update="list msg" actionListener="#{bean.action}"/>
上述<p:selectOneMenu>
支持的托管bean:
@ManagedBean
@ViewScoped
public class Bean implements Serializable {
private List<BigDecimal> list; // Getter only.
private BigDecimal value; // Getter & setter.
private static final long serialVersionUID = 1L;
public Bean() {}
@PostConstruct
private void init() {
list = new ArrayList<BigDecimal>(){{
add(BigDecimal.valueOf(10));
add(BigDecimal.valueOf(20.11));
add(BigDecimal.valueOf(30));
add(BigDecimal.valueOf(40));
add(BigDecimal.valueOf(50));
}};
}
public void action() {
System.out.println("action() called : " + value);
}
}
验证消息,&#34;验证错误:值无效&#34;在提交表格时出现。表单提交时getAsObject()
方法不会抛出任何异常。
如果在列表中选择了具有20.11
等比例的值,则验证通过。似乎equals()
类中的java.math.BigDecimal
方法变得可疑,例如,认为两个BigDecimal
个对象相等,只要它们的值和规模相等{{1}这需要10.0 != 10.00
才能使它们相等。
有什么建议吗?
答案 0 :(得分:1)
转换为String时丢失信息。默认的JSF BigDecimalConverter执行此操作,它在BigDecimal#toString
中使用getAsString
。 BigDecimal#toString
的javadoc说:
可区分的BigDecimal值与此转换的结果之间存在一对一的映射关系。也就是说,每个可区分的BigDecimal值(未缩放的值和比例)都具有使用toString的结果的唯一字符串表示形式。如果使用BigDecimal(String)构造函数将该字符串表示形式转换回BigDecimal,则将恢复原始值。
这正是您所需要的。不要对转换器进行处理,因为它们在转换为String时必须产生用户可读写的结果。他们一定不能也常常不会。它们生成对象的String表示或对象引用。而已。在这种情况下,selectItems
'itemLabel
定义了用户可读的表示。我假设您不想在此处使用用户可写值,您确实有一个固定的值列表供用户选择。
如果你的意思是这个数据必须始终具有2的标度,并且你需要一个用户可写值,那么在验证器中可以更好地检查它,并且p:inputMask
可以帮助输入用户输入。
最后,让我们撇开你的转换器不是最好的事实。它说“数据的比例必须为2”。然后,您应该在selectItems
中提供符合要求的数据。更一般地,服务器定义的值必须符合相关的转换器和验证器。例如。当使用带有模式DateTimeConverter
的{{1}}时,你可能会遇到同样的问题,但是在没有删除时间部分的情况下将默认值设置为"dd.MM.yyyy"
。
另请参阅(有关转换器的更一般概念):https://stackoverflow.com/a/30529976/1341535