import java.nio.file.*;
|
import java.time.*;
|
import java.time.format.*;
|
import java.util.*;
|
import com.alibaba.fastjson.JSON;
|
import com.huifu.bspay.sdk.opps.client.BasePayClient;
|
import com.huifu.bspay.sdk.opps.core.BasePay;
|
import com.huifu.bspay.sdk.opps.core.config.MerConfig;
|
import org.yaml.snakeyaml.Yaml;
|
|
/**
|
* Ticket02 只读能力核验面板:对一个商户拉取详情、微信配置、微信费率、多费率、实名状态。
|
* 不走 Spring、不连数据库、不含任何写入接口。
|
*
|
* 用法:java QueryCapabilities <huifu_id> [apply_no]
|
*/
|
public class QueryCapabilities {
|
|
/** 汇付官方文档里的只读查询端点;写入端点一律不允许出现在这里。 */
|
private static final Set<String> READ_ONLY = Set.of(
|
"v2.merchant.basicdata.query",
|
"v2.merchant.busi.config.query",
|
"v2.merchant.busi.realname.query",
|
"v2.merchant.basicdata.status.query",
|
"v2.merchant.fee-rate.query",
|
"v2.merchant.busi.multiFee.query");
|
|
public static void main(String[] args) throws Exception {
|
String target = args.length > 0 ? args[0] : "6666000241335656";
|
String applyNo = args.length > 1 ? args[1] : "";
|
|
Map root = new Yaml().load(Files.readString(Path.of("talent-card-server/src/main/resources/application.yml")));
|
Map config = find(root);
|
String identity = "" + config.get("system-id");
|
|
MerConfig mer = new MerConfig();
|
mer.setSysId(identity);
|
mer.setProductId("" + config.get("product-id"));
|
mer.setRsaPrivateKey("" + config.get("private-key"));
|
mer.setRsaPublicKey("" + config.get("platform-public-key"));
|
BasePay.debug = false;
|
BasePay.prodMode = BasePay.MODE_PROD;
|
BasePay.initWithMerConfig(mer);
|
|
System.out.println("### identity sys_id=" + identity + ", product_id=" + mer.getProductId());
|
System.out.println("### target huifu_id=" + target);
|
System.out.println();
|
|
query("v2.merchant.basicdata.query", mer, request(target));
|
query("v2.merchant.busi.config.query", mer, request(target));
|
query("v2.merchant.fee-rate.query", mer, request(target));
|
query("v2.merchant.busi.multiFee.query", mer, request(target));
|
|
Map<String, Object> realname = request(target);
|
realname.put("pay_scene", "01");
|
query("v2.merchant.busi.realname.query", mer, realname);
|
|
if (!applyNo.isBlank()) {
|
Map<String, Object> status = request(target);
|
status.put("apply_no", applyNo);
|
query("v2.merchant.basicdata.status.query", mer, status);
|
}
|
}
|
|
private static Map<String, Object> request(String huifuId) {
|
Map<String, Object> request = new LinkedHashMap<>();
|
request.put("req_seq_id", UUID.randomUUID().toString().replace("-", ""));
|
request.put("req_date", LocalDate.now(ZoneId.of("Asia/Shanghai")).format(DateTimeFormatter.BASIC_ISO_DATE));
|
request.put("huifu_id", huifuId);
|
return request;
|
}
|
|
private static void query(String function, MerConfig mer, Map<String, Object> request) {
|
if (!READ_ONLY.contains(function)) throw new IllegalArgumentException("Read only query required: " + function);
|
System.out.println("=== " + function + " ===");
|
System.out.println("req=" + JSON.toJSONString(request));
|
try {
|
Map<String, Object> response = BasePayClient.request(request, function, false);
|
System.out.println("resp=" + JSON.toJSONString(response, true));
|
} catch (Exception exception) {
|
System.out.println("sdk-exception=" + exception.getClass().getSimpleName() + ": " + exception.getMessage());
|
rawDiagnostic(function, mer, request);
|
}
|
System.out.println();
|
}
|
|
/**
|
* SDK 不认识该端点(或抛异常)时,直接发一次同样签名的原始 HTTP,取出状态码与网关返回体。
|
* 只用于诊断与读取,不作为能力生效证据。
|
*/
|
private static void rawDiagnostic(String function, MerConfig mer, Map<String, Object> request) {
|
try {
|
String body = JSON.toJSONString(request);
|
String signature = com.huifu.bspay.sdk.opps.core.utils.RsaUtils.sign(
|
com.huifu.bspay.sdk.opps.core.sign.JsonUtils.sort4JsonString(body, 0), mer.getRsaPrivateKey());
|
String envelope = JSON.toJSONString(Map.of(
|
"sys_id", mer.getSysId(), "product_id", mer.getProductId(), "data", request, "sign", signature));
|
var http = java.net.http.HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(15)).build();
|
var req = java.net.http.HttpRequest.newBuilder(java.net.URI.create("https://api.huifu.com/" + function.replace('.', '/')))
|
.timeout(Duration.ofSeconds(20)).header("Content-Type", "application/json")
|
.POST(java.net.http.HttpRequest.BodyPublishers.ofString(envelope)).build();
|
var res = http.send(req, java.net.http.HttpResponse.BodyHandlers.ofString());
|
System.out.println("http-status=" + res.statusCode());
|
System.out.println("http-body=" + res.body());
|
} catch (Exception diagnostic) {
|
System.out.println("diagnostic-failed=" + diagnostic);
|
}
|
}
|
|
private static Map find(Map root) {
|
if (root.containsKey("system-id") && root.containsKey("private-key")) return root;
|
for (Object value : root.values()) {
|
if (value instanceof Map nested) {
|
Map found = find(nested);
|
if (found != null) return found;
|
}
|
}
|
return null;
|
}
|
}
|