Java实现微信小程序V3支付 (完整demo)

1. 微信小程序支付-开发者文档https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml

2. 导入依赖

<!--小程序支付 v3-->
<dependency>
	<groupId>com.github.wechatpay-apiv3</groupId>
	<artifactId>wechatpay-apache-httpclient</artifactId>
	<version>0.4.9</version>
</dependency>

 
3. 微信支付工具类

import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.PrivateKey;

/**
 * 微信支付工具类
 */
@Component
public class WxPayUtils {

    // 商户号
    public static final String mchId = "xxxxxxx";
    // AppID(小程序ID)
    public static final String appId = "xxxxxxx";
    // AppSecret(小程序密钥)
    public static final String appSecret = "xxxxxxx";
    // 授权
    public final static String grantType = "authorization_code";
    // APIv3密钥
    public final static String apiV3Key = "xxxxxxx";
    // 证书序列号 (从p12文件解析)
    public final static String serialnumber = "xxxxxxx";


    // 证书私钥
    public static final String privateKey = "xxxxxxx";


    /**
     * 获取私钥。
     */
    public static PrivateKey getPrivateKey() throws IOException {
        // TODO
        return merchantPrivateKey;
    }
}

4. 微信支付URL工具类

public interface ConstantUtils {


    // JSAPI下单
    public final static String JSAPI_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
    // 支付通知
    public final static String NOTIFY_URL = "https://你的线上地址.com";
    // 关闭订单
    public final static String CLOSE_PAY_ORDER_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}/close";
    // 查询订单 (根据商户订单号查询)
    public final static String QUERY_PAY_RESULT_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/";
}

5. 微信支付API v3 HttpClient (自动处理签名和验签)

import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;


@Slf4j
@Component
@Order(3)
public class WechatPayaHttpclientUtils implements ApplicationRunner {

     // 商户API私钥
     public static PrivateKey merchantPrivateKey;
     // verifier
     public static Verifier verifier;
     // httpClient
     public static CloseableHttpClient httpClient;


    @Override
    public void run(ApplicationArguments args) {
        log.info("----------->构造微信支付API v3 HttpClient");
        createHttpClient();
    }


    /***
     * 微信支付API v3 HttpClient
     *
     * 自动处理签名和验签
     *
     * @return
     */
    public void createHttpClient() {

        // TODO

        httpClient = builder.build();
    }
}

6. controller

import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.ruoyils.sy.order.domain.LsOrder;
import com.ruoyi.ruoyils.wx.pay.service.IWxPayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@Api(value = "微信-支付", tags = {"微信-支付"})
@RestController
@RequestMapping("/ls/wx/pay")
public class WxPayController extends BaseController {

    @Autowired
    private IWxPayService wxPayService;


    /**
     * jsapi下单
     *
     * @param lsOrder   订单
     * @return
     */
    @ApiOperation("统一下单")
    @PostMapping(value = "/payment")
    public AjaxResult payment(@RequestBody LsOrder lsOrder) {
        return wxPayService.addOrder(lsOrder);
    }


    /**
     * 支付通知
     *
     * @param request
     * @param response
     * @return
     */
    @PostMapping("/notifyUrl")
    public AjaxResult notifyUrl(HttpServletRequest request, HttpServletResponse response) {
        return AjaxResult.success(wxPayService.notifyUrl(request, response));
    }

}

7. service


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.sign.Base64;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.ruoyils.exception.MyException;
import com.ruoyi.ruoyils.sy.append.domain.LsAppend;
import com.ruoyi.ruoyils.sy.append.mapper.LsAppendMapper;
import com.ruoyi.ruoyils.sy.order.domain.LsOrder;
import com.ruoyi.ruoyils.sy.order.mapper.LsOrderMapper;
import com.ruoyi.ruoyils.sy.order.service.impl.LsOrderServiceImpl;
import com.ruoyi.ruoyils.sy.product.domain.LsProduct;
import com.ruoyi.ruoyils.sy.product.mapper.LsProductMapper;
import com.ruoyi.ruoyils.utils.*;
import com.ruoyi.ruoyils.wx.pay.service.IWxPayService;
import com.ruoyi.ruoyils.wx.user.domain.LsUser;
import com.ruoyi.ruoyils.wx.user.mapper.LsUserMapper;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.Signature;
import java.util.*;

@Order(5)
@Slf4j
@Service
public class WxPayServiceImpl implements IWxPayService {

    @Autowired
    private LsOrderMapper orderMapper;
    @Autowired
    private LsUserMapper lsUserMapper;
    @Autowired
    private LsProductMapper lsProductMapper;
    @Autowired
    private LsAppendMapper lsAppendMapper;


    /**
     * 立即下单
     *
     * @param lsOrder 订单
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult addOrder(LsOrder lsOrder) {

            // TODO 订单业务操作

            // 生成订单
            int i = orderMapper.insertLsOrder(lsOrder);
            if (i > 0) {
                // 调起支付
                AjaxResult payment = this.payment(lsOrder);
                return payment;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
        return AjaxResult.error("下单失败 !");
    }


    /**
     * 调起支付
     *
     * @param lsOrder
     * @return
     */

