Erlo

来了,资金类交易业务(如电商交易、支付)中,经常提到的Money类!

2025-01-07 15:29:25 发布   21 浏览  
页面报错/反馈
收藏 点赞

资金类交易业务中 经常提到的Money类,大家了解一下。 了解了Money类,就会对资金类业务如电商交易、支付更了解。

资金类业务中,金额如果处理得不好,带来的直接后果就是资金损失(资损风险)。

对于研发经验不足的团队而言,经常会犯以下几种错误:

不统一,存在各系统使用BigDecimal、double、long等数据类型来定义金额。

手动对金额进行加、减、乘、除运算,单位(元与分)换算。

带来的后果,通常就是资金损失,再细化一下,最常见的情况有下面3种:

1)手动做单位换算导致金额被放大或缩小100倍。比如大家规定传的是元,但是其中有位同学忘记了,以为传的是分,外部渠道要求传元,就手动乘以100。或者反过来。

2)1分钱归属问题。比如结算给商家,或计算手续费时,碰到除不尽时,使用四舍五入,还是向零舍入,还是银行家舍入?这取决于财务策略。

3)精度丢失。在大金额时,double有可能会有精度丢失问题。

这时候,解决方案就是定义统一的 Money 类。并且,要明确统一使用 Money 类来处理金额数据。

1. 统一的Money 类

talk is cheap , show you the code directly.

package com.emax.trans;

import cn.hutool.core.lang.Assert;
import lombok.Getter;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;

/**
 * 资金类交易业务(如电商交易、支付)中,经常提到的Money类。
 * 

该类是不可变的(immutable),并且实现了Comparable和Serializable接口。 *

原始文章 * * @author zhangguozhan * @date 2025-01-07 14:40 */ @Getter public class Money implements Serializable, Comparable { private static final long serialVersionUID = 1L; private BigDecimal yuan; private long fen; /** * 私有构造函数,确保通过工厂方法{@link #of}来创建实例。 * * @param yuan * @param fen */ private Money(BigDecimal yuan, long fen) { this.yuan = yuan; this.fen = fen; } public static Money of(BigDecimal yuan) { Assert.notNull(yuan, "yuan is null"); return new Money(yuan, yuan.movePointRight(2).longValue()); } public static Money of(Long fen) { Assert.notNull(fen, "fen is null"); return new Money(BigDecimal.valueOf(fen * 100), fen); } /** * 加法操作,返回新的Money实例。(注意Money类是不可变类,此操作不会修改当前Money对象的属性值) * * @param other * @return */ public Money add(Money other) { Assert.notNull(other, "other is null"); Assert.notNull(other.yuan, "other.yuan is null"); BigDecimal sum = this.yuan.add(other.yuan); return of(sum); } /** * (按百分比费率)计算手续费 * * @param feeRatePercentage 百分比 的手续费费率比例,例如 5.5% 传 5.5 * @return */ public BigDecimal calculateFeeByPercentageRate(BigDecimal feeRatePercentage) { return calculateFeeByPercentageRate(feeRatePercentage, RoundingMode.HALF_UP); } /** * (按百分比费率)计算手续费 * * @param feeRatePercentage 百分比 的手续费费率比例,例如 5.5% 传 5.5 * @param roundingMode * @return */ public BigDecimal calculateFeeByPercentageRate(BigDecimal feeRatePercentage, RoundingMode roundingMode) { Assert.notNull(feeRatePercentage, "feeRatePercentage is null"); return yuan.multiply(feeRatePercentage).divide(BigDecimal.valueOf(100), 2, roundingMode); } /** * (按




测试:

    public static void main(String[] args) {
        Money money = Money.of(BigDecimal.valueOf(100));
        Money money2 = Money.of(BigDecimal.valueOf(200));
        System.out.println(money.compareTo(money2));
        System.out.println(money.equals(money2));
        System.out.println(money.add(money2));
        System.out.println(money.calculateFeeByPercentageRate(BigDecimal.valueOf(5.5)));
        System.out.println(money.calculateFeeByAbsRate(BigDecimal.valueOf(0.065)));
    }

输出:

-1
false
300元(30000分)
5.50
6.50

2. 如何统一使用 Money 类

待补充~


金额如果处理得不好,带来的直接后果就是资金损失,哪怕不是今天,早晚也得出事。
如果你是研发同学,发现内部还没有使用Money类处理金额,建议早点对内部系统做改造。如果你是产品经理,建议转给内部研发工程师,避免踩资损的坑。


当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/18657723


登录查看全部

参与评论

评论留言

还没有评论留言,赶紧来抢楼吧~~

手机查看

返回顶部

给这篇文章打个标签吧~

棒极了 糟糕透顶 好文章 PHP JAVA JS 小程序 Python SEO MySql 确认