diff --git a/weixin-java-pay/OVERSEAS_PAY.md b/weixin-java-pay/OVERSEAS_PAY.md new file mode 100644 index 0000000000..b9da9814f9 --- /dev/null +++ b/weixin-java-pay/OVERSEAS_PAY.md @@ -0,0 +1,120 @@ +# 境外微信支付(Overseas WeChat Pay)支持 + +本次更新添加了境外微信支付的支持,解决了 [Issue #3618](https://github.com/binarywang/WxJava/issues/3618) 中提到的问题。 + +## 问题背景 + +境外微信支付需要使用新的API接口地址和额外的参数: +- 使用不同的基础URL: `https://apihk.mch.weixin.qq.com` +- 需要额外的参数: `trade_type` 和 `merchant_category_code` +- 使用不同的API端点: `/global/v3/transactions/*` + +## 新增功能 + +### 1. GlobalTradeTypeEnum +新的枚举类,定义了境外支付的交易类型和对应的API端点: +- `APP`: `/global/v3/transactions/app` +- `JSAPI`: `/global/v3/transactions/jsapi` +- `NATIVE`: `/global/v3/transactions/native` +- `H5`: `/global/v3/transactions/h5` + +### 2. WxPayUnifiedOrderV3GlobalRequest +扩展的请求类,包含境外支付必需的额外字段: +- `trade_type`: 交易类型 (JSAPI, APP, NATIVE, H5) +- `merchant_category_code`: 商户类目代码(境外商户必填) + +### 3. 新的服务方法 +- `createOrderV3Global()`: 创建境外支付订单 +- `unifiedOrderV3Global()`: 境外统一下单接口 + +## 使用示例 + +### JSAPI支付示例 +```java +// 创建境外支付请求 +WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest(); +request.setOutTradeNo(RandomUtils.getRandomStr()); +request.setDescription("境外商品购买"); +request.setNotifyUrl("https://your-domain.com/notify"); + +// 设置金额 +WxPayUnifiedOrderV3GlobalRequest.Amount amount = new WxPayUnifiedOrderV3GlobalRequest.Amount(); +amount.setCurrency(WxPayConstants.CurrencyType.CNY); +amount.setTotal(100); // 1元,单位为分 +request.setAmount(amount); + +// 设置支付者 +WxPayUnifiedOrderV3GlobalRequest.Payer payer = new WxPayUnifiedOrderV3GlobalRequest.Payer(); +payer.setOpenid("用户的openid"); +request.setPayer(payer); + +// 设置境外支付必需的参数 +request.setTradeType("JSAPI"); +request.setMerchantCategoryCode("5812"); // 商户类目代码 + +// 调用境外支付接口 +WxPayUnifiedOrderV3Result.JsapiResult result = payService.createOrderV3Global( + GlobalTradeTypeEnum.JSAPI, + request +); +``` + +### APP支付示例 +```java +WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest(); +// ... 设置基础信息 ... + +request.setTradeType("APP"); +request.setMerchantCategoryCode("5812"); +request.setPayer(new WxPayUnifiedOrderV3GlobalRequest.Payer()); // APP支付不需要openid + +WxPayUnifiedOrderV3Result.AppResult result = payService.createOrderV3Global( + GlobalTradeTypeEnum.APP, + request +); +``` + +### NATIVE支付示例 +```java +WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest(); +// ... 设置基础信息 ... + +request.setTradeType("NATIVE"); +request.setMerchantCategoryCode("5812"); +request.setPayer(new WxPayUnifiedOrderV3GlobalRequest.Payer()); + +String codeUrl = payService.createOrderV3Global( + GlobalTradeTypeEnum.NATIVE, + request +); +``` + +## 配置说明 + +境外支付使用相同的 `WxPayConfig` 配置,无需特殊设置: + +```java +WxPayConfig config = new WxPayConfig(); +config.setAppId("你的AppId"); +config.setMchId("你的境外商户号"); +config.setMchKey("你的商户密钥"); +config.setNotifyUrl("https://your-domain.com/notify"); + +// V3相关配置 +config.setPrivateKeyPath("你的私钥文件路径"); +config.setCertSerialNo("你的商户证书序列号"); +config.setApiV3Key("你的APIv3密钥"); +``` + +**注意**: 境外支付会自动使用 `https://apihk.mch.weixin.qq.com` 作为基础URL,无需手动设置。 + +## 兼容性 + +- 完全向后兼容,不影响现有的国内支付功能 +- 使用相同的配置类和结果类 +- 遵循现有的代码风格和架构模式 + +## 参考文档 + +- [境外微信支付文档](https://pay.weixin.qq.com/doc/global/v3/zh/4013014223) +- [原始Issue #3618](https://github.com/binarywang/WxJava/issues/3618) \ No newline at end of file diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java index ae86b8c854..8615a2e461 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResult.java @@ -273,7 +273,7 @@ public String toString() { * */ @XStreamAlias("refund_recv_accout") - private String refundRecvAccout; + private String refundRecvAccount; /** *
@@ -324,7 +324,7 @@ public void loadXML(Document d) {
       settlementRefundFee = readXmlInteger(d, "settlement_refund_fee");
       refundStatus = readXmlString(d, "refund_status");
       successTime = readXmlString(d, "success_time");
-      refundRecvAccout = readXmlString(d, "refund_recv_accout");
+      refundRecvAccount = readXmlString(d, "refund_recv_accout");
       refundAccount = readXmlString(d, "refund_account");
       refundRequestSource = readXmlString(d, "refund_request_source");
     }
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3GlobalRequest.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3GlobalRequest.java
new file mode 100644
index 0000000000..296d3a8646
--- /dev/null
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/request/WxPayUnifiedOrderV3GlobalRequest.java
@@ -0,0 +1,57 @@
+package com.github.binarywang.wxpay.bean.request;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 
+ * 境外微信支付统一下单请求参数对象.
+ * 参考文档:https://pay.weixin.qq.com/doc/global/v3/zh/4013014223
+ * 
+ * + * @author Binary Wang + */ +@Data +@NoArgsConstructor +@Accessors(chain = true) +@EqualsAndHashCode(callSuper = true) +public class WxPayUnifiedOrderV3GlobalRequest extends WxPayUnifiedOrderV3Request implements Serializable { + private static final long serialVersionUID = 1L; + + /** + *
+   * 字段名:交易类型
+   * 变量名:trade_type
+   * 是否必填:是
+   * 类型:string[1,16]
+   * 描述:
+   *  交易类型,取值如下:
+   *  JSAPI--JSAPI支付
+   *  NATIVE--Native支付
+   *  APP--APP支付
+   *  H5--H5支付
+   *  示例值:JSAPI
+   * 
+ */ + @SerializedName(value = "trade_type") + private String tradeType; + + /** + *
+   * 字段名:商户类目
+   * 变量名:merchant_category_code
+   * 是否必填:是
+   * 类型:string[1,32]
+   * 描述:
+   *  商户类目,境外商户必填
+   *  示例值:5812
+   * 
+ */ + @SerializedName(value = "merchant_category_code") + private String merchantCategoryCode; +} \ No newline at end of file diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/GlobalTradeTypeEnum.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/GlobalTradeTypeEnum.java new file mode 100644 index 0000000000..fd33b240f1 --- /dev/null +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/bean/result/enums/GlobalTradeTypeEnum.java @@ -0,0 +1,36 @@ +package com.github.binarywang.wxpay.bean.result.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 境外微信支付方式 + * Overseas WeChat Pay trade types with global endpoints + * + * @author Binary Wang + */ +@Getter +@AllArgsConstructor +public enum GlobalTradeTypeEnum { + /** + * APP + */ + APP("/global/v3/transactions/app"), + /** + * JSAPI 或 小程序 + */ + JSAPI("/global/v3/transactions/jsapi"), + /** + * NATIVE + */ + NATIVE("/global/v3/transactions/native"), + /** + * H5 + */ + H5("/global/v3/transactions/h5"); + + /** + * 境外下单url + */ + private final String url; +} \ No newline at end of file diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java index 8ceac2b6ba..c73fb843e8 100644 --- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java +++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/WxPayService.java @@ -6,6 +6,7 @@ import com.github.binarywang.wxpay.bean.request.*; import com.github.binarywang.wxpay.bean.result.*; import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum; +import com.github.binarywang.wxpay.bean.result.enums.GlobalTradeTypeEnum; import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult; import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.constant.WxPayConstants; @@ -640,6 +641,17 @@ public interface WxPayService { */ T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException; + /** + * 境外微信支付调用统一下单接口,并组装生成支付所需参数对象. + * + * @param 请使用{@link WxPayUnifiedOrderV3Result}里的内部类或字段 + * @param tradeType the global trade type + * @param request 境外统一下单请求参数 + * @return 返回 {@link WxPayUnifiedOrderV3Result}里的内部类或字段 + * @throws WxPayException the wx pay exception + */ + T createOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException; + /** * 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识" * @@ -660,6 +672,16 @@ public interface WxPayService { */ WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException; + /** + * 境外微信支付在发起支付前,需要调用统一下单接口,获取"预支付交易会话标识" + * + * @param tradeType the global trade type + * @param request 境外请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置) + * @return the wx pay unified order result + * @throws WxPayException the wx pay exception + */ + WxPayUnifiedOrderV3Result unifiedOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException; + /** *
    * 合单支付API(APP支付、JSAPI支付、H5支付、NATIVE支付).
diff --git a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
index 5057ef2b6b..4177a54cd5 100644
--- a/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
+++ b/weixin-java-pay/src/main/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceImpl.java
@@ -11,6 +11,7 @@
 import com.github.binarywang.wxpay.bean.request.*;
 import com.github.binarywang.wxpay.bean.result.*;
 import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
+import com.github.binarywang.wxpay.bean.result.enums.GlobalTradeTypeEnum;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsNotifyResult;
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.config.WxPayConfigHolder;
@@ -746,6 +747,14 @@ public  T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOr
     return result.getPayInfo(tradeType, appId, request.getSubMchId(), this.getConfig().getPrivateKey());
   }
 
+  @Override
+  public  T createOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException {
+    WxPayUnifiedOrderV3Result result = this.unifiedOrderV3Global(tradeType, request);
+    // Convert GlobalTradeTypeEnum to TradeTypeEnum for getPayInfo method
+    TradeTypeEnum domesticTradeType = TradeTypeEnum.valueOf(tradeType.name());
+    return result.getPayInfo(domesticTradeType, request.getAppid(), request.getMchid(), this.getConfig().getPrivateKey());
+  }
+
   @Override
   public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException {
     if (StringUtils.isBlank(request.getSpAppid())) {
@@ -790,6 +799,28 @@ public WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUn
     return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class);
   }
 
+  @Override
+  public WxPayUnifiedOrderV3Result unifiedOrderV3Global(GlobalTradeTypeEnum tradeType, WxPayUnifiedOrderV3GlobalRequest request) throws WxPayException {
+    if (StringUtils.isBlank(request.getAppid())) {
+      request.setAppid(this.getConfig().getAppId());
+    }
+    if (StringUtils.isBlank(request.getMchid())) {
+      request.setMchid(this.getConfig().getMchId());
+    }
+    if (StringUtils.isBlank(request.getNotifyUrl())) {
+      request.setNotifyUrl(this.getConfig().getNotifyUrl());
+    }
+    if (StringUtils.isBlank(request.getTradeType())) {
+      request.setTradeType(tradeType.name());
+    }
+
+    // Use global WeChat Pay base URL for overseas payments
+    String globalBaseUrl = "https://apihk.mch.weixin.qq.com";
+    String url = globalBaseUrl + tradeType.getUrl();
+    String response = this.postV3WithWechatpaySerial(url, GSON.toJson(request));
+    return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class);
+  }
+
   @Override
   public CombineTransactionsResult combine(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException {
     if (StringUtils.isBlank(request.getCombineAppid())) {
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
index 963afb2618..e7a22ee6cd 100644
--- a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/bean/notify/WxPayRefundNotifyResultTest.java
@@ -119,7 +119,7 @@ public void testFromXMLFastMode() throws WxPayException {
       refundNotifyResult.loadReqInfo(xmlDecryptedReqInfo);
       assertEquals(refundNotifyResult.getReqInfo().getRefundFee().intValue(), 15);
       assertEquals(refundNotifyResult.getReqInfo().getRefundStatus(), "SUCCESS");
-      assertEquals(refundNotifyResult.getReqInfo().getRefundRecvAccout(), "用户零钱");
+      assertEquals(refundNotifyResult.getReqInfo().getRefundRecvAccount(), "用户零钱");
       System.out.println(refundNotifyResult);
     } finally {
       XmlConfig.fastMode = false;
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceGlobalImplTest.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceGlobalImplTest.java
new file mode 100644
index 0000000000..c648c8a171
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/BaseWxPayServiceGlobalImplTest.java
@@ -0,0 +1,89 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3GlobalRequest;
+import com.github.binarywang.wxpay.bean.result.enums.GlobalTradeTypeEnum;
+import com.github.binarywang.wxpay.constant.WxPayConstants;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import me.chanjar.weixin.common.util.RandomUtils;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/**
+ * 境外微信支付测试类
+ *
+ * @author Binary Wang
+ */
+public class BaseWxPayServiceGlobalImplTest {
+
+  private static final Gson GSON = new GsonBuilder().create();
+
+  @Test
+  public void testWxPayUnifiedOrderV3GlobalRequest() {
+    // Test that the new request class has the required fields
+    WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+    
+    // Set basic order information
+    String outTradeNo = RandomUtils.getRandomStr();
+    request.setOutTradeNo(outTradeNo);
+    request.setDescription("Test overseas payment");
+    request.setNotifyUrl("https://api.example.com/notify");
+    
+    // Set amount
+    WxPayUnifiedOrderV3GlobalRequest.Amount amount = new WxPayUnifiedOrderV3GlobalRequest.Amount();
+    amount.setCurrency(WxPayConstants.CurrencyType.CNY);
+    amount.setTotal(100); // 1 yuan in cents
+    request.setAmount(amount);
+    
+    // Set payer
+    WxPayUnifiedOrderV3GlobalRequest.Payer payer = new WxPayUnifiedOrderV3GlobalRequest.Payer();
+    payer.setOpenid("test_openid");
+    request.setPayer(payer);
+    
+    // Set the new required fields for global payments
+    request.setTradeType("JSAPI");
+    request.setMerchantCategoryCode("5812"); // Example category code
+    
+    // Assert that all fields are properly set
+    assertNotNull(request.getTradeType());
+    assertNotNull(request.getMerchantCategoryCode());
+    assertEquals("JSAPI", request.getTradeType());
+    assertEquals("5812", request.getMerchantCategoryCode());
+    assertEquals(outTradeNo, request.getOutTradeNo());
+    assertEquals("Test overseas payment", request.getDescription());
+    assertEquals(100, request.getAmount().getTotal());
+    assertEquals("test_openid", request.getPayer().getOpenid());
+    
+    // Test JSON serialization contains the new fields
+    String json = GSON.toJson(request);
+    assertTrue(json.contains("trade_type"));
+    assertTrue(json.contains("merchant_category_code"));
+    assertTrue(json.contains("JSAPI"));
+    assertTrue(json.contains("5812"));
+  }
+
+  @Test
+  public void testGlobalTradeTypeEnum() {
+    // Test that all trade types have the correct global endpoints
+    assertEquals("/global/v3/transactions/app", GlobalTradeTypeEnum.APP.getUrl());
+    assertEquals("/global/v3/transactions/jsapi", GlobalTradeTypeEnum.JSAPI.getUrl());
+    assertEquals("/global/v3/transactions/native", GlobalTradeTypeEnum.NATIVE.getUrl());
+    assertEquals("/global/v3/transactions/h5", GlobalTradeTypeEnum.H5.getUrl());
+  }
+
+  @Test
+  public void testGlobalTradeTypeEnumValues() {
+    // Test that we have all the main trade types
+    GlobalTradeTypeEnum[] tradeTypes = GlobalTradeTypeEnum.values();
+    assertEquals(4, tradeTypes.length);
+    
+    // Test that we can convert between enum name and TradeTypeEnum
+    for (GlobalTradeTypeEnum globalType : tradeTypes) {
+      // This tests that the enum names match between Global and regular TradeTypeEnum
+      String name = globalType.name();
+      assertNotNull(name);
+      assertTrue(name.equals("APP") || name.equals("JSAPI") || name.equals("NATIVE") || name.equals("H5"));
+    }
+  }
+}
\ No newline at end of file
diff --git a/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/OverseasWxPayExample.java b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/OverseasWxPayExample.java
new file mode 100644
index 0000000000..ccccf9c803
--- /dev/null
+++ b/weixin-java-pay/src/test/java/com/github/binarywang/wxpay/service/impl/OverseasWxPayExample.java
@@ -0,0 +1,153 @@
+package com.github.binarywang.wxpay.service.impl;
+
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3GlobalRequest;
+import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
+import com.github.binarywang.wxpay.bean.result.enums.GlobalTradeTypeEnum;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.constant.WxPayConstants;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import me.chanjar.weixin.common.util.RandomUtils;
+
+/**
+ * 境外微信支付使用示例
+ * Example usage for overseas WeChat Pay
+ *
+ * @author Binary Wang
+ */
+public class OverseasWxPayExample {
+
+  /**
+   * 境外微信支付JSAPI下单示例
+   * Example for overseas WeChat Pay JSAPI order creation
+   */
+  public void createOverseasJsapiOrder(WxPayService payService) throws WxPayException {
+    // 创建境外支付请求对象
+    WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+    
+    // 设置基础订单信息
+    request.setOutTradeNo(RandomUtils.getRandomStr()); // 商户订单号
+    request.setDescription("境外商品购买"); // 商品描述
+    request.setNotifyUrl("https://your-domain.com/notify"); // 支付通知地址
+    
+    // 设置金额信息
+    WxPayUnifiedOrderV3GlobalRequest.Amount amount = new WxPayUnifiedOrderV3GlobalRequest.Amount();
+    amount.setCurrency(WxPayConstants.CurrencyType.CNY); // 币种
+    amount.setTotal(100); // 金额,单位为分
+    request.setAmount(amount);
+    
+    // 设置支付者信息
+    WxPayUnifiedOrderV3GlobalRequest.Payer payer = new WxPayUnifiedOrderV3GlobalRequest.Payer();
+    payer.setOpenid("用户的openid"); // 用户openid
+    request.setPayer(payer);
+    
+    // 设置境外支付必需的参数
+    request.setTradeType("JSAPI"); // 交易类型
+    request.setMerchantCategoryCode("5812"); // 商户类目代码,境外商户必填
+    
+    // 可选:设置场景信息
+    WxPayUnifiedOrderV3GlobalRequest.SceneInfo sceneInfo = new WxPayUnifiedOrderV3GlobalRequest.SceneInfo();
+    sceneInfo.setPayerClientIp("用户IP地址");
+    request.setSceneInfo(sceneInfo);
+    
+    // 调用境外支付接口
+    WxPayUnifiedOrderV3Result.JsapiResult result = payService.createOrderV3Global(
+        GlobalTradeTypeEnum.JSAPI, 
+        request
+    );
+    
+    // 返回的result包含前端需要的支付参数
+    System.out.println("支付参数:" + result);
+  }
+
+  /**
+   * 境外微信支付APP下单示例
+   * Example for overseas WeChat Pay APP order creation
+   */
+  public void createOverseasAppOrder(WxPayService payService) throws WxPayException {
+    WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+    
+    // 设置基础信息
+    request.setOutTradeNo(RandomUtils.getRandomStr());
+    request.setDescription("境外APP商品购买");
+    request.setNotifyUrl("https://your-domain.com/notify");
+    
+    // 设置金额
+    WxPayUnifiedOrderV3GlobalRequest.Amount amount = new WxPayUnifiedOrderV3GlobalRequest.Amount();
+    amount.setCurrency(WxPayConstants.CurrencyType.CNY);
+    amount.setTotal(200); // 2元
+    request.setAmount(amount);
+    
+    // APP支付不需要设置payer.openid,但需要设置空的payer对象
+    request.setPayer(new WxPayUnifiedOrderV3GlobalRequest.Payer());
+    
+    // 境外支付必需参数
+    request.setTradeType("APP");
+    request.setMerchantCategoryCode("5812");
+    
+    // 调用境外APP支付接口
+    WxPayUnifiedOrderV3Result.AppResult result = payService.createOrderV3Global(
+        GlobalTradeTypeEnum.APP, 
+        request
+    );
+    
+    System.out.println("APP支付参数:" + result);
+  }
+
+  /**
+   * 境外微信支付NATIVE下单示例
+   * Example for overseas WeChat Pay NATIVE order creation  
+   */
+  public void createOverseasNativeOrder(WxPayService payService) throws WxPayException {
+    WxPayUnifiedOrderV3GlobalRequest request = new WxPayUnifiedOrderV3GlobalRequest();
+    
+    request.setOutTradeNo(RandomUtils.getRandomStr());
+    request.setDescription("境外扫码支付");
+    request.setNotifyUrl("https://your-domain.com/notify");
+    
+    // 设置金额
+    WxPayUnifiedOrderV3GlobalRequest.Amount amount = new WxPayUnifiedOrderV3GlobalRequest.Amount();
+    amount.setCurrency(WxPayConstants.CurrencyType.CNY);
+    amount.setTotal(300); // 3元
+    request.setAmount(amount);
+    
+    // NATIVE支付不需要设置payer.openid
+    request.setPayer(new WxPayUnifiedOrderV3GlobalRequest.Payer());
+    
+    // 境外支付必需参数
+    request.setTradeType("NATIVE");
+    request.setMerchantCategoryCode("5812");
+    
+    // 调用境外NATIVE支付接口
+    String result = payService.createOrderV3Global(
+        GlobalTradeTypeEnum.NATIVE, 
+        request
+    );
+    
+    System.out.println("NATIVE支付二维码链接:" + result);
+  }
+
+  /**
+   * 配置示例
+   * Configuration example
+   */
+  public WxPayConfig createOverseasConfig() {
+    WxPayConfig config = new WxPayConfig();
+    
+    // 基础配置
+    config.setAppId("你的AppId");
+    config.setMchId("你的境外商户号");
+    config.setMchKey("你的商户密钥");
+    config.setNotifyUrl("https://your-domain.com/notify");
+    
+    // 境外支付使用的是全球API,在代码中会自动使用 https://apihk.mch.weixin.qq.com 作为基础URL
+    // 无需额外设置payBaseUrl,方法内部会自动处理
+    
+    // V3相关配置(境外支付也使用V3接口)
+    config.setPrivateKeyPath("你的私钥文件路径");
+    config.setCertSerialNo("你的商户证书序列号");
+    config.setApiV3Key("你的APIv3密钥");
+    
+    return config;
+  }
+}
\ No newline at end of file