UniApp + SpringBoot 实现微信支付和退款功能

目录
  • 开发准备
  • 微信支付开发
    • 后端部分
    • 前端部分

开发准备

  • 一台用于支付的测试机,必须得是一个安卓机因为需要打支付基座才能使用。
  • 用于编写的后端框架接口的 IDE (IDEA 或者 Eclipse 都可以)
  • HBuilder X 用来编辑 UniApp 项目的编辑器和编译器
  • 基本的 SpringBoot 的脚手架,可以去 https://start.spring.io/或者 IDEA 自带的快速生成脚手架插件。
  • Jdk 11

微信支付开发

我这里省略了申请等步骤。如果没有申请过企业支付的可以去官网申请 https://pay.weixin.qq.com/static/applyment_guide/applyment_detail_app.shtml 。安卓测试必须要打成基座,或者是正式APP应用。

后端部分

在 SpringBoot 中添加以下坐标

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

<!-- 微信支付坐标 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>
<!-- 微信支付坐标 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 我们不去用默认的application.properties文件,毕竟 yml 更好看点。并在 yml 中添加以下内容

# 服务启动端口
server:
  port: 8080

# 微信支付
wxpay:
  appId: 开放平台的AppID
  mchId: 商户号
  mchKey: 商户密钥
  #  p12证书文件的绝对路径或者以classpath:开头的类路径.
  keyPath: classpath:/wxpay_cert/apiclient_cert.p12
  #  apiclient_key.pem证书文件的绝对路径或者以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

创建一个 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;
}

创建一个 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());
        // 可以指定是否使用沙箱环境
        payConfig.setUseSandboxEnv(false);
        payConfig.setSignType("MD5");

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

    /**
     * 创建微信订单给APP
     *
     * @param productTitle 商品标题
     * @param outTradeNo   订单号
     * @param totalFee     总价
     * @return
     */
    public Object createOrder(String productTitle, String outTradeNo, Integer totalFee) {
        try {
            WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
            // 支付描述
            request.setBody(productTitle);
            // 订单号
            request.setOutTradeNo(outTradeNo);
            // 请按照分填写
            request.setTotalFee(totalFee);
            // 回调链接
            request.setNotifyUrl(wechatPayConfig.getNotifyUrl());
            // 终端IP.
            request.setSpbillCreateIp(InetAddress.getLocalHost().getHostAddress());
            // 设置类型为APP
            request.setTradeType(WxPayConstants.TradeType.APP);
            // 一定要用 createOrder 不然得自己做二次校验
            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;
    }
}

创建一个 WechatController.java 来实现接口给前端调用时使用

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);

    /**
     * 创建微信订单给APP
     *
     * @return
     */
    @RequestMapping(value = "/unified/request", method = RequestMethod.GET)
    public Object appPayUnifiedRequest() {
        // totalFee 必须要以分为单位
        Object createOrderResult = wechatPayService.createOrder("测试支付", String.valueOf(System.currentTimeMillis()), 1);
        logger.info("统一下单的生成的参数:{}", 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())) {
                // 可以实现自己的逻辑
                logger.info("来自微信支付的回调:{}", 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 必须要以分为单位,退款的价格可以这里只做的全部退款
        WxPayRefundResult refund = wechatPayService.refund(transaction_id, 1);
        // 实现自己的逻辑
        logger.info("退款本地回调:{}", refund);
    }

    /**
     * 退款回调
     *
     * @param xmlData
     * @return
     */
    @RequestMapping(method = RequestMethod.POST, value = "refund_notify")
    public String refundNotify(@RequestBody String xmlData) {
        // 实现自己的逻辑
        logger.info("退款远程回调:{}", xmlData);
        // 必须要返回 SUCCESS 不过有 WxPayNotifyResponse 给整合成了 xml了
        return WxPayNotifyResponse.success("成功");
    }

}

上面的 controller 写了两个接口一个用来 app端的调用,一个给支付用来回调。回调接口的地址要放到刚才配置中的 notifyUrl 属性里。还有一个是微信的退款接口。

  • 由于支付宝回调要使用线上的地址作为回调地址,这里我推荐两个解决办法
  • 使用一台服务器+备案的域名搭建上面的后台地址
  • 使用 花生壳 来实现本地内网穿透

我使用的是 花生壳 作为本次的开发环境,启动 springboot 的服务,配置好花生壳。后台部分到目前为止已经结束了。

前端部分

