一、问题出现背景
- 返回json结果中如果有通过计算获取的double值,小数点后面有很多位小数
{
"payable": 25.00000000021
}
二、可能原因及尝试过程:
1、原因是double类型计算是不准确的,所以需要处理结果
2、百度找到序列化double的文章使用自定义序列化方法添加json注解解决返回数据double限定小数点后几位长度,多余的舍弃以及double数据控制保留小数的几种方法,关于Java中DecimalFormat()方法的调用
- 添加注解@JsonSerialize
@JsonSerialize(using = Double2Serializer.class)
private Double payable;
- 自定义序列化对象方法(注意此处JsonSerializer<Object>中的Object是对象类型的泛型,而不能用基本数据类型,编辑器会提示报错的,如double)
public class Double2Serializer extends JsonSerializer<Double> {
private DecimalFormat df = new DecimalFormat("0.00");
{
//显示几位修改几
df.setMaximumFractionDigits(2);
df.setGroupingSize(0);
//默认向上取整,这里直接舍去后面几位
df.setRoundingMode(RoundingMode.FLOOR);
}
@Override
public void serialize(Double doubleValue, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (Objects.nonNull(doubleValue)) {
// 返回出去是字符串
jsonGenerator.writeString(df.format(doubleValue));
// 返回出去是数字形式
//jsonGenerator.writeNumber(df.format(doubleValue));
} else {
System.err.println("====== null居然处理了 =====");
jsonGenerator.writeString(df.format(0.0));
//jsonGenerator.writeNumber(df.format(0.0));
}
}
}
- 结果是对小数只保留了两位小数,但对null仍然不做处理
package com.fasterxml.jackson.databind.ser;
@JacksonStdImpl
public class BeanPropertyWriter extends PropertyWriter implements Serializable {
private static final long serialVersionUID = 1L;
public static final Object MARKER_FOR_EMPTY;
protected final SerializedString _name;
protected final PropertyName _wrapperName;
protected final JavaType _declaredType;
protected final JavaType _cfgSerializationType;
protected JavaType _nonTrivialBaseType;
protected final transient Annotations _contextAnnotations;
protected final AnnotatedMember _member;
protected transient Method _accessorMethod;
protected transient Field _field;
protected JsonSerializer<Object> _serializer;
protected JsonSerializer<Object> _nullSerializer;
protected TypeSerializer _typeSerializer;
protected transient PropertySerializerMap _dynamicSerializers;
protected final boolean _suppressNulls;
protected final Object _suppressableValue;
protected final Class<?>[] _includeInViews;
protected transient HashMap<Object, Object> _internalSettings;
public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
Object value = this._accessorMethod == null ? this._field.get(bean) : this._accessorMethod.invoke(bean, (Object[])null);
// 对null用全局处理,无法继承重写方法
if (value == null) {
if (this._nullSerializer != null) {
gen.writeFieldName(this._name);
this._nullSerializer.serialize((Object)null, gen, prov);
}
} else {
JsonSerializer<Object> ser = this._serializer;
if (ser == null) {
Class<?> cls = value.getClass();
PropertySerializerMap m = this._dynamicSerializers;
ser = m.serializerFor(cls);
if (ser == null) {
ser = this._findAndAddDynamic(m, cls, prov);
}
}
if (this._suppressableValue != null) {
if (MARKER_FOR_EMPTY == this._suppressableValue) {
if (ser.isEmpty(prov, value)) {
return;
}
} else if (this._suppressableValue.equals(value)) {
return;
}
}
// 自定义序列化
if (value != bean || !this._handleSelfReference(bean, gen, prov, ser)) {
gen.writeFieldName(this._name);
if (this._typeSerializer == null) {
ser.serialize(value, gen, prov);
} else {
ser.serializeWithType(value, gen, prov, this._typeSerializer);
}
}
}
}
}
符号 | 位置 | 本地化? | 含义 |
0 | 数字 | 是 | 阿拉伯数字 |
# | 数字 | 是 | 阿拉伯数字 如果不存在就显示为空 |
. | 数字 | 是 | 小数分隔符或货币小数分隔符 |
- | 数字 | 是 | 减号 |
, | 数字 | 是 | 分组分隔符 |
E | 数字 | 是 | 分割科学技术法中的尾数和指数。在前缀和后缀中无需添加引号 |
; | 子模式边界 | 是 | 分隔正数和负数子模式 |
% | 前缀或后缀 | 是 | 乘以100并显示为百分数/u2030前缀或后缀是乘以1000并显示为千分数 |
¤ (\u00A4) | 前缀或后缀 | 否 | 货币记号,由货币符号替换。如果两个同时出现,则用国际货币符号替换。如果出现在某个模式中,则使用货币小数分隔符,而不使用小数分隔符 |
' | 前缀或后缀 | 否 | 用于在前缀或或后缀中为特殊字符加引号,例如 "'#'#" 将 123 格式化为 "#123"。要创建单引号本身,请连续使用两个单引号:"# o''clock" |
double pi = 3.1415927;//圆周率
//取一位整数
System.out.println(new DecimalFormat("0").format(pi));//3
//取一位整数和两位小数
System.out.println(new DecimalFormat("0.00").format(pi));//3.14
//取两位整数和三位小数,整数不足部分以0填补。
System.out.println(new DecimalFormat("00.000").format(pi));// 03.142
//取所有整数部分
System.out.println(new DecimalFormat("#").format(pi));//3
//以百分比方式计数,并取两位小数
System.out.println(new DecimalFormat("#.##%").format(pi));//314.16%
/**
* 上面的代码就是网上很经典的案例,下面我们来分析另外的一个值
*/
pi=12.34567;
//取一位整数
System.out.println(new DecimalFormat("0").format(pi));//12
//取一位整数和两位小数
System.out.println(new DecimalFormat("0.00").format(pi));//12.35
//取两位整数和三位小数,整数不足部分以0填补。
System.out.println(new DecimalFormat("00.000").format(pi));// 12.346
//取所有整数部分
System.out.println(new DecimalFormat("#").format(pi));//12
//以百分比方式计数,并取两位小数
System.out.println(new DecimalFormat("#.##%").format(pi));//1234.57%
/**
* 扩展,如果是其他的数字会是下面的效果
*/
pi=12.34;
//整数
System.out.println(new DecimalFormat("6").format(pi));//612
System.out.println(new DecimalFormat("60").format(pi));//612
System.out.println(new DecimalFormat("06").format(pi));//126
System.out.println(new DecimalFormat("00600").format(pi));//00126
System.out.println(new DecimalFormat("#####60000").format(pi));//00126
//小数
System.out.println(new DecimalFormat(".6").format(pi));//12.6
System.out.println(new DecimalFormat(".06").format(pi));//12.36
System.out.println(new DecimalFormat(".60").format(pi));//12.36
System.out.println(new DecimalFormat(".0600").format(pi));//12.3406
System.out.println(new DecimalFormat(".6000").format(pi));//12.3406
System.out.println(new DecimalFormat(".600000##").format(pi));//12.340006
三、最终解决:
- 使用自定义对象 Double2Serializer 处理 Double 的值,但是对 null 是不做处理的。
- 对计算结果进行处理,如果为 null 转为0(然后非null会序列化为0.00),或者根据需要不做处理(还是显示null)
备注: 本文主要是借助博客环境,同大家讨论异常问题解决的办法,欢迎大家评论,谢谢! |