最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

UniApp?+?SpringBoot?實(shí)現(xiàn)微信支付和退款功能

 更新時(shí)間:2022年06月06日 10:01:42   作者:奔跑的磚頭  
這篇文章主要介紹了UniApp?+?SpringBoot?實(shí)現(xiàn)微信支付和退款功能,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

開發(fā)準(zhǔn)備

  • 一臺(tái)用于支付的測(cè)試機(jī),必須得是一個(gè)安卓機(jī)因?yàn)樾枰蛑Ц痘拍苁褂谩?/li>
  • 用于編寫的后端框架接口的 IDE (IDEA 或者 Eclipse 都可以)
  • HBuilder X 用來(lái)編輯 UniApp 項(xiàng)目的編輯器和編譯器
  • 基本的 SpringBoot 的腳手架,可以去 https://start.spring.io/ 或者 IDEA 自帶的快速生成腳手架插件。
  • Jdk 11

微信支付開發(fā)

我這里省略了申請(qǐng)等步驟。如果沒(méi)有申請(qǐng)過(guò)企業(yè)支付的可以去官網(wǎng)申請(qǐng) https://pay.weixin.qq.com/static/applyment_guide/applyment_detail_app.shtml 。安卓測(cè)試必須要打成基座,或者是正式APP應(yīng)用。

后端部分

在 SpringBoot 中添加以下坐標(biāo)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 微信支付坐標(biāo) start-->
<dependency>
    <groupId>com.github.binarywang</groupId>
    <artifactId>weixin-java-pay</artifactId>
    <version>4.2.5.B</version>
</dependency>
<!-- 退款用 -->
<dependency>
    <groupId>org.jodd</groupId>
    <artifactId>jodd-http</artifactId>
    <version>6.0.8</version>
</dependency>
<!-- 微信支付坐標(biāo) end-->

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

在 resources 目錄下添加 application.yml 我們不去用默認(rèn)的 application.properties 文件,畢竟 yml 更好看點(diǎn)。并在 yml 中添加以下內(nèi)容

# 服務(wù)啟動(dòng)端口
server:
  port: 8080

# 微信支付
wxpay:
  appId: 開放平臺(tái)的AppID
  mchId: 商戶號(hào)
  mchKey: 商戶密鑰
  #  p12證書文件的絕對(duì)路徑或者以classpath:開頭的類路徑.
  keyPath: classpath:/wxpay_cert/apiclient_cert.p12
  #  apiclient_key.pem證書文件的絕對(duì)路徑或者以classpath:開頭的類路徑.
  privateKeyPath: classpath:/wxpay_cert/apiclient_key.pem
  privateCertPath: classpath:/wxpay_cert/apiclient_cert.pem
  notifyUrl: https://4789j06630.wocp.fun/wechat/pay/notify
  refundNotifyUrl: https://4789j06630.wocp.fun/wechat/pay/refund_notify

創(chuàng)建一個(gè) WechatPayConfig.java 使用上面的 ****wxpay

@Data
@ConfigurationProperties(prefix = "wxpay")
public class WechatPayConfig {
    private String appId;
    private String mchId;
    private String mchKey;
    private String keyPath;
    private String privateKeyPath;
    private String privateCertPath;
    private String notifyUrl;
    private String refundNotifyUrl;
}

創(chuàng)建一個(gè) BizWechatPayService.java

package com.runbrick.paytest.util.wxpay;

import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;

import java.net.InetAddress;

/**
 * 微信支付
 */
@Service
@ConditionalOnClass(WxPayService.class)
@EnableConfigurationProperties(WechatPayConfig.class)
@AllArgsConstructor
public class BizWechatPayService {

    private WechatPayConfig wechatPayConfig;

    public WxPayService wxPayService() {
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(wechatPayConfig.getAppId());
        payConfig.setMchId(wechatPayConfig.getMchId());
        payConfig.setMchKey(wechatPayConfig.getMchKey());
        payConfig.setKeyPath(wechatPayConfig.getKeyPath());
        payConfig.setPrivateKeyPath(wechatPayConfig.getPrivateKeyPath());
        payConfig.setPrivateCertPath(wechatPayConfig.getPrivateCertPath());
        // 可以指定是否使用沙箱環(huán)境
        payConfig.setUseSandboxEnv(false);
        payConfig.setSignType("MD5");

        WxPayService wxPayService = new WxPayServiceImpl();
        wxPayService.setConfig(payConfig);
        return wxPayService;
    }

