利用微信小程序+JAVA实现微信支付的全过程

 更新时间:2024年08月17日 13:56:49   作者:z不像程序员的程序猿  
微信支付是一种在线支付解决方案,允许用户通过微信内的支付功能进行付款,下面这篇文章主要给大家介绍了关于利用微信小程序+JAVA实现微信支付的相关资料,需要的朋友可以参考下

本文主要讲的是小程序实现微信支付功能,后台采用JAVA。

一.准备工作

1.小程序

2.微信商户号

1.商户号申请

这里对小程序的申请不做赘述。

如果没有微信商户号的同学,点击该链接https://pay.weixin.qq.com/,按照下属步骤进行商户号申请。

扫码之后点击"成为商家",这里主要有个体工商户和企业,按照事实填写,然后按照步骤填写就行了。
主要需要营业执照,法人信息,公账信息等。

2.微信商户号关联小程序

点击"产品中心"的"开发配置",点击"新增授权申请单"。

输入你的小程序appid,点击下一步。

然后到小程序后台>微信支付>商户号管理里,会出现一个申请单,点击“查看”。

点击确认绑定,这样你的商户号就与小程序进行绑定了。

二.代码编写

1.小程序

小程序这块主要是调用一下后台接口获取参数,然后通过参数拉起微信支付。

orderPay(payInfo){
  let that = this
  wx.requestPayment({
    'timeStamp': payInfo.timeStamp,
    'nonceStr': payInfo.nonceStr,
    'package': payInfo.package,
    'signType': payInfo.signType,
    'paySign': payInfo.paySign,
    'success': function (res) {
		// 支付成功的回调
    },
    'fail': function (res) {
      console.log(JSON.stringify(res));
      wx.showToast({title: '支付失败', icon: 'none',duration: 2000,mask: true})
    }
  })
},

这里的payInfo就是从后台接口获取的支付参数,通过wx.requestPayment就可以拉起微信支付了。具体的参数信息在下面会进行讲解。

2.服务端(JAVA)

服务端这边主要是三个接口:

1.提交支付订单

这个主要是为了获取提交支付订单,获取前端拉起支付的参数。

2.微信支付回调

当你小程序拉起支付并且成功支付后,会将支付结果回调到这个接口

3.支付订单查询

你也可以主动通过订单号查询支付订单状态

下面是我的代码,包含了我的业务代码,大家将就着看吧

controller:

import com.smart.iot.gmt.app.bean.CommonReponse;
import com.smart.iot.gmt.app.constant.ResponseContant;
import com.smart.iot.gmt.app.constant.SessionKeyConstants;
import com.smart.iot.gmt.app.request.wechatPay.PaymentRequest;
import com.smart.iot.gmt.app.request.wechatPay.QueryPayOrderRequest;
import com.smart.iot.gmt.app.response.wechat.WechatPaymentResponse;
import com.smart.iot.gmt.app.response.wechat.WechatQueryPayOrderResponse;
import com.smart.iot.gmt.app.service.CommonService;
import com.smart.iot.gmt.app.service.pay.wechat.WxPayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;

@Slf4j
@RestController
public class WxPayController {

    @Autowired
    private WxPayService service;
    @Autowired
    private CommonService commonService;

