1

问题:需要通过 JSF 格式化 BigDecimal,但是 JSF 破坏了 BigDecimal 的精度。

JSF:

<h:outputText value="#{webUtilMB.roundUp(indexPrice.percentage, 2)}"/>

爪哇:

public class IndexPrice {
  public BigDecimal getPercentage(){ return new BigDecimal("1.325"); }
}

@ManagedBean("webUtilMb")
public class WebUtilManagedBean{
  public BigDecimal roundUp(BigDecimal dbvalue, int scale){
    return dbvalue.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP);
  }
}

在 WebUtilManagedBean.roundUp 方法中有一个断点显示“dbvalue”是“1.3249999999999999555910790149937383830547332763671875”而不是“1.325”。

然后我重载了 WebUtilManagedBean 中的 roundUp 方法:

public Double roundUp(Double dvalue, int scale){
  System.out.println(dvalue);
}

在这个重载方法中有一个断点时让我感到惊讶的是: - 'dvalue' 是 '1.325',这是正确的。- 该方法实际上被调用而不是 roundUp(BigDecimal, int) 方法。

后来我尝试了 BigDecimal 构造函数,结果如下:

BigDecimal db1 = new BigDecimal("1.325"); -> 1.325
BigDecimal db2 = new BigDecimal(1.325d); -> 1.3249999999999999555910790149937383830547332763671875

理论:从上面看,似乎 JSF 将我的 BigDecimal 值转换为 String,而不是 Double,而不是在值上调用“new BigDecimal(double)”来获取 BigDecimal - 它返回错误的值。


修复:解决此问题的一种方法是使用以下代码:

@ManagedBean("webUtilMb")
public class WebUtilManagedBean{
  public Double roundUp(Double dvalue, int scale){
    return this.roundUp(**new BigDecimal(dvalue.toString())**, BigDecimal.ROUND_HALF_UP);
  }
  public BigDecimal roundUp(BigDecimal dbvalue, int scale){
    return dbvalue.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP);
  }
}

但这对我来说似乎是一种黑客行为。

有关解决此问题的任何想法及其背后的原因。谢谢。

4

1 回答 1

2

理想情况下,如果 f:convertNumber 具有“舍入”属性,则可以通过它来完成,但事实并非如此。

干净的方法是编写自己的综合 f:converter 类,并在 XHTML 中的适当位置使用 f:converter 标记,而不是使用 EL 方法调用。您的转换器将获得作为对象的值,即 BigDecimal,并负责将其转换为字符串本身。请参阅 f:converter 的文档。很惊讶 JSF 没有正确地做到这一点,但我想一旦你进入 EL 方法调用,一切都是一个字符串。像这样的东西(警告:未经测试):

import java.math.BigDecimal;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

/**
 * Use via e.g.:
 * <pre>
 * &lt;h:outputText value="#{EL}"&gt;
 *  &lt;f:converter id="com.edsi.jsf.RoundHalfUp"/&gt;
 *  &lt;f:attribute name="decimalPlaces" value="2"/&gt;
 * &lt;/h:outputText&gt;
 * <pre>
 * @author Esmond Pitt
 */
@FacesConverter(value="com.edsi.jsf.RoundHalfUp")
public class RoundHalfUpConverter implements Converter
{

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value)
    {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value)
    {
        BigDecimal  bd = (BigDecimal)value;
        int decimalPlaces;
        try
        {
            decimalPlaces = Integer.parseInt((String)component.getAttributes().get("decimalPlaces"));
        }
        catch (Exception exc)
        {
            decimalPlaces = 2;  // or whatever
        }
        return bd.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP).toString();
    }

}
于 2013-02-04T04:25:07.427 回答