国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SpringBoot 整合微信小程序微信支付V3 jsapi (支付、退款)

這篇具有很好參考價(jià)值的文章主要介紹了SpringBoot 整合微信小程序微信支付V3 jsapi (支付、退款)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

微信支付apiv3,spring boot,微信小程序
最近的一個(gè)微信小程序項(xiàng)目里有用到微信支付,網(wǎng)上找的資料都是特別亂,看起來特別懵,結(jié)合了好多文章的內(nèi)容,終于做了出來,可能我的這個(gè)博文看起來也是特別亂,但是是可以直接C走簡單改一改就可以用的。(支付成功回調(diào),和退款回調(diào)因?yàn)樽蛱靹傇诎⒗锷暾?qǐng)的域名還不讓備案,目前回調(diào)還不確定有什么問題,但是支付和退款經(jīng)過反復(fù)確認(rèn)是沒有問題的了)等域名備案成功后,回調(diào)如果有什么問題在更新改一下。

這是整體的一個(gè)微信支付+退款的項(xiàng)目結(jié)構(gòu)。
如果大家需要的話,我可以等確認(rèn)回調(diào)沒有問題以后可以把我這個(gè)項(xiàng)目中完整的jsapi支付及退款做一個(gè)demo?;蛘甙凑?qǐng)D片的順序把代碼貼進(jìn)來。

微信支付apiv3,spring boot,微信小程序?

1.微信支付-準(zhǔn)備工作?

1.獲取商戶號(hào)
微信商戶平臺(tái) 申請(qǐng)成為商戶 => 提交資料 => 簽署協(xié)議 => 獲取商戶號(hào)
2.獲取AppID
微信公眾平臺(tái) 注冊(cè)服務(wù)號(hào) => 服務(wù)號(hào)認(rèn)證 => 獲取APPID => 綁定商戶號(hào)
3.申請(qǐng)商戶證書
登錄商戶平臺(tái) => 選擇 賬戶中心 => 安全中心 => API安全 => 申請(qǐng)API證書 包括商戶證書和商戶私鑰
4.獲取微信的證書
獲取APIv3秘鑰(在微信支付回調(diào)通知和商戶獲取平臺(tái)證書使用APIv3密鑰)
登錄商戶平臺(tái) => 選擇 賬戶中心 => 安全中心 => API安全 => 設(shè)置APIv3密鑰

2.開干?。。?!

1.引入pom.xml

        <!-- 微信支付 -->
        <dependency>
            <groupId>com.github.wechatpay-apiv3</groupId>
            <artifactId>wechatpay-apache-httpclient</artifactId>
            <version>0.4.2</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.9</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.78</version>
        </dependency>

2.配置application.yml

# 微信相關(guān)配置
vx:
  # appid
  appId: appid
  # 小程序密鑰
  secret: 小程序密鑰
  # 商戶號(hào)
  mchId: 商戶號(hào)
  # 證書序列號(hào)
  mchSerialNo: 證書序列號(hào)
  # api密鑰
  apiKey: api密鑰
  # 證書地址
  keyPath: D:/wxPayPem/apiclient_key.pem
  certPath: D:/wxPayPem/apiclient_cert.pem
  certP12Path: D:/wxPayPem/apiclient_cert.p12

說明:這個(gè)證書地址是在微信商戶平臺(tái)內(nèi)生成下載的API證書文件
具體教程:什么是商戶API證書?如何獲取商戶API證書?

微信支付apiv3,spring boot,微信小程序微信支付apiv3,spring boot,微信小程序

3.都配置完了之后創(chuàng)建對(duì)應(yīng)的配置實(shí)體。

import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.Data;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;

/**
 * <p>
 * 配置信息實(shí)體
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/26 15:31
 */
@Configuration
@Data
public class WxPayConfig {
    /**
     * appid
     */
    @Value("${vx.appId}")
    private String appId;
    /**
     * 小程序密鑰
     */
    @Value("${vx.secret}")
    private String secret;
    /**
     * 商戶號(hào)
     */
    @Value("${vx.mchId}")
    private String mchId;
    /**
     * 證書序列號(hào)
     */
    @Value("${vx.mchSerialNo}")
    private String mchSerialNo;
    /**
     * api密鑰
     */
    @Value("${vx.apiKey}")
    private String apiKey;

    /**
     * 證書地址
     */
    @Value("${vx.keyPath}")
    private String keyPath;


    /**
     * 獲取商戶的私鑰文件
     *
     * @param filename 證書地址
     * @return 私鑰文件
     */
    public PrivateKey getPrivateKey(String filename) {
        try {
            return PemUtil.loadPrivateKey(new FileInputStream(filename));
        } catch (FileNotFoundException e) {
            throw new RuntimeException("私鑰文件不存在");
        }
    }


    /**
     * 獲取簽名驗(yàn)證器
     */
    @Bean
    public Verifier getVerifier() {
        // 獲取商戶私鑰
        final PrivateKey privateKey = getPrivateKey(keyPath);

        // 私鑰簽名對(duì)象
        PrivateKeySigner privateKeySigner = new PrivateKeySigner(mchSerialNo, privateKey);

        // 身份認(rèn)證對(duì)象
        WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);

        // 獲取證書管理器實(shí)例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();

        try {
            // 向證書管理器增加需要自動(dòng)更新平臺(tái)證書的商戶信息
            certificatesManager.putMerchant(mchId, wechatPay2Credentials, apiKey.getBytes(StandardCharsets.UTF_8));
        } catch (IOException | GeneralSecurityException | HttpCodeException e) {
            e.printStackTrace();
        }

