微信小程序中實現微信支付


最近在做微信小程序,今天剛好做到小程序里的微信支付這塊,踩過不少坑,特此寫個博客記錄下,希望能幫到其它人吧。

我總結了一下,小程序中的微信支付和之前其它的公眾號里的微信支付有兩個區別,第一就是小程序必須要Https接口,第二服務器在返回給小程序之前需要二次簽名,記住要二次簽名。

我發現網上的相關例子很多,但是也很亂,各種封裝類,五花八門的,在這里我用的是微信官方的方法,簡單,無腦,高效。

1,我們需要在Maven坐標系里導入官方封裝好的方法

<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>


2,寫一個MyConfig類繼承WXPayConfig
import com.baibeiyun.robot.base.util.PropertiesUtils;
import com.github.wxpay.sdk.WXPayConfig;

import java.io.InputStream;

/**
 * 配置類
 *
 * @author liyuan
 * @date 2018/3/30
 **/
public class MyConfig implements WXPayConfig {

    @Override
    public String getAppID() {
     // 放你的appid
return PropertiesUtils.getInstace("conf/webService.properties").getProperty("appId"); } @Override public String getMchID() {
     // 商戶號
return PropertiesUtils.getInstace("conf/webService.properties").getProperty("mchId"); } @Override public String getKey() {
     // 你的商戶號里的key
return PropertiesUtils.getInstace("conf/webService.properties").getProperty("key"); } @Override public InputStream getCertStream() { return null; } @Override public int getHttpConnectTimeoutMs() { return 8000; } @Override public int getHttpReadTimeoutMs() { return 10000; } }

3. 在服務器端充值接口里獲取到那5個關鍵參數傳給小程序

    @ApiOperation("小程序充值接口")
    @RequestMapping(value = "saveMoney", method = RequestMethod.POST)
    public String saveMoney(@ModelAttribute SaveMoney1Dto dto, HttpServletRequest request) throws Exception {
        if (!dto.checkParam()) {
            throw new MyParameterException(400, "請求參數異常");
        }

        // 獲取用戶userId
        Integer userId = Integer.valueOf(redisService.get(dto.getUuidKey()).substring(52));
        // 生成交易訂單號
        String orderNum = CommonUtils.getOrderNumber();
        MoneyTransaction moneyTransaction = new MoneyTransaction();
        moneyTransaction.setPayUserId(userId);
        moneyTransaction.setOrderNum(orderNum);
        moneyTransaction.setMoney(dto.getMoney());
        // 交易時間
        moneyTransaction.setGmtCreate(new Date());
        // 將交易訂單存入數據庫
        iMoneyTransactionService.insertSelective(moneyTransaction);


        // 給微信服務器統一下單
        MyConfig config = new MyConfig();
        WXPay wxpay = new WXPay(config);
        // 封裝入參字典
        Map<String, String> data = new HashMap<>(16);
        // 商品描述
        data.put("body", "機器人服務充值");
        // 商戶訂單號
        data.put("out_trade_no", orderNum);
        // 隨機字符串
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        // 總金額 分 將BigDecimal乘以100再轉為字符串
        String totalFee = (dto.getMoney().multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_HALF_UP)).toString();
        data.put("total_fee", totalFee);
        // 終端IP
        data.put("spbill_create_ip", request.getRemoteAddr());
        // 接收微信支付異步通知回調地址
        data.put("notify_url", PropertiesUtils.getInstace("conf/webService.properties").getProperty("notifyUrl"));
        // 交易類型
        data.put("trade_type", "JSAPI");
        // 獲取opneid
        String openid = redisService.get(dto.getUuidKey()).substring(24, 52);
        data.put("openid", openid);


        // 和微信服務器交互,統一下單
        Map<String, String> resp = wxpay.unifiedOrder(data);
        log.info("微信返回: " + resp);

        // 小程序再次簽名
        Map<String, String> data2 = new HashMap<>(16);
        data2.put("appId", resp.get("appid"));
        String timeStamp = System.currentTimeMillis()/1000 + "";
        data2.put("timeStamp", timeStamp);
        String nonceStr =  WXPayUtil.generateNonceStr();
        data2.put("nonceStr", nonceStr);
        String packages = "prepay_id="+resp.get("prepay_id");
        data2.put("package", packages);
        data2.put("signType", "MD5");
        String sign2 = WXPayUtil.generateSignature(data2, PropertiesUtils.getInstace("conf/webService.properties").getProperty("key"));

        // 封裝返回給前端map
        Map<String, String> result = new HashMap<>(16);
        result.put("timeStamp", timeStamp);
        result.put("nonceStr", nonceStr);
        result.put("package", packages);
        result.put("signType", "MD5");
        result.put("paySign", sign2);

        log.info("返回給前端: " + result);
        return YuanResultUtil.successWithDataAndMsg(result, "OK");
    }

在這里直接用微信的工具類,微信的方法比較高效,直接用map字典比較直觀,犯不上像網上大多數人那樣造一個封裝類轉來轉去的麻煩

4 微信通知回調類

    @ApiOperation("小程序充值結果(自動從微信服務器獲取,前端用不到)")
    @RequestMapping(value = "saveMoneyResult", method = RequestMethod.POST)
    public String saveMoneyResult(HttpServletRequest request) throws Exception {
        // 獲取支付結果,XML格式
        String notifyData = StreamUtil.read(request.getInputStream());
        log.info("支付結果: " + notifyData);

        MyConfig config = new MyConfig();
        WXPay wxPay = new WXPay(config);
        // 支付結果轉成map
        Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);
        if (wxPay.isPayResultNotifySignatureValid(notifyMap)) {
            // 簽名正確
            log.info("簽名正確: " + notifyMap);
            // 獲取訂單號
            String orderNum = notifyMap.get("out_trade_no");
            log.info("訂單號:" + orderNum);
            // 獲取金額(分)
            String  totalFee = notifyMap.get("total_fee");
            // 轉為BigDecimal
            BigDecimal totalFee2 = new BigDecimal(totalFee);
            totalFee2 = totalFee2.divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);

            // 根據訂單號獲取交易記錄
            MoneyTransaction moneyTransaction = iMoneyTransactionService.getMoneyTransactionByOrderNum(orderNum);
            if (moneyTransaction != null && moneyTransaction.getStatus() == 0 && moneyTransaction.getMoney().equals(totalFee2)) {
                // 設置狀態為支付成功
                moneyTransaction.setStatus(1);
                moneyTransaction.setGmtCreate(new Date());
                log.info("修改成功");
                iMoneyTransactionService.updateByPrimaryKeySelective(moneyTransaction);

                return "<xml><return_code>SUCCESS</return_code><return_msg>OK</return_msg></xml>";
            } else {
                log.info("修改失敗");
            }
        } else {
            // 簽名錯誤
            throw new BuinessException(501, "簽名錯誤");
        }
        return "<xml><return_code>FALL</return_code><return_msg>失敗</return_msg></xml>";
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM