前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >微信小程序支付Java工具类

微信小程序支付Java工具类

作者头像
默存
发布2024-04-16 16:24:32
910
发布2024-04-16 16:24:32
举报
文章被收录于专栏:默存默存

准备工作

微信支付开发前,需要先获取商家信息,包括商户号AppId证书和密钥

  • • 获取商户号:微信商户平台 申请成为商户 => 提交资料 => 签署协议 => 获取商户号
  • • 获取AppID:微信公众平台 注册服务号 => 服务号认证 => 获取APPID => 绑定商户号
  • • 申请商户证书:登录商户平台 => 选择 账户中心 => 安全中心 => API安全 => 申请API证书 包括商户证书和商户私钥
  • • 获取微信的证书:获取APIv3秘钥 登录商户平台 => 选择 账户中心 => 安全中心 => API安全 => 设置APIv3密钥

工具类

添加依赖

引入微信支付开放平台的 API 依赖,以便能够使用 Java 调用相关 API 接口。

微信支付 Java SDK 地址:

https://github.com/wechatpay-apiv3/wechatpay-java

代码语言:javascript
复制
<dependency>
    <groupId>com.github.wechatpay-apiv3</groupId>
    <artifactId>wechatpay-java</artifactId>
    <version>0.2.12</version>
</dependency>

支付工具类

  • • JSAPI支付下单:生成预支付订单并返回支付参数
  • • 关闭订单
  • • 微信支付订单号查询订单
  • • 商户订单号查询订单
  • • 申请退款:微信支付订单号和商家订单号二选一;
  • • 退款查询
代码语言:javascript
复制
package com.tansci.utils;

import com.alibaba.fastjson2.JSON;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
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.QueryByOutRefundNoRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.system.ApplicationHome;

import java.util.Objects;

/**
 * @path:com.tansci.utils.WxPayUtil.java
 * @className:WxPayUtil.java
 * @description: 微信小程序支付工具类
 * @author:tanyp
 * @editNote:
 */
@Slf4j
public class WxPayUtil {

    // appID
    private static String appid = "wx1fdfgfh149c6353";
    // 商户号
    private static String merchantId = "124589286";
    // 商户证书序列号
    private static String merchantSerialNumber = "3D3D4ADM154FDG44DFG45GF1SDF4JFA8DF95";
    // 商户APIV3密钥
    private static String apiV3Key = "yyh1466255d14dggh524dg666983286";
    // 商户API私钥
    private static String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPH5wD/SO6+3jMUdUio0awAwR+Ni7s22Csqk8EQLoYbeOzCN+4+bKJ4/jAuJ8CuqaCCCXtCDRlriLW35C7uzeuOiL3tN";
    // 支付回调地址
    private static String payNotifyUrl = "https://tansci.top/api/pay/payCallback";
    // 支付回调地址
    private static String refunNotifyUrl = "https://tansci.top/api/pay/refunCallback";

    private static JsapiServiceExtension jsapiService;

    private static RefundService refundService;

    public static void initConfig() {
        // 初始化商户配置
        Config config = new RSAAutoCertificateConfig.Builder()
                .merchantId(merchantId)
                .privateKey(privateKey)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(apiV3Key)
                .build();

        // 初始化服务
        jsapiService = new JsapiServiceExtension.Builder().config(config).build();
        refundService = new RefundService.Builder().config(config).build();
    }