        try {
            return certificatesManager.getVerifier(mchId);
        } catch (NotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("獲取簽名驗(yàn)證器失敗");
        }
    }

    /**
     * 獲取微信支付的遠(yuǎn)程請(qǐng)求對(duì)象
     * @return Http請(qǐng)求對(duì)象
     */
    @Bean
    public CloseableHttpClient getWxPayClient() {

        // 獲取簽名驗(yàn)證器
        Verifier verifier = getVerifier();

        // 獲取商戶私鑰
        final PrivateKey privateKey = getPrivateKey(keyPath);

        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create().withMerchant(mchId, mchSerialNo, privateKey)
                .withValidator(new WechatPay2Validator(verifier));

        return builder.build();
    }

}

4.創(chuàng)建一個(gè)枚舉類 type用到了什么就寫什么,或者不創(chuàng)建枚舉類都可以。

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * <p>
 * 請(qǐng)求地址枚舉類
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/26 15:41
 */
@AllArgsConstructor
@Getter
public enum WxApiConstants {

    /**
     * jsapi下單
     */
    JSAPI_PAY("/v3/pay/transactions/jsapi"),


    /**
     * 申請(qǐng)退款
     */
    DOMESTIC_REFUNDS("/v3/refund/domestic/refunds");

    /**
     * 類型
     */
    private final String type;


    public String getType() {
        return type;
    }
}

5.微信支付求數(shù)據(jù)的對(duì)象

import lombok.Data;
import lombok.experimental.Accessors;

import javax.validation.constraints.NotBlank;

/**
 * <p>
 * 預(yù)支付參數(shù)
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/26 13:30
 */
@Data
@Accessors(chain = true)
public class WxPayReqParam {

    /**
     * 總金額
     */
    @NotBlank(message = "總金額不能為空!")
    private String totalPrice;

    /**
     * 商品名稱
     */
    @NotBlank(message = "商品名稱不能為空!")
    private String goodsName;

    /**
     * openId
     */
    @NotBlank(message = "openId不能為空!")
    private String openId;

    /**
     * 訂單號(hào)
     */
    @NotBlank(message = "商品訂單號(hào)不能為空!")
    private String orderNumber;


}

6.將請(qǐng)求參數(shù)封裝成Map集合+創(chuàng)建微信支付訂單的三種方式(Native,Jsapi,App),
我使用的是Jsapi,別的支付方式可以在剛才的枚舉類中“WxApiConstants”,添加別的下單路徑,或者就是寫死了也可以,如果你也是Jsapi支付,應(yīng)該就不需要改動(dòng)什么。
開發(fā)指引-JSAPI支付 | 微信支付商戶平臺(tái)文檔中心

import com.cx.sasmc.vxpay.reqparam.WxPayReqParam;
import com.cx.sasmc.vxpay.vxapienum.WxApiConstants;
import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 將請(qǐng)求參數(shù)封裝成Map集合
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/26 15:54
 */
public class WxPayCommon {

    private final static Logger logger = LoggerFactory.getLogger(WxPayCommon.class);


    /**
     * 封裝基礎(chǔ)通用請(qǐng)求數(shù)據(jù)
     * @param wxPayConfig 微信的配置文件
     * @param basePayData 微信支付基礎(chǔ)請(qǐng)求數(shù)據(jù)
     * @return 封裝后的map對(duì)象
     */
    public static Map<String, Object> getBasePayParams(WxPayConfig wxPayConfig, WxPayReqParam basePayData) {
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("appid", wxPayConfig.getAppId());
        paramsMap.put("mchid", wxPayConfig.getMchId());
        // 如果商品名稱過長則截取
        String title = basePayData.getGoodsName().length() > 62 ? basePayData.getGoodsName().substring(0, 62) : basePayData.getGoodsName();
        paramsMap.put("description",title);
        paramsMap.put("out_trade_no", basePayData.getOrderNumber());
        paramsMap.put("notify_url", "https://你自己的回調(diào)域名.cn/vxPay/payNotify");
        Map<String, Integer> amountMap = new HashMap<>();
        amountMap.put("total", Integer.valueOf(basePayData.getTotalPrice()));
        paramsMap.put("amount", amountMap);
        return paramsMap;
    }

    /**
     * 獲取請(qǐng)求對(duì)象(Post請(qǐng)求)
     * @param paramsMap 請(qǐng)求參數(shù)
     * @return Post請(qǐng)求對(duì)象
     */
    public static HttpPost getHttpPost(String type, Map<String, Object> paramsMap) {

        // 1.設(shè)置請(qǐng)求地址
        HttpPost httpPost = new HttpPost(type);

        // 2.設(shè)置請(qǐng)求數(shù)據(jù)
        Gson gson = new Gson();
        String jsonParams = gson.toJson(paramsMap);

        // 3.設(shè)置請(qǐng)求信息
        StringEntity entity = new StringEntity(jsonParams, "utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept", "application/json");
        return httpPost;
    }

