1.申请商户获取参数或文件

微信小程序appid:xxxx
商户API证书私钥文件:xxxx(微信支付)
商户号:xxxx (微信支付)
商户API证书序列号:xxxx (微信支付)
商户API v2密钥:xxxx(自定义)
商户API v3密钥:xxxx(自定义)
微信平台证书文件:xxxx (自己生成或自动生成)
微信小程序开发密钥:xxxx(小程序)

平台证书不是API证书:需5年更换一次
下载jar包https://github.com/wechatpay-apiv3/CertificateDownloader
https://github.com/wechatpay-apiv3/CertificateDownloader/releases
2.application.properties配置

wechat.pay.app_id= xxxx # 微信小程序appid
wechat.pay.private_key_path=xxxx.pem #商户API证书私钥文件路径
wechat.pay.merchant_id= xxxx #商户号
wechat.pay.merchant_serial_number= xxxx #商户API证书序列号
wechat.pay.api_v2_key= xxxx #商户API v2密钥
wechat.pay.api_v3_key= xxxx #商户API v3密钥
wechat.pay.wechat_certificate_path= xxxx.pem #微信平台证书文件路径
wechat.pay.app_select=xxxx #微信小程序开发密钥
wechat.pay.notify_url=https://xxxxx.com:port/succeed.atcion#支付成功回调 https开头

3.maven pom

 <dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>0.4.8</version></dependency><dependency><groupId>commons-httpclient</groupId><artifactId>commons-httpclient</artifactId><version>3.1</version></dependency>

4.微信支付属性配置

