SpringBoot整合微信小程序支付全流程

1.首先要注册一个微信小程序账号

这里注意一定要是个体工商户类型或者是企业微信类型个人类型小程序是无法使用微信支付的!

注册之后我们获取到appid

2.注册商家收款账户

注册好之后我们需要用到一下内容

选择

全部填写

这里证书申请傻瓜式,按照官方提示即可

3.SpringBoot配置如下

需要的pom

<dependency>
    <groupId>com.github.wechatpay-apiv3</groupId>
    <artifactId>wechatpay-java</artifactId>
    <version>0.2.12</version>
</dependency>
<dependency>
    <groupId>com.squareup.okio</groupId>
    <artifactId>okio</artifactId>
    <version>3.3.0</version>
</dependency>

创建如下配置代码

import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.util.IOUtil;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.refund.RefundService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;

@Data
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "wx.pay")
public class WxPayConfig {

    private String appId;

    private String apiV3Key;

    private String notifyUrl;

    private String merchantId;

    private String privateKeyPath;

    private String merchantSerialNumber;

    // RSA配置
    private RSAAutoCertificateConfig RSAConfig;

    // JSAPI支付
    private JsapiServiceExtension jsapiServiceExtension;

    // 退款
    private RefundService refundService;

    /**
     * 初始化配置
     */
    @Bean
    public void initWxPayConfig() throws IOException {
        this.RSAConfig = buildRSAAutoCertificateConfig();
        this.jsapiServiceExtension = buildJsapiServiceExtension(RSAConfig);
        this.refundService = buildRefundService(RSAConfig);
    }

    // 构建并使用自动更新平台证书的RSA配置,一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
    private RSAAutoCertificateConfig buildRSAAutoCertificateConfig() throws IOException {
        // 将 resource 目录下的文件转为 InputStream,然后利用 IOUtil.toString(inputStream) 转化为密钥
        String privateKey = IOUtil.toString(new ClassPathResource(privateKeyPath).getInputStream());
        return new RSAAutoCertificateConfig.Builder()
                .merchantId(merchantId)
                .privateKey(privateKey)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(apiV3Key)
                .build();
    }

    // 构建JSAPI
    private JsapiServiceExtension buildJsapiServiceExtension(RSAAutoCertificateConfig config) {
        return new JsapiServiceExtension.Builder().config(config).build();
    }

    // 构建退款
    private RefundService buildRefundService(RSAAutoCertificateConfig config) {
        return new RefundService.Builder().config(config).build();
    }

}

继续

import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.RefundNotification;

import javax.servlet.http.HttpServletRequest;

public interface WxUserPayService {


    // 微信支付
    PrepayWithRequestPaymentResponse creationIndentPayment(String indentId, String myOpenId, Double amount);

    // 获取支付回调信息
    Transaction getTransaction(HttpServletRequest request);

    // 支付回调
    boolean indentPaymentBlack(Transaction transaction);

    // 退款申请
    Refund refundIndentPayment(String refundId, Double amount);

    // 获取退款回调信息
    RefundNotification getRefundNotification(HttpServletRequest request);

    // 退款回调
    boolean refundIndentBlack(RefundNotification refundNotification);
}

继续

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import com.zj.domain.UserOrder;
import com.zj.exception.BusinessException;
import com.zj.mapper.UserOrderMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.math.BigDecimal;

@Service
@Slf4j
public class WxUserPayServiceImpl implements WxUserPayService {