    /**
     * 創(chuàng)建微信訂單給APP
     *
     * @param productTitle 商品標(biāo)題
     * @param outTradeNo   訂單號(hào)
     * @param totalFee     總價(jià)
     * @return
     */
    public Object createOrder(String productTitle, String outTradeNo, Integer totalFee) {
        try {
            WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
            // 支付描述
            request.setBody(productTitle);
            // 訂單號(hào)
            request.setOutTradeNo(outTradeNo);
            // 請(qǐng)按照分填寫
            request.setTotalFee(totalFee);
            // 回調(diào)鏈接
            request.setNotifyUrl(wechatPayConfig.getNotifyUrl());
            // 終端IP.
            request.setSpbillCreateIp(InetAddress.getLocalHost().getHostAddress());
            // 設(shè)置類型為APP
            request.setTradeType(WxPayConstants.TradeType.APP);
            // 一定要用 createOrder 不然得自己做二次校驗(yàn)
            Object order = wxPayService().createOrder(request);
            return order;
        } catch (Exception e) {
            return null;
        }

    }

    /**
     * 退款
     *
     * @param tradeNo
     * @param totalFee
     * @return
     */
    public WxPayRefundResult refund(String tradeNo, Integer totalFee) {
        WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
        wxPayRefundRequest.setTransactionId(tradeNo);
        wxPayRefundRequest.setOutRefundNo(String.valueOf(System.currentTimeMillis()));
        wxPayRefundRequest.setTotalFee(totalFee);
        wxPayRefundRequest.setRefundFee(totalFee);
        wxPayRefundRequest.setNotifyUrl(wechatPayConfig.getRefundNotifyUrl());
        try {
            WxPayRefundResult refund = wxPayService().refundV2(wxPayRefundRequest);
            if (refund.getReturnCode().equals("SUCCESS") && refund.getResultCode().equals("SUCCESS")) {
                return refund;
            }

        } catch (WxPayException e) {
            e.printStackTrace();
        }
        return null;
    }
}

創(chuàng)建一個(gè) WechatController.java 來(lái)實(shí)現(xiàn)接口給前端調(diào)用時(shí)使用

package com.runbrick.paytest.controller;

import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.runbrick.paytest.util.wxpay.BizWechatPayService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/wechat/pay")
@AllArgsConstructor
public class WechatController {

    BizWechatPayService wechatPayService;

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

    /**
     * 創(chuàng)建微信訂單給APP
     *
     * @return
     */
    @RequestMapping(value = "/unified/request", method = RequestMethod.GET)
    public Object appPayUnifiedRequest() {
        // totalFee 必須要以分為單位
        Object createOrderResult = wechatPayService.createOrder("測(cè)試支付", String.valueOf(System.currentTimeMillis()), 1);
        logger.info("統(tǒng)一下單的生成的參數(shù):{}", createOrderResult);
        return createOrderResult;
    }

    @RequestMapping(method = RequestMethod.POST, value = "notify")
    public String notify(@RequestBody String xmlData) {
        try {
            WxPayOrderNotifyResult result = wechatPayService.wxPayService().parseOrderNotifyResult(xmlData);
            // 支付返回信息
            if ("SUCCESS".equals(result.getReturnCode())) {
                // 可以實(shí)現(xiàn)自己的邏輯
                logger.info("來(lái)自微信支付的回調(diào):{}", result);
            }

            return WxPayNotifyResponse.success("成功");
        } catch (WxPayException e) {
            logger.error(e.getMessage());
            return WxPayNotifyResponse.fail("失敗");
        }
    }

    /**
     * 退款
     *
     * @param transaction_id
     */
    @RequestMapping(method = RequestMethod.POST, value = "refund")
    public void refund(String transaction_id) {
        // totalFee 必須要以分為單位,退款的價(jià)格可以這里只做的全部退款
        WxPayRefundResult refund = wechatPayService.refund(transaction_id, 1);
        // 實(shí)現(xiàn)自己的邏輯
        logger.info("退款本地回調(diào):{}", refund);
    }