package com.mt.applets.config;import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;import java.io.*;
import java.security.PrivateKey;
import java.security.cert.*;@Data
@Component
@PropertySource("classpath:application.properties")
public class WxPayProperties {/***小程序appId*/@Value("${wechat.pay.app_id}")private String appId;/*** 私钥*/@Value("${wechat.pay.private_key_path}")private String privateKeyPath;/*** 商户号*/@Value("${wechat.pay.merchant_id}")private String merchantId;/*** 商户证书序列号* */@Value("${wechat.pay.merchant_serial_number}")private String merchantSerialNumber;/*** apiV3密钥*/@Value("${wechat.pay.api_v3_key}")private String apiV3Key;/*** 平台证书路径*/@Value("${wechat.pay.wechat_certificate_path}")private String wechatCertificatePath;/*** 回调路径*/@Value("${wechat.pay.notify_url}")private String notifyUrl;/*** App密钥*/@Value("${wechat.pay.app_select}")private String appSelect;/*** @Decription 获取商户的私钥* @Return  java.security.PrivateKey*/public PrivateKey getPrivateKey() {try {return PemUtil.loadPrivateKey(new FileInputStream(this.privateKeyPath));} catch (FileNotFoundException e) {//抛出异常,并把错误文件继续向上抛出throw new RuntimeException("私钥文件不存在", e);}}public X509Certificate getCertificate() throws IOException {InputStream fis = new FileInputStream(this.wechatCertificatePath);try (BufferedInputStream bis = new BufferedInputStream(fis)) {CertificateFactory cf = CertificateFactory.getInstance("X509");X509Certificate cert = (X509Certificate) cf.generateCertificate(bis);cert.checkValidity();return cert;} catch (CertificateExpiredException e) {throw new RuntimeException("证书已过期", e);} catch (CertificateNotYetValidException e) {throw new RuntimeException("证书尚未生效", e);} catch (CertificateException e) {throw new RuntimeException("无效的证书文件", e);}}}

5.支付相关业务,非自身业务

package com.mt.applets.service.impl;import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mt.api.dto.OrderPayInfo;
import com.mt.api.util.StringUtils;
import com.mt.applets.config.WxPayProperties;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.*;
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 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 org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
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.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;import javax.annotation.PostConstruct;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.stream.Collectors;
import java.util.stream.Stream;@Service
public class PayServiceImpl {@Autowiredprivate WxPayProperties wxPayProperties;private Verifier verifier;private CloseableHttpClient httpClient;private final Logger logger= LoggerFactory.getLogger(PayServiceImpl.class);@PostConstructprivate void init() throws IOException, HttpCodeException, GeneralSecurityException, NotFoundException {String merchantId= wxPayProperties.getMerchantId();String merchantSerialNumber= wxPayProperties.getMerchantSerialNumber();PrivateKey merchantPrivateKey =wxPayProperties.getPrivateKey();String apiV3Key =wxPayProperties.getApiV3Key();// 平台证书管理器CertificatesManager certificatesManager = CertificatesManager.getInstance();// 向证书管理器增加需要自动更新平台证书的商户信息certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId,new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),apiV3Key.getBytes(StandardCharsets.UTF_8));// 从证书管理器中获取verifierverifier = certificatesManager.getVerifier(merchantId);// 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create().withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey).withValidator(new WechatPay2Validator(verifier));httpClient = builder.build();}/***  签名*/public String sign(byte[] message) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {Signature sign = Signature.getInstance("SHA256withRSA");PrivateKey merchantPrivateKey = wxPayProperties.getPrivateKey();sign.initSign(merchantPrivateKey);sign.update(message);return Base64.getEncoder().encodeToString(sign.sign());}//创建订单,返回预处理订单public CloseableHttpResponse createPayOrder(OrderPayInfo orderPayInfo) throws IOException {// 请求body参数String billNo= orderPayInfo.getBillNo();Integer price= orderPayInfo.getPrice();String description= orderPayInfo.getDesc();String openId= orderPayInfo.getOpenId();String merchantId = wxPayProperties.getMerchantId();String appId = wxPayProperties.getAppId();String notifyUrl = wxPayProperties.getNotifyUrl();HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");httpPost.addHeader("Accept", "application/json");httpPost.addHeader("Content-type","application/json; charset=utf-8");ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectMapper objectMapper = new ObjectMapper();ObjectNode rootNode = objectMapper.createObjectNode();rootNode.put("mchid",merchantId).put("appid", appId).put("description", description).put("notify_url", notifyUrl).put("out_trade_no", billNo);rootNode.putObject("amount").put("total", price);rootNode.putObject("payer").put("openid", openId);objectMapper.writeValue(bos, rootNode);httpPost.setEntity(new StringEntity(bos.toString(StandardCharsets.UTF_8), "UTF-8"));CloseableHttpResponse response = httpClient.execute(httpPost);String bodyAsString = EntityUtils.toString(response.getEntity());logger.info(bodyAsString);response.close();return response;}//回调解析,获取支付回调数据public String notificationHandler(String nonce,String timestamp,String signature,String body) throws Exception {X509Certificate certificate = wxPayProperties.getCertificate();String serialNo = certificate.getSerialNumber().toString(16).toUpperCase();String apiV3Key = wxPayProperties.getApiV3Key();// 构建request,传入必要参数NotificationRequest request = new NotificationRequest.Builder().withSerialNumber(serialNo).withNonce(nonce).withTimestamp(timestamp).withSignature(signature).withBody(body).build();NotificationHandler handler = new NotificationHandler(verifier, apiV3Key.getBytes(StandardCharsets.UTF_8));// 验签和解析请求体Notification notification = handler.parse(request);// 从notification中获取解密报文return notification.getDecryptData();}//获取小程序登录者的appIDpublic String getOpenId(String code) {String secret=wxPayProperties.getAppSelect();String appId=wxPayProperties.getAppId();//appId和secret是开发者分别是小程序ID和小程序密钥,开发者通过微信公众平台-》设置-》开发设置就可以直接获取,String url="https://api.weixin.qq.com/sns/jscode2session?appid="+appId+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code";try{String res = null;CloseableHttpClient httpClient = HttpClientBuilder.create().build();HttpGet httpget = new HttpGet(url);CloseableHttpResponse response;// 配置信息RequestConfig requestConfig = RequestConfig.custom()// 设置连接超时时间(单位毫秒).setConnectTimeout(5000)// 设置请求超时时间(单位毫秒).setConnectionRequestTimeout(5000)// socket读写超时时间(单位毫秒).setSocketTimeout(5000)// 设置是否允许重定向(默认为true).setRedirectsEnabled(false).build();// 将上面的配置信息 运用到这个Get请求里httpget.setConfig(requestConfig);// 由客户端执行(发送)Get请求response = httpClient.execute(httpget);// 从响应模型中获取响应实体HttpEntity responseEntity = response.getEntity();if (responseEntity != null) {res = EntityUtils.toString(responseEntity);logger.info(res);}// 释放资源httpClient.close();response.close();JSONObject jo = (JSONObject) JSONUtil.parse(res);if(jo.get("openid")==null||StringUtils.isEmpty((String) jo.get("openid"))){throw new RuntimeException("获取openId失败");}return (String) jo.get("openid");}catch (Exception e) {throw new RuntimeException("获取openId失败", e);}}
}

6.调用试例(非完整)

//调用支付试例,返回给前端调起支付
public WeChatPayResult generateOrderToPay(String desc,Integer price,String billNo,String code) throws IOException {OrderPayInfo orderPayInfo = new OrderPayInfo();orderPayInfo.setDesc(desc);orderPayInfo.setPrice(price);orderPayInfo.setBillNo(billNo);String openId=payService.getOpenId(code);orderPayInfo.setOpenId(openId);try (CloseableHttpResponse response = payService.createPayOrder(orderPayInfo)) {String appId = wxPayProperties.getAppId();int statusCode = response.getStatusLine().getStatusCode();if (statusCode == 200 || statusCode == 204) {String entity = EntityUtils.toString(response.getEntity());JSONObject parse = JSONUtil.parseObj(entity);Object prepayIdObj = parse.get("prepay_id");String prepayId = String.valueOf(prepayIdObj);WeChatPayResult weChatPayResult = new WeChatPayResult();weChatPayResult.setPrepayId(prepayId);String nonceStr = StringUtils.getUUID(20);weChatPayResult.setNonceStr(nonceStr);long timestamp = System.currentTimeMillis() / 1000;weChatPayResult.setTimeStamp(timestamp);weChatPayResult.setSignType("RSA");String str = appId + "\n" +timestamp + "\n" +nonceStr + "\n" +"prepay_id=" + prepayId +"\n";String sign = payService.sign(str.getBytes(StandardCharsets.UTF_8));weChatPayResult.setPaySign(sign);weChatPayResult.setAppId(appId);return weChatPayResult;} else {logger.error(EntityUtils.toString(response.getEntity()));}} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {e.printStackTrace();}return null;}//回调试例public boolean confirmOrder(HttpServletRequest httpServletRequest) {String serial = httpServletRequest.getHeader("Wechatpay-Serial");String nonceStr = httpServletRequest.getHeader("Wechatpay-Nonce");String timestamp = httpServletRequest.getHeader("Wechatpay-Timestamp");String signature = httpServletRequest.getHeader("Wechatpay-Signature");if(StringUtils.isAnyEmpty(signature,nonceStr,timestamp,serial)){logger.error("微信回调请求头参数缺失");return false;}try {String bodyStr = this.getBodyStr(httpServletRequest);String result = payService.notificationHandler(nonceStr, timestamp, signature, bodyStr);JSONObject jsonObject = JSONUtil.parseObj(result);if("SUCCESS".equals(jsonObject.get("trade_state"))){Object successTime = jsonObject.get("success_time");JSONObject payer = (JSONObject)jsonObject.get("payer");Object openid = payer.get("openid");Object outTradeNo = jsonObject.get("out_trade_no");//自身业务}else{logger.error("支付失败");}}catch (Exception e){logger.error(e.getMessage());return false;}return true;}//获取请求体串public String getBodyStr(HttpServletRequest request) throws IOException {BufferedReader br = request.getReader();String str;StringBuilder wholeStr = new StringBuilder();while((str = br.readLine()) != null){wholeStr.append(str);}return wholeStr.toString();}

SpringBoot微信小程序V3支付相关推荐

