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

java微信支付v3系列——5.微信支付成功回調(diào)

這篇具有很好參考價值的文章主要介紹了java微信支付v3系列——5.微信支付成功回調(diào)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

java微信支付v3系列——1.微信支付準備工作
java微信支付v3系列——2.微信支付基本配置
java微信支付v3系列——3.訂單創(chuàng)建準備操作
java微信支付v3系列——4.創(chuàng)建訂單的封裝及使用
java微信支付v3系列——5.微信支付成功回調(diào)
java微信支付v3系列——6.微信支付查詢訂單API
java微信支付v3系列——7.微信支付之申請退款
java微信支付v3系列——8.微信支付之退款成功回調(diào)
java微信支付v3系列——9.微信支付之商家轉(zhuǎn)賬API

正文

同樣的通知可能會多次發(fā)送給商戶系統(tǒng)。商戶系統(tǒng)必須能夠正確處理重復(fù)的通知。 推薦的做法是,當(dāng)商戶系統(tǒng)收到通知進行處理時,先檢查對應(yīng)業(yè)務(wù)數(shù)據(jù)的狀態(tài),并判斷該通知是否已經(jīng)處理。如果未處理,則再進行處理;如果已處理,則直接返回結(jié)果成功。在對業(yè)務(wù)數(shù)據(jù)進行狀態(tài)檢查和處理之前,要采用數(shù)據(jù)鎖進行并發(fā)控制,以避免函數(shù)重入造成的數(shù)據(jù)混亂。

如果在所有通知頻率后沒有收到微信側(cè)回調(diào),商戶應(yīng)調(diào)用查詢訂單接口確認訂單狀態(tài)。

特別提醒:商戶系統(tǒng)對于開啟結(jié)果通知的內(nèi)容一定要做簽名驗證,并校驗通知的信息是否與商戶側(cè)的信息一致,防止數(shù)據(jù)泄露導(dǎo)致出現(xiàn)“假通知”,造成資金損失。

該鏈接是通過基礎(chǔ)下單接口中的請求參數(shù)“notify_url”來設(shè)置的,要求必須為https地址。請確?;卣{(diào)URL是外部可正常訪問的,且不能攜帶后綴參數(shù),否則可能導(dǎo)致商戶無法接收到微信的回調(diào)通知信息。

微信驗簽工具類

啥也不說了,直接復(fù)制即可,也沒什么注意事項。

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.*;

public class WechatPayValidatorForRequest {

    protected static final Logger log = LoggerFactory.getLogger(WechatPayValidatorForRequest.class);
    /**
     * 應(yīng)答超時時間,單位為分鐘
     */
    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) {
            log.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";
    }
}

對稱解密方法

創(chuàng)建 WxPayCallbackUtil 微信支付成功回調(diào)類,decryptFromResource用于解密微信

import com.card.config.WxPayConfig;
import com.card.exception.DefaultException;
import com.card.pay.domain.WxchatCallbackRefundData;
import com.card.pay.domain.WxchatCallbackSuccessData;
import com.card.utils.HttpUtils;
import com.card.utils.WechatPayValidatorForRequest;
import com.google.gson.Gson;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

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


@Slf4j
public class WxPayCallbackUtil {

    /**
     * 對稱解密
     */
    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");
        // 隨機串
        String nonce = resourceMap.get("nonce");
        // 附加數(shù)據(jù)
        String associateData = resourceMap.get("associated_data");
        AesUtil aesUtil = new AesUtil(wxPayConfig.getKey().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 DefaultException("解密失敗");
        }
    }
}

封裝微信返回的數(shù)據(jù)對象

微信返回給我們的數(shù)據(jù)是json格式的,我們需要將其轉(zhuǎn)換成java對象,方便我們調(diào)用。

import cn.hutool.core.date.DateUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

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


/**
 * @author cv大魔王
 * @version 1.0
 * @description 微信支付成功回調(diào)返回的數(shù)據(jù)
 * @date 2022/8/4
 */
@Data
@Slf4j
public class WxchatCallbackSuccessData {

    /**
     * 商戶訂單號
     */
    private String orderId;

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

    /**
     * 交易狀態(tài)
     * SUCCESS:支付成功
     * REFUND:轉(zhuǎn)入退款
     * NOTPAY:未支付
     * CLOSED:已關(guān)閉
     * REVOKED:已撤銷(付款碼支付)
     * USERPAYING:用戶支付中(付款碼支付)
     * PAYERROR:支付失敗(其他原因,如銀行返回失敗)
     */
    private String tradestate;

    /**
     * 支付完成時間
     */
    private Date successTime;

