微信支付 V2 提示 invalid total_fee,先检查实际发送的金额单位和整数格式。total_fee 使用“分”,不能直接传“元”,也不能让二进制浮点转换和隐式舍入决定应付金额。V2 金额字段

旧记录中的算式需要纠正

2018 年项目把字符串金额转成 Double 再乘 100,随后出现该错误。旧稿将输入 12 的结果写成 12.0,这个算式不成立:12 元对应 1200 分,浮点打印可能是 1200.0,而不是 12.0。

当时用 Math.round 去掉小数部分。这个动作不能解释所有失败:还要看请求实际序列化成什么、金额是否来自可信订单,以及是否发生了不符合业务规则的舍入。

从十进制字符串精确得到整数分

下面示例接受至多两位小数的非负十进制文本,并要求结果大于零、能放入 int。金额上限还需由业务额外限制:

import java.math.BigDecimal;

public final class MoneyInCents {
    public static int fromYuan(String amount) {
        if (amount == null || !amount.matches("[0-9]{1,9}(\\.[0-9]{1,2})?")) {
            throw new IllegalArgumentException("金额格式不正确");
        }
        int cents = new BigDecimal(amount)
                .movePointRight(2)
                .intValueExact();
        if (cents <= 0) {
            throw new IllegalArgumentException("金额必须大于零");
        }
        return cents;
    }
}

new BigDecimal(String) 直接保留十进制输入含义;intValueExact 拒绝不能精确表示的值及溢出,不会悄悄截断。Java 8 BigDecimal

用边界例子检查契约

输入本示例应如何处理
121200 分
12.301230 分
0.011 分
0、负数、空文本拒绝
1.234因超过两位小数拒绝
转换后超出 int抛出精确转换异常

上表是函数设计要求,不是已发起支付的结果。如果折扣产生更细小数,应先确定舍入政策再计算,不要临时用 round 修补。

金额应从服务端订单计算,不能直接信任客户端传来的价格。之后再按接口版本序列化和签名;同样的 total_fee 提示也可能只是上游下单失败的连带现象,见订单重复错误链。