    /**
     * 解析響應(yīng)數(shù)據(jù)
     * @param response 發(fā)送請(qǐng)求成功后,返回的數(shù)據(jù)
     * @return 微信返回的參數(shù)
     */
    public static HashMap<String, String> resolverResponse(CloseableHttpResponse response) {
        try {
            // 1.獲取請(qǐng)求碼
            int statusCode = response.getStatusLine().getStatusCode();
            // 2.獲取返回值 String 格式
            final String bodyAsString = EntityUtils.toString(response.getEntity());

            Gson gson = new Gson();
            if (statusCode == 200) {
                // 3.如果請(qǐng)求成功則解析成Map對(duì)象返回
                HashMap<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
                return resultMap;
            } else {
                if (StringUtils.isNoneBlank(bodyAsString)) {
                    logger.error("微信支付請(qǐng)求失敗,提示信息:{}", bodyAsString);
                    // 4.請(qǐng)求碼顯示失敗,則嘗試獲取提示信息
                    HashMap<String, String> resultMap = gson.fromJson(bodyAsString, HashMap.class);
                    throw new RuntimeException(resultMap.get("message"));
                }
                logger.error("微信支付請(qǐng)求失敗,未查詢到原因,提示信息:{}", response);
                // 其他異常,微信也沒有返回?cái)?shù)據(jù),這就需要具體排查了
                throw new IOException("request failed");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 創(chuàng)建微信支付訂單-jsapi方式
     * @param wxPayConfig 微信配置信息
     * @param basePayData 基礎(chǔ)請(qǐng)求信息,商品標(biāo)題、商家訂單id、訂單價(jià)格
     * @param openId 通過微信小程序或者公眾號(hào)獲取到用戶的openId
     * @param wxPayClient 微信請(qǐng)求客戶端()
     * @return 微信支付二維碼地址
     */
    public static String wxJsApiPay(WxPayConfig wxPayConfig, WxPayReqParam basePayData, String openId, CloseableHttpClient wxPayClient) {

        // 1.獲取請(qǐng)求參數(shù)的Map格式
        Map<String, Object> paramsMap = getBasePayParams(wxPayConfig, basePayData);

        // 1.1 添加支付者信息
        Map<String,String> payerMap = new HashMap<>();
        payerMap.put("openid",openId);
        paramsMap.put("payer",payerMap);

        // 2.獲取請(qǐng)求對(duì)象
        HttpPost httpPost = getHttpPost("https://api.mch.weixin.qq.com"+WxApiConstants.JSAPI_PAY.getType(),paramsMap);

        // 3.完成簽名并執(zhí)行請(qǐng)求
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpPost);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("微信支付請(qǐng)求失敗");
        }

        // 4.解析response對(duì)象
        HashMap<String, String> resultMap = resolverResponse(response);
        if (resultMap != null) {
            // native請(qǐng)求返回的是二維碼鏈接,前端將鏈接轉(zhuǎn)換成二維碼即可
            return resultMap.get("prepay_id");
        }
        return null;
    }

}

7.創(chuàng)建實(shí)體存儲(chǔ)前端微信支付所需參數(shù)(WxChatPayDto)
?小程序內(nèi)需要多個(gè)參數(shù)才可以喚起微信支付,就是輸入密碼支付的那個(gè)支付頁面。

import lombok.Data;

/**
 * <p>
 *  前端微信支付所需參數(shù)
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/26 16:26
 */
@Data
public class WxChatPayDto {

    /**
     * 需要支付的小程序id
     */
    private String appid;

    /**
     * 時(shí)間戳(當(dāng)前的時(shí)間)
     */
    private String timeStamp;

    /**
     * 隨機(jī)字符串,不長于32位。
     */
    private String nonceStr;

    /**
     * 小程序下單接口返回的prepay_id參數(shù)值,提交格式如:prepay_id=***
     */
    private String prepayId;

    /**
     * 簽名類型,默認(rèn)為RSA,僅支持RSA。
     */
    private String signType;

    /**
     * 簽名,使用字段appId、timeStamp、nonceStr、package計(jì)算得出的簽名值
     */
    private String paySign;
}

8. 微信支付