    @Resource
    private WxPayConfig wxPayConfig;
    @Resource
    private UserOrderMapper userOrderMapper;
    /**
     * 请求参数
     */
    public static RequestParam requestParam = null;
    @Override
    public PrepayWithRequestPaymentResponse creationIndentPayment(String orderId, String myOpenId, Double amount) {
        PrepayRequest request = new PrepayRequest();
        // 金额
        Amount WxAmount = new Amount();
        WxAmount.setTotal(new BigDecimal(String.valueOf(amount)).movePointRight(2).intValue());
        WxAmount.setCurrency("CNY");
        request.setAmount(WxAmount);
        // 公众号appId
        request.setAppid(wxPayConfig.getAppId());
        // 商户号
        request.setMchid(wxPayConfig.getMerchantId());
        // 支付者信息
        Payer payer = new Payer();
        payer.setOpenid(myOpenId);
        request.setPayer(payer);
        // 描述
        request.setDescription("代办服务");
        // 微信回调地址
        request.setNotifyUrl(wxPayConfig.getNotifyUrl()+"/end/IndentPayment");
        //系统内部订单号
        request.setOutTradeNo(orderId);
        //返回数据,前端调起支付
        return wxPayConfig.getJsapiServiceExtension().prepayWithRequestPayment(request);
    }

    // 获取支付回调信息
    @Override
    public Transaction getTransaction(HttpServletRequest request) {
        NotificationParser notificationParser = getNotificationParser(request);
        return notificationParser.parse(requestParam, Transaction.class);
    }

    // 支付回调
    @Override
    public boolean indentPaymentBlack(Transaction transaction) {
        System.out.println("---------------------------修改订单状态信息(下单)-------------------------------");
        // 获取订单号
        String orderId = transaction.getOutTradeNo();
        UserOrder userOrder = userOrderMapper.selectById(orderId);
        if (userOrder == null) {
            log.error("订单不存在");
            throw new BusinessException(40004,"订单不存在:" + transaction.getOutTradeNo());
        }
        log.info("下单成功");
        LambdaUpdateWrapper<UserOrder> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(UserOrder::getIsTrue,"已支付").eq(UserOrder::getOrderId,orderId);
        userOrderMapper.update(null,updateWrapper);
        System.out.println("---------------------------修改订单状态信息完毕-------------------------------");
        System.out.println("---------------------------添加微信支付记录完毕-------------------------------");
        return true;
    }
    @Override
    public Refund refundIndentPayment(String refundId, Double amount) {
//        Indent indent = this.baseMapper.selectById(refundId);
        // 退款请求
        CreateRequest createRequest = new CreateRequest();
        // 商户订单号
        createRequest.setOutTradeNo(refundId);
        // 商户退款单号
        createRequest.setOutRefundNo(refundId);
        // 退款结果回调
        createRequest.setNotifyUrl(wxPayConfig.getNotifyUrl() + "/refund/black");
        // 退款金额
        AmountReq amountReq = new AmountReq();
        long refundAmount = new BigDecimal(String.valueOf(amount)).movePointRight(2).intValue();
        amountReq.setRefund(refundAmount);
        amountReq.setTotal(refundAmount);
        amountReq.setCurrency("CNY");
        createRequest.setAmount(amountReq);
        // 申请退款
        System.out.println("退款请求:" + createRequest);
        Refund refund = wxPayConfig.getRefundService().create(createRequest);
        System.out.println("退款申请结果:" + refund);
        return refund;
    }

    // 获取退款回调信息
    @Override
    public RefundNotification getRefundNotification(HttpServletRequest request) {
        NotificationParser notificationParser = getNotificationParser(request);
        return notificationParser.parse(requestParam, RefundNotification.class);
    }

    // 退款回调
    @Override
    public boolean refundIndentBlack(RefundNotification refundNotification) {
        System.out.println("---------------------------修改订单状态信息(退款)-------------------------------");
        // 获取订单号
        String indentIdByString = refundNotification.getOutTradeNo();
        System.out.println("---------------------------修改订单状态信息完毕-------------------------------");
        return true;
    }