    @Override
    public AjaxResult payment(LsOrder lsOrder) {
        try {
            JSONObject order = new JSONObject();
            // 应用ID
            order.put("appid",WxPayUtils.appId);
            // 商户号
            order.put("mchid",WxPayUtils.mchId);
            // 商品描述
            order.put("description",lsOrder.getProductName());
            // 订单号
            order.put("out_trade_no",lsOrder.getOrderNo());
            // 通知地址
            order.put("notify_url",ConstantUtils.NOTIFY_URL+"/ls/wx/pay/notifyUrl");
            /**订单金额*/
            JSONObject amount = new JSONObject();
            // 总金额 (默认单位分)
//            amount.put("total",lsOrder.getTotalPrice().intValue()*100);
            amount.put("total",1);
            // 货币类型
            amount.put("currency","CNY");
            order.put("amount",amount);

            /**支付者*/
            JSONObject payer = new JSONObject();
            LsUser user = SpringUtils.getBean(LsUserMapper.class).selectLsUserById(lsOrder.getUserId());
            // 用户标识
            payer.put("openid",user.getOpenid());
            order.put("payer",payer);

          	// TODO
	        return null;
		  
    }

    /**
     * 支付通知
     *
     * @param servletRequest
     * @param response
     * @return
     */
    @Override
    public AjaxResult notifyUrl(HttpServletRequest servletRequest, HttpServletResponse response) {
        log.info("----------->微信支付回调开始<-----------");
        Map<String, String> map = new HashMap<>(12);
        String timeStamp = servletRequest.getHeader("Wechatpay-Timestamp");
        String nonce = servletRequest.getHeader("Wechatpay-Nonce");
        String signature = servletRequest.getHeader("Wechatpay-Signature");
        String certSn = servletRequest.getHeader("Wechatpay-Serial");
       
	   // TODO
	   return null;
    }

    /**
     * 关闭订单
     *
     * @param orderNo
     * @return
     */
    public boolean closePayOrder(String orderNo) {
        JSONObject obj = new JSONObject();
        // 直连商户号
        obj.put("mchid", WxPayUtils.mchId);
        // 请求地址
        String closeOrderUrl = ConstantUtils.CLOSE_PAY_ORDER_URL.replace("{out_trade_no}", orderNo);

        HttpPost httpPost = new HttpPost(closeOrderUrl);
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
        httpPost.setEntity(new StringEntity(obj.toJSONString(), "UTF-8"));

        // 微信httpClient
        CloseableHttpClient httpClient = WechatPayaHttpclientUtils.httpClient;
        try {
            if(httpClient == null){
                log.info("关闭订单失败,请重试,无法连接微信支付服务器!");
            }
            //执行请求
            CloseableHttpResponse response = httpClient.execute(httpPost);
            //状态码
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == 204) {
                //关闭订单成功!
                log.info("微信关闭订单成功: {}", orderNo);
            }else if(statusCode == 202){
                //用户支付中,需要输入密码
                log.info("关闭微信订单--用户支付中,需要输入密码,暂时不做处理!");
            }else{
                log.info("关闭微信订单--关闭支付订单失败,出现未知原因: {}", EntityUtils.toString(response.getEntity()));
            }
        } catch (IOException e) {
            log.info("关闭微信订单--关闭订单失败: {}", e.getMessage());
        }
        return false;
    }

    /**
     * 订单查询 (定时查询订单, 修改订单状态)
     *
     * @return
     */
    @Scheduled(cron="0/10 * * * * ?")
    public void queryOrder() {

		// TODO
    }
}

8. 返回给前端调起支付的必要参数

{
    "msg": "操作成功",
    "code": 200,
    "data": {
        "timeStamp": "1692334223808",
        "package": "prepay_id=wx18125024326178678d4e07673e277c0000",
        "paySign": "ocI64smXYkantoHEIkv7fibP0Y83pUmoVN1pQAjrJnFRI75sXCmQt09emPMhZJ+ujuemaGinJdJjmvGZv1JFoWvGSaMv8imDxOQV2EBr9QI+gybtUyC57+H2PhjXIR4gF0M8n7yv6Q9TA+7EIfpXOTaMJjDzM4AkFhAwz/quUAAEJVPLuaMsyF1xqi1qSY9AnE309YhqVG6ETDbZeP9/fuGCs9gD1HdD14HF4BndU696wR4TQdoiTzIyOokrE21oZLdK6Tp6sBPj2mGiIFX8viEHxq8GWOEMOIQXlr4NId4hrYA1Nn6xLk2Ka75t2t8L5V//3rWmbGSOaE5nrkeJcg==",
        "appId": "xxxxxxxxxxxxxx",
        "signType": "RSA",
        "nonceStr": "KFW6FBHHDMALH1A39FM07HKXM7I0T1GR"
    }
}

👉 点我获取demo

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
Java 实现微信小程序 V3 版本的支付需要依赖微信支付 V3 版本的 Java SDK。具体实现步骤如下: 1. 引入微信支付 V3 版本的 Java SDK。 ``` <dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-apiv3-sdk</artifactId> <version>1.1.0</version> </dependency> ``` 2. 构建微信支付 V3 版本的配置信息。 ``` WechatPayConfig config = new WechatPayConfig.Builder() .appId("微信小程序的 AppID") .mchId("商户号") .apiKey("API 密钥") .certSerialNo("API 证书序列号") .privateKey("API 密钥对应的私钥") .build(); ``` 3. 构建微信支付 V3 版本的 API 客户端。 ``` WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() .withMerchant(config); WechatPayHttpClient client = builder.build(); ``` 4. 构建微信支付 V3 版本的请求参数。 ``` WxPayNativeOrderRequest request = new WxPayNativeOrderRequest(); request.setAppid("微信小程序的 AppID"); request.setMchid("商户号"); request.setOutTradeNo("商户订单号"); request.setTotal("订单总金额"); request.setDescription("订单描述"); request.setNotifyUrl("支付回调地址"); ``` 5. 调用微信支付 V3 版本的 API 完成支付。 ``` WxPayNativeOrderResult result = client.execute(request); ``` 需要注意的是,微信支付 V3 版本的 API 接口和参数有所变化,需要根据官方文档进行调整。同时,需要在微信支付后台配置小程序支付回调地址,并保证服务器能够正常接收和处理支付回调信息。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yixian123.com

谢谢打赏,祝老板心想事成

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值