From 0c7b6713a86346f5e52f41393cbe6f2d03f8685e Mon Sep 17 00:00:00 2001 From: Binary Wang Date: Fri, 31 Jul 2026 04:01:57 +0000 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E9=94=99=E8=AF=AF=E5=A4=84?= =?UTF-8?q?=E7=90=86=EF=BC=9A=E9=81=BF=E5=85=8D=E5=BC=82=E5=B8=B8=E8=A2=AB?= =?UTF-8?q?=E9=9D=99=E9=BB=98=E5=90=9E=E6=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FileUtils.imageToBase64ByStream 读取失败时抛出 WxRuntimeException,不再 printStackTrace 后返回 null - AesUtils.HMACSHA256 签名计算失败时抛出 WxRuntimeException,不再返回 null 导致签名为空 - RequestUtils.readData 读取回调请求体失败时抛出异常,不再静默返回不完整内容 - PartnerTransferServiceImpl.spDayEndBalance 传播查询异常,不再返回 null - WxMpMemberCardServiceImpl.getActivatePluginParam 解析失败时抛出 WxErrorException - DefaultApacheHttpClientBuilder 空闲连接监控线程被中断时恢复中断标志 - 支付回调转换器、临时二维码文件删除、payBaseUrl 解析失败改为记录日志 新增 FileUtilsTest、AesUtilsTest 回归测试 Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../weixin/common/util/fs/FileUtils.java | 17 ++++--------- .../DefaultApacheHttpClientBuilder.java | 4 ++- .../weixin/common/util/fs/FileUtilsTest.java | 15 +++++++++++ .../miniapp/api/impl/WxMaCodeServiceImpl.java | 5 +++- .../api/impl/WxMpMemberCardServiceImpl.java | 4 +-- .../wxpay/config/VerifierBuilder.java | 6 +++-- .../WxPayOrderNotifyResultConverter.java | 5 +++- .../wxpay/service/PartnerTransferService.java | 2 +- .../impl/PartnerTransferServiceImpl.java | 8 +++--- .../binarywang/wxpay/util/RequestUtils.java | 17 ++++--------- .../v3/auth/PublicCertificateVerifier.java | 3 +++ .../binarywang/wxpay/v3/util/AesUtils.java | 6 ++--- .../wxpay/v3/util/AesUtilsTest.java | 25 +++++++++++++++++++ 13 files changed, 78 insertions(+), 39 deletions(-) create mode 100644 weixin-java-pay/src/test/java/com/github/binarywang/wxpay/v3/util/AesUtilsTest.java diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java index 8419c87d5a..855897f223 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/fs/FileUtils.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.common.util.fs; +import me.chanjar.weixin.common.error.WxRuntimeException; import org.apache.commons.io.IOUtils; import java.io.File; @@ -55,24 +56,16 @@ public static File createTmpFile(InputStream inputStream, String name, String ex * * @param in 文件流 * @return base64编码 + * @throws WxRuntimeException 读取文件流失败时抛出 */ public static String imageToBase64ByStream(InputStream in) { // 读取图片字节数组 - try { + try (InputStream input = in) { // 返回Base64编码过的字节数组字符串 - return Base64.getEncoder().encodeToString(IOUtils.toByteArray(in)); + return Base64.getEncoder().encodeToString(IOUtils.toByteArray(input)); } catch (IOException e) { - e.printStackTrace(); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } + throw new WxRuntimeException(e); } - return null; } } diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java index ef7120b768..14cceb38ef 100644 --- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java +++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/DefaultApacheHttpClientBuilder.java @@ -318,7 +318,9 @@ public void run() { TimeUnit.MILLISECONDS); } } - } catch (InterruptedException ignore) { + } catch (InterruptedException e) { + log.debug("空闲连接监控线程被中断,退出监控", e); + Thread.currentThread().interrupt(); } } diff --git a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/fs/FileUtilsTest.java b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/fs/FileUtilsTest.java index 3ab603e47c..23e761efd9 100644 --- a/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/fs/FileUtilsTest.java +++ b/weixin-java-common/src/test/java/me/chanjar/weixin/common/util/fs/FileUtilsTest.java @@ -1,5 +1,6 @@ package me.chanjar.weixin.common.util.fs; +import me.chanjar.weixin.common.error.WxRuntimeException; import org.apache.commons.io.IOUtils; import org.testng.annotations.Test; @@ -13,6 +14,7 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; public class FileUtilsTest { @@ -59,4 +61,17 @@ public int available() { String result = FileUtils.imageToBase64ByStream(chunked); assertThat(result).isEqualTo(Base64.getEncoder().encodeToString(original)); } + + @Test + public void testImageToBase64ByStreamThrowsOnIoError() { + InputStream failing = new InputStream() { + @Override + public int read() throws IOException { + throw new IOException("read failed"); + } + }; + assertThatThrownBy(() -> FileUtils.imageToBase64ByStream(failing)) + .isInstanceOf(WxRuntimeException.class) + .hasCauseInstanceOf(IOException.class); + } } diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImpl.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImpl.java index 921174f110..b4f92e6e30 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImpl.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaCodeServiceImpl.java @@ -7,6 +7,7 @@ import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor; @@ -29,6 +30,7 @@ * @author Charming * @since 2018-04-26 20:00 */ +@Slf4j @RequiredArgsConstructor public class WxMaCodeServiceImpl implements WxMaCodeService { private final WxMaService service; @@ -60,7 +62,8 @@ public byte[] getQrCode(String path) throws WxErrorException { try { // 及时删除二维码文件,避免积压过多缓存文件 Files.delete(qrCodeFilePath); - } catch (Exception ignored) { + } catch (Exception e) { + log.warn("删除临时二维码文件失败,path={}", qrCodeFilePath, e); } } } diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java index 7a01c6a014..445b5addf9 100644 --- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java +++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpMemberCardServiceImpl.java @@ -16,6 +16,7 @@ import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxError; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.common.util.json.WxGsonBuilder; import me.chanjar.weixin.mp.api.WxMpMemberCardService; @@ -253,9 +254,8 @@ public ActivatePluginParam getActivatePluginParam(String cardId, String outStr) activatePluginParam.setBiz(resultMap.get("biz") + "=="); return activatePluginParam; } catch (UnsupportedEncodingException e) { - e.printStackTrace(); + throw new WxErrorException(WxError.builder().errorMsg("解析激活插件参数失败:" + e.getMessage()).build(), e); } - return null; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/VerifierBuilder.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/VerifierBuilder.java index 4c8aafb8ee..616d000f52 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/VerifierBuilder.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/config/VerifierBuilder.java @@ -4,6 +4,7 @@ import com.github.binarywang.wxpay.v3.auth.*; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.net.URI; @@ -17,6 +18,7 @@ * * @author holy */ +@Slf4j @NoArgsConstructor(access = AccessLevel.PRIVATE) class VerifierBuilder { /** @@ -127,8 +129,8 @@ private static AutoUpdateCertificatesVerifier getCertificatesVerifier( if (StringUtils.isNotBlank(rawPath) && !"/".equals(rawPath)) { signUriStripPrefix = rawPath; } - } catch (URISyntaxException ignored) { - // ignore + } catch (URISyntaxException e) { + log.warn("payBaseUrl不是合法的URI,将不使用签名前缀剪裁,payBaseUrl={}", payBaseUrl, e); } } return new AutoUpdateCertificatesVerifier( diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java index e3e28e9183..899c664148 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/converter/WxPayOrderNotifyResultConverter.java @@ -12,6 +12,7 @@ import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import java.beans.PropertyDescriptor; @@ -26,6 +27,7 @@ * * @author aimilin */ +@Slf4j public class WxPayOrderNotifyResultConverter extends AbstractReflectionConverter { /** @@ -116,7 +118,8 @@ private void setFieldValue(UnmarshallingContext context, WxPayOrderNotifyResult PropertyDescriptor pd = new PropertyDescriptor((String) field.getName(), obj.getClass()); pd.getWriteMethod().invoke(obj, val); } - } catch (Exception ignored) { + } catch (Exception e) { + log.warn("支付回调报文字段赋值失败,field={}", field.getName(), e); } } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/PartnerTransferService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/PartnerTransferService.java index cea20e86f0..e1bfd2c5ff 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/PartnerTransferService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/PartnerTransferService.java @@ -195,7 +195,7 @@ public interface PartnerTransferService { * @param accountType 服务商账户类型 * @param date 查询日期 2020-09-11 * @return 返回数据 fund balance result - * @throws WxPayException the wx pay exception + * @throws me.chanjar.weixin.common.error.WxRuntimeException 查询失败时抛出,具体原因参见 cause */ FundBalanceResult spDayEndBalance(SpAccountTypeEnum accountType, String date); } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerTransferServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerTransferServiceImpl.java index 0fe6ac860d..a21eb4197c 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerTransferServiceImpl.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/PartnerTransferServiceImpl.java @@ -7,6 +7,7 @@ import com.github.binarywang.wxpay.service.PartnerTransferService; import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.v3.util.RsaCryptoUtil; +import me.chanjar.weixin.common.error.WxRuntimeException; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import jodd.util.StringUtil; @@ -315,16 +316,15 @@ public FundBalanceResult fundBalance(SpAccountTypeEnum accountType) throws WxPay * @param accountType 服务商账户类型 * @param date 查询日期 2020-09-11 * @return 返回数据 fund balance result - * @throws WxPayException the wx pay exception + * @throws WxRuntimeException 查询失败时抛出,具体原因参见 cause */ @Override public FundBalanceResult spDayEndBalance(SpAccountTypeEnum accountType, String date) { try { return this.payService.getEcommerceService().spDayEndBalance(accountType, date); - } catch (Exception e) { - e.printStackTrace(); + } catch (WxPayException e) { + throw new WxRuntimeException(e); } - return null; } diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/RequestUtils.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/RequestUtils.java index c4ad966415..608c3d48a1 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/RequestUtils.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/util/RequestUtils.java @@ -1,5 +1,7 @@ package com.github.binarywang.wxpay.util; +import me.chanjar.weixin.common.error.WxRuntimeException; + import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.IOException; @@ -19,12 +21,11 @@ public class RequestUtils { * * @param request HTTP请求对象 * @return 字符串 + * @throws WxRuntimeException 读取请求体失败时抛出 */ public static String readData(HttpServletRequest request) { - BufferedReader br = null; StringBuilder result = new StringBuilder(); - try { - br = request.getReader(); + try (BufferedReader br = request.getReader()) { for (String line; (line = br.readLine()) != null; ) { if (result.length() > 0) { result.append("\n"); @@ -32,15 +33,7 @@ public static String readData(HttpServletRequest request) { result.append(line); } } catch (IOException e) { - e.printStackTrace(); - } finally { - if (br != null) { - try { - br.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } + throw new WxRuntimeException("读取请求体失败", e); } return result.toString(); diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/PublicCertificateVerifier.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/PublicCertificateVerifier.java index 62ad61ce19..4485feb11d 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/PublicCertificateVerifier.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/PublicCertificateVerifier.java @@ -3,8 +3,10 @@ import java.security.*; import java.security.cert.X509Certificate; import java.util.Base64; +import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.error.WxRuntimeException; +@Slf4j public class PublicCertificateVerifier implements Verifier{ private final PublicKey publicKey; @@ -32,6 +34,7 @@ public boolean verify(String serialNumber, byte[] message, String signature) { } } catch (Exception e) { // 证书验证失败,继续尝试公钥验证 + log.debug("平台证书验签失败,降级为公钥验签,serialNumber={}", serialNumber, e); } } // 使用公钥验证(兜底方案,适用于公钥转账等场景) diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/AesUtils.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/AesUtils.java index 831dfe2bb1..f50eed65ab 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/AesUtils.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/util/AesUtils.java @@ -1,5 +1,6 @@ package com.github.binarywang.wxpay.v3.util; +import me.chanjar.weixin.common.error.WxRuntimeException; import org.apache.commons.lang3.StringUtils; import javax.crypto.Cipher; @@ -123,9 +124,8 @@ public static String HMACSHA256(String data, String key) { sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); } return sb.toString().toUpperCase(); - } catch (Exception e) { - e.printStackTrace(); - return null; + } catch (GeneralSecurityException | IllegalArgumentException e) { + throw new WxRuntimeException("HMAC-SHA256签名计算失败", e); } } diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/v3/util/AesUtilsTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/v3/util/AesUtilsTest.java new file mode 100644 index 0000000000..cf56d7228f --- /dev/null +++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/v3/util/AesUtilsTest.java @@ -0,0 +1,25 @@ +package com.github.binarywang.wxpay.v3.util; + +import me.chanjar.weixin.common.error.WxRuntimeException; +import org.testng.annotations.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * 测试 {@link AesUtils}. + */ +public class AesUtilsTest { + + @Test + public void testHmacSha256() { + assertThat(AesUtils.HMACSHA256("data", "key")).isNotEmpty(); + } + + @Test + public void testHmacSha256ThrowsOnInvalidKey() { + // 空密钥无法构造 SecretKeySpec,此前该场景会被静默吞掉并返回 null + assertThatThrownBy(() -> AesUtils.HMACSHA256("data", "")) + .isInstanceOf(WxRuntimeException.class); + } +}