  1. 基于springboot微信小程序支付功能实现

    基于springboot微信小程序支付功能实现 简单的封装微信小程序支付功能,支付工具类所依赖的fastjson.lombok.wagegger, 1.添加maven依赖: 版本号可根据自己项目的实际 ...

  2. SpringBoot微信小程序授权登录

    SpringBoot微信小程序授权登录 一.appId 1.1.自己是管理者:微信公众平台,申请或登录自己的微信小程序,在开发者管理中即可看到 2.2.自己是开发者:让管理员将自己加入到小程序开发者管 ...

  3. 微信小程序篇(微信小程序的支付)

    微信小程序的支付和微信公众号的支付是类似的,对比起来还比公众号支付简单了一些,我们只需要调用微信的统一下单接口获取prepay_id之后我们在调用微信的支付即可. 今天我们来封装一般node的支付接口 ...

  4. 微信小程序服务器支付sdk,微信小程序之支付后如何调用SDK的异步通知

    微信小程序之支付后如何调用SDK的异步通知 发布时间:2021-07-05 10:47:33 来源:亿速云 阅读:57 作者:小新 这篇文章主要介绍微信小程序之支付后如何调用SDK的异步通知,文中介绍 ...

  5. 基于SpringBoot+微信小程序的壁纸小程序