    /**
     * @methodName:jsapi
     * @description:JSAPI支付下单
     * @author:tanyp
     * @Params: [orderId, goodsName, openId, amount]
     * @Return: java.lang.String
     * @editNote:
     */
    public static Object jsapi(String orderId, String goodsName, String openId, Integer amount) {
        try {
            if (Objects.isNull(jsapiService)) {
                initConfig();
            }
            PrepayRequest request = new PrepayRequest();
            request.setAppid(appid);
            request.setMchid(merchantId);
            request.setOutTradeNo(orderId);
            request.setDescription(goodsName);
            request.setNotifyUrl(payNotifyUrl);
            // 支付者
            Payer payer = new Payer();
            payer.setOpenid(openId);
            request.setPayer(payer);
            // 订单金额,单位为分(正数)
            Amount _amount = new Amount();
            _amount.setCurrency("CNY");
            _amount.setTotal(amount);
            request.setAmount(_amount);

            log.info("JSAPI 支付下单请求参数:{}", JSON.toJSON(request));
            PrepayWithRequestPaymentResponse response = jsapiService.prepayWithRequestPayment(request);
            log.info("JSAPI 支付下单返回参数:{}", JSON.toJSON(response));
            return response;
        } catch (HttpException e) {
            // 发送HTTP请求失败
            log.error("支付异常,发送HTTP请求失败:{}", e);
            return e.getMessage();
        } catch (ServiceException e) {
            log.error("支付异常,服务返回状态异常:{}", e);
            return e.getErrorMessage();
        } catch (MalformedMessageException e) {
            log.error("支付异常,服务返回成功,返回体类型不合法,或者解析返回体失败:{}", e);
            return e.getMessage();
        }
    }

    /**
     * @methodName:closeOrder
     * @description:关闭订单
     * @author:tanyp
     * @Params: [orderId]
     * @Return: java.lang.String
     * @editNote:
     */
    public static String closeOrder(String orderId) {
        try {
            if (Objects.isNull(jsapiService)) {
                initConfig();
            }
            CloseOrderRequest request = new CloseOrderRequest();
            request.setMchid(merchantId);
            request.setOutTradeNo(orderId);
            jsapiService.closeOrder(request);
            return "ok";
        } catch (HttpException e) {
            // 发送HTTP请求失败
            log.error("支付异常,发送HTTP请求失败:{}", e);
            return e.getMessage();
        } catch (ServiceException e) {
            log.error("支付异常,服务返回状态异常:{}", e);
            return e.getErrorMessage();
        } catch (MalformedMessageException e) {
            log.error("支付异常,服务返回成功,返回体类型不合法,或者解析返回体失败:{}", e);
            return e.getMessage();
        }
    }

    /**
     * @methodName:queryOrderById
     * @description:微信支付订单号查询订单
     * @author:tanyp
     * @Params: [transactionId]
     * @Return: com.wechat.pay.java.service.payments.model.Transaction
     * @editNote:
     */
    public static Transaction queryOrderById(String transactionId) {
        try {
            if (Objects.isNull(jsapiService)) {
                initConfig();
            }
            QueryOrderByIdRequest request = new QueryOrderByIdRequest();
            request.setMchid(merchantId);
            request.setTransactionId(transactionId);
            return jsapiService.queryOrderById(request);
        } catch (HttpException e) {
            // 发送HTTP请求失败
            log.error("支付异常,发送HTTP请求失败:{}", e);
        } catch (ServiceException e) {
            log.error("支付异常,服务返回状态异常:{}", e);
        } catch (MalformedMessageException e) {
            log.error("支付异常,服务返回成功,返回体类型不合法,或者解析返回体失败:{}", e);
        }
        return null;
    }

    /**
     * @methodName:queryOrderByOutTradeNo
     * @description:商户订单号查询订单
     * @author:tanyp
     * @Params: [orderId]
     * @Return: com.wechat.pay.java.service.payments.model.Transaction
     * @editNote:
     */
    public static Transaction queryOrderByOutTradeNo(String orderId) {
        try {
            if (Objects.isNull(jsapiService)) {
                initConfig();
            }
            QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
            request.setMchid(merchantId);
            request.setOutTradeNo(orderId);
            return jsapiService.queryOrderByOutTradeNo(request);
        } catch (HttpException e) {
            // 发送HTTP请求失败
            log.error("支付异常,发送HTTP请求失败:{}", e);
        } catch (ServiceException e) {
            log.error("支付异常,服务返回状态异常:{}", e);
        } catch (MalformedMessageException e) {
            log.error("支付异常,服务返回成功,返回体类型不合法,或者解析返回体失败:{}", e);
        }
        return null;
    }

