fix(core): 修复LocalDateTime反序列化和微信支付参数验证问题
- 移除JacksonConfig中未使用的LocalDateTimeDeserializer导入 - 增强LocalDateTimeDeserializer支持时间戳格式解析,兼容前端发送的数字时间戳 - 添加构造函数支持自定义日期时间格式器 - 修复ShopDealerWithdrawController中微信支付批次号长度不足问题,使用零填充确保最小长度 - 添加微信支付服务中outBatchNo和outDetailNo参数长度验证规则 - 移除WxTransferService中的冗余代码行
This commit is contained in:
@@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package com.gxwebsoft.common.core.config;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
@@ -16,14 +19,43 @@ import java.time.format.DateTimeFormatter;
|
||||
*/
|
||||
public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
|
||||
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
private final DateTimeFormatter formatter;
|
||||
|
||||
public LocalDateTimeDeserializer() {
|
||||
this(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
|
||||
}
|
||||
|
||||
public LocalDateTimeDeserializer(DateTimeFormatter formatter) {
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
|
||||
String value = p.getValueAsString();
|
||||
if (value != null && !value.isEmpty()) {
|
||||
return LocalDateTime.parse(value, FORMATTER);
|
||||
JsonToken t = p.currentToken();
|
||||
ZoneId zoneId = ctxt.getTimeZone() != null ? ctxt.getTimeZone().toZoneId() : ZoneId.systemDefault();
|
||||
|
||||
// Accept epoch timestamps (seconds or millis) for compatibility with frontends that send numbers.
|
||||
if (t == JsonToken.VALUE_NUMBER_INT) {
|
||||
long ts = p.getLongValue();
|
||||
// Heuristic: 10+ digits is seconds; 13+ digits is millis (most common in JS).
|
||||
Instant instant = (String.valueOf(Math.abs(ts)).length() >= 13)
|
||||
? Instant.ofEpochMilli(ts)
|
||||
: Instant.ofEpochSecond(ts);
|
||||
return LocalDateTime.ofInstant(instant, zoneId);
|
||||
}
|
||||
return null;
|
||||
|
||||
String value = p.getValueAsString();
|
||||
if (value == null || value.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Handle numeric timestamps passed as strings, e.g. "1769618486000"
|
||||
if (value.chars().allMatch(Character::isDigit)) {
|
||||
long ts = Long.parseLong(value);
|
||||
Instant instant = (value.length() >= 13) ? Instant.ofEpochMilli(ts) : Instant.ofEpochSecond(ts);
|
||||
return LocalDateTime.ofInstant(instant, zoneId);
|
||||
}
|
||||
|
||||
return LocalDateTime.parse(value, formatter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,9 +60,16 @@ public class WxTransferService {
|
||||
if (StrUtil.isBlank(outBatchNo) || !outBatchNo.matches("^[0-9A-Za-z]+$")) {
|
||||
throw PaymentException.paramError("outBatchNo不合法(仅允许数字/大小写字母)");
|
||||
}
|
||||
// 微信接口限制:商家批次单号长度需在区间内(当前实测最小 5)。
|
||||
if (outBatchNo.length() < 5 || outBatchNo.length() > 32) {
|
||||
throw PaymentException.paramError("outBatchNo长度不合法(要求 5-32)");
|
||||
}
|
||||
if (StrUtil.isBlank(outDetailNo) || !outDetailNo.matches("^[0-9A-Za-z]+$")) {
|
||||
throw PaymentException.paramError("outDetailNo不合法(仅允许数字/大小写字母)");
|
||||
}
|
||||
if (outDetailNo.length() > 32) {
|
||||
throw PaymentException.paramError("outDetailNo长度不合法(最大 32)");
|
||||
}
|
||||
|
||||
// 微信要求金额单位为“分”,必须为整数
|
||||
long amountFen = amountYuan
|
||||
@@ -133,4 +140,3 @@ public class WxTransferService {
|
||||
return s.substring(0, maxLen);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,8 +138,10 @@ public class ShopDealerWithdrawController extends BaseController {
|
||||
return fail("用户openid为空,无法发起微信转账");
|
||||
}
|
||||
|
||||
String outBatchNo = "WD" + db.getId();
|
||||
String outDetailNo = "WD" + db.getId() + "D1";
|
||||
// 微信支付批量转账接口对 out_batch_no 有最小长度限制(当前为 >= 5)。
|
||||
// 使用 0 填充,避免如 "WD59" 这种过短导致 PARAM_ERROR。
|
||||
String outBatchNo = String.format("WD%03d", db.getId());
|
||||
String outDetailNo = outBatchNo + "D1";
|
||||
String remark = "分销商提现";
|
||||
String userName = db.getRealName();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user