spring boot - 格式化 金额

spring boot - 格式化 金额

场景

业务场景上要对后端返回金额类型字段的数据进行格式化处理,保留两位小数,不足的补0

方案

要求对返回数据格式化,那只能在序列化的下手脚了

CurrencyFormatterSerializer2

所有金额类型返回 string 类型(好像不太完美,但也合理)

public class CurrencyFormatterSerializer2 extends JsonSerializer<Object> {
    private static final DecimalFormat FORMAT = new DecimalFormat("0.00");

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        try {
            gen.writeString(FORMAT.format(Double.parseDouble(value.toString())));
        } catch (NumberFormatException e) {
            throw new RuntimeException("异常");
        }
    }

}

测试:

@NoArgsConstructor
@Data
public class QueryTranDetailResp {

    @JsonSerialize(using = CurrencyFormatterSerializer2.class)
    private String str;

    @JsonSerialize(using = CurrencyFormatterSerializer2.class)
    private Double d1;

    @JsonSerialize(using = CurrencyFormatterSerializer2.class)
    private Float f1;
}

缺点就是 只能格式化一种类型,每次都要重写,还这么长。。

CurrencyFormatterSerializer

目的可以指定格式

1.定义注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@JacksonAnnotationsInside
@JsonSerialize(using = CurrencyFormatterSerializer.class)
public @interface CurrencyFormatter {

    /**
     * 格式化精度
     * @return
     */
    String pattern() default "0.00";

    /**
     * 取整类型
     * @return
     */
    RoundingMode mode() default RoundingMode.HALF_UP;
}

2.CurrencyFormatterSerializer

@Slf4j
public class CurrencyFormatterSerializer extends JsonSerializer<Object> implements ContextualSerializer {

    private String pattern;
    private RoundingMode mode;

    private static Map<String, CurrencyDecimalFormat> map = new ConcurrentHashMap<>();

    /**
     * 反序列化默认无参构造函数
     */
    public CurrencyFormatterSerializer() {
    }

    public CurrencyFormatterSerializer(String pattern, RoundingMode mode) {
        this.pattern = pattern;
        this.mode = mode;
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        //key = pattern.concat(mode.toString())
        DecimalFormat FORMAT = map.computeIfAbsent(pattern.concat(mode.toString()), str -> new CurrencyDecimalFormat(new DecimalFormat(pattern), mode)).getFormat();
        if (value == null) {
            gen.writeNull();
            return;
        }
        if (value instanceof String) {
            try {
                gen.writeString(FORMAT.format(Float.parseFloat(value.toString())));
            } catch (NumberFormatException e) {
                e.printStackTrace();
                throw new RuntimeException("异常");
            }
        } else if (value instanceof Double | value instanceof Float | value instanceof Integer | value instanceof BigDecimal) {
            log.info("value: {}", FORMAT.format(value));
            gen.writeNumber(FORMAT.format(value));
        } else {
            throw new RuntimeException("异常");
        }
    }


    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException {
        if (property != null) {
            CurrencyFormatter annotation = property.getAnnotation(CurrencyFormatter.class);
            if (annotation == null) {
                annotation = property.getContextAnnotation(CurrencyFormatter.class);
            }
            if (annotation != null) {
                return new CurrencyFormatterSerializer(annotation.pattern(), annotation.mode());
            }
            return prov.findValueSerializer(property.getType(), property);
        }
        return prov.findNullValueSerializer(property);
    }


    @Data
    class CurrencyDecimalFormat {
        private DecimalFormat format;
        private RoundingMode mode;

        public CurrencyDecimalFormat(DecimalFormat format, RoundingMode mode) {
            this.format = format;
            this.mode = mode;
            format.setRoundingMode(mode);
        }
    }

}

3.测试

@NoArgsConstructor
@Data
public class QueryTranDetailResp {

    @CurrencyFormatter(pattern = "0.000")
    private String str;

    @CurrencyFormatter
    private Double d1;

    @CurrencyFormatter(mode = RoundingMode.HALF_DOWN)
    private Double d2;

    @CurrencyFormatter
    private Float f1;

    @CurrencyFormatter
    private Integer i1;

    @CurrencyFormatter
    private Integer i2;

    @CurrencyFormatter
    private BigDecimal b1;
}


@GetMapping("/currency")
public QueryTranDetailResp queryTranDetail() {
    QueryTranDetailResp resp = new QueryTranDetailResp();
    resp.setStr("100.0184938");
    resp.setF1(0.0F);
    resp.setD1(200.306D);
    resp.setD2(200.301D);
    resp.setI1(20);
    resp.setB1(new BigDecimal("32.12356"));
    return resp;
}

结果:

{
    "str": "100.018",
    "d1": 200.31, //向上
    "d2": 200.30, //向下
    "f1": 0.00,
    "i1": 20.00,
    "i2": null,
    "b1": 32.12
}

good luck!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值