    /**
     *
     * @author Rick chou
     * @date 2024/7/18 15:33
     * 提交支付
     *
     */
    @PostMapping("/payment")
    public CommonReponse payment(@RequestBody PaymentRequest paymentRequest) {
        Integer price = paymentRequest.getPrice();
        String orderId = paymentRequest.getOrderId();
        Map<String, Object> result = service.payment(price, orderId, userId);
        CommonReponse commonResponse = commonService.getCommonResponse(ResponseContant.SUCCESS_CODE, ResponseContant.SUCCESS, result);
        return new WechatPaymentResponse(commonResponse,result);
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/15 16:57
     * 微信支付回调
     *
     */
    @PostMapping("/payNotify")
    public void payNotify(HttpServletRequest request) throws Exception {
        service.payNotify(request);
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/15 16:57
     * 支付查询
     *
     */
    @PostMapping("/queryPayOrder")
    public CommonReponse queryPayOrder(@RequestBody QueryPayOrderRequest request) {
        Map<String, Object> result = service.queryPayOrder(request);
        CommonReponse commonResponse = commonService.getCommonResponse(ResponseContant.SUCCESS_CODE, ResponseContant.SUCCESS, result);
        return new WechatQueryPayOrderResponse(commonResponse,result);
    }
}

service:

import com.alibaba.fastjson.JSON;
import com.smart.iot.constant.RedisKeys;
import com.smart.iot.device.dto.LockNotifyMessageDTO;
import com.smart.iot.device.service.DeviceRedisCacheService;
import com.smart.iot.gmt.app.annotation.SpringUtil;
import com.smart.iot.gmt.app.bo.*;
import com.smart.iot.gmt.app.entity.MemberOrderDetailEntity;
import com.smart.iot.gmt.app.enums.MemberOrderStateEnum;
import com.smart.iot.gmt.app.request.wechatPay.QueryPayOrderRequest;
import com.smart.iot.gmt.app.service.LockNotifyMessageService;
import com.wechat.pay.java.service.payments.model.Transaction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import java.util.Map;

@Slf4j
@Service
public class WxPayService {

    public Map<String, Object> payment(Integer price, String orderId, String userId){
        Map<String, Object> result = WechatPayBo.payment(price, orderId, userId);
        return result;
    }

    @Transactional
    public void payNotify(HttpServletRequest request) throws Exception {
        Transaction parse = WechatPayBo.payNotify(request);
        updateAccountDetail(parse,false);
    }

    @Transactional
    public Map<String,Object> queryPayOrder(QueryPayOrderRequest request) {
        String orderId = request.getOrderId();
        Transaction parse = WechatPayBo.queryPayOrder(orderId);
        return updateAccountDetail(parse,true);
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 11:03
     * 支付回调处理
     * 1.更新订单状态
     * 2.添加支付记录
     * 3.通知小程序
     *
     */
    public Map<String,Object> updateAccountDetail(Transaction parse, boolean active) {
        String orderId = parse.getOutTradeNo();
        Transaction.TradeStateEnum tradeState = parse.getTradeState();
        if(tradeState==Transaction.TradeStateEnum.SUCCESS) {
            if(OrderBo.check(orderId).getState() == MemberOrderStateEnum.IN_PROGRESS.code) {
                OrderBo order = this.updateOrder(orderId);
                this.renewMember(orderId);
                this.saveRecord(parse, order.getUserId());
            }
        }
        if(active){
            return JSON.parseObject(buildParse(parse),Map.class);
        }else{
            this.payNoticeMessage(parse,orderId);
        }
        return null;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/19 15:31
     * 更新订单状态
     *
     */
    private OrderBo updateOrder(String orderId){
        OrderBo order = OrderBo.check(orderId);
        order.finish();
        String key = RedisKeys.ADD_ORDER_PAY_TIME_PREFIX + orderId;
        SpringUtil.getBean(DeviceRedisCacheService.class).delete(key);
        return order;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/19 15:32
     * 更新会员时间
     *
     */
    private void renewMember(String orderId){
        MemberOrderDetailEntity orderDetail = OrderDetailBo.getByOrderId(orderId);
        UserMemberBo.renew(orderDetail);
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/19 15:33
     * 保存支付记录
     *
     */
    private void saveRecord(Transaction parse,String userId){
        String orderId = parse.getOutTradeNo();
        Integer amount = parse.getAmount().getTotal();
        String tradeType = parse.getTradeType().name();
        PayRecordBo.create(userId,orderId,amount,tradeType);
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/19 15:38
     * 将支付结果下发小程序
     *
     */
    private void payNoticeMessage(Transaction parse,String orderId){
        MemberOrderDetailEntity detail = OrderDetailBo.getByOrderId(orderId);
        LockNotifyMessageService service = SpringUtil.getBean(LockNotifyMessageService.class);
        LockNotifyMessageDTO dto = new LockNotifyMessageDTO();
        dto.setLockId(detail.getDeviceId());
        dto.setMessageParams(buildParse(parse));
        service.dealPayResultNotifyMessage(dto);
    }

    private String buildParse(Transaction parse){
        parse.setMchid(null);
        parse.setAppid(null);
        parse.setBankType(null);
        parse.setBankType(null);
        parse.setAttach(null);
        return JSON.toJSONString(parse);
    }
}

bo:

import com.smart.iot.gmt.app.annotation.SpringUtil;
import com.smart.iot.gmt.app.entity.PayRecordEntity;
import com.smart.iot.gmt.app.service.pay.wechat.PayInfoConfig;
import com.smart.iot.gmt.app.service.pay.wechat.WXPayUtil;
import com.smart.iot.util.StringUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.exception.ValidationException;
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.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static com.wechat.pay.java.core.http.Constant.*;

/**
 *
 * @author Rick chou
 * @date 2024/7/16 9:10
 * 微信支付BO
 *
 */
@Slf4j
@Component
public class WechatPayBo extends PayRecordEntity {

    private static PayInfoConfig getConfig(){
        PayInfoConfig payInfoConfig = SpringUtil.getBean(PayInfoConfig.class);
        return payInfoConfig;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 9:35
     * 构建支付请求SERVICE
     *
     */
    public static JsapiService getService(){
        PayInfoConfig payInfoConfig = getConfig();
        Config config = new RSAAutoCertificateConfig.Builder()
            .merchantId(payInfoConfig.getMchId())
            .privateKeyFromPath(payInfoConfig.getKeyPath())
            .merchantSerialNumber(payInfoConfig.getMchSerialNo())
            .apiV3Key(payInfoConfig.getApiKey())
            .build();
        JsapiService service = new JsapiService.Builder().config(config).build();
        return service;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 10:31
     * 构造NOTIFY_CONFIG
     *
     */
    private static NotificationConfig buildNotifyConfig(){
        PayInfoConfig payInfoConfig = getConfig();
        NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                .merchantId(payInfoConfig.getMchId())
                .privateKeyFromPath(payInfoConfig.getKeyPath())
                .merchantSerialNumber(payInfoConfig.getMchSerialNo())
                .apiV3Key(payInfoConfig.getApiKey())
                .build();
        return config;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 9:35
     * 构建支付请求参数
     *
     */
    private static PrepayRequest buildParam(Integer price, String orderId, String userId){
        PayInfoConfig payInfoConfig = getConfig();
        PrepayRequest prepayRequest = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(price);
        prepayRequest.setAmount(amount);
        prepayRequest.setAppid(payInfoConfig.getAppId());
        prepayRequest.setMchid(payInfoConfig.getMchId());
        prepayRequest.setNotifyUrl(payInfoConfig.getNotifyUrl());				// 回调接口地址
        prepayRequest.setDescription("微信支付");
        prepayRequest.setOutTradeNo(orderId);       // 订单号
        prepayRequest.setAttach("member");                                     // 订单类型(回调时可根据这个数据辨别订单类型或其他)

        //根据token拿到openid,指定该预支付订单的支付者身份
        Payer payer = new Payer();
        payer.setOpenid(WeixinUserBo.getOpenId(userId));
        prepayRequest.setPayer(payer);
        return prepayRequest;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 9:53
     * 解析支付结果
     *
     */
    private static Map<String,Object> parsePay(PrepayResponse response){
        PayInfoConfig payInfoConfig = getConfig();
        Map<String, Object> params = new HashMap<>();
        Long timeStamp = System.currentTimeMillis() / 1000;
        String substring = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
        String signatureStr = Stream.of(
                payInfoConfig.getAppId(),
                String.valueOf(timeStamp),
                substring,
                "prepay_id=" + response.getPrepayId()
        ).collect(Collectors.joining("\n", "", "\n"));
        String sign = WXPayUtil.getSign(signatureStr, payInfoConfig.getKeyPath());
        params.put("timeStamp", String.valueOf(timeStamp));
        params.put("nonceStr", substring);
        params.put("paySign", sign);
        params.put("signType", "RSA");
        params.put("package", "prepay_id=" + response.getPrepayId());
        return params;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 10:33
     * 解析回调结果
     *
     */
    private static RequestParam parseNotify(HttpServletRequest request)throws IOException {
        String data = StringUtil.getStringForInput(request.getInputStream());
        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);

        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serialNo)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .signType(signType)         // 若未设置signType,默认值为 WECHATPAY2-SHA256-RSA2048
                .body(data)
                .build();
        return requestParam;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 9:47
     * 调起支付
     *
     */
    public static Map<String, Object> payment(Integer price, String orderId, String userId){
        JsapiService service = getService();
        PrepayRequest prepayRequest = buildParam(price, orderId, userId);
        PrepayResponse response = service.prepay(prepayRequest);
        Map<String, Object> result = parsePay(response);
        result.put("orderId",orderId);
        return result;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 10:16
     * 支付回调
     *
     */
    public static Transaction payNotify(HttpServletRequest request) throws Exception {
        NotificationConfig config = buildNotifyConfig();
        NotificationParser parser = new NotificationParser(config);
        RequestParam requestParam = parseNotify(request);
        Transaction parse = null;
        try {
             parse = parser.parse(requestParam, Transaction.class);
        }catch (ValidationException e){
            log.error("sign verification failed", e);
        }
        return parse;
    }

    /**
     *
     * @author Rick chou
     * @date 2024/7/16 11:17
     * 查询订单
     *
     */
    public static Transaction queryPayOrder(String orderId) {
        PayInfoConfig payInfoConfig = getConfig();
        JsapiService service = getService();
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(payInfoConfig.getMchId());
        queryRequest.setOutTradeNo(orderId);
        Transaction parse = null;
        try {
            parse = service.queryOrderByOutTradeNo(queryRequest);
        }catch (ServiceException e){
            log.info("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            log.info("reponse body=[%s]\n", e.getResponseBody());
        }
        return parse;
    }
}

PayInfoConfig

import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Data
@ToString
@Component
@ConfigurationProperties(prefix = "wx")
public class PayInfoConfig {

    //小程序appid
    private String appId;
    //商户号
    private String mchId;
    //证书序列号
    private String mchSerialNo;
    //小程序秘钥
    private String appSecret;
    //api秘钥
    private String apiKey;
    //回调接口地址
    private String notifyUrl;
    //证书地址
    private String keyPath;
}

上述的PayInfoConfig中的参数第二、三、五、七个参数去商户号后台获取。

三.补充说明

在实际的支付开发中需要注意一些比较重要的点,假设你现在做的是一个会员开通功能。

1.在你点击开通的时候,你需要做的肯定是调用你自己的后台业务接口生成一个会员订单,同时调用微信支付获取支付参数返回到前端。这样用户看到的就是直接拉起支付。

2.当你执行支付操作后你的支付回调接口会收到支付结果,这个时候你服务端要主动通知小程序,并且当小程序拉起支付后要定时调用支付查询接口来主动查询支付完成支付。做个双保险比较好。

3.微信支付完成后有个"完成"按钮,点击后就会回到wx.requestPayment的success回调里,这里最好也要查询下订单状态。

4.还有点我还没怎么做处理,也是个题外话,就是当支付回调时服务器挂了咋整,得想个万全之策,这个就交给你们解答了。

到此这篇关于利用微信小程序+JAVA实现微信支付的文章就介绍到这了,更多相关微信小程序 JAVA实现微信支付内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IntelliJ IDEA下SpringBoot如何指定某一个配置文件启动项目

    IntelliJ IDEA下SpringBoot如何指定某一个配置文件启动项目

    这篇文章主要介绍了IntelliJ IDEA下SpringBoot如何指定某一个配置文件启动项目问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • SpringBoot集成ActiveMQ的实战全过程

    SpringBoot集成ActiveMQ的实战全过程

    消息队列中间件是分布式系统中重要的组件,主要解决应用耦合、异步消息、流量削锋等问题,实现高性能、高可用、可伸缩和最终一致性架构,是大型分布式系统不可缺少的中间件,这篇文章主要给大家介绍了关于SpringBoot集成ActiveMQ的相关资料,需要的朋友可以参考下
    2021-11-11
  • kaptcha验证码组件使用简介解析

    kaptcha验证码组件使用简介解析

    这篇文章主要介绍了kaptcha验证码组件使用简介解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • IntelliJ IDEA 2019.3激活破解的详细方法(亲测有效,可激活至 2089 年)

    IntelliJ IDEA 2019.3激活破解的详细方法(亲测有效,可激活至 2089&

    本教程适用于 JetBrains 全系列产品,包括 Pycharm、IDEA、WebStorm、Phpstorm、Datagrip、RubyMine、CLion、AppCode 等,本教程无需修改 hosts 文件,对IntelliJ IDEA 2019.3激活破解的详细方法的相关知识感兴趣的朋友一起看看吧
    2020-09-09
  • Nacos负载均衡策略总结

    Nacos负载均衡策略总结

    Nacos 作为目前主流的微服务中间件,包含了两个顶级的微服务功能:配置中心和注册中心,本文给大家总结了几种Nacos负载均衡策略,通过图文结合介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • Java pdf文件书签承前缩放验证的设置方法

    Java pdf文件书签承前缩放验证的设置方法

    很多朋友不知道是什么是书签承前缩放,简单说就是可以任意改变当前pdf文档缩放比例,点击书签后不影响其缩放比率,本文给大家介绍下Java pdf文件书签承前缩放验证的设置方法,感兴趣的朋友一起看看吧
    2022-02-02
  • Spring集成Struts与Hibernate入门详解

    Spring集成Struts与Hibernate入门详解

    这篇文章主要给大家介绍了关于Spring集成Struts与Hibernate的相关资料,文中介绍的非常详细,对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。
    2017-03-03
  • spring Cloud微服务跨域实现步骤

    spring Cloud微服务跨域实现步骤

    这篇文章主要介绍了spring Cloud微服务跨域实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Java在Word中插入上标和下标的实现方法

    Java在Word中插入上标和下标的实现方法

    在某些情况下,你可能需要在Microsoft Word中插入上标和下标。例如,当你正在创建一个涉及科学公式的学术文件时,在这篇文章中,你将学习如何使用Spire.Doc for Java库在Word文档中插入上标和下标,需要的朋友可以参考下
    2022-10-10
  • 详解Java中的阻塞队列

    详解Java中的阻塞队列

    在去年的面试过程中,被面试官问道“阻塞队列”这个问题,因为当时并没有对此问题进行深入理解,只是按照自己的理解说明了该问题,最后面试结果也不太好,今天对该问题进行简要的面试并记录如下;如有错误,欢迎指正,需要的朋友可以参考下
    2021-06-06

最新评论