微信支付-开发教程

一、JDK版本需要1.8u162+以上版本

微信支付-开发教程_第1张图片


        
            com.github.wechatpay-apiv3
            wechatpay-java
            0.2.7
        
        
            com.github.wechatpay-apiv3
            wechatpay-apache-httpclient
            0.4.9
        

二、前期准备

官网引导:接入前准备-小程序支付 | 微信支付商户平台文档中心

①appid:小程序appid-登录小程序后台获取

②secret:小程序密钥-登录小程序后台获取

登录小程序后台:微信支付-开发教程_第2张图片

微信支付-开发教程_第3张图片

③appV3Secret:商户apiV3密钥-登录商户后台获取

④mchid:商户号-登录商户后台获取(商户号要绑定小程序)

⑤certpath:微信平台证书-登录商户后台获取

⑥privateKeyPath:商户私钥证书-登录商户后台获取

⑦merchantSerialNumber:商户证书序列化-登录商户后台获取

登录商户后台:微信支付-开发教程_第4张图片

三、证书存放地

微信支付-开发教程_第5张图片

四、配置与加载

# application-dev.yml

wx:
  miniapp:
    configs:
    - appid: wx1fcxxxxxxxx
      secret: 1exxxxxxxxxxxxxxxxxxxxxxxxxxxxx
      token:  #微信小程序消息服务器配置的token
      aesKey:  #微信小程序消息服务器配置的EncodingAESKey
      msgDataFormat: JSON
      appV3Secret: ADxxxAas654xxxxxxxxxxxxxxxxxx # V3密钥
      mchid: 12345678 # 商户号
      certpath: D:/workspace/hxj-miniprogram-java/src/main/resources/wxpay/apiclient_cert.pem # 微信平台证书(发布时换成linux地址)
      privateKeyPath: D:/workspace/hxj-miniprogram-java/src/main/resources/wxpay/apiclient_key.pem # 商户私钥证书(发布时换成linux地址)
      payCallBackUrl: https://xxxxxxxxxxxxx/wechatPay/payCallback # 支付结束回调地址
      timeExpire: 1200000 # 交易过期时间(单位毫秒)
      merchantSerialNumber: 37ABCD098765ADCBF124656099AB # 商户证书序列号

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;

/**
 * @author xuhj
 */
@Slf4j
@Data
@ConfigurationProperties(prefix = "wx.miniapp")
public class WxMaProperties {
    private List configs;

    @Data
    public static class Config {
        /**
         * 设置微信小程序的appid
         */
        private String appid;

        /**
         * 设置微信小程序的Secret
         */
        private String secret;

        /**
         * 设置微信小程序消息服务器配置的token
         */
        private String token;

        /**
         * 设置微信小程序消息服务器配置的EncodingAESKey
         */
        private String aesKey;

        /**
         * 消息格式,XML或者JSON
         */
        private String msgDataFormat;
        /**
         * appV3Secret V3密钥
         */
        private String appV3Secret;
        /**
         * mchid 商户号
         */
        private String mchid;
        /**
         * 微信支付平台证书地址,注意 windows地址与linux地址不同
         */
        private String certpath;
        /**
         * 商户API证书的路径(一般和上边的certpath在一起下载)
         */
        private String privateKeyPath;
        /**
         * 支付回调地址
         */
        private String payCallBackUrl;
        /**
         * 交易过期时间(单位毫秒)
         */
        private Long timeExpire;
        /**
         * 商户证书序列号
         */
        private String merchantSerialNumber;

    }
}

五、证书自动更新

