欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 国际 > Java实现微信小程序商家转账到零钱功能V3

Java实现微信小程序商家转账到零钱功能V3

2024/10/23 15:28:31 来源:https://blog.csdn.net/weixin_45444807/article/details/142860074  浏览:    关键词:Java实现微信小程序商家转账到零钱功能V3

Java实现微信小程序商家转账到零钱功能V3版本

工具类

该工具类主要用于发送请求签名等

@Slf4j
public class WechatPayV3Util {/*** @param method       请求方法 post* @param canonicalUrl 请求地址* @param body         请求参数* @param merchantId   商户号* @param certSerialNo 商户证书序列号* @param keyPath      私钥商户证书地址* @return* @throws Exception*/public static String getToken(String method,String canonicalUrl,String body,String merchantId,String certSerialNo,String keyPath) throws Exception {String signStr = "";//获取32位随机字符串String nonceStr = getRandomString(32);//当前系统运行时间long timestamp = System.currentTimeMillis() / 1000;if (StringUtils.isEmpty(body)) {body = "";}String message = buildMessage(method, canonicalUrl, timestamp, nonceStr, body);//签名操作//签名操作String signature = sign(message.getBytes(StandardCharsets.UTF_8), keyPath);//组装参数signStr = "mchid=\"" + merchantId + "\",timestamp=\"" +  timestamp+ "\",nonce_str=\"" + nonceStr+ "\",serial_no=\"" + certSerialNo + "\",signature=\"" + signature + "\"";return signStr;}public static String buildMessage(String method, String canonicalUrl, long timestamp, String nonceStr, String body) {return method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";}public static String sign(byte[] message, String keyPath) throws Exception {Signature sign = Signature.getInstance("SHA256withRSA");sign.initSign(getPrivateKey(keyPath));sign.update(message);return Base64.encodeBase64String(sign.sign());}/*** @param filename 私钥文件路径  (required)* @return 私钥对象*/public static PrivateKey getPrivateKey(String filename) throws IOException {//todo 我放在项目里的  也可以放在服务器上 都可以 看自己需求了String content = new String(Files.readAllBytes(Paths.get("src/main/resources" + filename)), StandardCharsets.UTF_8);try {String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");KeyFactory kf = KeyFactory.getInstance("RSA");return kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey)));} catch (NoSuchAlgorithmException e) {throw new RuntimeException("不支持RSA", e);} catch (InvalidKeySpecException e) {throw new RuntimeException("无效的密钥格式");}}/*** 获取随机位数的字符串* @param length  随机数长度* @return*/public static String getRandomString(int length) {String base = "abcdefghijklmnopqrstuvwxyz0123456789";Random random = new Random();StringBuffer sb = new StringBuffer();for (int i = 0; i < length; i++) {int number = random.nextInt(base.length());sb.append(base.charAt(number));}return sb.toString();}/*** 微信敏感数据加密-公钥* @return*/public static X509Certificate getSaveCertificates(String platformCertPath) throws IOException {InputStream inputStream = Files.newInputStream(new File(platformCertPath).toPath());BufferedInputStream bis = new BufferedInputStream(inputStream);return PemUtil.loadCertificate(bis);}
}

请求地址信息

public class WxApiUrl {/*** 商家转账到零钱*/public static String WECHAT_TRANSFERS_URL = "https://api.mch.weixin.qq.com/v3/transfer/batches";/*** 商户批次号查询*/public static String SELECT_ORDER_URL = "https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no";
}

配置文件中值填充到属性中

@Configuration
@ConfigurationProperties(prefix = "wxpay") //读取wxpay节点
@Data //使用set方法将wxpay节点中的值填充到当前类的属性中
@Slf4j
public class WxPayConfig {// 商户号private String mchId;// 商户API证书序列号private String mchSerialNo;// 商户私钥文件private String privateKeyName;// APIv3密钥private String apiV3Key;// APPIDprivate String appid;// 微信服务器地址private String domain;// 接收结果通知地址private String notifyDomain;
}

配置文件

# 微信支付相关参数
wxpay:# 商户号mch-id: xxxxxxx# 商户API证书序列号mch-serial-no: xxxxxxxxxxxxxxxxxxxxxxxxxxx# 商户私钥文件# 注意:该文件放在resource/fileprivate-key-name: file/apiclient_key.pem# APIv3密钥api-v3-key: xxxxxxxxxxxxxxxxxxxxx# APPIDappid: xxxxxxxxxxxxxxx# 微信服务器地址domain: https://api.mch.weixin.qq.com# 接收结果通知地址# 注意:每次重新启动ngrok,都需要根据实际情况修改这个配置notify-domain: http://tozzn.e3.luyouxia.net:10062

提现与账单查询

public interface WeChatApiDao {/*** 提現* @return*/boolean transfers(String realName,String openId ,String outTradeNo, BigDecimal amount);/*** 状态 0待确认 1已受理 2转账中 3已完成 4已关闭* @param outTradeNo* @return*/Integer queryTransfersStatus(String outTradeNo);
}
@Slf4j
@Component
public class WeChatApiDaoImpl implements WeChatApiDao {@Resourceprivate WxPayConfig wxPayConfig;@Override@SneakyThrowspublic boolean transfers(String realName,String openId ,String outTradeNo, BigDecimal amount) {//        if (StringUtils.isBlank(realName)) {
//            throw new NingException(500, "请确认是否设置真实姓名");
//        }int value = amount.multiply(new BigDecimal(100)).intValue();Map<String, Object> postMap = new HashMap<String, Object>();//小程序 idpostMap.put("appid", wxPayConfig.getAppid()); // 需要跟商户ID 绑定的奥postMap.put("out_batch_no", outTradeNo);//该笔批量转账的名称postMap.put("batch_name", "提现");//转账说明postMap.put("batch_remark", "提现");//转账金额单位为“分”。 总金额postMap.put("total_amount", value);//转账总笔数postMap.put("total_num", 1);// 转账批次集合List<Map<String, Object>> list = new ArrayList<>();Map<String, Object> subMap = new HashMap<>(4);//商家明细单号 (系统内唯一)subMap.put("out_detail_no", CommUtils.getUUID());//转账金额subMap.put("transfer_amount", value);//转账备注subMap.put("transfer_remark", "提现到账");//用户使用小程序时 记录了用户的微信opneId  必须是在Appid 下的openId  不然不会成功的奥subMap.put("openid", openId);//大金额需要传入真实姓名 根据自己需求设置
//        subMap.put("user_name", RsaCryptoUtil.encryptOAEP(realName, WechatPayV3Util.getSaveCertificates(wxPayConfig.getPrivateKeyName())));list.add(subMap);postMap.put("transfer_detail_list", list);log.info("请求参数:{}",JSONObject.toJSONString(postMap));String result = HttpUtil.postTransBatRequest(WxApiUrl.WECHAT_TRANSFERS_URL,// 请求地址JSONObject.toJSONString(postMap),// 请求参数wxPayConfig.getMchSerialNo(),// 支付证书序列号wxPayConfig.getMchId(),// 商户号wxPayConfig.getPrivateKeyName()); //证书私钥地址JSONObject jsonObject = JSONObject.parseObject(result);log.info("返回结果:{}",jsonObject);/*正常返回*{"out_batch_no" : "plfk2020042013","batch_id" : "1030000071100999991182020050700019480001","create_time" : "2015-05-20T13:29:35.120+08:00","batch_status" : "ACCEPTED"}*/return "ACCEPTED".equals(jsonObject.getString("batch_status"));}@Overridepublic Integer queryTransfersStatus(String outTradeNo) {String result = HttpUtil.getTransBatRequest(WxApiUrl.SELECT_ORDER_URL + "/" + outTradeNo + "?need_query_detail=true&detail_status=ALL",// 请求地址wxPayConfig.getMchSerialNo(),// 支付证书序列号wxPayConfig.getMchId(),// 商户号wxPayConfig.getPrivateKeyName(),"/v3/transfer/batches/out-batch-no/" + outTradeNo + "?need_query_detail=true&detail_status=ALL"); //证书私钥地址JSONObject jsonObject = JSONObject.parseObject(result);JSONArray orderArr = jsonObject.getJSONArray("transfer_detail_list");if(orderArr == null){return 5;}JSONObject transferBatch = (JSONObject) orderArr.get(0);String status = transferBatch.getString("detail_status");if ("WAIT_PAY".equals(status)) {return 1;}else if ("PROCESSING".equals(status)) {return 2;}else if ("SUCCESS".equals(status)) {return 3;}else if ("FAIL".equals(status)) {return 4;}else if ("INIT".equals(status)) {return 0;}return 5;}

ok,大功告成,亲测可用~

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com