    /**
     * 交易類型
     * JSAPI:公眾號支付
     * NATIVE:掃碼支付
     * APP:APP支付
     * MICROPAY:付款碼支付
     * MWEB:H5支付
     * FACEPAY:刷臉支付
     */
    private String 	tradetype;

    /**
     * 訂單總金額
     */
    private BigDecimal totalMoney;


    public Date getSuccessTime() {
        return successTime;
    }

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

支付成功回調(diào)使用方法

我們先不看回調(diào)是如何封裝的,先來看使用方法。

@Autowired
private WxPayConfig wxPayConfig;

@Autowired
private Verifier verifier;

@ApiOperation("微信支付回調(diào)接口")
@PostMapping("/wx/callback")
public String courseNative(HttpServletRequest request, HttpServletResponse response) {
    return WxPayCallbackUtil.wxPaySuccessCallback(request, response, verifier, wxPayConfig, callbackData -> {
        // TODO 處理你的業(yè)務(wù)邏輯,下面說一下一般業(yè)務(wù)邏輯處理方法
        log.info("微信支付返回的信息:{}", callbackData);
        // 1.根據(jù)訂單id獲取訂單信息

        // 2.判斷金額是否相符,如果不相符則調(diào)用退款接口,并取消該訂單,通知客戶支付金額不符

        // 3.查詢訂單狀態(tài)是否是未支付,如果是未支付則改為已支付,填充其他邏輯,

        // 4.如果是其他狀態(tài)綜合你的業(yè)務(wù)邏輯來處理

        // 5.如果是虛擬物品,則對應(yīng)充值,等等其他邏輯
    });
}

封裝后就這么一句話,就獲取到了微信返回給我們的數(shù)據(jù),其中callbackData就是上面封裝的WxchatCallbackSuccessData對象,我們只需要在回調(diào)方法中完成我們的業(yè)務(wù)邏輯即可。

支付成功回調(diào)方法封裝

import java.util.function.Consumer;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.card.pay.domain.WxchatCallbackSuccessData;
import com.card.utils.HttpUtils;
import com.card.utils.WechatPayValidatorForRequest;

@Slf4j
public class WxPayCallbackUtil {


   /**
     * 微信支付創(chuàng)建訂單回調(diào)方法
     * @param verifier 證書
     * @param wxPayConfig 微信配置
     * @param businessCallback 回調(diào)方法,用于處理業(yè)務(wù)邏輯
     * @return json格式的string數(shù)據(jù),直接返回給微信
     */
    public static String wxPaySuccessCallback(HttpServletRequest request, HttpServletResponse response, Verifier verifier, WxPayConfig wxPayConfig, Consumer<WxchatCallbackSuccessData> businessCallback) {
        Gson gson = new Gson();

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

        // 2.簽名驗證
        WechatPayValidatorForRequest wechatForRequest = new WechatPayValidatorForRequest(verifier, body, (String) bodyMap.get("id"));
        try {
            if (!wechatForRequest.validate(request)) {
                // 通知驗簽失敗
                response.setStatus(500);
                final HashMap<String, Object> map = new HashMap<>();
                map.put("code", "ERROR");
                map.put("message", "通知驗簽失敗");
                return gson.toJson(map);
            }
        } catch (IOException 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ù)
        WxchatCallbackSuccessData callbackData = new WxchatCallbackSuccessData();
        callbackData.setSuccessTime(String.valueOf(plainTextMap.get("success_time")));
        callbackData.setOrderId(String.valueOf(plainTextMap.get("out_trade_no")));
        callbackData.setTransactionId(String.valueOf(plainTextMap.get("transaction_id")));
        callbackData.setTradestate(String.valueOf(plainTextMap.get("trade_state")));
        callbackData.setTradetype(String.valueOf(plainTextMap.get("trade_type")));
        String amount = String.valueOf(plainTextMap.get("amount"));
        HashMap<String,Object> amountMap = gson.fromJson(amount, HashMap.class);
        String total = String.valueOf(amountMap.get("total"));
        callbackData.setTotalMoney(new BigDecimal(total).movePointLeft(2));
        log.info("callbackData:{}",callbackData);

        if ("SUCCESS".equals(callbackData.getTradestate())) {
            // 執(zhí)行業(yè)務(wù)邏輯
            businessCallback.accept(callbackData);
        }

        // 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 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");
        // 隨機串
        String nonce = resourceMap.get("nonce");
        // 附加數(shù)據(jù)
        String associateData = resourceMap.get("associated_data");
        AesUtil aesUtil = new AesUtil(wxPayConfig.getKey().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 DefaultException("解密失敗");
        }
    }

}

注意看方法的最后一個參數(shù),Consumer<WxchatCallbackSuccessData> businessCallback,這是一個jdk自帶的函數(shù)式接口,通過接口回調(diào)的方式,完善業(yè)務(wù)邏輯。函數(shù)式接口或者回調(diào)函數(shù)不理解的可以觀看jdk自帶函數(shù)接口以及其系列文章,當(dāng)然您也可以直接使用。

麻煩點個贊再走吧~~文章來源地址http://www.zghlxwxcb.cn/news/detail-796826.html

到了這里,關(guān)于java微信支付v3系列——5.微信支付成功回調(diào)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

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

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

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