    基于SpringBoot+微信小程序的壁纸小程序 ✌全网粉丝20W+,csdn特邀作者.博客专家.CSDN新星计划导师.java领域优质创作者,博客之星.掘金/华为云/阿里云/InfoQ等平台优质作者 ...

  6. 微信小程序调用支付接口支付(tp5、小程序)

    微信小程序调用支付接口支付 今天记录一下学习的小程序调用微信支付接口 一.先理清一下调起微信支付的整个流程. 1.就是先调用微信的支付统一下单api获取到prepay_id 2.然后后端再将这个pre ...

  7. ios微信小程序虚拟支付解决办法

    ios微信小程序虚拟支付整理介绍 目前iOS端暂不支持虚拟支付,微信小程序虚拟支付仅涉及到ios端,安卓端不受影响. 小程序支付规范 https://developers.weixin.qq.com/ ...

  8. (附源码)基于springboot微信小程序的长沙县图书馆图书导览系统 毕业设计 170900

    基于springboot微信小程序的长沙县图书馆图书导览系统 摘  要 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也 ...

  9. 微信小程序—微信小程序端支付代码

    只有微信小程序端的代码,如下 Page({data: {},onLoad: function (options) {// 页面初始化 options为页面跳转所带来的参数var that = this ...

最新文章

  1. 深入理解Java内存模型(四)——volatile
  2. 大小端字节序介绍以及判断当前环境字节序的程序【C语言】
  3. Merkle山脉(Merkle Mountain Range)详解
  4. 为什么有三AI从来不追热点,信息越多学的越慢
  5. IE6 下图片少一块
  6. C++描述杭电OJ 2018.母牛的故事 ||
  7. springboot和springcloud有什么关系
  8. 交叉熵代价函数(损失函数)及其求导推导
  9. SoapUI Pro Project Solution Collection-DataSource(jdbc,excel)
  10. 四种方法下载网络文本数据到本地内存
  11. 微信小游戏代码包侵权解决方案升级版
  12. 【网络覆盖优化】基于matlab的网络覆盖遗传优化问题仿真
  13. 记一次接口压力测试与性能调优
  14. 城市大数据及开放数据索引
  15. 奇安信技术总监熬夜总结,全网最全内网渗透姿势!
  16. MATLAB基础图像处理算法
  17. 华维单片机编程-无线红外探测器03-环境搭建及程序详解
  18. log4j输出多个自定义日志文件、动态配置多个日志文件
  19. fedora15 安装nvidia 显卡驱动
  20. 2021年复旦大学961真题回顾

热门文章

  1. PA1.3 代码+笔记
  2. this.name=name
  3. Windows——卸载MinGW的方法
  4. 如何将小鹤单字挂接到搜狗输入法
  5. 浩辰CAD参考图剪辑编辑
  6. 3DMAX解析愤怒的小鸟
  7. aws课程_AWS DeepRacer,Reinforcement Learning 101和一门关于AI管治的小课程
  8. Python的起源与Python之父
  9. 语音邮件 voice mail 概述
  10. 通过“单键锁配置法”实现访问控制