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 [apply_no] */ public class QueryCapabilities { /** 汇付官方文档里的只读查询端点;写入端点一律不允许出现在这里。 */ private static final Set 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 realname = request(target); realname.put("pay_scene", "01"); query("v2.merchant.busi.realname.query", mer, realname); if (!applyNo.isBlank()) { Map status = request(target); status.put("apply_no", applyNo); query("v2.merchant.basicdata.status.query", mer, status); } } private static Map request(String huifuId) { Map 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 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 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 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; } }