 /**
     * 微信用戶調(diào)用微信支付
     */
    @Override
    public WxChatPayDto wxPay(WxPayReqParam param) {
            String prepayId = WxPayCommon.wxJsApiPay(wxPayConfig, param, param.getOpenId(), wxPayClient);
            WxChatPayDto wxChatPayDto = new WxChatPayDto();
            wxChatPayDto.setAppid(wxPayConfig.getAppId());
            wxChatPayDto.setTimeStamp(String.valueOf(System.currentTimeMillis() / 1000));
            wxChatPayDto.setNonceStr(UUID.randomUUID().toString().replaceAll("-", ""));
            wxChatPayDto.setPrepayId("prepay_id=" + prepayId);
            wxChatPayDto.setSignType("RSA");
            wxChatPayDto.setPaySign(getSign(wxChatPayDto.getNonceStr(),wxChatPayDto.getAppid(),wxChatPayDto.getPrepayId(),Long.parseLong(wxChatPayDto.getTimeStamp())));
            return wxChatPayDto;
    }

返回給小程序的wxChatPayDto就可以喚起支付頁面了。

9.成功回調(diào)

import com.alibaba.fastjson.JSONObject;
import com.cx.sasmc.vxpay.config.WxPayConfig;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 微信支付回調(diào)工具類
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/27 8:50
 */
@Component
public class WxPayCallbackUtil {
    @Resource
    private Verifier verifier;
    @Resource
    private WxPayConfig wxPayConfig;
    /**
     * 獲取回調(diào)數(shù)據(jù)
     * @param request
     * @param response
     * @return
     */
    public Map<String, String> wxChatPayCallback(HttpServletRequest request, HttpServletResponse response) {
        //獲取報(bào)文
        String body = getRequestBody(request);

        //隨機(jī)串
        String nonceStr = request.getHeader("Wechatpay-Nonce");

        //微信傳遞過來的簽名
        String signature = request.getHeader("Wechatpay-Signature");

        //證書序列號(hào)(微信平臺(tái))
        String serialNo = request.getHeader("Wechatpay-Serial");

        //時(shí)間戳
        String timestamp = request.getHeader("Wechatpay-Timestamp");

        //構(gòu)造簽名串  應(yīng)答時(shí)間戳\n,應(yīng)答隨機(jī)串\n,應(yīng)答報(bào)文主體\n
        String signStr = Stream.of(timestamp, nonceStr, body).collect(Collectors.joining("\n", "", "\n"));

        Map<String, String> map = new HashMap<>(2);
        try {
            //驗(yàn)證簽名是否通過
            boolean result = verifiedSign(serialNo, signStr, signature);
            if(result){
                //解密數(shù)據(jù)
                String plainBody = decryptBody(body);
                return convertWechatPayMsgToMap(plainBody);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 轉(zhuǎn)換body為map
     * @param plainBody
     * @return
     */
    public Map<String,String> convertWechatPayMsgToMap(String plainBody){

        Map<String,String> paramsMap = new HashMap<>(2);

        JSONObject jsonObject = JSONObject.parseObject(plainBody);

        //商戶訂單號(hào)
        paramsMap.put("out_trade_no",jsonObject.getString("out_trade_no"));

        //交易狀態(tài)
        paramsMap.put("trade_state",jsonObject.getString("trade_state"));

        //附加數(shù)據(jù)
        paramsMap.put("attach",jsonObject.getString("attach"));
        if (jsonObject.getJSONObject("attach") != null && !jsonObject.getJSONObject("attach").equals("")){
            paramsMap.put("account_no",jsonObject.getJSONObject("attach").getString("accountNo"));
        }
        return paramsMap;

    }

    /**
     * 解密body的密文
     *
     * "resource": {
     *         "original_type": "transaction",
     *         "algorithm": "AEAD_AES_256_GCM",
     *         "ciphertext": "",
     *         "associated_data": "",
     *         "nonce": ""
     *     }
     *
     * @param body body
     * @return
     */
    public String decryptBody(String body) throws UnsupportedEncodingException, GeneralSecurityException {
        AesUtil aesUtil = new AesUtil(wxPayConfig.getApiKey().getBytes("utf-8"));
        JSONObject object = JSONObject.parseObject(body);
        JSONObject resource = object.getJSONObject("resource");
        String ciphertext = resource.getString("ciphertext");
        String associatedData = resource.getString("associated_data");
        String nonce = resource.getString("nonce");
        return aesUtil.decryptToString(associatedData.getBytes("utf-8"),nonce.getBytes("utf-8"),ciphertext);
    }


    /**
     * 驗(yàn)證簽名
     *
     * @param serialNo  微信平臺(tái)-證書序列號(hào)
     * @param signStr   自己組裝的簽名串
     * @param signature 微信返回的簽名
     * @return
     * @throws UnsupportedEncodingException
     */
    public boolean verifiedSign(String serialNo, String signStr, String signature) throws UnsupportedEncodingException {
        return verifier.verify(serialNo, signStr.getBytes("utf-8"), signature);
    }

    /**
     * 讀取請(qǐng)求數(shù)據(jù)流
     *
     * @param request
     * @return
     */
    public String getRequestBody(HttpServletRequest request) {
        StringBuffer sb = new StringBuffer();
        try (ServletInputStream inputStream = request.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        ) {
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();

    }
}

成功回調(diào)方法

/**
     * 微信支付成功回調(diào)
     * @param request request
     * @param response response
     * @return map
     */
    @Override
    public Map<String, String> wxOrderCallBack(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> map = new HashMap<>(2);
        try {
            Map<String, String> stringMap = wxChatPayCallback.wxChatPayCallback(request, response);
            //支付成功
            if (stringMap.get("trade_state").equals("SUCCESS")){
                // 獲取咱們自己生成的訂單號(hào)
                String out_trade_no = stringMap.get("out_trade_no");
                if (!stringRedisTemplate.hasKey("ORDER_NO:"+out_trade_no)){
                    QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("orderNumber",OrderStatusConstants.UNPAID);
                    Order order = orderMapper.selectOne(queryWrapper);
                    if (ObjectUtil.isNotEmpty(order)){
                        //編寫支付成功后邏輯 修改訂單為已付款。
                        Order upOrder = new Order();
                        upOrder.setId(order.getId());
                        upOrder.setOrderStatus(OrderStatusConstants.PAID);
                        orderMapper.updateById(upOrder);
                        // (通知頻率為15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 總計(jì) 24h4m)
                        // 數(shù)據(jù)有效期設(shè)置25小時(shí)
                        stringRedisTemplate.opsForValue().set("ORDER_NO:"+out_trade_no,out_trade_no,25L, TimeUnit.HOURS);
                    }

                }
            }
            //響應(yīng)微信
            map.put("code", "SUCCESS");
            map.put("message", "成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

微信支付apiv3,spring boot,微信小程序

至此支付就完成了。

10.退款 說明(項(xiàng)目中用到了Sa-token,@SaIgnore注解標(biāo)識(shí)這個(gè)方法無需鑒權(quán),可以匿名訪問)

 /**
     * 申請(qǐng)退款
     */
    @SaIgnore
    @PostMapping("/vxPayRefund")
    public Result payRefund(@RequestBody @Validated WxPayRefundReqParam param){
       String s = vxPayService.payRefund(param);
       if (ObjectUtil.isNotEmpty(s)){
           return Result.ok(s);
       } else {
           return Result.fail("退款失敗");
       }
    }
 /**
     * 申請(qǐng)退款
     * @param param param
     * @return string
     */
    @Override
    public String payRefund(WxPayRefundReqParam param) {
        Map<String, String> map = WxPayRefundUtil.refundPay(param, wxPayClient);
        Order upOrder = new Order();
        upOrder.setRefundNumber(map.get("refundNumber"));
        upOrder.setOrderStatus(OrderStatusConstants.REFUND_PROCESSING);
        UpdateWrapper<Order> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("orderNumber",param.getTransactionId());
        orderMapper.update(upOrder,updateWrapper);
        return map.get("refund_id");
    }
 /**
     * 發(fā)起微信退款申請(qǐng)
     * @param param 微信支付申請(qǐng)退款請(qǐng)求參數(shù)
     * @return 微信支付二維碼地址
     */
    public static Map<String,String> refundPay(WxPayRefundReqParam param,CloseableHttpClient wxPayClient) {
        Map<String,String> returnMap = new HashMap<>();

        // 1.獲取請(qǐng)求參數(shù)的Map格式
        Map<String, Object> paramsMap = getRefundParams(param);

        // 2.獲取請(qǐng)求對(duì)象
        HttpPost httpPost = WxPayCommon.getHttpPost("https://api.mch.weixin.qq.com"+ WxApiConstants.DOMESTIC_REFUNDS.getType(), paramsMap);

        // 3.完成簽名并執(zhí)行請(qǐng)求
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpPost);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("微信支付請(qǐng)求失敗");
        }

        // 4.解析response對(duì)象
        HashMap<String, String> resultMap = WxPayCommon.resolverResponse(response);
        if (resultMap != null) {
            // 返回微信支付退款單號(hào)
            returnMap.put("refund_id",resultMap.get("refund_id"));
            returnMap.put("refundNumber",paramsMap.get("out_refund_no").toString());
            return returnMap;

        }
        return null;
    }

退款請(qǐng)求參數(shù):

package com.cx.sasmc.vxpay.vxpayutil;

import com.cx.sasmc.utils.OrderNumberGenerate;
import com.cx.sasmc.vxpay.config.WxPayCommon;
import com.cx.sasmc.vxpay.reqparam.WxPayRefundReqParam;
import com.cx.sasmc.vxpay.vxapienum.WxApiConstants;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 微信支付退款
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/27 9:49
 */
public class WxPayRefundUtil {
    /**
     * 封裝微信支付申請(qǐng)退款請(qǐng)求參數(shù)
     * @param param 微信支付申請(qǐng)退款請(qǐng)求參數(shù)
     * @return 封裝后的map微信支付申請(qǐng)退款請(qǐng)求參數(shù)對(duì)象
     */
    private static Map<String, Object> getRefundParams(WxPayRefundReqParam param) {
        String out_refund_no = OrderNumberGenerate.orderNo("100001");
        Map<String, Object> paramsMap = new HashMap<>();
        if (StringUtils.isNoneBlank(param.getTransactionId())) {
            paramsMap.put("out_trade_no", param.getTransactionId());
        }
        paramsMap.put("out_refund_no", out_refund_no);
        paramsMap.put("notify_url", "https://你自己的回調(diào)域名.cn/vxPay/refundWechatCallback");
        Map<String, Object> amountMap = new HashMap<>();
        amountMap.put("refund", Long.valueOf(param.getRefundMoney()));
        amountMap.put("total", Long.valueOf(param.getTotalMoney()));
        amountMap.put("currency", "CNY");
        paramsMap.put("amount", amountMap);
        return paramsMap;
    }

    /**
     * 發(fā)起微信退款申請(qǐng)
     * @param param 微信支付申請(qǐng)退款請(qǐng)求參數(shù)
     * @return 微信支付二維碼地址
     */
    public static Map<String,String> refundPay(WxPayRefundReqParam param,CloseableHttpClient wxPayClient) {
        Map<String,String> returnMap = new HashMap<>();

        // 1.獲取請(qǐng)求參數(shù)的Map格式
        Map<String, Object> paramsMap = getRefundParams(param);

        // 2.獲取請(qǐng)求對(duì)象
        HttpPost httpPost = WxPayCommon.getHttpPost("https://api.mch.weixin.qq.com"+ WxApiConstants.DOMESTIC_REFUNDS.getType(), paramsMap);

        // 3.完成簽名并執(zhí)行請(qǐng)求
        CloseableHttpResponse response = null;
        try {
            response = wxPayClient.execute(httpPost);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("微信支付請(qǐng)求失敗");
        }

        // 4.解析response對(duì)象
        HashMap<String, String> resultMap = WxPayCommon.resolverResponse(response);
        if (resultMap != null) {
            // 返回微信支付退款單號(hào)
            returnMap.put("refund_id",resultMap.get("refund_id"));
            returnMap.put("refundNumber",paramsMap.get("out_refund_no").toString());
            return returnMap;

        }
        return null;
    }

}

退款回調(diào)的請(qǐng)求參數(shù)

import cn.hutool.core.date.DateUtil;
import lombok.Data;

import java.math.BigDecimal;
import java.util.Date;

/**
 * <p>
 * 微信退款回調(diào)參數(shù)
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/27 13:40
 */
@Data
public class WxChatCallbackRefundReqParam {
    /**
     * 商戶訂單號(hào)
     */
    private String orderId;

    /**
     * 商戶退款單號(hào),out_refund_no
     */
    private String refundId;

    /**
     * 微信支付系統(tǒng)生成的訂單號(hào)
     */
    private String transactionId;

    /**
     * 微信支付系統(tǒng)生成的退款訂單號(hào)
     */
    private String transactionRefundId;

    /**
     * 退款渠道 1.ORIGINAL:原路退款 2.BALANCE:退回到余額
     *         3.OTHER_BALANCE:原賬戶異常退到其他余額賬戶
     *         4.OTHER_BANKCARD:原銀行卡異常退到其他銀行卡
     */
    private String 	channel;

    /**
     * 退款成功時(shí)間 當(dāng)前退款成功時(shí)才有此返回值
     */
    private Date successTime;

    /**
     * 退款狀態(tài)  退款到銀行發(fā)現(xiàn)用戶的卡作廢或者凍結(jié)了,導(dǎo)致原路退款銀行卡失敗,可前往商戶平臺(tái)-交易中心,手動(dòng)處理此筆退款。
     * 1.SUCCESS:退款成功 2.CLOSED:退款關(guān)閉 3.PROCESSING:退款處理中 4.ABNORMAL:退款異常
     */
    private String 	status;

    /**
     * 退款金額
     */
    private BigDecimal refundMoney;

    public Date getSuccessTime() {
        return successTime;
    }

    public void setSuccessTime(String successTime) {
        // Hutool工具包的方法,自動(dòng)識(shí)別一些常用格式的日期字符串
        this.successTime = DateUtil.parse(successTime);
    }

}

?退款業(yè)務(wù)處理接口

import com.cx.sasmc.vxpay.reqparam.WxChatCallbackRefundReqParam;

/**
 * <p>
 * 退款回調(diào)
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/27 13:54
 */
public interface WechatRefundCallback {
    /**
     * 退款成功處理情況
     */
    void success(WxChatCallbackRefundReqParam refundData);

    /**
     * 退款失敗處理情況
     */
    void fail(WxChatCallbackRefundReqParam refundData);
}

?微信退款回調(diào)方法

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;

/**
 * <p>
 * 將通知參數(shù)轉(zhuǎn)化為字符串
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/27 13:43
 */
public class HttpUtils {
    /**
     * 將通知參數(shù)轉(zhuǎn)化為字符串
     * @param request
     * @return
     */
    public static String readData(HttpServletRequest request) {
        BufferedReader br = null;
        try {
            StringBuilder result = new StringBuilder();
            br = request.getReader();
            for (String line; (line = br.readLine()) != null; ) {
                if (result.length() > 0) {
                    result.append("\n");
                }
                result.append(line);
            }
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.DateTimeException;
import java.time.Duration;
import java.time.Instant;

import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.*;

import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.WECHAT_PAY_SERIAL;

/**
 * <p>
 * 微信支付 退款回調(diào)請(qǐng)求驗(yàn)證
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/27 13:47
 */
public class WechatPayValidatorForRequest {

    private final Logger logger = LoggerFactory.getLogger(WechatPayValidatorForRequest.class);
    /**
     * 應(yīng)答超時(shí)時(shí)間,單位為分鐘
     */
    protected static final long RESPONSE_EXPIRED_MINUTES = 5;
    protected final Verifier verifier;
    protected final String body;
    protected final String requestId;

    public WechatPayValidatorForRequest(Verifier verifier, String body, String requestId) {
        this.verifier = verifier;
        this.body = body;
        this.requestId = requestId;
    }

    protected static IllegalArgumentException parameterError(String message, Object... args) {
        message = String.format(message, args);
        return new IllegalArgumentException("parameter error: " + message);
    }

    protected static IllegalArgumentException verifyFail(String message, Object... args) {
        message = String.format(message, args);
        return new IllegalArgumentException("signature verify fail: " + message);
    }

    public final boolean validate(HttpServletRequest request) throws IOException {
        try {
            validateParameters(request);

            String message = buildMessage(request);
            String serial = request.getHeader(WECHAT_PAY_SERIAL);
            String signature = request.getHeader(WECHAT_PAY_SIGNATURE);

            if (!verifier.verify(serial, message.getBytes(StandardCharsets.UTF_8), signature)) {
                throw verifyFail("serial=[%s] message=[%s] sign=[%s], request-id=[%s]",
                        serial, message, signature, request.getHeader(REQUEST_ID));
            }
        } catch (IllegalArgumentException e) {
            logger.warn(e.getMessage());
            return false;
        }

        return true;
    }

    protected final void validateParameters(HttpServletRequest request) {

        // NOTE: ensure HEADER_WECHAT_PAY_TIMESTAMP at last
        String[] headers = {WECHAT_PAY_SERIAL, WECHAT_PAY_SIGNATURE, WECHAT_PAY_NONCE, WECHAT_PAY_TIMESTAMP};

        String header = null;
        for (String headerName : headers) {
            header = request.getHeader(headerName);
            if (header == null) {
                throw parameterError("empty [%s], request-id=[%s]", headerName, requestId);
            }
        }

        String timestampStr = header;
        try {
            Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestampStr));
            // 拒絕過期應(yīng)答
            if (Duration.between(responseTime, Instant.now()).abs().toMinutes() >= RESPONSE_EXPIRED_MINUTES) {
                throw parameterError("timestamp=[%s] expires, request-id=[%s]", timestampStr, requestId);
            }
        } catch (DateTimeException | NumberFormatException e) {
            throw parameterError("invalid timestamp=[%s], request-id=[%s]", timestampStr, requestId);
        }
    }

    protected final String buildMessage(HttpServletRequest request) throws IOException {
        String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
        String nonce = request.getHeader(WECHAT_PAY_NONCE);
        return timestamp + "\n"
                + nonce + "\n"
                + body + "\n";
    }

}
import com.cx.sasmc.vxpay.config.WxPayConfig;
import com.cx.sasmc.vxpay.reqparam.WxChatCallbackRefundReqParam;
import com.cx.sasmc.vxpay.service.WechatRefundCallback;
import com.google.gson.Gson;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 微信支付申請(qǐng)退款回調(diào)
 * </p>
 *
 * @author Lch
 * @dateTime 2024/2/27 13:51
 */
public class WxPayRefundCallbackUtil {
    /**
     * 微信支付申請(qǐng)退款回調(diào)方法
     *
     * @param verifier       證書
     * @param wxPayConfig    微信配置
     * @param refundCallback 回調(diào)方法,用于處理業(yè)務(wù)邏輯,包含退款成功處理于退款失敗處理
     * @return json格式的string數(shù)據(jù),直接返回給微信
     */
    public static String wxPayRefundCallback(HttpServletRequest request, HttpServletResponse response, Verifier verifier, WxPayConfig wxPayConfig, WechatRefundCallback refundCallback) {
        Gson gson = new Gson();

        // 1.處理通知參數(shù)
        final String body = HttpUtils.readData(request);
        HashMap<String, Object> bodyMap = gson.fromJson(body, HashMap.class);

        // 2.簽名驗(yàn)證
        WechatPayValidatorForRequest wechatForRequest = new WechatPayValidatorForRequest(verifier, body, (String) bodyMap.get("id"));
        try {

            if (!wechatForRequest.validate(request)) {
                // 通知驗(yàn)簽失敗
                response.setStatus(500);
                final HashMap<String, Object> map = new HashMap<>();
                map.put("code", "ERROR");
                map.put("message", "通知驗(yàn)簽失敗");
                return gson.toJson(map);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 3.獲取明文數(shù)據(jù)
        String plainText = decryptFromResource(bodyMap, wxPayConfig);
        HashMap<String, Object> plainTextMap = gson.fromJson(plainText, HashMap.class);
//        log.info("退款plainTextMap:{}", plainTextMap);
        // 4.封裝微信返回的數(shù)據(jù)
        WxChatCallbackRefundReqParam refundData = getRefundCallbackData(plainTextMap);

        if ("SUCCESS".equals(refundData.getStatus())) {
            // 執(zhí)行業(yè)務(wù)邏輯
            refundCallback.success(refundData);
        } else {
            // 特殊情況退款失敗業(yè)務(wù)處理,退款到銀行發(fā)現(xiàn)用戶的卡作廢或者凍結(jié)了,導(dǎo)致原路退款銀行卡失敗,可前往商戶平臺(tái)-交易中心,手動(dòng)處理此筆退款
            refundCallback.fail(refundData);
        }

        // 5.成功應(yīng)答
        response.setStatus(200);
        final HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("code", "SUCCESS");
        resultMap.put("message", "成功");
        return gson.toJson(resultMap);
    }

    private static WxChatCallbackRefundReqParam getRefundCallbackData(HashMap<String, Object> plainTextMap) {
        Gson gson = new Gson();
        WxChatCallbackRefundReqParam refundData = new WxChatCallbackRefundReqParam();
        String successTime = String.valueOf(plainTextMap.get("success_time"));
        if (StringUtils.isNoneBlank(successTime)) {
            refundData.setSuccessTime(successTime);
        }
        refundData.setOrderId(String.valueOf(plainTextMap.get("out_trade_no")));
        refundData.setRefundId(String.valueOf(plainTextMap.get("out_refund_no")));
        refundData.setTransactionId(String.valueOf(plainTextMap.get("transaction_id")));
        refundData.setTransactionRefundId(String.valueOf(plainTextMap.get("refund_id")));
        refundData.setChannel(String.valueOf(plainTextMap.get("channel")));
        final String status = String.valueOf(plainTextMap.get("refund_status"));
        refundData.setStatus(status);
        String amount = String.valueOf(plainTextMap.get("amount"));
        HashMap<String, Object> amountMap = gson.fromJson(amount, HashMap.class);
        String refundMoney = String.valueOf(amountMap.get("refund"));
        refundData.setRefundMoney(new BigDecimal(refundMoney).movePointLeft(2));
//        log.info("refundData:{}", refundData);
        return refundData;
    }

    /**
     * 對(duì)稱解密
     */
    private static String decryptFromResource(HashMap<String, Object> bodyMap, WxPayConfig wxPayConfig) {
        // 通知數(shù)據(jù)
        Map<String, String> resourceMap = (Map) bodyMap.get("resource");
        // 數(shù)據(jù)密文
        String ciphertext = resourceMap.get("ciphertext");
        // 隨機(jī)串
        String nonce = resourceMap.get("nonce");
        // 附加數(shù)據(jù)
        String associateData = resourceMap.get("associated_data");
        AesUtil aesUtil = new AesUtil(wxPayConfig.getApiKey().getBytes(StandardCharsets.UTF_8));
        try {
            return aesUtil.decryptToString(associateData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            throw new RuntimeException("解密失敗");
        }
    }

}
    /**
     * 退款回調(diào)
     * @param request r
     * @param response rp
     * @return s
     */
    @Override
    public String refundWechatCallback(HttpServletRequest request, HttpServletResponse response) {
        return WxPayRefundCallbackUtil.wxPayRefundCallback(request, response, verifier, wxPayConfiga, new WechatRefundCallback() {

            /**
             * 退款成功
             */
            @Override
            public void success(WxChatCallbackRefundReqParam refundData) {
                Order upOrder = new Order();
                upOrder.setId(Long.valueOf(refundData.getOrderId()));
                upOrder.setOrderStatus(OrderStatusConstants.CANCELED);
                orderMapper.updateById(upOrder);
            }

            /**
             * 退款失敗
             */
            @Override
            public void fail(WxChatCallbackRefundReqParam refundData) {
                Order order = orderMapper.selectById(Long.valueOf(refundData.getOrderId()));
                if (ObjectUtil.isNotEmpty(order.getOperatorName()) && ObjectUtil.isNotEmpty(order.getOperatorId())){
                    Order upOrder = new Order();
                    upOrder.setId(Long.valueOf(refundData.getOrderId()));
                    upOrder.setOrderStatus(OrderStatusConstants.OPERATOR_ACCEPTED);
                    orderMapper.updateById(upOrder);
                } else {
                    Order upOrder = new Order();
                    upOrder.setId(Long.valueOf(refundData.getOrderId()));
                    upOrder.setOrderStatus(OrderStatusConstants.PAID);
                    orderMapper.updateById(upOrder);
                }
            }
        });
    }

也是真亂啊 如果大家需要demo就留個(gè)言或者私信我一下我就弄一個(gè),或者在在博文里按照?qǐng)D片的順序把所有代碼全部貼進(jìn)來。文章來源地址http://www.zghlxwxcb.cn/news/detail-857341.html

到了這里,關(guān)于SpringBoot 整合微信小程序微信支付V3 jsapi (支付、退款)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • springboot實(shí)現(xiàn)微信小程序V3微信支付功能

    appId:小程序appid appSecret:小程序的secret mchId:商戶號(hào) keyPath:商戶私鑰路徑(apiclient_key.pem) certPath:證書路徑(apiclient_cert.pem) platFormPath:平臺(tái)證書(cert.pem) 注 : 需要通過寫程序生成平臺(tái)證書(見v3Get()方法) apiKey3:apiv3密鑰 serialnumber:商戶證書序列號(hào) notifyUrl:回調(diào)地

    2024年02月12日
    瀏覽(96)
  • 微信小程序基于java實(shí)現(xiàn)v2支付,提現(xiàn),退款

    微信小程序基于java實(shí)現(xiàn)v2支付,提現(xiàn),退款

    v2微信官方文檔 封裝支付請(qǐng)求實(shí)體 controller接口暴露層 payFoodOrder 支付接口實(shí)現(xiàn)類 獲取請(qǐng)求ip wxform.setNotifyUrl(WechatUtil.getPayNotifyUrl() + WXPAY_NOTIFY_URL_FOOD_ORDER); 這個(gè)回調(diào)地址是你自己代碼里面定義的回調(diào)接口,例如你定義的controller回調(diào)接口url是 feedback/wx/notifurl , 即是 wxform.setNoti

    2024年02月09日
    瀏覽(24)
  • uniapp微信小程序JSAPI支付前端生成簽名,并調(diào)起微信支付

    簽名方式使用的是SHA256withRSA 插件 npm install jsrsasign 使用

    2024年01月17日
    瀏覽(94)
  • 微信小程序JSAPI下單支付PHP前后端教程

    微信小程序JSAPI下單支付PHP前后端教程

    準(zhǔn)備數(shù)據(jù): 微信支付API證書,微信支付商戶號(hào),小程序appid,微信支付API證書序列號(hào) 獲取微信支付api證書教程:如何下載微信支付證書(API證書)_荒~的博客-CSDN博客_微信支付證書 獲取微信支付API證書序列號(hào):點(diǎn)擊管理證書即可看到 ? 第一步:生成預(yù)支付交易單 參考文檔:

    2024年02月11日
    瀏覽(20)
  • java微信小程序支付-回調(diào)(Jsapi-APIv3)

    ? ? ? ? 準(zhǔn)備: ?接入前準(zhǔn)備-小程序支付 | 微信支付商戶平臺(tái)文檔中心 準(zhǔn)備好了就可以獲得( 第二點(diǎn)里需要的參數(shù) ): ????????參數(shù)1?商戶號(hào) merchantId:xxxxxx(全是數(shù)字) ????????參數(shù)2?商戶APIV3密鑰 apiV3key:xxxxxxx(32位字母數(shù)字大小寫串,開發(fā)自己準(zhǔn)備的) ????????參

    2024年02月08日
    瀏覽(35)
  • 微信小程序拉起支付報(bào): 調(diào)用支付JSAPI缺少參數(shù): total_fee
  • 微信公眾號(hào)使用uniappH5、python對(duì)接微信支付V3-JSAPI的支付功能

    微信公眾號(hào)使用uniappH5、python對(duì)接微信支付V3-JSAPI的支付功能

    微信公眾號(hào)網(wǎng)頁用uniapp,后臺(tái)用的python,近期對(duì)接微信支付-apiv3版-jsapi支付,特此整理記錄方便日后查找使用 apiv3升級(jí)后,請(qǐng)求體使用不用xml使用json,每次請(qǐng)求需要在header中添加簽名,而簽名需要用微信支付的商戶證書私鑰進(jìn)行RSA加密 使用公眾號(hào)進(jìn)行對(duì)接流程如下 先保存公

    2024年02月02日
    瀏覽(22)
  • 【微信小程序】Java實(shí)現(xiàn)微信支付(小程序支付JSAPI-V3)java-sdk工具包

    【微信小程序】Java實(shí)現(xiàn)微信支付(小程序支付JSAPI-V3)java-sdk工具包

    ? ? ? 對(duì)于一個(gè)沒有寫過支付的小白,打開微信支付官方文檔時(shí)徹底懵逼 ,因?yàn)?微信支付文檔太過詳細(xì), 導(dǎo)致我無從下手,所以寫此文章,幫助第一次寫支付的小伙伴梳理一下。 一、流程分為三個(gè)接口:(這是前言,先看一遍,保持印象,方便理解代碼) 1、第一個(gè)接口:

    2024年02月03日
    瀏覽(30)
  • 【微信支付】java-微信小程序支付-V3接口

    【微信支付】java-微信小程序支付-V3接口

    最開始需要在微信支付的官網(wǎng)注冊(cè)一個(gè)商戶; 在管理頁面中申請(qǐng)關(guān)聯(lián)小程序,通過小程序的 appid 進(jìn)行關(guān)聯(lián);商戶號(hào)和appid之間是多對(duì)多的關(guān)系 進(jìn)入微信公眾平臺(tái),功能-微信支付中確認(rèn)關(guān)聯(lián) 具體流程請(qǐng)瀏覽官方文檔:接入前準(zhǔn)備-小程序支付 | 微信支付商戶平臺(tái)文檔中心 流程走

    2024年02月06日
    瀏覽(33)
  • 微信小程序支付V3版本接口實(shí)現(xiàn)

    微信小程序支付V3版本接口實(shí)現(xiàn)

    特別說明:遇到 java.security.InvalidKeyException: Illegal key size ******* getValidator的錯(cuò)誤 參考添加鏈接描述 JDK7的下載地址 JDK8的下載地址: 下載后解壓,可以看到local_policy.jar和US_export_policy.jar以及readme.txt 如果安裝了JRE,將兩個(gè)jar文件放到%JRE_HOME%libsecurity目錄下覆蓋原來的文件 如果安

    2024年02月09日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包