微信官方文档–小程序支付:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_5_1.shtml

微信官方文档–支付接入前准备https://pay.weixin.qq.com/wiki/doc/apiv3/open/pay/chapter2_8_1.shtml

下载平台证书报错处理:https://blog.csdn.net/aiguo94/article/details/124037688

使用Apache HttpClient处理HTTP的Java开发库(封装了签名生成、签名验证、敏感信息加/解密、媒体文件上传等基础功能):https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient

maven导包

<dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>0.4.5</version>
</dependency>
<dependency><groupId>com.github.javen205</groupId><artifactId>IJPay-WxPay</artifactId>
</dependency>

实体类

wxpay_v3.properties(微信支付配置,有appId,商户id,API密钥,证书地址,回调地址,该文件在resource根目录)
WxPayV3Bean (微信支付配置对象,获取wxpay_v3.properties中的配置的参数值)
PayOrderDTO (微信下单对象)
WxPayVO (微信下单后返回给前端的对象)
WxQueryVO(微信查单返回的对象)
WxPayStateEnum (微信支付订单状态枚举)

wxpay_v3.properties(其中,apiclient_key.pem,apiclient_cert.pem,apiclient_cert.p12是通过接入前准备,在微信支付商户平台配置后获取,platformCert.pem的获取参考https://blog.csdn.net/aiguo94/article/details/124037688)

v3.appId=wx10xxxxxxxxxxxx
v3.mchId=16xxxxxxxxx
v3.mchSerialNo=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
v3.apiKey3=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
v3.keyPath=/cert/apiclient_key.pem
v3.certPath=/cert/apiclient_cert.pem
v3.certP12Path=/cert/apiclient_cert.p12
v3.platformCertPath=/cert/platformCert.pem
v3.notifyUrl=https:/xxxxxxxxxxxxxxxxx/app/pay/payNotify
import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** 配置对象* @Author smilehan*/
@Component
@ConfigurationProperties(prefix = "v3")
@Data
@ToString
public class WxPayV3Bean {private String appId;private String mchId;private String mchSerialNo;private String apiKey3;private String keyPath;private String certPath;private String certP12Path;private String platformCertPath;private String notifyUrl;
}
import lombok.Data;
import lombok.experimental.Accessors;/*** 支付下单* @Author smilehan*/
@Data
@Accessors(chain = true)
public class PayOrderDTO {private Long userId;private Integer totalPrice;private String goodsName;private String openId;private String orderSn;
}
import lombok.Data;
import lombok.experimental.Accessors;import java.io.Serializable;/*** 微信下单返回* @Author smilehan*/
@Data
@Accessors(chain = true)
public class WxPayVO implements Serializable {private static final long serialVersionUID = 1L;/*** 预支付交易会话标识小程序下单接口返回的prepay_id参数值*/private String prepayId;/*** 随机字符串*/private String nonceStr;/*** 时间戳*/private String timeStamp;/*** 签名*/private String paySign;
}
import lombok.Data;
import lombok.experimental.Accessors;import java.io.Serializable;/*** 微信订单查询* @Author smilehan*/
@Data
@Accessors(chain = true)
public class WxQueryVO implements Serializable {private static final long serialVersionUID = 1L;/*** 订单号*/private String outTradeNo;/*** 交易状态(0:支付成功 1:转入退款 2:未支付 3:已关闭 4:已撤销(付款码支付)" +*             " 5:用户支付中(付款码支付) 6:支付失败(其他原因,如银行返回失败) 7:已接收,等待扣款 8: 订单不存在)*/private Integer tradeState;/*** 交易状态描述*/private String tradeStateDesc;/*** 支付单号*/private String transactionId;
}
import lombok.AllArgsConstructor;
import lombok.Getter;/*** 微信支付状态值* @Author smilehan*/
@Getter
@AllArgsConstructor
public enum  WxPayStateEnum {SUCCESS(0, "SUCCESS", "支付成功"),REFUND(1, "REFUND", "转入退款"),NOTPAY(2, "NOTPAY", "未支付"),CLOSED(3, "CLOSED", "已关闭"),REVOKED(4, "REVOKED", "已撤销(付款码支付)"),USERPAYING(5, "USERPAYING", "用户支付中(付款码支付)"),PAYERROR(6, "PAYERROR", "支付失败(其他原因,如银行返回失败)"),ACCEPT(7, "ACCEPT", "已接收,等待扣款"),ABSENCE(8, "ABSENCE", "订单不存在"),OK(9, "OK", "OK"),PROCESS(10, "PROCESSING", "PROCESSING");private Integer code;private String name;private String description;public static WxPayStateEnum getByName(String name) {for (WxPayStateEnum wxPayStateEnum : WxPayStateEnum.values()) {if (wxPayStateEnum.getName().equals(name)) {return wxPayStateEnum;}}return null;}}

工具类

WxPayUtil(支付util,初始化httpClient,生成签名,支付时间转换)

import cn.hutool.core.date.DateTime;
import cn.hutool.core.io.FileUtil;
import com.ijpay.core.kit.PayKit;
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.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.entity.pay.WxPayV3Bean;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;/*** 支付相关* @Author smilehan*/
@Component
@Slf4j
@Data
public class WxPayUtil {@Resourceprivate WxPayV3Bean wxPayV3Bean;private CloseableHttpClient httpClient;private Verifier verifier;@PostConstructpublic void initHttpClient(){log.info("微信支付httpClient初始化");PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(FileUtil.getInputStream(wxPayV3Bean.getKeyPath()));X509Certificate wechatPayCertificate = PemUtil.loadCertificate(FileUtil.getInputStream(wxPayV3Bean.getPlatformCertPath()));ArrayList<X509Certificate> listCertificates = new ArrayList<>();listCertificates.add(wechatPayCertificate);httpClient = WechatPayHttpClientBuilder.create().withMerchant(wxPayV3Bean.getMchId(), wxPayV3Bean.getMchSerialNo(), merchantPrivateKey).withWechatPay(listCertificates).build();}@PostConstructpublic void initVerifier() throws Exception{log.info("微信支付Verifier初始化");PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(FileUtil.getInputStream(wxPayV3Bean.getKeyPath()));// 获取证书管理器实例CertificatesManager certificatesManager = CertificatesManager.getInstance();// 向证书管理器增加需要自动更新平台证书的商户信息certificatesManager.putMerchant(wxPayV3Bean.getMchId(), new WechatPay2Credentials(wxPayV3Bean.getMchId(),new PrivateKeySigner(wxPayV3Bean.getMchSerialNo(), merchantPrivateKey)), wxPayV3Bean.getApiKey3().getBytes(StandardCharsets.UTF_8));// 从证书管理器中获取verifierverifier = certificatesManager.getVerifier(wxPayV3Bean.getMchId());}/*** 生成签名* @param appId* @param timestamp* @param nonceStr* @param prepayId* @return* @throws Exception*/public String getSign(String appId, String timestamp, String nonceStr, String prepayId) throws Exception{String message=appId + "\n"+ timestamp + "\n"+ nonceStr + "\n"+ prepayId + "\n";String sign = PayKit.createSign(message, wxPayV3Bean.getKeyPath());return sign;}/*** 回调的支付时间转成date* @param dateTimeString* @return*/public Date dateTimeToDate(String dateTimeString){DateTime dateTime = new DateTime(dateTimeString);long timeInMillis = dateTime.toCalendar(Locale.getDefault()).getTimeInMillis();return new Date(timeInMillis);}}

service

WxPayService (生成本系统自有订单后调用,微信下单,生成预支付交易会话等信息WxPayVO返回给小程序)

import com.web.controller.dto.pay.PayOrderDTO;
import com.web.controller.vo.pay.WxPayVO;
import com.web.controller.vo.pay.WxQueryVO;public interface WxPayService {/*** 微信下单* @param dto* @return*/WxPayVO createOrder(PayOrderDTO dto) throws Exception;/*** 查询订单。queryType。1,根据支付订单查询。2,根据系统自有订单号查询* @return*/WxQueryVO queryOrder(String payNumber,Integer queryType);
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.ijpay.core.kit.WxPayKit;
import com.base.execption.RRException;
import com.common.enums.pay.WxPayStateEnum;
import com.common.utils.WxPayUtil;
import com.entity.pay.WxPayV3Bean;
import com.service.pay.WxPayService;
import com.web.controller.dto.pay.PayOrderDTO;
import com.web.controller.vo.pay.WxPayVO;
import com.web.controller.vo.pay.WxQueryVO;
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.stereotype.Service;
import org.springframework.util.StringUtils;import java.io.ByteArrayOutputStream;
import java.io.IOException;import static org.apache.http.HttpHeaders.ACCEPT;
import static org.apache.http.HttpHeaders.CONTENT_TYPE;
import static org.apache.http.entity.ContentType.APPLICATION_JSON;/*** 微信下单/查单* @Author smilehan*/
@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {@Autowiredprivate WxPayV3Bean wxPayV3Bean;@Autowiredprivate WxPayUtil wxPayUtil;@Overridepublic WxPayVO createOrder(PayOrderDTO orderDetailEntity) throws Exception {HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");httpPost.addHeader(ACCEPT, APPLICATION_JSON.toString());httpPost.addHeader(CONTENT_TYPE, APPLICATION_JSON.toString());ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectMapper objectMapper = new ObjectMapper();ObjectNode rootNode = objectMapper.createObjectNode();rootNode.put("mchid", wxPayV3Bean.getMchId()).put("appid", wxPayV3Bean.getAppId()).put("description", orderDetailEntity.getGoodsName()).put("notify_url", wxPayV3Bean.getNotifyUrl()).put("out_trade_no", orderDetailEntity.getOrderSn()).put("attach", orderDetailEntity.getUserId().toString());rootNode.putObject("amount").put("total", orderDetailEntity.getTotalPrice());rootNode.putObject("payer").put("openid", orderDetailEntity.getOpenId());objectMapper.writeValue(bos, rootNode);httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));CloseableHttpClient httpClient = wxPayUtil.getHttpClient();CloseableHttpResponse response = httpClient.execute(httpPost);WxPayVO wxPayVO = new WxPayVO();try {int statusCode = response.getStatusLine().getStatusCode();if (statusCode == 200) {wxPayVO.setNonceStr(WxPayKit.generateStr());wxPayVO.setTimeStamp(System.currentTimeMillis() / 1000 + "");JSONObject jsonObject = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));String prepay_id = jsonObject.getString("prepay_id");wxPayVO.setPrepayId("prepay_id=" + prepay_id);wxPayVO.setPaySign(wxPayUtil.getSign(wxPayV3Bean.getAppId(), wxPayVO.getTimeStamp(), wxPayVO.getNonceStr(), wxPayVO.getPrepayId()));log.info("200success,return body:{} ", EntityUtils.toString(response.getEntity()));} else if (statusCode == 204) {log.info("204success");} else {log.info("failed,resp code:{} ,return body:{} ", statusCode, EntityUtils.toString(response.getEntity()));throw new IOException("request failed");}} catch (Exception e) {e.printStackTrace();throw new Exception("系统错误");}return wxPayVO;}/*** 订单查询** @return*/@Overridepublic WxQueryVO queryOrder(String payNumber, Integer queryType) {WxQueryVO vo = new WxQueryVO();try {String url = "";if (queryType.equals(1)) {//根据支付订单查询url = "https://api.mch.weixin.qq.com/v3/pay/transactions/id/" + payNumber;} else {//根据系统自有订单号查询url = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + payNumber;}URIBuilder uriBuilder = new URIBuilder(url);uriBuilder.setParameter("mchid", wxPayV3Bean.getMchId());HttpGet httpGet = new HttpGet(uriBuilder.build());httpGet.addHeader(ACCEPT, APPLICATION_JSON.toString());CloseableHttpClient httpClient = wxPayUtil.getHttpClient();CloseableHttpResponse response = httpClient.execute(httpGet);String bodyAsString = EntityUtils.toString(response.getEntity());JSONObject data = JSON.parseObject(bodyAsString);log.info("微信订单查询结果:{}", data);if (StringUtils.hasText(data.getString("out_trade_no"))&& StringUtils.hasText(data.getString("trade_state"))) {vo.setOutTradeNo(data.getString("out_trade_no"));vo.setTradeState(WxPayStateEnum.getByName(data.getString("trade_state")).getCode());vo.setTradeStateDesc(data.getString("trade_state_desc"));vo.setTransactionId(data.getString("transaction_id"));} else {vo.setTradeState(WxPayStateEnum.ABSENCE.getCode());vo.setTradeStateDesc(data.getString("message"));}} catch (Exception e) {e.printStackTrace();}return vo;}
}

controller

WxPayV3Controller (用于支付成功后的回调处理)

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
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 com.common.enums.pay.WxPayStateEnum;
import com.common.utils.WxPayUtil;
import com.entity.pay.WxPayV3Bean;
import com.web.controller.dto.pay.PayNotifyDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.wildfly.common.Assert;import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;import static com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders.*;
import static org.apache.http.HttpHeaders.CONTENT_TYPE;
import static org.apache.http.entity.ContentType.APPLICATION_JSON;/*** 微信支付回调* @Author smilehan*/
@RestController
@RequestMapping("/app/pay")
@Slf4j
public class WxPayV3Controller {@Autowiredprivate WxPayV3Bean wxPayV3Bean;@Autowiredprivate WxPayUtil wxPayUtil;/*** 微信支付回调通知*/@PostMapping(value = "/payNotify")public void payNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {log.info("微信回调开始");//读取请求体的信息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 serialNo = request.getHeader(WECHAT_PAY_SERIAL);String signature = request.getHeader(WECHAT_PAY_SIGNATURE);// 构建request,传入必要参数NotificationRequest notificationRequest = new NotificationRequest.Builder().withSerialNumber(serialNo).withNonce(nonce).withTimestamp(timestamp).withSignature(signature).withBody(s1).build();NotificationHandler handler = new NotificationHandler(wxPayUtil.getVerifier(), wxPayV3Bean.getApiKey3().getBytes(StandardCharsets.UTF_8));// 验签和解析请求体Notification notification = handler.parse(notificationRequest);Assert.assertNotNull(notification);log.info("回调结果:{}",notification);JSONObject jsonObject = JSONObject.parseObject(notification.getDecryptData());String tradeState = jsonObject.getString("trade_state");String paySn = jsonObject.getString("transaction_id");String successTime = jsonObject.getString("success_time");String attach = jsonObject.getString("attach");JSONObject amount = JSONObject.parseObject(jsonObject.getString("amount"));String payerTotal = amount.getString("payer_total");String orderSn = jsonObject.getString("out_trade_no");try {PayNotifyDTO payNotifyDTO = new PayNotifyDTO().setPaySn(paySn).setPayPrice(new BigDecimal(payerTotal).divide(new BigDecimal("100"))).setPayTime(wxPayUtil.dateTimeToDate(successTime)).setAttach(attach).setOrderSn(orderSn);if (StringUtils.hasText(tradeState) && WxPayStateEnum.SUCCESS.getName().equals(tradeState)) {//用payNotifyDTO处理相关逻辑(比如:更改订单状态为已支付,将微信支付单号-支付金额-支付时间存到订单表等等)}response.setStatus(200);}catch (Exception e){Map<String, String> map = new HashMap<>(12);response.setStatus(500);map.put("code", "FAIL");map.put("message", "失败");response.addHeader(CONTENT_TYPE, APPLICATION_JSON.toString());response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));}finally {response.flushBuffer();}}
}

小程序,确定订单信息后——>确认支付——>调用后端的生成订单接口——>后端生成系统自有订单——>后端通过自有订单号、金额、openid等去请求微信下单接口,微信返回预支付交易会话标识prepay_id——>后端给appid、timestamp、nonceStr、prepayId签名,并将签名、timestamp、nonceStr、prepay_id返回给小程序——>小程序调用wx.requestPayment拉起微信支付——>用户付完钱后,微信根据下单时候填的回调地址,请求自有系统的回调接口,自有系统处理相应的逻辑

Java--微信支付--小程序支付--v3版--完整的代码例子相关推荐

  1. jsapi支付签名_微信支付小程序支付全流程

    点击蓝色字关注我们! 一个努力中的公众号 长的好看的人都关注了 本文给大家讲解微信小程序支付全流程,以及相关功能源代码,项目不开放,带来不便尽请谅解.小程序支付主要包含如下几步骤,1.预下单-调用微信 ...

  2. 微信支付-小程序支付全流程

    点击蓝色字关注我们! 一个努力中的公众号 长的好看的人都关注了 本文给大家讲解微信小程序支付全流程,以及相关功能源代码,项目不开放,带来不便尽请谅解.小程序支付主要包含如下几步骤,1.预下单-调用微信 ...

  3. 微信支付:小程序支付/扫码支付

    0.yml文件配置 1.微信支付controller import io.swagger.annotations.Api; import io.swagger.annotations.ApiOpera ...

  4. java对接支付宝小程序支付

    今天晚上12点部署生产项目,又是个不眠夜. 之前整的好多东西都忘光了,还是记录下来吧. 跟对接支付宝支付差不多,地址:小程序支付能力介绍 | 小程序 开通流程: 1.先要去支付宝开放平台,创建小程序. ...

  5. 微信支付小程序支付和APP支付

    这里介绍的是微信小程序支付和APP支付 引入的依赖是微信支付第三方jar weixin-java-pay github:WxJava <dependency><groupId> ...

  6. 微信服务商-小程序支付-商户传入的appid参数不正确,请联系商户处理

    报错:商户传入的appid参数不正确,请联系商户处理. 处理方式: 1. 2.需要在商户号,配置小程序的APPID https://pay.weixin.qq.com/static/pay_setti ...

  7. Java微信授权小程序获取用户手机号信息

    注意:目前该接口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体).需谨慎使用,若用户举报较多或被发现在不必要场景下使用,微信有权永久回收该小程序的该接口权限. 官网地址如下: https: ...

  8. 微信退款小程序支付/退款

    最近在写微信退款的时候发现了很多的Demo,但是方法都不同,而且很难确定Demo是不是适用自己的项目. 在发起退款的时候第一步自然还是先去下载证书,这个没话说,下载完成后在退款Controller可以 ...

  9. 微信支付,JSAPI支付,APP支付,H5支付,Native支付,小程序支付功能详情以及回调处理

    一.支付相关文档地址 支付wiki:https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml 支付api: https://pay.weixin.qq. ...

最新文章

  1. 剑指offer_第17题_树的子结构_Python
  2. 洛谷 P1583 魔法照片
  3. 课后作业-阅读任务-阅读笔记
  4. LwIP 之六 详解动态内存管理 内存池(memp.c/h)
  5. ssm项目之maven添加pom jar包配置
  6. RabbitMQ管理(2)——用户管理
  7. how I can force redetermination everytime
  8. webUI自动化二-获取元素信息相关方法
  9. Jenkins关联GitHub进行构建
  10. php 实现两变量值对换,PHP互换两个变量值的方法(不用第三变量)
  11. CIO思考:混合云为行业注入了哪些活力?
  12. mysql order 中文版,MySQL Order By排序结果
  13. Win装linux双系统教程
  14. ucinet计算聚类系数大于1怎么办_UCINET 6
  15. 速锐得整车CAN网络控制策略数据解析方案
  16. 项目管理高手常用的10张图表推荐!(小白也能懂的项目管理)
  17. Jackson修改字段名和自定义命名策略
  18. 机器学习——支持向量机support vector machine
  19. vue table表格中身份证隐藏中间几位
  20. 搜狗大数据总监、Polarr 联合创始人关于深度学习的分享交流 | 架构师小组交流会...

热门文章

  1. ios图像和图形最佳实践(三)
  2. 又是传销的 喜欢看故事的也可以看看 非常恐怖 都看看吧 加强自我保护意识(转自糗百)
  3. 论文阅读——MISF:Multi-level Interactive Siamese Filtering for High-Fidelity Image Inpainting
  4. Amazon AWS S3 for PHP 的API使用测试
  5. 联想台式机linux系统安装教程,商用台式一键恢复软件各版本使用介绍(适用于现有上市机型)...
  6. 深入分析Win32k系统调用过滤机制
  7. tensorflow微调vgg16 程序代码汇总
  8. 003 免格式化U盘部署PE(UEFI)
  9. EXCEL中如何根据标点符号进行表格分列
  10. Stm32端口复用与重映射