From 4a1fa6911e5461c7d74e0da4a540c186fc3b3064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Sun, 10 Aug 2025 13:30:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E5=95=86=E5=93=81?= =?UTF-8?q?=E6=8F=8F=E8=BF=B0=E8=BF=87=E9=95=BF=E5=AF=BC=E8=87=B4=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E5=A4=B1=E8=B4=A5=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/impl/ShopOrderServiceImpl.java | 47 +++++++- .../shop/WechatPayDescriptionTest.java | 113 ++++++++++++++++++ 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/gxwebsoft/shop/WechatPayDescriptionTest.java diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java index 2921a5c..71b2c10 100644 --- a/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java @@ -141,7 +141,13 @@ import com.gxwebsoft.common.core.service.PaymentCacheService; request.setAmount(amount); request.setAppid(payment.getAppId()); request.setMchid(payment.getMchId()); - request.setDescription(order.getComments()); + // 微信支付description字段限制127字节,需要截断处理 + String description = order.getComments(); + if (description != null) { + // 确保字节数不超过127字节 + description = truncateToByteLimit(description, 127); + } + request.setDescription(description); request.setOutTradeNo(order.getOrderNo()); request.setAttach(order.getTenantId().toString()); final Payer payer = new Payer(); @@ -667,4 +673,43 @@ import com.gxwebsoft.common.core.service.PaymentCacheService; } } + /** + * 截断字符串以确保字节数不超过指定限制 + * 微信支付description字段限制127字节 + * + * @param text 原始文本 + * @param maxBytes 最大字节数 + * @return 截断后的文本 + */ + private String truncateToByteLimit(String text, int maxBytes) { + if (text == null || text.isEmpty()) { + return text; + } + + byte[] bytes = text.getBytes(java.nio.charset.StandardCharsets.UTF_8); + if (bytes.length <= maxBytes) { + return text; + } + + // 截断字节数组,但要确保不会截断UTF-8字符的中间 + int truncateLength = maxBytes; + while (truncateLength > 0) { + byte[] truncated = new byte[truncateLength]; + System.arraycopy(bytes, 0, truncated, 0, truncateLength); + + try { + String result = new String(truncated, java.nio.charset.StandardCharsets.UTF_8); + // 检查是否有无效字符(被截断的UTF-8字符) + if (!result.contains("\uFFFD")) { + return result; + } + } catch (Exception e) { + // 继续尝试更短的长度 + } + truncateLength--; + } + + return ""; // 如果无法安全截断,返回空字符串 + } + } diff --git a/src/test/java/com/gxwebsoft/shop/WechatPayDescriptionTest.java b/src/test/java/com/gxwebsoft/shop/WechatPayDescriptionTest.java new file mode 100644 index 0000000..f6ea883 --- /dev/null +++ b/src/test/java/com/gxwebsoft/shop/WechatPayDescriptionTest.java @@ -0,0 +1,113 @@ +package com.gxwebsoft.shop; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * 微信支付商品描述字段测试 + * 验证字节长度限制处理 + */ +@SpringBootTest +public class WechatPayDescriptionTest { + + /** + * 截断字符串以确保字节数不超过指定限制 + * 微信支付description字段限制127字节 + * + * @param text 原始文本 + * @param maxBytes 最大字节数 + * @return 截断后的文本 + */ + private String truncateToByteLimit(String text, int maxBytes) { + if (text == null || text.isEmpty()) { + return text; + } + + byte[] bytes = text.getBytes(StandardCharsets.UTF_8); + if (bytes.length <= maxBytes) { + return text; + } + + // 截断字节数组,但要确保不会截断UTF-8字符的中间 + int truncateLength = maxBytes; + while (truncateLength > 0) { + byte[] truncated = new byte[truncateLength]; + System.arraycopy(bytes, 0, truncated, 0, truncateLength); + + try { + String result = new String(truncated, StandardCharsets.UTF_8); + // 检查是否有无效字符(被截断的UTF-8字符) + if (!result.contains("\uFFFD")) { + return result; + } + } catch (Exception e) { + // 继续尝试更短的长度 + } + truncateLength--; + } + + return ""; // 如果无法安全截断,返回空字符串 + } + + @Test + public void testTruncateToByteLimit() { + // 测试正常情况 - 字符串长度在限制内 + String shortText = "正常商品描述"; + String result1 = truncateToByteLimit(shortText, 127); + assertEquals(shortText, result1); + assertTrue(result1.getBytes(StandardCharsets.UTF_8).length <= 127); + + // 测试超长中文字符串 + String longText = "【湾区认证】【百千万工程帮扶产品 通过远方320项检测 湾区认证 丰江桥佛手瓜面】独特风味低脂轻食便捷速食非油炸 720g/袋"; + String result2 = truncateToByteLimit(longText, 127); + assertNotNull(result2); + assertTrue(result2.getBytes(StandardCharsets.UTF_8).length <= 127); + System.out.println("原始文本字节数: " + longText.getBytes(StandardCharsets.UTF_8).length); + System.out.println("截断后文本: " + result2); + System.out.println("截断后字节数: " + result2.getBytes(StandardCharsets.UTF_8).length); + + // 测试null和空字符串 + assertNull(truncateToByteLimit(null, 127)); + assertEquals("", truncateToByteLimit("", 127)); + + // 测试英文字符串 + String englishText = "This is a very long English description that might exceed the byte limit for WeChat Pay description field"; + String result3 = truncateToByteLimit(englishText, 127); + assertNotNull(result3); + assertTrue(result3.getBytes(StandardCharsets.UTF_8).length <= 127); + + // 测试混合字符串 + String mixedText = "Product Name 产品名称 with special characters @#$%^&*()"; + String result4 = truncateToByteLimit(mixedText, 50); + assertNotNull(result4); + assertTrue(result4.getBytes(StandardCharsets.UTF_8).length <= 50); + } + + @Test + public void testSpecificErrorCase() { + // 测试错误信息中的具体案例 + String errorText = "【湾区认证】【百千万工程帮扶产品 通过远方320项检测 湾区认证 丰江桥佛手瓜面】独特风味低脂轻食便捷速食非油炸 720g/袋"; + + // 验证原始文本确实超过127字节 + int originalBytes = errorText.getBytes(StandardCharsets.UTF_8).length; + System.out.println("原始文本: " + errorText); + System.out.println("原始字节数: " + originalBytes); + assertTrue(originalBytes > 127, "原始文本应该超过127字节"); + + // 测试截断 + String truncated = truncateToByteLimit(errorText, 127); + int truncatedBytes = truncated.getBytes(StandardCharsets.UTF_8).length; + + System.out.println("截断后文本: " + truncated); + System.out.println("截断后字节数: " + truncatedBytes); + + // 验证截断后的文本符合要求 + assertNotNull(truncated); + assertTrue(truncatedBytes <= 127, "截断后字节数应该不超过127"); + assertFalse(truncated.contains("\uFFFD"), "截断后的文本不应包含无效字符"); + } +}