Browse Source

微信支付提交

master
Aug 1 day ago
parent
commit
1a52df26ee
14 changed files with 861 additions and 301 deletions
  1. +5
    -6
      .idea/compiler.xml
  2. +0
    -3
      .idea/encodings.xml
  3. +0
    -207
      jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/pay/WeChatPayConfig2.java
  4. +1
    -0
      jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
  5. +82
    -85
      jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/cityMoneyLog/controller/CityMoneyLogController.java
  6. +1
    -0
      jeecg-boot-module-system/pom.xml
  7. +20
    -0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/CashoutService.java
  8. +29
    -0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/CashoutServiceImpl.java
  9. +35
    -0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/CashoutController.java
  10. +257
    -0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/transferTest/TransferToUser.java
  11. +381
    -0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/transferTest/WXPayUtility.java
  12. +13
    -0
      jeecg-boot-module-system/src/main/java/org/jeecg/modules/transferTest/test.java
  13. +28
    -0
      jeecg-boot-module-system/src/main/resources/apiclient_key_yaodu.pem
  14. +9
    -0
      jeecg-boot-module-system/src/main/resources/pub_key_yaodu.pem

+ 5
- 6
.idea/compiler.xml View File

@ -7,25 +7,24 @@
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="jeecg-boot-base-core" />
<module name="jeecg-system-local-api" />
<module name="jeecg-boot-module-system" />
<module name="jeecg-boot-base-tools" />
<module name="jeecg-boot-base-core" />
<module name="han-hai-module-pay" />
<module name="jeecg-boot-module-system" />
<module name="jeecg-system-cloud-api" />
<module name="jeecg-system-local-api" />
</profile>
</annotationProcessing>
<bytecodeTargetLevel>
<module name="module-pay" target="1.8" />
<module name="yaodu-api" target="1.8" />
</bytecodeTargetLevel>
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="han-hai-module-pay" options="-parameters" />
<module name="han-hai-parent" options="-parameters" />
<module name="jeecg-boot-base" options="-parameters" />
<module name="jeecg-boot-base-api" options="-parameters" />
<module name="jeecg-boot-base" options="" />
<module name="jeecg-boot-base-api" options="" />
<module name="jeecg-boot-base-core" options="-parameters" />
<module name="jeecg-boot-base-tools" options="-parameters" />
<module name="jeecg-boot-module-system" options="-parameters" />


+ 0
- 3
.idea/encodings.xml View File

@ -4,11 +4,8 @@
<file url="file://$PROJECT_DIR$/han-hai-module-pay/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/jeecg-boot-base/jeecg-boot-base-api/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/jeecg-boot-base/jeecg-boot-base-core/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/jeecg-boot-base/jeecg-boot-base-tools/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/jeecg-boot-base/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/jeecg-boot-module-system/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
</component>
</project>

+ 0
- 207
jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/pay/WeChatPayConfig2.java View File

@ -1,207 +0,0 @@
package org.jeecg.config.pay;
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 com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
/**
* @author java996.icu
* @title: WeChatPayConfig2
* @projectName chemu
* @description: TODO
* @date 2022/12/7 16:36
* @Version V1.0
*/
@Component
@Data
@Slf4j
@ConfigurationProperties(prefix = "wxpay")
public class WeChatPayConfig2 {
/**
* 应用编号
*/
private String appId;
/**
* 商户号
*/
private String mchId;
/**
* 服务商商户号
*/
private String slMchId;
/**
* APIv2密钥
*/
private String apiKey;
/**
* APIv3密钥
*/
private String apiV3Key;
/**
* 支付通知回调地址
*/
private String notifyUrl;
/**
* 退款回调地址
*/
private String refundNotifyUrl;
/**
* API 证书中的 key.pem
*/
private String keyPemPath;
/**
* 商户序列号
*/
private String serialNo;
/**
* 微信支付V3-url前缀
*/
private String baseUrl;
/**
* 获取商户的私钥文件
* @param keyPemPath
* @return
*/
public PrivateKey getPrivateKey(String keyPemPath){
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(keyPemPath);
if(inputStream==null){
throw new RuntimeException("私钥文件不存在");
}
return PemUtil.loadPrivateKey(inputStream);
}
//
// /**
// * 获取证书管理器实例
// * @return
// */
// @Bean
// public Verifier getVerifier() throws GeneralSecurityException, IOException, HttpCodeException, NotFoundException {
//
// log.info("获取证书管理器实例");
//
// //获取商户私钥
// PrivateKey privateKey = getPrivateKey(keyPemPath);
//
// //私钥签名对象
// PrivateKeySigner privateKeySigner = new PrivateKeySigner(serialNo, privateKey);
//
// //身份认证对象
// WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);
//
// // 使用定时更新的签名验证器不需要传入证书
// CertificatesManager certificatesManager = CertificatesManager.getInstance();
// certificatesManager.putMerchant(mchId,wechatPay2Credentials,apiV3Key.getBytes(StandardCharsets.UTF_8));
//
// return certificatesManager.getVerifier(mchId);
// }
@Bean
public Verifier getVerifier() throws GeneralSecurityException, IOException, HttpCodeException, NotFoundException {
log.info("开始获取微信支付证书管理器实例");
// 验证关键参数
log.debug("商户号: {}", mchId);
log.debug("证书序列号: {}", serialNo);
log.debug("APIv3密钥长度: {}", apiV3Key.length()); // 不记录具体密钥内容
// 获取商户私钥
PrivateKey privateKey = getPrivateKey(keyPemPath);
if (privateKey == null) {
throw new IllegalArgumentException("无法从路径加载私钥: " + keyPemPath);
}
// 创建签名器
PrivateKeySigner privateKeySigner = new PrivateKeySigner(serialNo, privateKey);
WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner);
try {
CertificatesManager certificatesManager = CertificatesManager.getInstance();
// 显式设置域名如果库需要
// certificatesManager.setDomain("api.mch.weixin.qq.com");
// 添加商户信息
certificatesManager.putMerchant(mchId, wechatPay2Credentials, apiV3Key.getBytes(StandardCharsets.UTF_8));
// 获取验证器
Verifier verifier = certificatesManager.getVerifier(mchId);
log.info("成功获取证书管理器实例");
return verifier;
} catch (HttpCodeException e) {
log.error("微信支付API返回错误: "+ e);
throw e;
} catch (Exception e) {
log.error("获取证书管理器实例时发生错误", e);
throw e;
}
}
/**
* 获取支付http请求对象
* @param verifier
* @return
*/
@Bean(name = "wxPayClient")
public CloseableHttpClient getWxPayClient(Verifier verifier) {
//获取商户私钥
PrivateKey privateKey = getPrivateKey(keyPemPath);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, serialNo, privateKey)
.withValidator(new WechatPay2Validator(verifier));
// 通过WechatPayHttpClientBuilder构造的HttpClient会自动的处理签名和验签并进行证书自动更新
return builder.build();
}
/**
* 获取HttpClient无需进行应答签名验证跳过验签的流程
*/
@Bean(name = "wxPayNoSignClient")
public CloseableHttpClient getWxPayNoSignClient(){
//获取商户私钥
PrivateKey privateKey = getPrivateKey(keyPemPath);
//用于构造HttpClient
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
//设置商户信息
.withMerchant(mchId, serialNo, privateKey)
//无需进行签名验证通过withValidator((response) -> true)实现
.withValidator((response) -> true);
// 通过WechatPayHttpClientBuilder构造的HttpClient会自动的处理签名和验签并进行证书自动更新
return builder.build();
}
}