    /**
     * 退款回調(diào)
     *
     * @param xmlData
     * @return
     */
    @RequestMapping(method = RequestMethod.POST, value = "refund_notify")
    public String refundNotify(@RequestBody String xmlData) {
        // 實(shí)現(xiàn)自己的邏輯
        logger.info("退款遠(yuǎn)程回調(diào):{}", xmlData);
        // 必須要返回 SUCCESS 不過(guò)有 WxPayNotifyResponse 給整合成了 xml了
        return WxPayNotifyResponse.success("成功");
    }

}

上面的 controller 寫了兩個(gè)接口一個(gè)用來(lái) app端的調(diào)用,一個(gè)給支付用來(lái)回調(diào)。回調(diào)接口的地址要放到剛才配置中的 notifyUrl 屬性里。還有一個(gè)是微信的退款接口。

  • 由于支付寶回調(diào)要使用線上的地址作為回調(diào)地址,這里我推薦兩個(gè)解決辦法
  • 使用一臺(tái)服務(wù)器+備案的域名搭建上面的后臺(tái)地址
  • 使用 花生殼 來(lái)實(shí)現(xiàn)本地內(nèi)網(wǎng)穿透

我使用的是 花生殼 作為本次的開發(fā)環(huán)境,啟動(dòng) springboot 的服務(wù),配置好花生殼。后臺(tái)部分到目前為止已經(jīng)結(jié)束了。

前端部分

創(chuàng)建部分和我寫的支付寶那個(gè)一樣,如果不知道可以去看一下。所以跳過(guò)創(chuàng)建部分了,直接來(lái)到了代碼實(shí)現(xiàn)。要在 manifest.json 勾選微信支付支持

創(chuàng)建前端支付代碼 index.vue

<template>
    <view class="content">
        <view class="text-area">
            <text class="title">{{title}}</text>
        </view>
        <button type="default" @click="goPay()">點(diǎn)我前去支付</button>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                title: '跟我去支付'
            }
        },
        onLoad() {

        },
        methods: {
            goPay() {
                uni.request({
                    url: "https://4789j06630.wocp.fun/wechat/pay/unified/request",
                    success(res) {
                        let obj = {
                            appid: res.data.appId,
                            noncestr: res.data.nonceStr,
                            package: res.data.packageValue,
                            partnerid: res.data.partnerId,
                            prepayid: res.data.prepayId,
                            timestamp: parseInt(res.data.timeStamp),
                            sign: res.data.sign,
                        };

                        uni.requestPayment({
                            provider: "wxpay",
                            orderInfo: obj,
                            success(res) {
                                uni.showModal({
                                    content: "支付成功",
                                    showCancel: false
                                })
                            },
                            fail(e) {
                                uni.showModal({
                                    content: "支付失敗,原因?yàn)? " + e.errMsg,
                                    showCancel: false
                                })
                            },
                            complete() {
                                console.log("啥也沒(méi)干");
                            }
                        });

                    }
                })

            }
        }
    }
</script>

<style>
    page {
        background-color: #ff5500;
    }

    .content {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
    }

    .text-area {
        display: flex;
        justify-content: center;
    }

    .title {
        font-size: 36rpx;
        color: #8f8f94;
    }
</style>

點(diǎn)擊按鈕就可以前往微信支付看下后臺(tái)的生成的組合參數(shù)

跳轉(zhuǎn)微信支付之后會(huì)跳回這里,提示支付成功。查看一下后臺(tái)回調(diào)

之后的業(yè)務(wù)按照支付邏輯開發(fā)就可以,簡(jiǎn)單的支付已經(jīng)完成。在按照剛才給的回調(diào)參數(shù)做個(gè)退款操作

我們使用 apipost 一個(gè)很強(qiáng)大的工具,被同事安利的。那就正好拿他測(cè)測(cè)退款借口,就不寫代碼了。

此時(shí)如果沒(méi)有任何錯(cuò)誤,后臺(tái)控制臺(tái)會(huì)返回退款本地和遠(yuǎn)程回調(diào)信息

此時(shí)微信也收到退款信息了。

整套支付流程都上傳到 github 了可以查看 github的源碼 https://github.com/runbrick/pay_spring

