分账提现接口
This commit is contained in:
@@ -1,76 +0,0 @@
|
||||
package com.czg.service.Impl;
|
||||
|
||||
import com.czg.service.RedisService;
|
||||
import com.czg.system.service.SysParamsService;
|
||||
import com.czg.service.WxService;
|
||||
import com.ijpay.core.kit.RsaKit;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
|
||||
/**
|
||||
* 微信支付service
|
||||
* @author Administrator
|
||||
*/
|
||||
@DubboService
|
||||
@Slf4j
|
||||
public class AppWxServiceImpl implements WxService {
|
||||
|
||||
@Resource
|
||||
private RedisService autoRedisService;
|
||||
@DubboReference
|
||||
private SysParamsService paramsService;
|
||||
private static RedisService redisService;
|
||||
private WxService.Config config = new Config();
|
||||
|
||||
@Override
|
||||
public Config getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedisService getRedisService() {
|
||||
return redisService;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
// 小程序id
|
||||
config.appId = paramsService.getSysParamValue("shop_wx_appid");
|
||||
// 小程序secrete
|
||||
config.appSecret = paramsService.getSysParamValue("shop_wx_secrete");
|
||||
config.certPath = "";
|
||||
// 微信支付公钥
|
||||
config.pubKey = paramsService.getSysParamValue("wx_pub_key");
|
||||
// api支付证书私钥
|
||||
config.apiCertKey = paramsService.getSysParamValue("wx_apiclient_key");
|
||||
// api支付证书公钥
|
||||
config.apiCert = paramsService.getSysParamValue("wx_apiclient_cert");
|
||||
try {
|
||||
config.privateKey = RsaKit.loadPrivateKey(config.apiCertKey);
|
||||
} catch (Exception e) {
|
||||
log.warn("微信加载api证书失败");
|
||||
}
|
||||
// 平台证书
|
||||
config.platformCertPath = "";
|
||||
// 平台证书编号
|
||||
config.platformCertNo = "";
|
||||
// 商户号
|
||||
config.mchId = paramsService.getSysParamValue("wx_mch_id");
|
||||
// v3密钥
|
||||
config.apiV3Key = paramsService.getSysParamValue("wx_v3_key");
|
||||
config.apiV2Key = "";
|
||||
// 回调地址
|
||||
config.notifyUrl = paramsService.getSysParamValue("native_notify_url") + "/wx/pay";
|
||||
config.refundNotifyUrl = "";
|
||||
config.transferNotifyUrl = paramsService.getSysParamValue("native_notify_url") + "/wx/transfer";
|
||||
redisService = this.autoRedisService;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
package com.czg.service.Impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.exception.CzgException;
|
||||
import com.czg.service.RedisService;
|
||||
import com.czg.system.service.SysParamsService;
|
||||
import com.czg.service.WxService;
|
||||
import com.ijpay.core.kit.RsaKit;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.dubbo.config.annotation.DubboReference;
|
||||
import org.apache.dubbo.config.annotation.DubboService;
|
||||
|
||||
|
||||
/**
|
||||
* 微信支付service
|
||||
* @author Administrator
|
||||
*/
|
||||
@DubboService
|
||||
@Slf4j
|
||||
public class WxServiceImpl implements WxService {
|
||||
|
||||
|
||||
@Resource
|
||||
private RedisService autoRedisService;
|
||||
@DubboReference
|
||||
private SysParamsService paramsService;
|
||||
private static RedisService redisService;
|
||||
private WxService.Config config = new Config();
|
||||
|
||||
@Override
|
||||
public Config getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedisService getRedisService() {
|
||||
return redisService;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
// 小程序id
|
||||
config.appId = paramsService.getSysParamValue("shop_wx_appid");
|
||||
// 小程序secrete
|
||||
config.appSecret = paramsService.getSysParamValue("shop_wx_secrete");
|
||||
config.certPath = "";
|
||||
// 微信支付公钥
|
||||
config.pubKey = paramsService.getSysParamValue("wx_pub_key");
|
||||
// api支付证书私钥
|
||||
config.apiCertKey = paramsService.getSysParamValue("wx_apiclient_key");
|
||||
// api支付证书公钥
|
||||
config.apiCert = paramsService.getSysParamValue("wx_apiclient_cert");
|
||||
try {
|
||||
config.privateKey = RsaKit.loadPrivateKey(config.apiCertKey);
|
||||
} catch (Exception e) {
|
||||
log.warn("微信加载api证书失败");
|
||||
}
|
||||
// 平台证书
|
||||
config.platformCertPath = "";
|
||||
// 平台证书编号
|
||||
config.platformCertNo = "";
|
||||
// 商户号
|
||||
config.mchId = paramsService.getSysParamValue("wx_mch_id");
|
||||
// v3密钥
|
||||
config.apiV3Key = paramsService.getSysParamValue("wx_v3_key");
|
||||
config.apiV2Key = "";
|
||||
// 回调地址
|
||||
config.notifyUrl = paramsService.getSysParamValue("native_notify_url") + "/wx/pay";
|
||||
config.refundNotifyUrl = "";
|
||||
config.transferNotifyUrl = paramsService.getSysParamValue("native_notify_url") + "/wx/transfer";
|
||||
redisService = this.autoRedisService;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,392 +0,0 @@
|
||||
package com.czg.service;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.exception.CzgException;
|
||||
import com.ijpay.core.IJPayHttpResponse;
|
||||
import com.ijpay.core.enums.RequestMethodEnum;
|
||||
import com.ijpay.core.enums.SignType;
|
||||
import com.ijpay.core.kit.AesUtil;
|
||||
import com.ijpay.core.kit.PayKit;
|
||||
import com.ijpay.core.kit.WxPayKit;
|
||||
import com.ijpay.wxpay.WxPayApi;
|
||||
import com.ijpay.wxpay.enums.WxDomainEnum;
|
||||
import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
|
||||
import com.ijpay.wxpay.model.v3.*;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import lombok.Data;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Base64;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 微信支付相关
|
||||
* @author Administrator
|
||||
*/
|
||||
public interface WxService {
|
||||
Logger log = LoggerFactory.getLogger(WxService.class);
|
||||
@Data
|
||||
class Config {
|
||||
public String appId;
|
||||
public String appSecret;
|
||||
public String certPath;
|
||||
public String pubKey;
|
||||
public String apiCertKey;
|
||||
public PrivateKey privateKey;
|
||||
public String apiCert;
|
||||
public String platformCertPath;
|
||||
public String platformCertNo;
|
||||
public String mchId;
|
||||
public String apiV3Key;
|
||||
public String apiV2Key;
|
||||
public String notifyUrl;
|
||||
public String refundNotifyUrl;
|
||||
public String transferNotifyUrl;
|
||||
}
|
||||
Config getConfig();
|
||||
RedisService getRedisService();
|
||||
|
||||
|
||||
default String getPhone(String code) {
|
||||
String requestBody = JSONObject.toJSONString(Map.of("code", code));
|
||||
String response = HttpUtil.post("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken(false), requestBody);
|
||||
log.info("获取手机号响应: {}", response);
|
||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||
Integer errCode = jsonObject.getInteger("errcode");
|
||||
|
||||
if (Integer.valueOf(0).equals(errCode)) {
|
||||
return jsonObject.getJSONObject("phone_info").getString("phoneNumber");
|
||||
} else if (Integer.valueOf(40001).equals(errCode)) {
|
||||
getAccessToken(true);
|
||||
}
|
||||
throw new RuntimeException("获取手机号失败");
|
||||
}
|
||||
|
||||
default String getAccessToken(boolean refresh) {
|
||||
Object token = getRedisService().get("access_token");
|
||||
Config config = getConfig();
|
||||
if (!refresh && token instanceof String) {
|
||||
return (String) token;
|
||||
}
|
||||
|
||||
String response = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token",
|
||||
Map.of("grant_type", "client_credential", "appid", config.appId, "secret", config.appSecret)
|
||||
);
|
||||
|
||||
log.info("获取access_token响应: {}", response);
|
||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||
String accessToken = jsonObject.getString("access_token");
|
||||
if (accessToken == null) {
|
||||
throw new RuntimeException("获取access_token失败");
|
||||
}
|
||||
Long expiresIn = jsonObject.getLong("expires_in");
|
||||
if (expiresIn == null) {
|
||||
expiresIn = 7200L;
|
||||
}
|
||||
getRedisService().set("access_token", accessToken, expiresIn - 200);
|
||||
return accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用微信支付平台证书公钥加密敏感信息(OAEP)
|
||||
*/
|
||||
default String encryptByPlatformCert(String content) {
|
||||
Config config = getConfig();
|
||||
|
||||
try (var certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(config.getPlatformCertPath())) {
|
||||
if (certStream == null) {
|
||||
throw new RuntimeException("未找到微信支付平台证书文件: " + config.getPlatformCertPath());
|
||||
}
|
||||
X509Certificate certificate = PayKit.getCertificate(certStream);
|
||||
if (certificate == null) {
|
||||
throw new RuntimeException("读取证书失败");
|
||||
}
|
||||
return PayKit.rsaEncryptOAEP(content, certificate);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
default String getSerialNumberFromPem(String certContent) {
|
||||
try {
|
||||
// 去掉 PEM 头尾并清理空格换行
|
||||
String pem = certContent
|
||||
.replace("-----BEGIN CERTIFICATE-----", "")
|
||||
.replace("-----END CERTIFICATE-----", "")
|
||||
.replaceAll("\\s+", "");
|
||||
|
||||
// Base64 解码
|
||||
byte[] certBytes = Base64.getDecoder().decode(pem);
|
||||
|
||||
try (ByteArrayInputStream bis = new ByteArrayInputStream(certBytes)) {
|
||||
X509Certificate certificate = PayKit.getCertificate(bis);
|
||||
|
||||
if (certificate != null) {
|
||||
String serialNo = certificate.getSerialNumber()
|
||||
.toString(16)
|
||||
.toUpperCase(Locale.getDefault());
|
||||
|
||||
System.out.println("证书序列号:" + serialNo);
|
||||
|
||||
return serialNo;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("无效的证书", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
default String getSerialNumber() {
|
||||
Config config = getConfig();
|
||||
try (var certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(config.getCertPath())) {
|
||||
X509Certificate certificate = PayKit.getCertificate(certStream);
|
||||
if (certificate != null) {
|
||||
String serialNo = certificate.getSerialNumber().toString(16).toUpperCase(Locale.getDefault());
|
||||
boolean isValid = PayKit.checkCertificateIsValid(certificate, config.getMchId(), -2);
|
||||
log.info("证书是否可用 {} 证书有效期为 {}", isValid, certificate.getNotAfter());
|
||||
log.info("证书序列号: {}", serialNo);
|
||||
return serialNo;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("读取证书失败", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
default JSONObject verifySignature(HttpServletRequest request) {
|
||||
Config config = getConfig();
|
||||
|
||||
try {
|
||||
log.info("开始校验签名并解密");
|
||||
String timestamp = request.getHeader("Wechatpay-Timestamp");
|
||||
String nonce = request.getHeader("Wechatpay-Nonce");
|
||||
String serialNo = request.getHeader("Wechatpay-Serial");
|
||||
String signature = request.getHeader("Wechatpay-Signature");
|
||||
String result = request.getReader().lines().reduce((a, b) -> a + b).orElse("");
|
||||
String resp = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp, config.getApiV3Key(), config.getPlatformCertPath());
|
||||
log.info("解密明文{}", resp);
|
||||
return JSONObject.parseObject(resp);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
default String decryptToString(String associatedData, String nonceStr, String ciphertext) {
|
||||
AesUtil aesUtil = new AesUtil(getConfig().getApiV3Key().getBytes(StandardCharsets.UTF_8));
|
||||
try {
|
||||
return aesUtil.decryptToString(
|
||||
associatedData.getBytes(StandardCharsets.UTF_8),
|
||||
nonceStr.getBytes(StandardCharsets.UTF_8),
|
||||
ciphertext
|
||||
);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
default String getOpenId(String code) {
|
||||
Config config = getConfig();
|
||||
String response = HttpUtil.get("https://api.weixin.qq.com/sns/jscode2session",
|
||||
Map.of("appid", config.getAppId() , "secret", config.getAppSecret(), "js_code", code, "grant_type", "authorization_code")
|
||||
);
|
||||
log.info("获取openId响应: {}", response);
|
||||
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||
String openId = jsonObject.getString("openid");
|
||||
if (openId != null && !openId.isBlank()) {
|
||||
return openId;
|
||||
}
|
||||
throw new RuntimeException("获取openId失败");
|
||||
}
|
||||
|
||||
default Map<String, String> v3Pay(String openId, BigDecimal amount, String desc, String tradeNo, String type) {
|
||||
Config config = getConfig();
|
||||
if (desc == null) desc = "订单支付";
|
||||
UnifiedOrderModel model = new UnifiedOrderModel();
|
||||
model.setAppid(config.getAppId());
|
||||
model.setMchid(config.getMchId());
|
||||
model.setDescription(desc);
|
||||
model.setOut_trade_no(tradeNo);
|
||||
int total = amount.setScale(2, RoundingMode.UP).multiply(new BigDecimal(100)).intValueExact();
|
||||
model.setAmount(new Amount(total, "CNY"));
|
||||
model.setNotify_url(config.getNotifyUrl() + "/" + type);
|
||||
model.setPayer(new Payer(openId, null, null));
|
||||
|
||||
String payInfo = JSONObject.toJSONString(model);
|
||||
log.info("统一下单参数: {}", payInfo);
|
||||
|
||||
IJPayHttpResponse resp;
|
||||
try {
|
||||
resp = WxPayApi.v3(
|
||||
RequestMethodEnum.POST,
|
||||
WxDomainEnum.CHINA.toString(),
|
||||
BasePayApiEnum.JS_API_PAY.toString(),
|
||||
config.mchId,
|
||||
getSerialNumberFromPem(config.apiCert),
|
||||
null,
|
||||
config.privateKey,
|
||||
payInfo
|
||||
);
|
||||
log.info("统一下单响应: {}", resp);
|
||||
String body = resp.getBody();
|
||||
JSONObject jsonObject = JSONObject.parseObject(body);
|
||||
String prepayId = jsonObject.getString("prepay_id");
|
||||
if (StrUtil.isBlank(prepayId)) {
|
||||
throw new RuntimeException(jsonObject.getString("message"));
|
||||
}
|
||||
return WxPayKit.jsApiCreateSign(config.appId, prepayId, config.privateKey);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
default Map<String, String> v2Pay(String openId, BigDecimal amount, String desc, String tradeNo) {
|
||||
Config config = getConfig();
|
||||
Map<String, String> payModel = com.ijpay.wxpay.model.UnifiedOrderModel.builder()
|
||||
.appid(config.appId)
|
||||
.mch_id(config.mchId)
|
||||
.body(desc)
|
||||
.out_trade_no(tradeNo)
|
||||
.total_fee(amount.setScale(2, RoundingMode.UP).multiply(new BigDecimal(100)).intValueExact() + "")
|
||||
.fee_type("CNY")
|
||||
.notify_url(config.notifyUrl)
|
||||
.openid(openId)
|
||||
.trade_type("JSAPI")
|
||||
.build()
|
||||
.createSign(config.apiV2Key, SignType.MD5);
|
||||
|
||||
log.info("统一下单参数: {}", payModel);
|
||||
String resp = WxPayApi.pushOrder(false, payModel);
|
||||
log.info("统一下单响应: {}", resp);
|
||||
|
||||
Map<String, String> resultMap = WxPayKit.xmlToMap(resp);
|
||||
String returnCode = resultMap.get("return_code");
|
||||
String returnMsg = resultMap.get("return_msg");
|
||||
if (!WxPayKit.codeIsOk(returnCode)) {
|
||||
throw new CzgException(returnMsg);
|
||||
}
|
||||
String resultCode = resultMap.get("result_code");
|
||||
if (!WxPayKit.codeIsOk(resultCode)) {
|
||||
throw new CzgException(returnMsg);
|
||||
}
|
||||
String prepayId = resultMap.get("prepay_id");
|
||||
return WxPayKit.prepayIdCreateSign(prepayId, config.appId, config.appSecret, SignType.MD5);
|
||||
}
|
||||
|
||||
|
||||
default String refund(String tradeNo, String refundTradeNo, BigDecimal amount) {
|
||||
Config config = getConfig();
|
||||
int finalAmount = amount.multiply(new BigDecimal(100)).intValueExact();
|
||||
RefundModel model = new RefundModel();
|
||||
model.setOut_trade_no(tradeNo);
|
||||
model.setOut_refund_no(refundTradeNo);
|
||||
model.setAmount(new RefundAmount(finalAmount, "CNY", finalAmount));
|
||||
model.setNotify_url(config.refundNotifyUrl);
|
||||
|
||||
String info = JSONObject.toJSONString(model);
|
||||
log.info("统一退款参数: {}", info);
|
||||
IJPayHttpResponse response;
|
||||
try {
|
||||
response = WxPayApi.v3(
|
||||
RequestMethodEnum.POST,
|
||||
WxDomainEnum.CHINA.toString(),
|
||||
BasePayApiEnum.REFUND.toString(),
|
||||
config.mchId,
|
||||
getSerialNumber(),
|
||||
getSerialNumber(),
|
||||
config.apiCertKey,
|
||||
info
|
||||
);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
log.info("统一退款响应 {}", response);
|
||||
String body = response.getBody();
|
||||
JSONObject jsonObject = JSONObject.parseObject(body);
|
||||
if ("ABNORMAL".equals(jsonObject.getString("status")) || response.getStatus() != 200) {
|
||||
throw new CzgException("退款异常," + jsonObject.getString("message"));
|
||||
}
|
||||
return jsonObject.getString("refund_id");
|
||||
}
|
||||
|
||||
default String genCode(int shopId, int id, String path) {
|
||||
Map<String, Object> params = Map.of(
|
||||
"scene", "id=" + id + "&shopId=" + shopId,
|
||||
"page", path,
|
||||
"width", 430
|
||||
);
|
||||
var response = HttpRequest.post("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + getAccessToken(false))
|
||||
.body(JSONObject.toJSONString(params))
|
||||
.execute();
|
||||
|
||||
byte[] bodyBytes = response.bodyBytes();
|
||||
String str = new String(bodyBytes);
|
||||
if (str.contains("errmsg")) {
|
||||
JSONObject json = JSONObject.parseObject(str);
|
||||
throw new CzgException(json.getString("errmsg"));
|
||||
}
|
||||
return "data:image/png;base64," + Base64.getEncoder().encodeToString(bodyBytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
default JSONObject transferBalance(String openId, String name, BigDecimal amount, String remarkTxt, String billNoTxt) {
|
||||
Config config = getConfig();
|
||||
String remark = remarkTxt == null ? "佣金" : remarkTxt;
|
||||
String billNo = billNoTxt == null ? IdUtil.simpleUUID() : billNoTxt;
|
||||
Map<String, Object> params = Map.of(
|
||||
"appid", config.appId,
|
||||
"out_bill_no", billNo,
|
||||
"transfer_scene_id", "1005",
|
||||
"openid", openId,
|
||||
"user_name", encryptByPlatformCert(name),
|
||||
"transfer_amount", amount.multiply(BigDecimal.valueOf(100)).intValue(),
|
||||
"transfer_remark", remark,
|
||||
"notify_url", config.transferNotifyUrl,
|
||||
"transfer_scene_report_infos", new Object[]{
|
||||
Map.of("info_type", "岗位类型", "info_content", "加盟商"),
|
||||
Map.of("info_type", "报酬说明", "info_content", "测试")
|
||||
}
|
||||
);
|
||||
log.info("转账到零钱参数: {}", JSONObject.toJSONString(params));
|
||||
IJPayHttpResponse response = null;
|
||||
try {
|
||||
response = WxPayApi.v3(
|
||||
RequestMethodEnum.POST,
|
||||
WxDomainEnum.CHINA.toString(),
|
||||
"/v3/fund-app/mch-transfer/transfer-bills",
|
||||
config.mchId,
|
||||
getSerialNumber(),
|
||||
config.platformCertNo,
|
||||
config.apiCertKey,
|
||||
JSONObject.toJSONString(params)
|
||||
);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
log.info("转账到零钱响应 {}", response.getBody());
|
||||
JSONObject resp = JSONObject.parseObject(response.getBody());
|
||||
if (resp.containsKey("code")) {
|
||||
throw new CzgException("转账到零钱失败" + resp.getString("message") + ", 响应: " + resp.toJSONString());
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user