+ 1
- 0
jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java View File

@ -76,6 +76,7 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/login/**", "anon");
filterChainDefinitionMap.put("/token/**", "anon");
filterChainDefinitionMap.put("/city/**", "anon");
filterChainDefinitionMap.put("/cashout/**", "anon");


+ 82
- 85
jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/cityMoneyLog/controller/CityMoneyLogController.java View File

@ -20,7 +20,6 @@ import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.pay.WeChatPayConfig2;
import org.jeecg.modules.cityMoneyLog.entity.CityMoneyLog;
import org.jeecg.modules.cityMoneyLog.req.TransferBatchesDetailsRequest;
import org.jeecg.modules.cityMoneyLog.req.TransferBatchesRequest;
@ -68,8 +67,6 @@ public class CityMoneyLogController extends JeecgController<CityMoneyLog, ICityM
private IHanHaiMemberService hanHaiMemberService;
@Resource
private RedisUtil redisUtil;
@Resource
private WeChatPayConfig2 weChatPayConfig2;
@Value("${wxpay.appId}")
private String appId;
@Value("${wxpay.transferBatchUrl}")
@ -121,88 +118,88 @@ public class CityMoneyLogController extends JeecgController<CityMoneyLog, ICityM
cityMoneyLogService.save(cityMoneyLog);
return Result.OK("添加成功!");
}
/**
* 编辑
*
* @param hanHaiWater
* @return
*/
@AutoLog(value = "佣金流水-编辑")
@ApiOperation(value="佣金流水-编辑", notes="佣金流水-编辑")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody CityMoneyLog hanHaiWater) {
HanHaiMember hanHaiMember = hanHaiMemberService.getById(hanHaiWater.getUserId());
Integer n = (Integer) redisUtil.get("WITHDRAWAL:" + hanHaiWater.getId());
if (n != null) {
throw new JeecgBootException("请勿重复点击,后果自负!");
}
redisUtil.set("WITHDRAWAL:" + hanHaiWater.getId(), 1, 5);
//微信-商家转账到零钱
String idStr = "H" + IdWorker.getIdStr();
TransferBatchesRequest transferBatchesRequest = new TransferBatchesRequest();
transferBatchesRequest.setAppid(appId);
transferBatchesRequest.setOutBillNo(idStr);
transferBatchesRequest.setTransferRemark("商家提现");
transferBatchesRequest.setOpenid(hanHaiMember.getAppletOpenid());
transferBatchesRequest.setTransferSceneId("1005");
transferBatchesRequest.setNotifyUrl(withdrawalNotifyUrl);
String serialNo = null;
//加密真实姓名
try {
X509Certificate certificate = weChatPayConfig2.getVerifier().getValidCertificate();
serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
//这里放真实姓名目前你的数据库表没有这个字段
String encryptOAEP = RsaCryptoUtil.encryptOAEP(hanHaiWater.getName(), certificate);
transferBatchesRequest.setUserName(encryptOAEP);
} catch (Exception e) {
log.info("真实姓名加密失败");
e.printStackTrace();
throw new JeecgBootException("真实姓名加密失败");
}
transferBatchesRequest.setTransferAmount(MoneyUtil.Yuan2Fen(hanHaiWater.getPrice().doubleValue()));
List<TransferBatchesDetailsRequest> transferBatchesDetailsRequests = new ArrayList<>();
TransferBatchesDetailsRequest transferBatchesDetailsRequest = new TransferBatchesDetailsRequest();
transferBatchesDetailsRequest.setInfoType("岗位类型");
transferBatchesDetailsRequest.setInfoContent("销售员");
TransferBatchesDetailsRequest transferBatchesDetailsRequest2 = new TransferBatchesDetailsRequest();
transferBatchesDetailsRequest2.setInfoType("报酬说明");
transferBatchesDetailsRequest2.setInfoContent("佣金报酬");
transferBatchesDetailsRequests.add(transferBatchesDetailsRequest);
transferBatchesDetailsRequests.add(transferBatchesDetailsRequest2);
transferBatchesRequest.setTransferDetailList(transferBatchesDetailsRequests);
String jsonString = JSONObject.toJSONString(transferBatchesRequest);
log.info("请求参数:"+jsonString);
String postTransBatRequest = HttpRequestUtil.postTransBatRequest(transferBatchUrl, jsonString, serialNo, wxsSerialNo, mchId, pemPath);
log.error("返回结果1:" + postTransBatRequest);
TransferBatchesResp transferBatchesResp = JSON.parseObject(postTransBatRequest, TransferBatchesResp.class);
log.error("返回结果2:" + transferBatchesResp);
if (transferBatchesResp == null || org.apache.commons.lang3.StringUtils.isBlank(transferBatchesResp.getOutBillNo()) || transferBatchesResp.getState().equals("FAIL")) {
throw new JeecgBootException("打款失败");
}
//这里写自己的逻辑比如改变这条记录的状态变成提现成功
CityMoneyLog hanHaiWater1 = new CityMoneyLog();
hanHaiWater1.setId(hanHaiWater.getId());
hanHaiWater1.setState(1);
hanHaiWater1.setPackageInfo(transferBatchesResp.getPackageInfo());
hanHaiWater1.setOutBatchNo(transferBatchesResp.getOutBillNo());
hanHaiWater1.setBatchId(transferBatchesResp.getTransferBillNo());
cityMoneyLogService.updateById(hanHaiWater1);
return Result.OK("提现成功");
}
//
// /**
// * 编辑
// *
// * @param hanHaiWater
// * @return
// */
// @AutoLog(value = "佣金流水-编辑")
// @ApiOperation(value="佣金流水-编辑", notes="佣金流水-编辑")
// @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
// public Result<String> edit(@RequestBody CityMoneyLog hanHaiWater) {
// HanHaiMember hanHaiMember = hanHaiMemberService.getById(hanHaiWater.getUserId());
// Integer n = (Integer) redisUtil.get("WITHDRAWAL:" + hanHaiWater.getId());
// if (n != null) {
// throw new JeecgBootException("请勿重复点击,后果自负!");
// }
// redisUtil.set("WITHDRAWAL:" + hanHaiWater.getId(), 1, 5);
//
// //微信-商家转账到零钱
//
// String idStr = "H" + IdWorker.getIdStr();
// TransferBatchesRequest transferBatchesRequest = new TransferBatchesRequest();
//
// transferBatchesRequest.setAppid(appId);
// transferBatchesRequest.setOutBillNo(idStr);
// transferBatchesRequest.setTransferRemark("商家提现");
// transferBatchesRequest.setOpenid(hanHaiMember.getAppletOpenid());
// transferBatchesRequest.setTransferSceneId("1005");
// transferBatchesRequest.setNotifyUrl(withdrawalNotifyUrl);
// String serialNo = null;
// //加密真实姓名
// try {
//
// X509Certificate certificate = weChatPayConfig2.getVerifier().getValidCertificate();
// serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
// //这里放真实姓名目前你的数据库表没有这个字段
// String encryptOAEP = RsaCryptoUtil.encryptOAEP(hanHaiWater.getName(), certificate);
// transferBatchesRequest.setUserName(encryptOAEP);
// } catch (Exception e) {
// log.info("真实姓名加密失败");
// e.printStackTrace();
// throw new JeecgBootException("真实姓名加密失败");
// }
// transferBatchesRequest.setTransferAmount(MoneyUtil.Yuan2Fen(hanHaiWater.getPrice().doubleValue()));
// List<TransferBatchesDetailsRequest> transferBatchesDetailsRequests = new ArrayList<>();
// TransferBatchesDetailsRequest transferBatchesDetailsRequest = new TransferBatchesDetailsRequest();
// transferBatchesDetailsRequest.setInfoType("岗位类型");
// transferBatchesDetailsRequest.setInfoContent("销售员");
// TransferBatchesDetailsRequest transferBatchesDetailsRequest2 = new TransferBatchesDetailsRequest();
// transferBatchesDetailsRequest2.setInfoType("报酬说明");
// transferBatchesDetailsRequest2.setInfoContent("佣金报酬");
//
//
// transferBatchesDetailsRequests.add(transferBatchesDetailsRequest);
// transferBatchesDetailsRequests.add(transferBatchesDetailsRequest2);
// transferBatchesRequest.setTransferDetailList(transferBatchesDetailsRequests);
// String jsonString = JSONObject.toJSONString(transferBatchesRequest);
//
// log.info("请求参数:"+jsonString);
//
// String postTransBatRequest = HttpRequestUtil.postTransBatRequest(transferBatchUrl, jsonString, serialNo, wxsSerialNo, mchId, pemPath);
// log.error("返回结果1:" + postTransBatRequest);
// TransferBatchesResp transferBatchesResp = JSON.parseObject(postTransBatRequest, TransferBatchesResp.class);
// log.error("返回结果2:" + transferBatchesResp);
// if (transferBatchesResp == null || org.apache.commons.lang3.StringUtils.isBlank(transferBatchesResp.getOutBillNo()) || transferBatchesResp.getState().equals("FAIL")) {
// throw new JeecgBootException("打款失败");
// }
//
// //这里写自己的逻辑比如改变这条记录的状态变成提现成功
//
// CityMoneyLog hanHaiWater1 = new CityMoneyLog();
// hanHaiWater1.setId(hanHaiWater.getId());
// hanHaiWater1.setState(1);
// hanHaiWater1.setPackageInfo(transferBatchesResp.getPackageInfo());
// hanHaiWater1.setOutBatchNo(transferBatchesResp.getOutBillNo());
// hanHaiWater1.setBatchId(transferBatchesResp.getTransferBillNo());
// cityMoneyLogService.updateById(hanHaiWater1);
//
//
// return Result.OK("提现成功");
// }
//
/**
* 通过id删除
*


+ 1
- 0
jeecg-boot-module-system/pom.xml View File

@ -82,6 +82,7 @@
</dependencies>
<build>
<finalName>yaodu-api</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>


+ 20
- 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/CashoutService.java View File

@ -0,0 +1,20 @@
package org.jeecg.modules.api.service;
import io.swagger.annotations.ApiOperation;
import org.jeecg.common.api.vo.Result;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
public interface CashoutService {
//会员中心-开通会员
@ApiOperation(value="测试提现-提现", notes="测试提现-提现")
@RequestMapping(value = "/cashout", method = {RequestMethod.POST})
public Result<?> cashout();
//开通会员支付回调
//支付回调
@PostMapping("/cashoutNotify")
public Object cashoutNotify(@RequestBody String requestBody);
}

+ 29
- 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/service/impl/CashoutServiceImpl.java View File

@ -0,0 +1,29 @@
package org.jeecg.modules.api.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.api.service.CashoutService;
import org.jeecg.modules.transferTest.TransferToUser;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class CashoutServiceImpl implements CashoutService {
@Override
public Result<?> cashout() {
String mchid = "1673516176";
String certiticateSerialNo ="525CDBD76E640EFB008288572C97D2715F3F18B2";
String privateKeyFilePath = "jeecg-boot-module-system/src/main/resources/apiclient_key_yaodu.pem";
String wechatPayPublicKeyId = "PUB_KEY_ID_0116735161762025040100448900000949";
String wechatPayPublicKeyFilePaht = "jeecg-boot-module-system/src/main/resources/pub_key_yaodu.pem";
TransferToUser transferToUser = new TransferToUser(mchid, certiticateSerialNo, privateKeyFilePath, wechatPayPublicKeyId, wechatPayPublicKeyFilePaht );
transferToUser.run();
return Result.OK("测试提现结束");
}
@Override
public Object cashoutNotify(String requestBody) {
System.out.println("测试提现回调");
return Result.OK("测试回调");
}
}

+ 35
- 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/api/yaoduapi/CashoutController.java View File

@ -0,0 +1,35 @@
package org.jeecg.modules.api.yaoduapi;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.api.service.CashoutService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@Api(tags="测试提现接口-提现")
@RestController
@RequestMapping("/cashout")
@Slf4j
public class CashoutController {
/******************************************************************************************************************/
//会员信息
@Resource
private CashoutService cashoutService;
/******************************************************************************************************************/
//会员中心-开通会员
@ApiOperation(value="测试提现-提现", notes="测试提现-提现")
@RequestMapping(value = "/cashout", method = {RequestMethod.POST})
public Result<?> cashout(){
return cashoutService.cashout();
}
//提现回调
@PostMapping("/cashoutNotify")
public Object cashoutNotify(@RequestBody String requestBody){
return cashoutService.cashoutNotify(requestBody);
}
}