到此這篇關(guān)于UniApp + SpringBoot 實(shí)現(xiàn)微信支付和退款的文章就介紹到這了,更多相關(guān)SpringBoot 微信支付和退款內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring Boot設(shè)置支持跨域請(qǐng)求過(guò)程詳解

    Spring Boot設(shè)置支持跨域請(qǐng)求過(guò)程詳解

    這篇文章主要介紹了Spring Boot設(shè)置支持跨域請(qǐng)求過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 詳解springboot整合ehcache實(shí)現(xiàn)緩存機(jī)制

    詳解springboot整合ehcache實(shí)現(xiàn)緩存機(jī)制

    這篇文章主要介紹了詳解springboot整合ehcache實(shí)現(xiàn)緩存機(jī)制,ehcache提供了多種緩存策略,主要分為內(nèi)存和磁盤兩級(jí),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java基礎(chǔ)之集合Set詳解

    Java基礎(chǔ)之集合Set詳解

    這篇文章主要介紹了Java基礎(chǔ)之集合Set詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • IDEA項(xiàng)目的依賴(pom.xml文件)導(dǎo)入問(wèn)題及解決

    IDEA項(xiàng)目的依賴(pom.xml文件)導(dǎo)入問(wèn)題及解決

    這篇文章主要介紹了IDEA項(xiàng)目的依賴(pom.xml文件)導(dǎo)入問(wèn)題及解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • java啟動(dòng)命令中-D和--的區(qū)別解析

    java啟動(dòng)命令中-D和--的區(qū)別解析

    在 SpringBoot 項(xiàng)目中,啟動(dòng)時(shí),通過(guò) -D 或 -- 添加參數(shù),都可以直接覆蓋 yml 或 properties 配置文件中的同名配置,如果不存在則相當(dāng)于添加了一個(gè)配置,這篇文章主要介紹了java啟動(dòng)命令中-D和--的區(qū)別,需要的朋友可以參考下
    2024-08-08
  • java TreeMap源碼解析詳解

    java TreeMap源碼解析詳解

    這篇文章主要介紹了java TreeMap源碼解析詳解的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • 如何在IDEA啟動(dòng)多個(gè)Spring Boot工程實(shí)例(圖文)

    如何在IDEA啟動(dòng)多個(gè)Spring Boot工程實(shí)例(圖文)

    這篇文章主要介紹了如何在IDEA啟動(dòng)多個(gè)Spring Boot工程實(shí)例(圖文),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • 利用JSONObject.toJSONString()包含或排除指定的屬性

    利用JSONObject.toJSONString()包含或排除指定的屬性

    這篇文章主要介紹了利用JSONObject.toJSONString()包含或排除指定的屬性,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java實(shí)現(xiàn)解壓zip壓縮包的兩種方法(支持多層級(jí))

    Java實(shí)現(xiàn)解壓zip壓縮包的兩種方法(支持多層級(jí))

    壓縮文件在生活中經(jīng)常能用到,在Java中提供了壓縮和解壓縮文件的功能,本文主要介紹了Java實(shí)現(xiàn)解壓zip壓縮包的兩種方法(支持多層級(jí)),感興趣的可以了解一下
    2024-03-03
  • hadoop運(yùn)行java程序(jar包)并運(yùn)行時(shí)動(dòng)態(tài)指定參數(shù)

    hadoop運(yùn)行java程序(jar包)并運(yùn)行時(shí)動(dòng)態(tài)指定參數(shù)

    這篇文章主要介紹了hadoop如何運(yùn)行java程序(jar包)并運(yùn)行時(shí)動(dòng)態(tài)指定參數(shù),使用hadoop 運(yùn)行 java jar包,Main函數(shù)一定要加上全限定類名,需要的朋友可以參考下
    2021-06-06

最新評(píng)論

育儿| 枣强县| 精河县| 陇川县| 堆龙德庆县| 关岭| 紫金县| 霸州市| 会昌县| 象州县| 新巴尔虎右旗| 汾阳市| 禹城市| 台中市| 毕节市| 贵州省| 留坝县| 遵化市| 宝山区| 密山市| 大石桥市| 奉节县| 桃源县| 敦煌市| 昌都县| 临桂县| 吴川市| 婺源县| 杭锦后旗| 凌海市| 达州市| 栾川县| 桐庐县| 关岭| 武乡县| 治多县| 河源市| 古田县| 读书| 宁武县| 志丹县|