工作中有一个需求,在填写一些金额和面积数据时,要求新增时前端传double类型,后端将其乘以10000并转换为Long类型,存入数据库
返回详情时后端又将其除以10000并转换为double类型返回给前端
以此来达到精度不丢失的情况(这种情况我以前一直用的是BigDecimal,觉得没啥问题,组长却告诉我会有精度丢失,有知道原因的兄弟能帮我解答下吗)
一开始,我是打算直接在后台get字段数据转换即可
但是后面数据量太庞大了,造成代码很多,就想着写个自定义注解来解决.在网上看了一下,最后实现了
上图这是原来的写法,可以看到,如果数据量再大一些,就只有继续往后添加,太麻烦了
现在我们来写自定义注解
当初我是看的这篇文章(附原文地址:fastJson 自定义注解和过滤器完成自定义序列化 - 简书)
整个创建步骤:
1.创建注解,在这里注解只作为一个标识
2.准备两个自定义类(A类,B类),字段名相同,数据类型不同(将传来的A类中的字段转换类型,最后再转成B类)
3.通过阿里的JSON中toJSONStirng()方法来进行数据转换,传一个转换Filter
4.自定义转换逻辑,创建类去实现ValueFilter接口,重写process()方法
5.将需要转换的对象通过toJSONStirng()方法转换为String字符串,再将字符串转为想要的类
fastjson支持6种SerializeFilter,用于不同场景的定制序列化。
PropertyPreFilter 根据PropertyName判断是否序列化
PropertyFilter 根据PropertyName和PropertyValue来判断是否序列化
NameFilter 修改Key,如果需要修改Key,process返回值则可
ValueFilter 修改Value
BeforeFilter 序列化时在最前添加内容
AfterFilter 序列化时在最后添加内容
一. 创建注解
/**
* double类型转为Long类型
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DoubleCovertToLong {
public String value() default "true";
}
/**
* Long类型转为double类型
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface LongCovertToDouble {
public String value() default "true";
}
二. 准备A类B类,字段名相同,数据类型不同
接收前端传的Double类型
A类
/** 建设规模(公顷) */
@DoubleCovertToLong
private Double constrArea;
/** 预计投资金额 */
@DoubleCovertToLong
private Double investMoney;
后端入数据库的Long类型
B类
/** 建设规模(公顷) */
@LongCovertToDouble
private Long constrArea;
/** 预计投资金额 */
@LongCovertToDouble
private Long investMoney;
三. 自定义类实现ValueFilter接口,重写process方法,实现转换逻辑
/**
* 转换类-Long
*/
public class BeanPropertyToLangFilter implements ValueFilter {
private Field field = null;
@Override
public Object process(Object obj, String name, Object value) {
Boolean flag = false;
try {
field = obj.getClass().getDeclaredField(name);
// 获取注解
flag = field.getAnnotation(DoubleCovertToLong.class).value().equals("true");
if (flag == true && value != null) {
// 这里 其他类型转换成Long类型
// value += "";
value = Double.valueOf((Double) value*10000).longValue();
}
} catch (NoSuchFieldException e) {
return value;
} catch (Exception e) {
return value;
}
return value;
}
}
/**
* 转换类-Double
*/
public class BeanPropertyToDoubleFilter implements ValueFilter {
private Field field = null;
@Override
public Object process(Object obj, String name, Object value) {
Boolean flag = false;
try {
field = obj.getClass().getDeclaredField(name);
// 获取注解
flag = field.getAnnotation(LongCovertToDouble.class).value().equals("true");
if (flag == true && value != null) {
// 这里 其他类型转换成Double类型
value = Double.parseDouble(value.toString())/10000;
}
} catch (NoSuchFieldException e) {
return value;
} catch (Exception e) {
return value;
}
return value;
}
}
四. 具体实现
新增,Double->Long
try {
// 创建转换工具类对象
BeanPropertyToLangFilter beanPropertyToLangFilter =new BeanPropertyToLangFilter();
// 转换
String jsonString = JSON.toJSONString(a, beanPropertyToLangFilter);
b = JSON.parseObject(jsonString, b.getClass());
} catch (Exception e) {
throw new RuntimeException(e);
}
详情,Long-> Double
try {
// 创建转换工具类对象
BeanPropertyToDoubleFilter beanPropertyToDoubleFilter =new BeanPropertyToDoubleFilter();
String jsonString = JSON.toJSONString(b, beanPropertyToDoubleFilter);
// 转换
a = JSON.parseObject(jsonString,a.getClass());
}catch(Exception e){
throw new RuntimeException(e);
}
注意: 大家在运行时可以debug调试,在转为json字符串时,实际上是发现该对象所有字段上包含
@DoubleCovertToLong注解的或者包含@LongCovertToDouble注解的字段
然后如果你还要进行其他的重新赋值操作,建议先转换完类型之后再做其他操作,不然会有数据丢失的情况,具体的大家可以调试