创建部分和我写的支付宝那个一样,如果不知道可以去看一下。所以跳过创建部分了,直接来到了代码实现。要在 manifest.json 勾选微信支付支持

创建前端支付代码 index.vue

<template>
    <view class="content">
        <view class="text-area">
            <text class="title">{{title}}</text>
        </view>
        <button type="default" @click="goPay()">点我前去支付</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: "支付失败,原因为: " + e.errMsg,
                                    showCancel: false
                                })
                            },
                            complete() {
                                console.log("啥也没干");
                            }
                        });

                    }
                })

            }
        }
    }
</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>

点击按钮就可以前往微信支付看下后台的生成的组合参数

跳转微信支付之后会跳回这里,提示支付成功。查看一下后台回调

之后的业务按照支付逻辑开发就可以,简单的支付已经完成。在按照刚才给的回调参数做个退款操作

我们使用 apipost 一个很强大的工具,被同事安利的。那就正好拿他测测退款借口,就不写代码了。

此时如果没有任何错误,后台控制台会返回退款本地和远程回调信息

此时微信也收到退款信息了。

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

到此这篇关于UniApp + SpringBoot 实现微信支付和退款的文章就介绍到这了,更多相关SpringBoot 微信支付和退款内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot 微信退款功能的示例代码

    一:微信支付证书配置 二:证书读取以及读取后的使用 package com.zhx.guides.assistant.config.wechatpay; import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.H

  • SpringBoot实现整合微信支付方法详解

    目录 1.准备工作 1.1 数据库表 1.2 实体类 1.3 导入依赖 1.4 配置文件 1.5 创建读取微信支付相关信息的工具类 1.6 其他工具类 2.生成订单 2.1 远程调用用户模块和课程模块 2.2 远程调用方法的实现 2.3 根据课程id和用户id生成订单 3.查询订单信息 3.1 controller层 3.2 service层 4.生成微信支付的二维码 4.1 controller层 4.2 service层 5.查询订单支付状态 5.1 controller层 5.2 serv

  • 一篇文章带你入门Springboot整合微信登录与微信支付(附源码)

    0. 前期准备 在使用微信支付前,默认小伙伴已经具备以下技能: 熟练使用springboot(SSM) + Mybatis(plus)/JPA + HttpClient + mysql5.x 了解JWT 权限校验 阅读过微信开放平台微信支付与微信登录相关文档,可以简单看懂时序图 有微信开放平台开发者资质认证账户,具备开通微信支付(如果不具备的小伙伴可以找身边有的人借一下) 1. 微信扫码登录 1.1 微信授权一键登录功能介绍 简介:登录方式优缺点和微信授权一键登录功能介绍 # 1.手机号或者邮箱

  • springboot整合微信支付sdk过程解析

    前言 之前做的几个微信小程序项目,大部分客户都有要在微信小程序前端提现的需求.提现功能的实现,自然使用企业付款接口,不过这个功能开通比较麻烦,要满足3个条件; 之前实现过几个微信支付的接口,不过都是自己码的代码,从网上找找拼凑,觉得看起来不舒服~_~ 于是乎找到了微信官方提供的支付sdk.这里用的是java版本,springboot整合java 下载sdk,引入项目 这里可以直接下载官方提供的sdk,然后将几个java类拷贝到你的项目,也可以直接引入maven依赖,这里是直接将Java类拷贝到我

  • springboot对接微信支付的完整流程(附前后端代码)

    展示图: 对接的完整流程如下 首先是配置 gzh.appid=公众号appid wxPay.mchId=商户号 wxPay.key=支付密钥 wxPay.notifyUrl=域名回调地址 常量: /**微信支付统一下单接口*/ public static final String unifiedOrderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder"; public static String SUCCESSxml = &q

  • SpringBoot集成支付宝沙箱支付(支付、退款)

    前言 支付宝推出一个沙箱环境,能够很好的模拟支付宝支付,并且还提供了demo,但demo是一个普通web项目,怎么整合到Spring Boot项目呢,其实很简单 简单配置请参照支付宝沙箱支付开发文档 一.支付部分 AlipayConfig配置:我使用的是页面跳转同步通知,返回路径return_url为公网访问地址,也可以使用localhost,且不能携带参数,APPID.商户私钥.支付宝公钥和支付宝网关换为自己的. public class AlipayConfig{ // 应用ID,您的APP

  • UniApp + SpringBoot 实现微信支付和退款功能

    目录 开发准备 微信支付开发 后端部分 前端部分 开发准备 一台用于支付的测试机,必须得是一个安卓机因为需要打支付基座才能使用. 用于编写的后端框架接口的 IDE (IDEA 或者 Eclipse 都可以) HBuilder X 用来编辑 UniApp 项目的编辑器和编译器 基本的 SpringBoot 的脚手架,可以去 https://start.spring.io/或者 IDEA 自带的快速生成脚手架插件. Jdk 11 微信支付开发 我这里省略了申请等步骤.如果没有申请过企业支付的可以去官

  • UniApp + SpringBoot 实现支付宝支付和退款功能

    目录 开发准备 支付宝支付开发 后端部分 前端部分 支付宝退款开发 后端部分 上篇介绍了UniApp + SpringBoot 实现微信支付和退款功能,喜欢的朋友可以点击查看. 开发准备 一台用于支付的测试机 用于编写的后端框架接口的 IDE (IDEA 或者 Eclipse 都可以) HBuilder X 用来编辑 UniApp 项目的编辑器和编译器 基本的 SpringBoot 的脚手架,可以去 https://start.spring.io/或者 IDEA 自带的快速生成脚手架插件. Jd

  • php实现微信支付之退款功能

    网上的很多PHP微信支付接入教程都颇为复杂,且需要配置和引入较多的文件,本人通过整理后给出一个单文件版的,希望可以给各位想接入微信支付的带来些许帮助和借鉴意义. 直接运行该文件即可给指定的微信用户退款. 需要注意的事项: 1.微信退款到零钱要求必传证书,需要到这里账户中心->账户设置->API安全->下载证书,然后修改代码中的证书路径 2.该文件需放到支付授权目录下,可以在微信支付商户平台->产品中心->开发配置中设置. 3.如提示签名错误可以通过微信支付签名验证工具进行验证

  • java服务器端微信、支付宝支付和退款功能

    工作需要,写了服务器端的支付和退款功能,包含微信和支付宝,网上也有很多demo可以借鉴,我把我的代码放出来,写的比较简单,有问题的欢迎指正,大家一起学习. 微信支付需要调用微信的统一下单接口,而支付宝不用. 我写的时候微信和支付宝都单独写了一个工具类,来调用支付,给前端返回需要的数据. ps:支付是可以不需要服务器端的,不过为了安全一点点,所以前端需要调起支付的字段都直接从服务器端返回,前端拿到字段直接调起支付就可以了. Map<String,String> map = new HashMap

  • Springboot整合微信支付(订单过期取消及商户主动查单)

    目录 一:问题引入 二:处理流程 三:代码实现 一:问题引入 前面讲到用户支付完成之后微信支付服务器会发送回调通知给商户,商户要能够正常处理这个回调通知并返回正确的状态码给微信支付后台服务器,不然微信支付后台服务器就会在一段时间之内重复发送回调通知给商户.具体流程见下图: 那么这时候问题就来了,微信后台发送回调通知次数也是有限制的,而且,微信支付开发文档中这样说到:对后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成

  • Android 高仿微信支付数字键盘功能

    现在很多app的支付.输入密码功能,都已经开始使用自定义数字键盘,不仅更加方便.其效果着实精致. 下面带着大家学习下,如何高仿微信的数字键盘,可以拿来直接用在自身的项目中. 先看下效果图: 1. 自定义布局 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

  • 微信小程序支付及退款流程详解

    首先说明一下,微信小程序支付的主要逻辑集中在后端,前端只需携带支付所需的数据请求后端接口然后根据返回结果做相应成功失败处理即可.我在后端使用的是php,当然在这篇博客里我不打算贴一堆代码来说明支付的具体实现,而主要会侧重于整个支付的流程和一些细节方面的东西.所以使用其他后端语言的朋友有需要也是可以看一下的.很多时候开发的需求和相应问题的解决真的要跳出语言语法层面,去从系统和流程的角度考虑.好的,也不说什么废话了.进入正题. 一. 支付 支付主要分为几个步骤: 前端携带支付需要的数据(商品id,购

  • Android实现微信支付功能详解

    1.集成微信支付SDK: 在build.gradle中,添加如下依赖 compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+' 2.设置微信支付回调页面: 路径:项目包名.wxapi 名称:WXPayEntryActivity public class WXPayEntryActivity extends Activity implements IWXAPIEventHandler { private IWXAPI api; @

随机推荐