import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WxPayConfig {

    @Autowired
    private WxMaProperties properties;

    /**
     * 初始化商户配置(只能加载一次)
     * 确保是单例
     *
     * @return
     */
    @Bean
    public RSAAutoCertificateConfig rsaAutoCertificateConfig() {
        RSAAutoCertificateConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(properties.getConfigs().get(0).getMchid())
                .privateKeyFromPath(properties.getConfigs().get(0).getPrivateKeyPath())
                .merchantSerialNumber(properties.getConfigs().get(0).getMerchantSerialNumber())
                .apiV3Key(properties.getConfigs().get(0).getAppV3Secret())
                .build();
        return 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.core.notification.RequestParam;
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 io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;

import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.WECHAT_PAY_SIGNATURE;
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_NONCE;
import static com.wechat.pay.java.core.http.Constant.WECHAT_PAY_TIMESTAMP;

/**
 * 

* 微信支付 前端控制器 *

* * @author sunziwen * @since 2023-03-23 */ @Api(tags = {"微信支付"}) @Slf4j @RestController @RequestMapping("/wechatPay") @Validated public class PayController extends BaseController { /** * 配置文件 */ @Autowired private WxMaProperties properties; @Autowired private RSAAutoCertificateConfig rsaAutoCertificateConfig; @Autowired private IOrderMasterService iOrderMasterService; @ApiOperation(value = "预支付-委托") @PostMapping("preparePayment") @ApiImplicitParams({ @ApiImplicitParam(name = "openid", value = "openid"), @ApiImplicitParam(name = "description", value = "商品描述"), @ApiImplicitParam(name = "outTradeNo", value = "商户订单号"), @ApiImplicitParam(name = "total", value = "订单总金额,单位为分") }) public ServiceResult preparePayment(String openid, String description, String outTradeNo, Integer total) { // 初始化服务 JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).build(); PrepayRequest request = new PrepayRequest(); // 应用ID request.setAppid(properties.getConfigs().get(0).getAppid()); // 直连商户号 request.setMchid(properties.getConfigs().get(0).getMchid()); // 商品描述 request.setDescription(description); // 商户订单号 request.setOutTradeNo(outTradeNo); // 交易结束时间:2018-06-08T10:34:56+08:00 request.setTimeExpire(timeStampToRfc3339(System.currentTimeMillis() + properties.getConfigs().get(0).getTimeExpire())); // 附加数据:在查询API和支付通知中原样返回,可作为自定义参数使用 request.setAttach(""); // 回调地址:异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 公网域名必须为https request.setNotifyUrl(properties.getConfigs().get(0).getPayCallBackUrl()); // 商品标记,代金券或立减优惠功能的参数 request.setGoodsTag(""); // 限制支付类型 // request.setLimitPay(LimitPayEnum.); // 电子发票入口开放标识:传入true时,支付成功消息和支付详情页将出现开票入口。需要在微信支付商户平台或微信公众平台开通电子发票功能,传此字段才可生效 request.setSupportFapiao(true); Amount amount = new Amount(); amount.setTotal(total); amount.setCurrency("CNY"); // 订单金额信息 request.setAmount(amount); Payer payer = new Payer(); payer.setOpenid(openid); // 支付者信息 request.setPayer(payer); // 优惠功能 request.setDetail(null); // 支付场景描述 request.setSceneInfo(null); // 结算信息 request.setSettleInfo(null); PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request); //重复支付判断TODO // 存储预付订单信息 TODO log.info("发起预支付成功-" + response.toString()); return success(response); } @ApiOperation(value = "预支付-回调(或退款)") @RequestMapping("payCallback") public synchronized String payCallback(HttpServletRequest request) throws IOException { log.info("收到支付回调-------------"); // 请求头Wechatpay-nonce String nonce = request.getHeader(WECHAT_PAY_NONCE); // 请求头Wechatpay-Timestamp String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP); // 请求头Wechatpay-Signature String signature = request.getHeader(WECHAT_PAY_SIGNATURE); // 微信支付证书序列号 TODO 这里千万不能搞错,不能是商家证书序列号!!! String serial = request.getHeader("Wechatpay-Serial"); // 签名方式 String signType = request.getHeader("Wechatpay-Signature-Type"); // 构造 RequestParam RequestParam requestParam = new RequestParam.Builder() .serialNumber(serial) // TODO 不能搞错!!! .nonce(nonce) .signature(signature) .timestamp(timestamp) .signType(signType) .body(getRequestBody()) .build(); // 初始化 NotificationParser NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig); // 以支付通知回调为例,验签、解密并转换成 Transaction log.info("验签参数:" + requestParam); Transaction transaction = parser.parse(requestParam, Transaction.class); log.info("验签成功!-支付回调结果:" + transaction.toString()); // RefundNotification refundNotification = parser.parse(requestParam, RefundNotification.class); // 修改订单之前,主动去微信支付主动查询订单是否已经支付成功,这一步不能少,防止有人假冒主动post接口。 /** * 收到支付成功的回调:这里进行处理业务 */ // List orderMasters = iOrderMasterService.lambdaQuery().eq(OrderMaster::getOrderNo, transaction.getOutTradeNo()).list(); // Assert.isTrue(orderMasters.size() == 1, "根据订单编号未查到订单OR查到了多个订单!!!"); // if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) { // //支付成功 0待付款1待发货2待收货3已完成4已取消 // orderMasters.get(0).setBuyStatus(1); // // 1待送仓2待打款3已完成4已取消 // orderMasters.get(0).setSaleStatus(1); // // 1现金,2余额,3网银,4支付宝,5微信 // orderMasters.get(0).setPaymentMethod(5); // return "{\"code\": \"FAIL\",\"message\": \"失败\"}"; // } else { // log.info("支付未成功:" + transaction.getTradeState()); // } // // TODO 存储支付流水 return "{\"code\": \"FAIL\",\"message\": \"失败\"}"; } }

你可能感兴趣的:(Java专栏,微信小程序,微信支付,微信小程序支付)