    /**
     * 根据微信官方发送的请求获取信息
     */
    @SneakyThrows
    public NotificationParser getNotificationParser(HttpServletRequest request) {
        System.out.println("---------------------------获取信息-------------------------------");
        // 获取RSA配置
        NotificationParser notificationParser = new NotificationParser(wxPayConfig.getRSAConfig());
        // 构建请求
        StringBuilder bodyBuilder = new StringBuilder();
        BufferedReader reader = request.getReader();
        String line;
        while ((line = reader.readLine()) != null) {
            bodyBuilder.append(line);
        }
        String body = bodyBuilder.toString();
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String signature = request.getHeader("Wechatpay-Signature");
        String singType = request.getHeader("Wechatpay-Signature-Type");
        String wechatPayCertificateSerialNumber = request.getHeader("Wechatpay-Serial");
        requestParam = new RequestParam.Builder()
                .serialNumber(wechatPayCertificateSerialNumber)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .signType(singType)
                .body(body)
                .build();
        System.out.println(requestParam.toString());
        System.out.println("---------------------------信息获取完毕-------------------------------");
        return notificationParser;
    }
}

 继续

import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import com.zj.utils.Result;
import com.zj.utils.ResultUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping
public class WxUserPayController {
    @Resource
    private WxUserPayService wxUserPayService;
    /**
     * JSAPI 下单
     */
    @GetMapping("/create/IndentPayment")
    public Result creationIndentPayment(String openId) {
        PrepayWithRequestPaymentResponse paymentResponse = wxUserPayService.creationIndentPayment(IdUtil.simpleUUID(), openId,0.01);
        return ResultUtils.success(paymentResponse);
    }

    /**
     * JSAPI 下单回调
     */
    @PostMapping("/end/IndentPayment")
    @Transactional(rollbackFor = Exception.class)
    public synchronized Result endIndentPayment(HttpServletRequest request) {
        // 获取下单信息
        Transaction transaction = wxUserPayService.getTransaction(request);
        // 修改订单状态
        boolean result = wxUserPayService.indentPaymentBlack(transaction);
//        ThrowUtils.throwIf(!result, ErrorCode.SYSTEM_ERROR, "修改订单失败");
        return ResultUtils.success(result);
    }

    /**
     * 退款
     */
    @GetMapping("/refund/IndentPayment")
    public Result<Refund> refundIndentPayment(@RequestParam String orderId,@RequestParam Double amount ) {
        Refund refund = wxUserPayService.refundIndentPayment(orderId,amount);
        return ResultUtils.success(refund);
    }

    /**
     * 退款回调
     */
    @PostMapping("/refund/black")
    public Result<Boolean> endRefundIndent(HttpServletRequest request) {
        // 获取退款信息
        RefundNotification refundNotification = wxUserPayService.getRefundNotification(request);
        // 修改订单状态
        boolean result = wxUserPayService.refundIndentBlack(refundNotification);
        return ResultUtils.success(result);
    }
}

ok了就然后写前端测试demo

<template>
	<view class="content">
		<view class="text-area">
			<text class="title">{{title}}</text>
		</view>
		<button type="default" @click="goPay()">点我前去支付</button>
		<button type="default" @click="login()">退款</button>
	</view>
</template>

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

		},
		methods: {
			goPay() {
				uni.request({
					url: 'https://你自己的支付接口/create/IndentPayment',
					method: 'GET',
					data:{
						openId:"真实用户OpenId",
					},
					success(res) {
						console.log(res);
						
						console.log(res.data.data.nonceStr),
						wx.requestPayment({
							nonceStr: res.data.data.nonceStr,
							package: res.data.data.packageVal,
							paySign: res.data.data.paySign,
							prepayid: res.data.data.prepayId,
							timeStamp: res.data.data.timeStamp,
							signType: res.data.data.signType,
							success(res) {
								uni.showModal({
									content: "支付成功",
									showCancel: false
								})
								console.log(res);
							},
							fail(e) {
								uni.showModal({
									content: "支付失败,原因为: " + e.errMsg,
									showCancel: false
								})
								console.log(e.errMsg);
							},
							complete() {
								console.log("啥也没干");
							}
						});

					}
				})

			},
			login(){
				uni.request({
					url: 'https://你自己的退款接口/foodCombo/userQueryAllFoodCombo',
					method: 'GET',
					data:{
						orderId:'真实用户OpenId',
						amount: 0.01,
					},
					success(res) {
						console.log(res);
					}
				})
			}
		}
	}
</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>

运行即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值