    /**
     * @methodName:refund
     * @description:申请退款
     * @author:tanyp
     * @Params: [transactionId, orderId, refunId, reason, refunAmount, payAmount]
     * @Return: com.wechat.pay.java.service.refund.model.Refund
     * @editNote:
     */
    public static Refund refund(String transactionId, String orderId, String refunId, String reason, Integer refunAmount, Integer payAmount) {
        try {
            if (Objects.isNull(refundService)) {
                initConfig();
            }
            CreateRequest request = new CreateRequest();
            if (Objects.isNull(transactionId)) {
                request.setTransactionId(transactionId);
            }
            request.setOutTradeNo(orderId);
            request.setOutRefundNo(refunId);
            request.setNotifyUrl(refunNotifyUrl);
            request.setReason(reason);
            // 订单金额,单位为分(正数)
            AmountReq _amount = new AmountReq();
            _amount.setCurrency("CNY");
            _amount.setRefund(refunAmount.longValue());
            _amount.setTotal(payAmount.longValue());
            request.setAmount(_amount);

            return refundService.create(request);
        } catch (HttpException e) {
            // 发送HTTP请求失败
            log.error("退款异常,发送HTTP请求失败:{}", e);
        } catch (ServiceException e) {
            log.error("退款异常,服务返回状态异常:{}", e);
        } catch (MalformedMessageException e) {
            log.error("退款异常,服务返回成功,返回体类型不合法,或者解析返回体失败:{}", e);
        }
        return null;
    }

    /**
     * @methodName:queryByOutRefundNo
     * @description:退款查询
     * @author:tanyp
     * @Params: [refunId]
     * @Return: com.wechat.pay.java.service.refund.model.Refund
     * @editNote:
     */
    public static Refund queryByOutRefundNo(String refunId) {
        try {
            if (Objects.isNull(refundService)) {
                initConfig();
            }
            QueryByOutRefundNoRequest request = new QueryByOutRefundNoRequest();
            request.setOutRefundNo(refunId);
            return refundService.queryByOutRefundNo(request);
        } catch (HttpException e) {
            // 发送HTTP请求失败
            log.error("退款异常,发送HTTP请求失败:{}", e);
        } catch (ServiceException e) {
            log.error("退款异常,服务返回状态异常:{}", e);
        } catch (MalformedMessageException e) {
            log.error("退款异常,服务返回成功,返回体类型不合法,或者解析返回体失败:{}", e);
        }
        return null;
    }

}

回调通知

创建一个公开的 HTTP 端点,接受来自微信支付的支付、退款回调通知。

PayController.java

代码语言:javascript
复制
package com.tansci.controller;

import com.tansci.common.WrapMapper;
import com.tansci.common.Wrapper;
import com.tansci.service.PayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * @ClassName: PayController.java
 * @Description: 支付、退款回调通知
 * @Author: tanyp
 **/
@RestController
@RequestMapping("/api/pay")
public class PayController {

    @Autowired
    private PayService payService;

    @PostMapping("/payCallback")
    public Wrapper payCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return WrapMapper.ok(payService.payCallback(request, response));
    }

    @PostMapping("/refunCallback")
    public Wrapper refunCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        return WrapMapper.ok(payService.refunCallback(request, response));
    }

}

PayService.java

代码语言:javascript
复制
package com.tansci.service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

public interface PayService {

    Object payCallback(HttpServletRequest request, HttpServletResponse response) throws Exception;

    Object refunCallback(HttpServletRequest request, HttpServletResponse response) throws Exception;

}

PayServiceImpl.java

代码语言:javascript
复制
package com.tansci.service.impl;

import com.alibaba.fastjson2.JSON;
import com.tansci.service.PayService;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.Objects;

import static com.wechat.pay.java.core.http.Constant.*;

@Slf4j
@Service
public class PayServiceImpl implements PayService {

    // 商户号
    private static String merchantId = "124589286";
    // 商户证书序列号
    private static String merchantSerialNumber = "3D3D4ADM154FDG44DFG45GF1SDF4JFA8DF95";
    // 商户APIV3密钥
    private static String apiV3Key = "yyh1466255d14dggh524dg666983286";
    // 商户API私钥
    private static String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPH5wD/SO6+3jMUdUio0awAwR+Ni7s22Csqk8EQLoYbeOzCN+4+bKJ4/jAuJ8CuqaCCCXtCDRlriLW35C7uzeuOiL3tN";

