欢迎光临
我们一直在努力

Java后端接入微信支付与支付宝支付完整指南(含沙箱环境配置)

前言

在开发电商、SaaS等需要在线支付的应用时,微信支付和支付宝是最常用的两种支付方式。本文将详细介绍如何在Java后端项目中接入这两种支付方式,包括:

  • 如何申请微信支付和支付宝商户账号

  • 如何配置沙箱环境进行测试

  • Java后端的配置类编写

  • 完整的支付流程代码示例

适用版本:微信支付 V3 API、支付宝开放平台最新API


一、微信支付接入

1.1 申请微信支付商户号

申请条件
  • 已认证的微信公众号(服务号)或小程序

  • 企业营业执照

  • 法人身份证

  • 对公银行账户

申请流程
  • 登录微信公众平台

    • 访问 微信公众平台

    • 使用公众号管理员账号登录

  • 进入微信支付申请页面

    • 左侧菜单:微信支付 → 开通

    • 或直接访问 微信支付 – 中国领先的第三方支付平台 | 微信支付提供安全快捷的支付方式

  • 填写申请信息

    商户简称:显示在用户账单中的名称
    客服电话:用户可联系的电话
    经营类目:根据实际业务选择
    营业执照:上传清晰的营业执照照片
    法人身份证:正反面照片

  • 等待审核

    • 审核时间:1-5个工作日

    • 审核通过后会收到邮件通知

  • 账户验证

    • 使用对公账户向腾讯指定账户打款(随机金额)

    • 验证通过后即可获得商户号

  • 获取关键参数

    申请成功后,在商户平台(微信支付 – 中国领先的第三方支付平台 | 微信支付提供安全快捷的支付方式)获取以下信息:

    商户号(mchId):如 1600000001
    API密钥(apiKey):在API安全中设置,32位字符串
    APIv3密钥(apiV3Key):V3接口使用
    商户证书序列号(merchantCertificateSerial):在API安全中下载证书
    商户私钥(merchantPrivateKey):证书中的私钥文件


    1.2 配置微信支付沙箱环境

    微信支付提供了沙箱环境用于开发测试。

    获取沙箱参数
  • 访问 微信支付 – 中国领先的第三方支付平台 | 微信支付提供安全快捷的支付方式

  • 进入:开发配置 → 沙箱环境

  • 获取沙箱商户号和沙箱API密钥

  • 注意:微信支付沙箱环境功能相对有限,建议使用真实商户号的小额支付进行测试。

    沙箱环境地址

    沙箱API地址:https://api.mch.weixin.qq.com/sandboxnew/
    正式API地址:https://api.mch.weixin.qq.com/


    1.3 Java后端配置

    1.3.1 添加Maven依赖

    <dependencies>
       <!– 微信支付SDK –>
       <dependency>
           <groupId>com.github.wechatpay-apiv3</groupId>
           <artifactId>wechatpay-java</artifactId>
           <version>0.2.14</version>
       </dependency>
       
       <!– HTTP客户端 –>
       <dependency>
           <groupId>org.apache.httpcomponents</groupId>
           <artifactId>httpclient</artifactId>
           <version>4.5.14</version>
       </dependency>
       
       <!– JSON处理 –>
       <dependency>
           <groupId>com.google.code.gson</groupId>
           <artifactId>gson</artifactId>
           <version>2.10.1</version>
       </dependency>
    </dependencies>

    1.3.2 配置文件 application.yml

    wechat:
    pay:
       # 商户号
      mch-id: "1600000001"
       # 商户API密钥(V2接口使用)
      api-key: "your-api-key-here"
       # 商户APIv3密钥
      api-v3-key: "your-api-v3-key-here"
       # 商户证书序列号
      merchant-certificate-serial: "your-certificate-serial"
       # 商户私钥文件路径(classpath下的文件名)
      merchant-private-key-path: "classpath:cert/apiclient_key.pem"
       # 支付结果通知地址(必须是公网可访问的HTTPS地址)
      notify-url: "https://your-domain.com/api/pay/wechat/notify"
       # 退款结果通知地址
      refund-notify-url: "https://your-domain.com/api/pay/wechat/refund-notify"

    1.3.3 微信支付配置类

    package com.example.config;

    import com.wechat.pay.java.core.Config;
    import com.wechat.pay.java.core.RSAAutoCertificateConfig;
    import com.wechat.pay.java.core.notification.NotificationConfig;
    import com.wechat.pay.java.core.notification.NotificationParser;
    import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
    import com.wechat.pay.java.service.payments.nativepay.NativePayService;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    import java.io.IOException;
    import java.io.InputStream;
    import java.nio.charset.StandardCharsets;

    /**
    * 微信支付配置类
    */
    @Configuration
    public class WechatPayConfig {

       @Value("${wechat.pay.mch-id}")
       private String merchantId;

       @Value("${wechat.pay.api-v3-key}")
       private String apiV3Key;

       @Value("${wechat.pay.merchant-certificate-serial}")
       private String merchantCertificateSerial;

       @Value("${wechat.pay.merchant-private-key-path}")
       private String merchantPrivateKeyPath;

       @Value("${wechat.pay.notify-url}")
       private String notifyUrl;

       /**
        * 配置微信支付核心配置
        */
       @Bean
       public Config wechatPayConfig() throws IOException {
           // 读取商户私钥
           String privateKey = loadPrivateKey();

           // 构建配置(自动更新平台证书)
           return new RSAAutoCertificateConfig.Builder()
                  .merchantId(merchantId)
                  .privateKey(privateKey)
                  .merchantSerialNumber(merchantCertificateSerial)
                  .apiV3Key(apiV3Key)
                  .build();
      }

       /**
        * 配置Native支付服务(PC扫码支付)
        */
       @Bean
       public NativePayService nativePayService(Config config) {
           return new NativePayService.Builder().config(config).build();
      }

       /**
        * 配置JSAPI支付服务(微信内支付)
        */
       @Bean
       public JsapiServiceExtension jsapiServiceExtension(Config config) {
           return new JsapiServiceExtension.Builder().config(config).build();
      }

       /**
        * 配置通知解析器
        */
       @Bean
       public NotificationParser notificationParser(Config config) {
           return new NotificationParser((NotificationConfig) config);
      }

       /**
        * 读取商户私钥文件
        */
       private String loadPrivateKey() throws IOException {
           try (InputStream inputStream = getClass().getClassLoader()
                  .getResourceAsStream("cert/apiclient_key.pem")) {
               if (inputStream == null) {
                   throw new IOException("商户私钥文件不存在");
              }
               return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
          }
      }
    }

    1.3.4 微信支付Service类

    package com.example.service;

    import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
    import com.wechat.pay.java.service.payments.jsapi.model.*;
    import com.wechat.pay.java.service.payments.model.Transaction;
    import com.wechat.pay.java.service.payments.nativepay.NativePayService;
    import com.wechat.pay.java.service.payments.nativepay.model.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;

    import java.util.HashMap;
    import java.util.Map;

    /**
    * 微信支付Service
    */
    @Service
    public class WechatPayService {

       private static final Logger log = LoggerFactory.getLogger(WechatPayService.class);

       @Autowired
       private NativePayService nativePayService;

       @Autowired
       private JsapiServiceExtension jsapiServiceExtension;

       @Value("${wechat.pay.notify-url}")
       private String notifyUrl;

       /**
        * 创建Native支付订单(PC扫码支付)
        *
        * @param orderId   商户订单号
        * @param amount   支付金额(单位:分)
        * @param description 商品描述
        * @return 二维码链接
        */
       public String createNativeOrder(String orderId, Long amount, String description) {
           try {
               // 构建请求参数
               PrepayRequest request = new PrepayRequest();
               request.setAppid("your-appid");           // 公众号或小程序appid
               request.setMchid("your-mchid");           // 商户号
               request.setDescription(description);
               request.setOutTradeNo(orderId);
               request.setNotifyUrl(notifyUrl);

               // 设置金额
               Amount amountObj = new Amount();
               amountObj.setTotal(amount.intValue());
               amountObj.setCurrency("CNY");
               request.setAmount(amountObj);

               // 调用下单接口
               PrepayResponse response = nativePayService.prepay(request);
               log.info("Native支付订单创建成功,订单号:{},二维码:{}", orderId, response.getCodeUrl());

               return response.getCodeUrl();
          } catch (Exception e) {
               log.error("Native支付订单创建失败,订单号:{}", orderId, e);
               throw new RuntimeException("创建支付订单失败", e);
          }
      }

       /**
        * 创建JSAPI支付订单(微信内H5支付)
        *
        * @param orderId     商户订单号
        * @param amount     支付金额(单位:分)
        * @param description 商品描述
        * @param openid     用户openid
        * @return 支付参数Map,前端用于调起支付
        */
       public Map<String, String> createJsapiOrder(String orderId, Long amount,
                                                   String description, String openid) {
           try {
               // 构建请求参数
               PrepayRequest request = new PrepayRequest();
               request.setAppid("your-appid");
               request.setMchid("your-mchid");
               request.setDescription(description);
               request.setOutTradeNo(orderId);
               request.setNotifyUrl(notifyUrl);

               // 设置金额
               Amount amountObj = new Amount();
               amountObj.setTotal(amount.intValue());
               amountObj.setCurrency("CNY");
               request.setAmount(amountObj);

               // 设置支付者信息
               Payer payer = new Payer();
               payer.setOpenid(openid);
               request.setPayer(payer);

               // 调用下单接口,获取前端调起支付所需的参数
               PrepayWithRequestPaymentResponse response = jsapiServiceExtension.prepayWithRequestPayment(request);

               // 封装返回给前端的参数
               Map<String, String> paymentParams = new HashMap<>();
               paymentParams.put("appId", response.getAppId());
               paymentParams.put("timeStamp", response.getTimeStamp());
               paymentParams.put("nonceStr", response.getNonceStr());
               paymentParams.put("package", response.getPackageVal());
               paymentParams.put("signType", response.getSignType());
               paymentParams.put("paySign", response.getPaySign());

               log.info("JSAPI支付订单创建成功,订单号:{}", orderId);
               return paymentParams;
          } catch (Exception e) {
               log.error("JSAPI支付订单创建失败,订单号:{}", orderId, e);
               throw new RuntimeException("创建支付订单失败", e);
          }
      }

       /**
        * 查询订单状态
        *
        * @param orderId 商户订单号
        * @return 订单状态
        */
       public Transaction queryOrder(String orderId) {
           try {
               QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
               request.setMchid("your-mchid");
               request.setOutTradeNo(orderId);

               Transaction transaction = nativePayService.queryOrderByOutTradeNo(request);
               log.info("订单查询成功,订单号:{},状态:{}", orderId, transaction.getTradeState());
               return transaction;
          } catch (Exception e) {
               log.error("订单查询失败,订单号:{}", orderId, e);
               throw new RuntimeException("查询订单失败", e);
          }
      }

       /**
        * 关闭订单
        *
        * @param orderId 商户订单号
        */
       public void closeOrder(String orderId) {
           try {
               CloseOrderRequest request = new CloseOrderRequest();
               request.setMchid("your-mchid");
               request.setOutTradeNo(orderId);

               nativePayService.closeOrder(request);
               log.info("订单关闭成功,订单号:{}", orderId);
          } catch (Exception e) {
               log.error("订单关闭失败,订单号:{}", orderId, e);
               throw new RuntimeException("关闭订单失败", e);
          }
      }
    }

    1.3.5 微信支付Controller类

    package com.example.controller;

    import com.example.service.WechatPayService;
    import com.wechat.pay.java.core.notification.NotificationParser;
    import com.wechat.pay.java.core.notification.RequestParam;
    import com.wechat.pay.java.service.payments.model.Transaction;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;

    import javax.servlet.http.HttpServletRequest;
    import java.io.BufferedReader;
    import java.util.HashMap;
    import java.util.Map;

    /**
    * 微信支付Controller
    */
    @RestController
    @RequestMapping("/api/pay/wechat")
    public class WechatPayController {

       private static final Logger log = LoggerFactory.getLogger(WechatPayController.class);

       @Autowired
       private WechatPayService wechatPayService;

       @Autowired
       private NotificationParser notificationParser;

       /**
        * 创建Native支付订单(返回二维码链接)
        */
       @PostMapping("/native/create")
       public Map<String, Object> createNativeOrder(@RequestParam String orderId,
                                                     @RequestParam Long amount,
                                                     @RequestParam String description) {
           Map<String, Object> result = new HashMap<>();
           try {
               String codeUrl = wechatPayService.createNativeOrder(orderId, amount, description);
               result.put("code", 200);
               result.put("data", codeUrl);
               result.put("message", "创建成功");
          } catch (Exception e) {
               result.put("code", 500);
               result.put("message", e.getMessage());
          }
           return result;
      }

       /**
        * 创建JSAPI支付订单(返回前端调起支付的参数)
        */
       @PostMapping("/jsapi/create")
       public Map<String, Object> createJsapiOrder(@RequestParam String orderId,
                                                    @RequestParam Long amount,
                                                    @RequestParam String description,
                                                    @RequestParam String openid) {
           Map<String, Object> result = new HashMap<>();
           try {
               Map<String, String> paymentParams = wechatPayService.createJsapiOrder(
                       orderId, amount, description, openid);
               result.put("code", 200);
               result.put("data", paymentParams);
               result.put("message", "创建成功");
          } catch (Exception e) {
               result.put("code", 500);
               result.put("message", e.getMessage());
          }
           return result;
      }

       /**
        * 微信支付异步通知回调
        */
       @PostMapping("/notify")
       public Map<String, String> handleNotify(HttpServletRequest request) {
           Map<String, String> result = new HashMap<>();
           try {
               // 读取请求体
               String body = readRequestBody(request);
               
               // 获取请求头
               String signature = request.getHeader("Wechatpay-Signature");
               String nonce = request.getHeader("Wechatpay-Nonce");
               String timestamp = request.getHeader("Wechatpay-Timestamp");
               String serial = request.getHeader("Wechatpay-Serial");

               // 构建通知参数
               RequestParam requestParam = new RequestParam.Builder()
                      .serialNumber(serial)
                      .nonce(nonce)
                      .signature(signature)
                      .timestamp(timestamp)
                      .body(body)
                      .build();

               // 解析通知内容
               Transaction transaction = notificationParser.parse(requestParam, Transaction.class);

               // 处理支付结果
               if ("SUCCESS".equals(transaction.getTradeState())) {
                   String orderId = transaction.getOutTradeNo();
                   log.info("支付成功,订单号:{}", orderId);
                   
                   // TODO: 更新订单状态为已支付
                   // orderService.updateOrderStatus(orderId, OrderStatus.PAID);
              }

               // 返回成功响应
               result.put("code", "SUCCESS");
               result.put("message", "处理成功");
          } catch (Exception e) {
               log.error("处理微信支付通知失败", e);
               result.put("code", "FAIL");
               result.put("message", e.getMessage());
          }
           return result;
      }

       /**
        * 查询订单状态
        */
       @GetMapping("/query/{orderId}")
       public Map<String, Object> queryOrder(@PathVariable String orderId) {
           Map<String, Object> result = new HashMap<>();
           try {
               Transaction transaction = wechatPayService.queryOrder(orderId);
               result.put("code", 200);
               result.put("data", transaction);
               result.put("message", "查询成功");
          } catch (Exception e) {
               result.put("code", 500);
               result.put("message", e.getMessage());
          }
           return result;
      }

       /**
        * 读取请求体内容
        */
       private String readRequestBody(HttpServletRequest request) {
           try (BufferedReader reader = request.getReader()) {
               StringBuilder sb = new StringBuilder();
               String line;
               while ((line = reader.readLine()) != null) {
                   sb.append(line);
              }
               return sb.toString();
          } catch (Exception e) {
               log.error("读取请求体失败", e);
               return "";
          }
      }
    }


    二、支付宝支付接入

    2.1 申请支付宝开放平台账号

    申请条件
    • 企业支付宝账号

    • 企业营业执照

    • 法人身份证

    申请流程
  • 注册企业支付宝账号

    • 访问 注册 – 支付宝

    • 选择"企业账户"注册

  • 入驻开放平台

    • 访问 支付宝开放平台

    • 使用企业支付宝账号登录

    • 完成开发者入驻(需要企业认证)

  • 创建应用

    • 进入开放平台 → 控制台 → 创建应用

    • 选择"网页/移动应用"

    • 填写应用名称、图标等信息

  • 添加支付能力

    • 在应用详情页 → 产品绑定

    • 添加"电脑网站支付"或"手机网站支付"

    • 等待审核(通常1-3个工作日)

  • 配置密钥

    • 使用支付宝开放平台密钥工具生成密钥对

    • 在应用详情页 → 开发设置 → 接口加签方式

    • 上传应用公钥,保存支付宝公钥

  • 获取关键参数

    应用ID(appId):在应用详情页获取
    应用私钥(privateKey):本地生成的私钥
    支付宝公钥(alipayPublicKey):上传公钥后获取的支付宝公钥


    2.2 配置支付宝沙箱环境

    支付宝提供了完整的沙箱环境用于开发测试。

    获取沙箱参数
  • 访问 支付宝开放平台

  • 进入:开发中心 → 沙箱环境

  • 获取以下信息:

    沙箱应用ID
    沙箱网关地址
    沙箱RSA2密钥(需自己生成)

  • 沙箱环境地址

    沙箱网关:https://openapi-sandbox.dl.alipaydev.com/gateway.do
    正式网关:https://openapi.alipay.com/gateway.do

    沙箱测试账号

    支付宝会提供沙箱买家账号和卖家账号,用于测试支付流程。


    2.3 Java后端配置

    2.3.1 添加Maven依赖

    <dependencies>
       <!– 支付宝SDK –>
       <dependency>
           <groupId>com.alipay.sdk</groupId>
           <artifactId>alipay-sdk-java</artifactId>
           <version>4.39.0.ALL</version>
       </dependency>
       
       <!– 支付宝小程序/生活号SDK(可选) –>
       <dependency>
           <groupId>com.alipay.sdk</groupId>
           <artifactId>alipay-sdk-java-duoyilang</artifactId>
           <version>4.39.0.ALL</version>
       </dependency>
    </dependencies>

    2.3.2 配置文件 application.yml

    alipay:
     # 应用ID
    app-id: "2021000000000000"
     # 应用私钥
    private-key: "MIIEvgIBADANBgkqhkiG9w0BAQEFAASC…"
     # 支付宝公钥
    alipay-public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ…"
     # 支付网关(沙箱环境使用沙箱网关)
    gateway-url: "https://openapi-sandbox.dl.alipaydev.com/gateway.do"
     # 正式环境网关
     # gateway-url: "https://openapi.alipay.com/gateway.do"
     # 签名类型
    sign-type: "RSA2"
     # 异步通知地址
    notify-url: "https://your-domain.com/api/pay/alipay/notify"
     # 同步跳转地址
    return-url: "https://your-domain.com/api/pay/alipay/return"
     # 编码格式
    charset: "UTF-8"
     # 格式
    format: "json"

    2.3.3 支付宝支付配置类

    package com.example.config;

    import com.alipay.api.AlipayClient;
    import com.alipay.api.AlipayConfig;
    import com.alipay.api.DefaultAlipayClient;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    /**
    * 支付宝支付配置类
    */
    @Configuration
    public class AlipayConfig {

       @Value("${alipay.app-id}")
       private String appId;

       @Value("${alipay.private-key}")
       private String privateKey;

       @Value("${alipay.alipay-public-key}")
       private String alipayPublicKey;

       @Value("${alipay.gateway-url}")
       private String gatewayUrl;

       @Value("${alipay.sign-type}")
       private String signType;

       @Value("${alipay.charset}")
       private String charset;

       @Value("${alipay.format}")
       private String format;

       @Value("${alipay.notify-url}")
       private String notifyUrl;

       @Value("${alipay.return-url}")
       private String returnUrl;

       /**
        * 配置支付宝客户端
        */
       @Bean
       public AlipayClient alipayClient() throws Exception {
           AlipayConfig alipayConfig = new AlipayConfig();
           alipayConfig.setServerUrl(gatewayUrl);
           alipayConfig.setAppId(appId);
           alipayConfig.setPrivateKey(privateKey);
           alipayConfig.setAlipayPublicKey(alipayPublicKey);
           alipayConfig.setSignType(signType);
           alipayConfig.setCharset(charset);
           alipayConfig.setFormat(format);

           return new DefaultAlipayClient(alipayConfig);
      }

       // Getter方法,供其他类使用
       public String getNotifyUrl() {
           return notifyUrl;
      }

       public String getReturnUrl() {
           return returnUrl;
      }

       public String getAppId() {
           return appId;
      }
    }

    2.3.4 支付宝支付Service类

    package com.example.service;

    import com.alipay.api.AlipayApiException;
    import com.alipay.api.AlipayClient;
    import com.alipay.api.domain.*;
    import com.alipay.api.internal.util.AlipaySignature;
    import com.alipay.api.request.*;
    import com.alipay.api.response.*;
    import com.example.config.AlipayConfig;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;

    import java.util.HashMap;
    import java.util.Map;

    /**
    * 支付宝支付Service
    */
    @Service
    public class AlipayService {

       private static final Logger log = LoggerFactory.getLogger(AlipayService.class);

       @Autowired
       private AlipayClient alipayClient;

       @Autowired
       private AlipayConfig alipayConfig;

       /**
        * 创建电脑网站支付订单
        *
        * @param orderId     商户订单号
        * @param amount     支付金额(单位:元)
        * @param subject     订单标题
        * @param body       订单描述
        * @return 支付表单HTML
        */
       public String createPagePayOrder(String orderId, String amount, String subject, String body) {
           try {
               AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
               request.setNotifyUrl(alipayConfig.getNotifyUrl());
               request.setReturnUrl(alipayConfig.getReturnUrl());

               AlipayTradePagePayModel model = new AlipayTradePagePayModel();
               model.setOutTradeNo(orderId);
               model.setTotalAmount(amount);
               model.setSubject(subject);
               model.setBody(body);
               model.setProductCode("FAST_INSTANT_TRADE_PAY");
               request.setBizModel(model);

               AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
               if (response.isSuccess()) {
                   log.info("电脑网站支付订单创建成功,订单号:{}", orderId);
                   return response.getBody();
              } else {
                   log.error("电脑网站支付订单创建失败,订单号:{},错误:{}", orderId, response.getSubMsg());
                   throw new RuntimeException("创建支付订单失败:" + response.getSubMsg());
              }
          } catch (AlipayApiException e) {
               log.error("电脑网站支付订单创建异常,订单号:{}", orderId, e);
               throw new RuntimeException("创建支付订单异常", e);
          }
      }

       /**
        * 创建手机网站支付订单
        *
        * @param orderId     商户订单号
        * @param amount     支付金额(单位:元)
        * @param subject     订单标题
        * @param body       订单描述
        * @return 支付链接
        */
       public String createWapPayOrder(String orderId, String amount, String subject, String body) {
           try {
               AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
               request.setNotifyUrl(alipayConfig.getNotifyUrl());
               request.setReturnUrl(alipayConfig.getReturnUrl());

               AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
               model.setOutTradeNo(orderId);
               model.setTotalAmount(amount);
               model.setSubject(subject);
               model.setBody(body);
               model.setProductCode("QUICK_WAP_WAY");
               request.setBizModel(model);

               AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
               if (response.isSuccess()) {
                   log.info("手机网站支付订单创建成功,订单号:{}", orderId);
                   return response.getBody();
              } else {
                   log.error("手机网站支付订单创建失败,订单号:{},错误:{}", orderId, response.getSubMsg());
                   throw new RuntimeException("创建支付订单失败:" + response.getSubMsg());
              }
          } catch (AlipayApiException e) {
               log.error("手机网站支付订单创建异常,订单号:{}", orderId, e);
               throw new RuntimeException("创建支付订单异常", e);
          }
      }

       /**
        * 查询订单状态
        *
        * @param orderId 商户订单号
        * @return 订单信息
        */
       public AlipayTradeQueryResponse queryOrder(String orderId) {
           try {
               AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
               AlipayTradeQueryModel model = new AlipayTradeQueryModel();
               model.setOutTradeNo(orderId);
               request.setBizModel(model);

               AlipayTradeQueryResponse response = alipayClient.execute(request);
               if (response.isSuccess()) {
                   log.info("订单查询成功,订单号:{},状态:{}", orderId, response.getTradeStatus());
                   return response;
              } else {
                   log.error("订单查询失败,订单号:{},错误:{}", orderId, response.getSubMsg());
                   throw new RuntimeException("查询订单失败:" + response.getSubMsg());
              }
          } catch (AlipayApiException e) {
               log.error("订单查询异常,订单号:{}", orderId, e);
               throw new RuntimeException("查询订单异常", e);
          }
      }

       /**
        * 关闭订单
        *
        * @param orderId 商户订单号
        */
       public void closeOrder(String orderId) {
           try {
               AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
               AlipayTradeCloseModel model = new AlipayTradeCloseModel();
               model.setOutTradeNo(orderId);
               request.setBizModel(model);

               AlipayTradeCloseResponse response = alipayClient.execute(request);
               if (response.isSuccess()) {
                   log.info("订单关闭成功,订单号:{}", orderId);
              } else {
                   log.error("订单关闭失败,订单号:{},错误:{}", orderId, response.getSubMsg());
                   throw new RuntimeException("关闭订单失败:" + response.getSubMsg());
              }
          } catch (AlipayApiException e) {
               log.error("订单关闭异常,订单号:{}", orderId, e);
               throw new RuntimeException("关闭订单异常", e);
          }
      }

       /**
        * 申请退款
        *
        * @param orderId     商户订单号
        * @param refundId     退款订单号
        * @param refundAmount 退款金额
        * @param refundReason 退款原因
        * @return 退款结果
        */
       public AlipayTradeRefundResponse refund(String orderId, String refundId,
                                               String refundAmount, String refundReason) {
           try {
               AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
               AlipayTradeRefundModel model = new AlipayTradeRefundModel();
               model.setOutTradeNo(orderId);
               model.setOutRequestNo(refundId);
               model.setRefundAmount(refundAmount);
               model.setRefundReason(refundReason);
               request.setBizModel(model);

               AlipayTradeRefundResponse response = alipayClient.execute(request);
               if (response.isSuccess()) {
                   log.info("退款申请成功,订单号:{},退款号:{}", orderId, refundId);
                   return response;
              } else {
                   log.error("退款申请失败,订单号:{},错误:{}", orderId, response.getSubMsg());
                   throw new RuntimeException("退款申请失败:" + response.getSubMsg());
              }
          } catch (AlipayApiException e) {
               log.error("退款申请异常,订单号:{}", orderId, e);
               throw new RuntimeException("退款申请异常", e);
          }
      }

       /**
        * 验证支付宝异步通知签名
        *
        * @param params 通知参数
        * @return 验证结果
        */
       public boolean verifyNotify(Map<String, String> params) {
           try {
               return AlipaySignature.rsaCheckV1(params,
                       alipayConfig.getAlipayPublicKey(),
                       "UTF-8",
                       "RSA2");
          } catch (AlipayApiException e) {
               log.error("支付宝通知签名验证失败", e);
               return false;
          }
      }
    }

    2.3.5 支付宝支付Controller类

    package com.example.controller;

    import com.alipay.api.response.AlipayTradeQueryResponse;
    import com.alipay.api.response.AlipayTradeRefundResponse;
    import com.example.service.AlipayService;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;

    /**
    * 支付宝支付Controller
    */
    @RestController
    @RequestMapping("/api/pay/alipay")
    public class AlipayController {

       private static final Logger log = LoggerFactory.getLogger(AlipayController.class);

       @Autowired
       private AlipayService alipayService;

       /**
        * 创建电脑网站支付订单
        */
       @PostMapping("/page/create")
       public void createPagePayOrder(@RequestParam String orderId,
                                       @RequestParam String amount,
                                       @RequestParam String subject,
                                       @RequestParam String body,
                                       HttpServletResponse response) {
           try {
               String formHtml = alipayService.createPagePayOrder(orderId, amount, subject, body);
               response.setContentType("text/html;charset=UTF-8");
               response.getWriter().write(formHtml);
               response.getWriter().flush();
          } catch (IOException e) {
               log.error("返回支付表单失败", e);
               throw new RuntimeException("创建支付订单失败", e);
          }
      }

       /**
        * 创建手机网站支付订单
        */
       @PostMapping("/wap/create")
       public void createWapPayOrder(@RequestParam String orderId,
                                      @RequestParam String amount,
                                      @RequestParam String subject,
                                      @RequestParam String body,
                                      HttpServletResponse response) {
           try {
               String formHtml = alipayService.createWapPayOrder(orderId, amount, subject, body);
               response.setContentType("text/html;charset=UTF-8");
               response.getWriter().write(formHtml);
               response.getWriter().flush();
          } catch (IOException e) {
               log.error("返回支付表单失败", e);
               throw new RuntimeException("创建支付订单失败", e);
          }
      }

       /**
        * 支付宝异步通知回调
        */
       @PostMapping("/notify")
       public String handleNotify(HttpServletRequest request) {
           try {
               // 获取支付宝POST过来的信息
               Map<String, String> params = new HashMap<>();
               Map<String, String[]> requestParams = request.getParameterMap();
               for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
                   String name = iter.next();
                   String[] values = requestParams.get(name);
                   String valueStr = "";
                   for (int i = 0; i < values.length; i++) {
                       valueStr = (i == values.length – 1) ? valueStr + values[i] : valueStr + values[i] + ",";
                  }
                   params.put(name, valueStr);
              }

               // 验证签名
               boolean signVerified = alipayService.verifyNotify(params);
               if (signVerified) {
                   // 获取关键参数
                   String orderId = params.get("out_trade_no");
                   String tradeNo = params.get("trade_no");
                   String tradeStatus = params.get("trade_status");
                   String totalAmount = params.get("total_amount");

                   log.info("支付宝异步通知,订单号:{},交易号:{},状态:{}", orderId, tradeNo, tradeStatus);

                   // 处理支付结果
                   if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
                       // TODO: 验证金额是否正确
                       // TODO: 更新订单状态为已支付
                       // orderService.updateOrderStatus(orderId, OrderStatus.PAID);
                       return "success";
                  }
                   return "success";
              } else {
                   log.error("支付宝异步通知签名验证失败");
                   return "failure";
              }
          } catch (Exception e) {
               log.error("处理支付宝通知异常", e);
               return "failure";
          }
      }

       /**
        * 支付宝同步跳转(支付成功后跳转)
        */
       @GetMapping("/return")
       public String handleReturn(HttpServletRequest request) {
           // 重定向到前端支付成功页面
           return "redirect:/pay/success";
      }

       /**
        * 查询订单状态
        */
       @GetMapping("/query/{orderId}")
       public Map<String, Object> queryOrder(@PathVariable String orderId) {
           Map<String, Object> result = new HashMap<>();
           try {
               AlipayTradeQueryResponse response = alipayService.queryOrder(orderId);
               result.put("code", 200);
               result.put("data", response);
               result.put("message", "查询成功");
          } catch (Exception e) {
               result.put("code", 500);
               result.put("message", e.getMessage());
          }
           return result;
      }

       /**
        * 申请退款
        */
       @PostMapping("/refund")
       public Map<String, Object> refund(@RequestParam String orderId,
                                          @RequestParam String refundId,
                                          @RequestParam String refundAmount,
                                          @RequestParam String refundReason) {
           Map<String, Object> result = new HashMap<>();
           try {
               AlipayTradeRefundResponse response = alipayService.refund(
                       orderId, refundId, refundAmount, refundReason);
               result.put("code", 200);
               result.put("data", response);
               result.put("message", "退款成功");
          } catch (Exception e) {
               result.put("code", 500);
               result.put("message", e.getMessage());
          }
           return result;
      }
    }


    三、支付流程对比

    特性微信支付支付宝支付
    申请难度 需要认证公众号,审核严格 企业支付宝入驻,审核较快
    沙箱环境 功能有限,建议小额真实测试 功能完善,有测试账号
    支付方式 Native(扫码)、JSAPI、小程序、H5 电脑网站、手机网站、APP
    金额单位 分(Integer) 元(String,2位小数)
    通知方式 异步通知(POST JSON) 异步通知(POST Form)
    签名方式 V3使用RSA,证书方式 RSA2,公钥私钥方式

    四、常见问题及解决方案

    4.1 微信支付常见问题

    Q1: 调用接口返回"签名错误"

    • 检查API密钥是否正确

    • 检查商户证书是否过期

    • 确认请求参数的编码格式

    Q2: 支付回调通知接收不到

    • 确认通知地址是公网可访问的HTTPS地址

    • 检查服务器防火墙是否放行

    • 查看微信商户平台的回调日志

    Q3: 沙箱环境测试报错

    • 微信沙箱环境功能有限,建议使用真实商户号小额测试

    • 确保使用正确的沙箱API地址

    4.2 支付宝支付常见问题

    Q1: 调用接口返回"签名错误"

    • 检查应用私钥和支付宝公钥是否匹配

    • 确认签名方式(RSA2)与配置一致

    • 使用支付宝密钥工具重新生成密钥对

    Q2: 异步通知验签失败

    • 确认使用的是支付宝公钥(非应用公钥)

    • 检查公钥是否完整(包含BEGIN和END标记)

    • 确认签名方式与配置一致

    Q3: 沙箱环境无法调起支付

    • 确认使用沙箱网关地址

    • 使用沙箱提供的测试账号登录

    • 检查沙箱应用是否添加了支付能力


    五、安全建议

    5.1 密钥管理

    /**
    * 密钥配置最佳实践
    *
    * 1. 私钥不要硬编码在代码中
    * 2. 使用配置中心或环境变量管理密钥
    * 3. 生产环境使用密钥管理服务(KMS)
    * 4. 定期轮换密钥
    */

    5.2 金额校验

    /**
    * 支付回调金额校验示例
    *
    * 必须在回调中校验金额,防止恶意篡改
    */
    public boolean verifyAmount(String orderId, String notifyAmount) {
       // 从数据库查询订单金额
       Order order = orderService.getByOrderId(orderId);
       BigDecimal orderAmount = order.getTotalAmount();
       BigDecimal payAmount = new BigDecimal(notifyAmount);
       
       // 校验金额是否一致
       return orderAmount.compareTo(payAmount) == 0;
    }

    5.3 幂等性处理

    /**
    * 支付回调幂等性处理示例
    *
    * 防止重复通知导致重复处理
    */
    public void handlePaymentSuccess(String orderId) {
       // 使用分布式锁或数据库乐观锁保证幂等
       boolean locked = redisLock.tryLock("pay:" + orderId, 10, TimeUnit.SECONDS);
       if (locked) {
           try {
               Order order = orderService.getByOrderId(orderId);
               if (order.getStatus() != OrderStatus.PAID) {
                   // 更新订单状态
                   orderService.updateOrderStatus(orderId, OrderStatus.PAID);
                   // 其他业务处理
              }
          } finally {
               redisLock.unlock("pay:" + orderId);
          }
      }
    }


    六、总结

    本文详细介绍了Java后端接入微信支付和支付宝支付的完整流程,包括:

  • 商户账号申请:两个平台都需要企业资质,申请流程相对规范

  • 沙箱环境配置:支付宝沙箱更完善,微信建议小额真实测试

  • Java配置类编写:使用官方SDK,配置类清晰易维护

  • 支付流程实现:创建订单、异步通知、查询退款等核心功能

  • 在实际开发中,建议:

    • 优先使用官方SDK,避免自己封装

    • 做好异常处理和日志记录

    • 重视安全性,特别是密钥管理和金额校验

    • 充分测试后再上线


    参考资料

    • 微信支付开发文档

    • 支付宝开放平台文档

    • 微信支付Java SDK

    • 支付宝Java SDK

    赞(0)
    未经允许不得转载:171主机测评 » Java后端接入微信支付与支付宝支付完整指南(含沙箱环境配置)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址