+ 257
- 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/transferTest/TransferToUser.java View File

@ -0,0 +1,257 @@
package org.jeecg.modules.transferTest;
import com.google.gson.annotations.SerializedName;
import okhttp3.*;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
/**
* 发起转账
*/
public class TransferToUser {
private static String HOST = "https://api.mch.weixin.qq.com";
private static String METHOD = "POST";
private static String PATH = "/v3/fund-app/mch-transfer/transfer-bills";
public static void main(String[] args) {
// TODO: 请准备商户开发必要参数参考https://pay.weixin.qq.com/doc/v3/merchant/4013070756
// String mchid = "1712378227";
// String certiticateSerialNo ="33E9FE8076531A7C7AD401DC34E053DBD7C28E22";
// String privateKeyFilePath = "jeecg-boot-module-system/src/main/resources/apiclient_key.pem";
// String wechatPayPublicKeyId = "PUB_KEY_ID_0117123782272025033100396400002931";
// String wechatPayPublicKeyFilePaht = "jeecg-boot-module-system/src/main/resources/pub_key.pem";
String mchid = "1673516176";
String certiticateSerialNo ="525CDBD76E640EFB008288572C97D2715F3F18B2";
String privateKeyFilePath = "jeecg-boot-module-system/src/main/resources/apiclient_key_yaodu.pem";
String wechatPayPublicKeyId = "PUB_KEY_ID_0116735161762025040100448900000949";
String wechatPayPublicKeyFilePaht = "jeecg-boot-module-system/src/main/resources/pub_key_yaodu.pem";
TransferToUser client = new TransferToUser(
mchid, // 商户号是由微信支付系统生成并分配给每个商户的唯一标识符商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
certiticateSerialNo, // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
privateKeyFilePath, // 商户API证书私钥文件路径本地文件路径
wechatPayPublicKeyId, // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
wechatPayPublicKeyFilePaht // 微信支付公钥文件路径本地文件路径
);
String appid = "wxa4d29e67e8a58d38";
String openid = "oFzrW4migndUepy7zYgYO2YoZ5to";
String notifyUrl = "https://admin.hhlm1688.com/api/hello/";
TransferToUserRequest request = new TransferToUserRequest();
request.appid = appid;
request.outBillNo = "plfk2020042013";
request.transferSceneId = "1000";
request.openid = openid;
request.userName = client.encrypt("唐斌");
request.transferAmount = 400L;
request.transferRemark = "新会员开通有礼";
request.notifyUrl = notifyUrl;
request.userRecvPerception = "现金奖励";
request.transferSceneReportInfos = new ArrayList<>();
{
TransferSceneReportInfo item0 = new TransferSceneReportInfo();
item0.infoType = "活动名称";
item0.infoContent = "新会员有礼";
request.transferSceneReportInfos.add(item0);
TransferSceneReportInfo item1 = new TransferSceneReportInfo();
item1.infoType = "奖励说明";
item1.infoContent = "注册会员抽奖一等奖";
request.transferSceneReportInfos.add(item1);
};
try {
TransferToUserResponse response = client.run(request);
// TODO: 请求成功继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public void run(){
String mchid = "1673516176";
String certiticateSerialNo ="525CDBD76E640EFB008288572C97D2715F3F18B2";
String privateKeyFilePath = "jeecg-boot-module-system/src/main/resources/apiclient_key_yaodu.pem";
String wechatPayPublicKeyId = "PUB_KEY_ID_0116735161762025040100448900000949";
String wechatPayPublicKeyFilePaht = "jeecg-boot-module-system/src/main/resources/pub_key_yaodu.pem";
TransferToUser client = new TransferToUser(
mchid, // 商户号是由微信支付系统生成并分配给每个商户的唯一标识符商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
certiticateSerialNo, // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
privateKeyFilePath, // 商户API证书私钥文件路径本地文件路径
wechatPayPublicKeyId, // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
wechatPayPublicKeyFilePaht // 微信支付公钥文件路径本地文件路径
);
String appid = "wxa4d29e67e8a58d38";
String openid = "oFzrW4migndUepy7zYgYO2YoZ5to";
String notifyUrl = "https://admin.hhlm1688.com/api/cashout/cashout/";
TransferToUserRequest request = new TransferToUserRequest();
request.appid = appid;
request.outBillNo = "plfk2020042013";
request.transferSceneId = "1000";
request.openid = openid;
request.userName = client.encrypt("唐斌");
request.transferAmount = 400L;
request.transferRemark = "新会员开通有礼";
request.notifyUrl = notifyUrl;
request.userRecvPerception = "现金奖励";
request.transferSceneReportInfos = new ArrayList<>();
{
TransferSceneReportInfo item0 = new TransferSceneReportInfo();
item0.infoType = "活动名称";
item0.infoContent = "新会员有礼";
request.transferSceneReportInfos.add(item0);
TransferSceneReportInfo item1 = new TransferSceneReportInfo();
item1.infoType = "奖励说明";
item1.infoContent = "注册会员抽奖一等奖";
request.transferSceneReportInfos.add(item1);
};
try {
TransferToUserResponse response = client.run(request);
// TODO: 请求成功继续业务逻辑
System.out.println(response);
} catch (WXPayUtility.ApiException e) {
// TODO: 请求失败根据状态码执行不同的逻辑
e.printStackTrace();
}
}
public TransferToUserResponse run(TransferToUserRequest request) {
String uri = PATH;
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, METHOD, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(METHOD, requestBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, TransferToUserResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public TransferToUser(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public String encrypt(String plainText) {
return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText);
}
public static class TransferToUserResponse {
@SerializedName("out_bill_no")
public String outBillNo;
@SerializedName("transfer_bill_no")
public String transferBillNo;
@SerializedName("create_time")
public String createTime;
@SerializedName("state")
public TransferBillStatus state;
@SerializedName("package_info")
public String packageInfo;
}
public enum TransferBillStatus {
@SerializedName("ACCEPTED")
ACCEPTED,
@SerializedName("PROCESSING")
PROCESSING,
@SerializedName("WAIT_USER_CONFIRM")
WAIT_USER_CONFIRM,
@SerializedName("TRANSFERING")
TRANSFERING,
@SerializedName("SUCCESS")
SUCCESS,
@SerializedName("FAIL")
FAIL,
@SerializedName("CANCELING")
CANCELING,
@SerializedName("CANCELLED")
CANCELLED
}
public static class TransferSceneReportInfo {
@SerializedName("info_type")
public String infoType;
@SerializedName("info_content")
public String infoContent;
}
public static class TransferToUserRequest {
@SerializedName("appid")
public String appid;
@SerializedName("out_bill_no")
public String outBillNo;
@SerializedName("transfer_scene_id")
public String transferSceneId;
@SerializedName("openid")
public String openid;
@SerializedName("user_name")
public String userName;
@SerializedName("transfer_amount")
public Long transferAmount;
@SerializedName("transfer_remark")
public String transferRemark;
@SerializedName("notify_url")
public String notifyUrl;
@SerializedName("user_recv_perception")
public String userRecvPerception;
@SerializedName("transfer_scene_report_infos")
public List<TransferSceneReportInfo> transferSceneReportInfos;
}
}

+ 381
- 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/transferTest/WXPayUtility.java View File

@ -0,0 +1,381 @@
package org.jeecg.modules.transferTest;
import com.google.gson.*;
import com.google.gson.annotations.Expose;
import okhttp3.Headers;
import okhttp3.Response;
import okio.BufferedSource;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.DateTimeException;
import java.time.Duration;
import java.time.Instant;
import java.util.Base64;
import java.util.Map;
import java.util.Objects;
public class WXPayUtility {
private static final Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
final Expose expose = fieldAttributes.getAnnotation(Expose.class);
return expose != null && !expose.serialize();
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
return false;
}
})
.addDeserializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
final Expose expose = fieldAttributes.getAnnotation(Expose.class);
return expose != null && !expose.deserialize();
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
return false;
}
})
.create();
private static final char[] SYMBOLS =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static final SecureRandom random = new SecureRandom();
/**
* Object 转换为 JSON 字符串
*/
public static String toJson(Object object) {
return gson.toJson(object);
}
/**
* JSON 字符串解析为特定类型的实例
*/
public static <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
return gson.fromJson(json, classOfT);
}
/**
* 从公私钥文件路径中读取文件内容
*
* @param keyPath 文件路径
* @return 文件内容
*/
private static String readKeyStringFromPath(String keyPath) {
try {
return new String(Files.readAllBytes(Paths.get(keyPath)), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* 读取 PKCS#8 格式的私钥字符串并加载为私钥对象
*
* @param keyString 私钥文件内容 -----BEGIN PRIVATE KEY----- 开头
* @return PrivateKey 对象
*/
public static PrivateKey loadPrivateKeyFromString(String keyString) {
try {
keyString = keyString.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
return KeyFactory.getInstance("RSA").generatePrivate(
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(keyString)));
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException(e);
}
}
/**
* PKCS#8 格式的私钥文件中加载私钥
*
* @param keyPath 私钥文件路径
* @return PrivateKey 对象
*/
public static PrivateKey loadPrivateKeyFromPath(String keyPath) {
return loadPrivateKeyFromString(readKeyStringFromPath(keyPath));
}
/**
* 读取 PKCS#8 格式的公钥字符串并加载为公钥对象
*
* @param keyString 公钥文件内容 -----BEGIN PUBLIC KEY----- 开头
* @return PublicKey 对象
*/
public static PublicKey loadPublicKeyFromString(String keyString) {
try {
keyString = keyString.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s+", "");
return KeyFactory.getInstance("RSA").generatePublic(
new X509EncodedKeySpec(Base64.getDecoder().decode(keyString)));
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException(e);
}
}
/**
* PKCS#8 格式的公钥文件中加载公钥
*
* @param keyPath 公钥文件路径
* @return PublicKey 对象
*/
public static PublicKey loadPublicKeyFromPath(String keyPath) {
return loadPublicKeyFromString(readKeyStringFromPath(keyPath));
}
/**
* 创建指定长度的随机字符串字符集为[0-9a-zA-Z]可用于安全相关用途
*/
public static String createNonce(int length) {
char[] buf = new char[length];
for (int i = 0; i < length; ++i) {
buf[i] = SYMBOLS[random.nextInt(SYMBOLS.length)];
}
return new String(buf);
}
/**
* 使用公钥按照 RSA_PKCS1_OAEP_PADDING 算法进行加密
*
* @param publicKey 加密用公钥对象
* @param plaintext 待加密明文
* @return 加密后密文
*/
public static String encrypt(PublicKey publicKey, String plaintext) {
final String transformation = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
try {
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)));
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalArgumentException("The current Java environment does not support " + transformation, e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("RSA encryption using an illegal publicKey", e);
} catch (BadPaddingException | IllegalBlockSizeException e) {
throw new IllegalArgumentException("Plaintext is too long", e);
}
}
/**
* 使用私钥按照指定算法进行签名
*
* @param message 待签名串
* @param algorithm 签名算法 SHA256withRSA
* @param privateKey 签名用私钥对象
* @return 签名结果
*/
public static String sign(String message, String algorithm, PrivateKey privateKey) {
byte[] sign;
try {
Signature signature = Signature.getInstance(algorithm);
signature.initSign(privateKey);
signature.update(message.getBytes(StandardCharsets.UTF_8));
sign = signature.sign();
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("The current Java environment does not support " + algorithm, e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException(algorithm + " signature uses an illegal privateKey.", e);
} catch (SignatureException e) {
throw new RuntimeException("An error occurred during the sign process.", e);
}
return Base64.getEncoder().encodeToString(sign);
}
/**
* 使用公钥按照特定算法验证签名
*
* @param message 待签名串
* @param signature 待验证的签名内容
* @param algorithm 签名算法SHA256withRSA
* @param publicKey 验签用公钥对象
* @return 签名验证是否通过
*/
public static boolean verify(String message, String signature, String algorithm,
PublicKey publicKey) {
try {
Signature sign = Signature.getInstance(algorithm);
sign.initVerify(publicKey);
sign.update(message.getBytes(StandardCharsets.UTF_8));
return sign.verify(Base64.getDecoder().decode(signature));
} catch (SignatureException e) {
return false;
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("verify uses an illegal publickey.", e);
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("The current Java environment does not support" + algorithm, e);
}
}
/**
* 根据微信支付APIv3请求签名规则构造 Authorization 签名
*
* @param mchid 商户号
* @param certificateSerialNo 商户API证书序列号
* @param privateKey 商户API证书私钥
* @param method 请求接口的HTTP方法请使用全大写表述 GETPOSTPUTDELETE
* @param uri 请求接口的URL
* @param body 请求接口的Body
* @return 构造好的微信支付APIv3 Authorization
*/
public static String buildAuthorization(String mchid, String certificateSerialNo,
PrivateKey privateKey,
String method, String uri, String body) {
String nonce = createNonce(32);
long timestamp = Instant.now().getEpochSecond();
String message = String.format("%s\n%s\n%d\n%s\n%s\n", method, uri, timestamp, nonce,
body == null ? "" : body);
String signature = sign(message, "SHA256withRSA", privateKey);
return String.format(
"WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",signature=\"%s\"," +
"timestamp=\"%d\",serial_no=\"%s\"",
mchid, nonce, signature, timestamp, certificateSerialNo);
}
/**
* 对参数进行 URL 编码
*
* @param content 参数内容
* @return 编码后的内容
*/
public static String urlEncode(String content) {
try {
return URLEncoder.encode(content, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
/**
* 对参数Map进行 URL 编码生成 QueryString
*
* @param params Query参数Map
* @return QueryString
*/
public static String urlEncode(Map<String, Object> params) {
if (params == null || params.isEmpty()) {
return "";
}
int index = 0;
StringBuilder result = new StringBuilder();
for (Map.Entry<String, Object> entry : params.entrySet()) {
result.append(entry.getKey())
.append("=")
.append(urlEncode(entry.getValue().toString()));
index++;
if (index < params.size()) {
result.append("&");
}
}
return result.toString();
}
/**
* 从应答中提取 Body
*
* @param response HTTP 请求应答对象
* @return 应答中的Body内容Body为空时返回空字符串
*/
public static String extractBody(Response response) {
if (response.body() == null) {
return "";
}
try {
BufferedSource source = response.body().source();
return source.readUtf8();
} catch (IOException e) {
throw new RuntimeException(String.format("An error occurred during reading response body. Status: %d", response.code()), e);
}
}
/**
* 根据微信支付APIv3应答验签规则对应答签名进行验证验证不通过时抛出异常
*
* @param wechatpayPublicKeyId 微信支付公钥ID
* @param wechatpayPublicKey 微信支付公钥对象
* @param headers 微信支付应答 Header 列表
* @param body 微信支付应答 Body
*/
public static void validateResponse(String wechatpayPublicKeyId, PublicKey wechatpayPublicKey,
Headers headers,
String body) {
String timestamp = headers.get("Wechatpay-Timestamp");
try {
Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestamp));
// 拒绝过期请求
if (Duration.between(responseTime, Instant.now()).abs().toMinutes() >= 5) {
throw new IllegalArgumentException(
String.format("Validate http response,timestamp[%s] of httpResponse is expires, "
+ "request-id[%s]",
timestamp, headers.get("Request-ID")));
}
} catch (DateTimeException | NumberFormatException e) {
throw new IllegalArgumentException(
String.format("Validate http response,timestamp[%s] of httpResponse is invalid, " +
"request-id[%s]", timestamp,
headers.get("Request-ID")));
}
String message = String.format("%s\n%s\n%s\n", timestamp, headers.get("Wechatpay-Nonce"),
body == null ? "" : body);
String serialNumber = headers.get("Wechatpay-Serial");
if (!Objects.equals(serialNumber, wechatpayPublicKeyId)) {
throw new IllegalArgumentException(
String.format("Invalid Wechatpay-Serial, Local: %s, Remote: %s", wechatpayPublicKeyId,
serialNumber));
}
String signature = headers.get("Wechatpay-Signature");
boolean success = verify(message, signature, "SHA256withRSA", wechatpayPublicKey);
if (!success) {
throw new IllegalArgumentException(
String.format("Validate response failed,the WechatPay signature is incorrect.%n"
+ "Request-ID[%s]\tresponseHeader[%s]\tresponseBody[%.1024s]",
headers.get("Request-ID"), headers, body));
}
}
/**
* 微信支付API错误异常发送HTTP请求成功但返回状态码不是 2XX 时抛出本异常
*/
public static class ApiException extends RuntimeException {
public final int statusCode;
public final String body;
public final Headers headers;
public ApiException(int statusCode, String body, Headers headers) {
super(String.format("微信支付API访问失败,StatusCode: %s, Body: %s", statusCode, body));
this.statusCode = statusCode;
this.body = body;
this.headers = headers;
}
}
}

+ 13
- 0
jeecg-boot-module-system/src/main/java/org/jeecg/modules/transferTest/test.java View File

@ -0,0 +1,13 @@
package org.jeecg.modules.transferTest;
public class test {
public static void main(String[] args) {
String mchid = "1673516176";
String certiticateSerialNo ="525CDBD76E640EFB008288572C97D2715F3F18B2";
String privateKeyFilePath = "jeecg-boot-module-system/src/main/resources/apiclient_key_yaodu.pem";
String wechatPayPublicKeyId = "PUB_KEY_ID_0116735161762025040100448900000949";
String wechatPayPublicKeyFilePaht = "jeecg-boot-module-system/src/main/resources/pub_key_yaodu.pem";
TransferToUser transferToUser = new TransferToUser(mchid, certiticateSerialNo, privateKeyFilePath, wechatPayPublicKeyId, wechatPayPublicKeyFilePaht );
transferToUser.run();
}
}

+ 28
- 0
jeecg-boot-module-system/src/main/resources/apiclient_key_yaodu.pem View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDFHyPaZuXY6GCd
mC/CId2jMQ3Iun2cZycw2LxdWLNwtKGYKVk+GWa4upm60Zl+qrNpLam3qTD5Oyy3
T8Mz9EWHwBYr2xTSKINRbIjabdVyV0/H2RLitwRg3XyHQPxYFcvI9t9F2GHELsAA
qGmFp0+PiCVMzT+nB3sU+yLaNyiMC8rcprjh4tBV857K3Y5rzljbJsxa9WVzS0EM
GQRwPV2LaWPApcGZIKJLRAUa8yGMKMINyb9iJjdA1/4vD8tLWmvFhXtTYmrWmFhu
5QsyKDClOek2gqGgxDL9Hvvx5PYR59Mg57kyz0vSKhYa0MKgsFLuu7QJOFXk2bJo
DJymcLypAgMBAAECggEBAL+1626riHsOdXiP3FLYEPB38sn35dZI1GrDP18ht1Kz
uj18aVjl52tdv8lbtAbnCZoPWPJQUFr0XCbkIhrTRRQjkuyQI43I7P4xql+VVnPf
yq24xo9MI6v5fPUmFMWuXQVUZA1PxrXAKef54raj49LaPDyXmYJe2iurm1fTMVIR
Jba1rBi0hp5W1fMCiCPk1SMfANTE0UOTYdSRhNVSgf51aJHFI+FR8iSmf8rEv+B0
s8uDXvxTGgbEaZsO7wcjQfsbQixoqEmfTzEoBTHkQ1npigG32gsz8QO6P4dhJRX7
WJ3N8x0vgJqxCLeRLEb6c8ZJ62SuEi6PtETVWXujeCECgYEA/gP8fyp5lBKF/weC
UzMCEAJzwTKjmC0IOWnoIwQTSKZTCKHmz5LMNYn3nTf2d8LpbB9GYmBhUdiO/88f
AZ/vbuskkoH0rmOgelVx13tDaVuNOOVmtKmKvzYOxiGeL6ooX2cwfRnVOMIPTBFM
G1lAzxeowTy5uLKvuuMGBVJj7MUCgYEAxqleqjcp3+4QoE9Z/2hEt6sYnI/I1T/h
kbgTO8wQSGG8ambl/qJu+9ON/Ag1jK2amrNKP1vXbTQsjkUby6U5MgVwGDB4bNN1
+wgwxMXJ74QJtbnXp7XBqC96S6Pyw+cLEjvWk0xJ14Os2oCO1OvZibu5KHrsPECn
3OmddJkjFpUCgYEAoiwHW2TRxCBjXiP8J4QMUA5QusrKuVAezRD5fMmQSjSuFHfQ
9Tsilxfjd4OQHnvZLQd2lz4zQ96/xUAF6rKiWa1UZxkDDwdaIGBG0yzGKBCkQ+vp
u3P2ugcYPZSe+o1nQymNQoFoqNj0jTsJ3PgJsW3Idr5/UBT8rpNcd69XToUCgYB8
AQTCIyTUTnm6V03KC3+5VedK8sVdtz5KAyieTsZrJ/bAQ/KUezfjoS4jf8xNP6Ad
qIRUADP8SnD1bVXoS/3jp1lNABRreaNPStGGQh/GjhixgouGeAGlxd0EkhXbCsDy
ZL+PujLtf5fJ3C1L4twrCS6OggwroAAn+Pr76Qrp8QKBgQD9uH47NRToKkaTPflY
mVlbLKCWnAjoqlxHrANjM6lOeC4SfAYaZRIpCK9B7LFR7eeqIb0Y/RjfwtLdFKQF
1hVCnLYTsEJ5gG64qqInVb4e0FCF/2w1uoBGwB2pUWjd0DUXH3yHc3LVCBhxOkRa
oULtLnG34V6fFclMh3Stk/pMVg==
-----END PRIVATE KEY-----

+ 9
- 0
jeecg-boot-module-system/src/main/resources/pub_key_yaodu.pem View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxK2wqQooeGKkAQchZdwK
U3qFiPSyf83l7USGGAdEhb78iq0Dvi7RfgdHuqSVBv0fnSQJicNO+s10ofi9waxl
SCPnuO8t9MeOuS4IpZ54VWY/9pJ5A2Z0x49L0djoFWStFCpKzsg2fWBvc/7kYVFr
nq/jFyRho8/GZtxL9RLZjWLyfnpe+erxSNFEnQLoW6LC4D5L0w9oiHboHmN9Igzc
uB6pIuMwccImX1xPeu/jx2QMYrxAW/2bW3e6z4ojQWqhRtFq55INnXLV8VXE7rwI
1L0RB4R39JOsKroVE/g7SiHRbGEem2BbNaAFhjCMuZzpWSCFQkTlxLJMxxTt9j0S
+wIDAQAB
-----END PUBLIC KEY-----

Loading…
Cancel
Save