    2024年02月06日
    瀏覽(33)
  • 【Java】微信小程序V3支付(后臺)

    【Java】微信小程序V3支付(后臺)

    目錄 ????????相關(guān)官網(wǎng)文檔 ????????1.需要的參數(shù) ????????2.引入庫 ????????3.用到的工具類 ????????4.支付下單實現(xiàn) ????????5.支付回調(diào) 接入前準備-小程序支付 | 微信支付商戶平臺文檔中心 微信支付-JSAPI下單 獲取平臺證書列表-文檔中心-微信支付商戶平

    2024年02月12日
    瀏覽(53)
  • Java實現(xiàn)微信小程序V3支付

    Java實現(xiàn)微信小程序V3支付

    2024年02月12日
    瀏覽(27)
  • 小程序微信支付V3版本Java集成

    相較于之前的微信支付API,主要區(qū)別是: 遵循統(tǒng)一的REST的設(shè)計風(fēng)格 使用JSON作為數(shù)據(jù)交互的格式,不再使用XML 使用基于非對稱密鑰的SHA256-RSA的數(shù)字簽名算法,不再使用MD5或HMAC-SHA256 不再要求攜帶HTTPS客戶端證書(僅需攜帶證書序列號) 使用AES-256-GCM,對回調(diào)中的關(guān)鍵信息進

    2024年02月11日
    瀏覽(20)
  • Java實現(xiàn)微信小程序V3支付 (完整demo)
  • java微信小程序支付-回調(diào)(Jsapi-APIv3)

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

    2024年02月08日
    瀏覽(36)
  • weixin-java-pay對接微信V3支付記錄

    https://github.com/binarywang/weixin-java-pay-demo 這個demo里, 沒有v3版本的配置, 這里記錄一下 v3支付, 相對之前的版本來說, 更為安全, 也相對繁瑣一些, 而且請求和響應(yīng)都使用了json格式的數(shù)據(jù) 1. 配置 發(fā)起支付所需的配置有三個證書文件, 在商戶后臺申請 apiclient_cert.p12 apiclient_key.pem ap

    2024年02月11日
    瀏覽(25)
  • 【微信小程序】Java實現(xiàn)微信支付(小程序支付JSAPI-V3)java-sdk工具包(包含支付出現(xiàn)的多次回調(diào)的問題解析,接口冪等性)

    【微信小程序】Java實現(xiàn)微信支付(小程序支付JSAPI-V3)java-sdk工具包(包含支付出現(xiàn)的多次回調(diào)的問題解析,接口冪等性)

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

    2024年01月16日
    瀏覽(31)
  • 微信支付開發(fā) 認清微信支付v2和v3

    微信支付開發(fā) 認清微信支付v2和v3

    2014年9月10號之前申請的為v2版(舊版本),之后申請的為v3版。 V2版中的參數(shù)有 AppID AppSecret 支付專用簽名串PaySignKey 商戶號PartnerID 初始密鑰PartnerKey 并且包含一個證書文件: 安全證書 V3版中的參數(shù)有 AppID AppSecret 商戶號PartnerID 初始密鑰PartnerKey 商戶號MCHID 申請編號 商戶平臺登

    2023年04月08日
    瀏覽(32)
  • 微信H5支付及通知回調(diào)

    1.在微信商戶平臺中進行登錄并申請相關(guān)功能和配置 1.1微信商戶平臺https://pay.weixin.qq.com/index.php/core/home/loginreturn_url=%2F 登錄并配置,在商戶平臺上 - 產(chǎn)品中心 - 開通相關(guān)的產(chǎn)品,比如我這里使用的是 H5支付 1.2 然后配置相關(guān)的參數(shù) 2.1導(dǎo)入相關(guān)依賴 2.2 代碼編寫 2.3 編寫H5支付回調(diào)

    2024年02月12日
    瀏覽(23)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包