    @Override
    public Object payCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //读取请求体的信息
        ServletInputStream inputStream = request.getInputStream();
        StringBuffer stringBuffer = new StringBuffer();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s;
        //读取回调请求体
        while ((s = bufferedReader.readLine()) != null) {
            stringBuffer.append(s);
        }
        String s1 = stringBuffer.toString();
        String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
        String nonce = request.getHeader(WECHAT_PAY_NONCE);
        String signType = request.getHeader("Wechatpay-Signature-Type");
        String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
        String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
        // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
        // 没有的话,则构造一个
        NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(merchantId)
                .privateKey(privateKey)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(apiV3Key)
                .build();
        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serialNo)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                // 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
                .signType(signType)
                .body(s1)
                .build();
        Transaction parse = parser.parse(requestParam, Transaction.class);
        log.info("支付回调参数:{}", JSON.toJSON(parse));

        try {
            /**
             * trade_state:
             * SUCCESS:支付成功
             * REFUND:转入退款
             * NOTPAY:未支付
             * CLOSED:已关闭
             * REVOKED:已撤销(付款码支付)
             * USERPAYING:用户支付中(付款码支付)
             * PAYERROR:支付失败(其他原因,如银行返回失败)
             */
            if ("SUCCESS".equals(parse.getTradeState().toString())) {
                // 成功

                log.info("==========支付回调【支付成功】=============");
            } else if ("USERPAYING".equals(parse.getTradeState().toString())
                    || "NOTPAY".equals(parse.getTradeState().toString())) {
                // 未支付

                 log.info("==========支付回调【未支付】=============");
            } else if ("PAYERROR".equals(parse.getTradeState().toString())
                    || "REVOKED".equals(parse.getTradeState().toString())
                    || "REFUND".equals(parse.getTradeState().toString())
                    || "CLOSED".equals(parse.getTradeState().toString())) {
                // 支付失败

                 log.info("==========支付回调【支付失败】=============");
            }
        } catch (Exception e) {
            log.error("支付回调处理异常:{}", e);
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        log.info("-----------------------支付回调完成-----------------------");
        return HttpStatus.OK;
    }

    @Override
    public Object refunCallback(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //读取请求体的信息
        ServletInputStream inputStream = request.getInputStream();
        StringBuffer stringBuffer = new StringBuffer();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String s;
        //读取回调请求体
        while ((s = bufferedReader.readLine()) != null) {
            stringBuffer.append(s);
        }
        String s1 = stringBuffer.toString();
        String timestamp = request.getHeader(WECHAT_PAY_TIMESTAMP);
        String nonce = request.getHeader(WECHAT_PAY_NONCE);
        String signType = request.getHeader("Wechatpay-Signature-Type");
        String serialNo = request.getHeader(WECHAT_PAY_SERIAL);
        String signature = request.getHeader(WECHAT_PAY_SIGNATURE);
        // 如果已经初始化了 RSAAutoCertificateConfig,可直接使用
        // 没有的话,则构造一个
        NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(merchantId)
                .privateKey(privateKey)
                .merchantSerialNumber(merchantSerialNumber)
                .apiV3Key(apiV3Key)
                .build();
        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serialNo)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                // 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
                .signType(signType)
                .body(s1)
                .build();
        RefundNotification parse = parser.parse(requestParam, RefundNotification.class);
        log.info("退款回调参数:{}", JSON.toJSON(parse));

        try {
            /**
             * refund_status:
             * SUCCESS:退款成功
             * CLOSED:退款关闭
             * ABNORMAL:退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款
             */
            if ("SUCCESS".equals(parse.getRefundStatus().toString())) {
                // 成功

                log.info("==========退款回调【退款失败】=============");
            } else if ("CLOSED".equals(parse.getRefundStatus().toString()) || "ABNORMAL".equals(parse.getRefundStatus().toString())) {
                // 失败

                log.info("==========退款回调【退款失败】=============");
            }
        } catch (Exception e) {
            log.error("退款回调处理异常:{}", e);
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        log.info("-----------------------退款回调完成-----------------------");
        return HttpStatus.OK;
    }

}

小程序统一发送消息

微信发送模板消息

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全栈客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 准备工作
  • 工具类
  • 回调通知
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档