Parcourir la source

商户的支付证书存储到指定路径中

zhangchen il y a 1 mois
Parent
commit
538a754fed

+ 155 - 0
alien-store/src/main/java/shop/alien/store/config/StorePaymentConfigCertInitRunner.java

@@ -0,0 +1,155 @@
+package shop.alien.store.config;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import shop.alien.entity.store.StoreInfo;
+import shop.alien.entity.store.StorePaymentConfig;
+import shop.alien.store.service.StoreInfoService;
+import shop.alien.store.service.StorePaymentConfigService;
+
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * 项目启动时将 store_payment_config 中的证书内容写入本地目录,路径按店铺ID和店铺手机号区分。
+ * 目录结构:{basePath}/{storeId}_{storeTel}/ 下存放各证书文件。
+ *
+ * @author system
+ */
+@Slf4j
+@Component
+@Order(100)
+@RequiredArgsConstructor
+public class StorePaymentConfigCertInitRunner implements ApplicationRunner {
+
+    private static final Pattern NON_ALNUM = Pattern.compile("[^0-9a-zA-Z]");
+
+    /** 证书根目录,默认当前工作目录下的 payment-certs */
+    @Value("${payment.cert.base-path:${user.dir}/payment-certs}")
+    private String certBasePath;
+
+    private final StorePaymentConfigService storePaymentConfigService;
+    private final StoreInfoService storeInfoService;
+
+    @Override
+    public void run(ApplicationArguments args) {
+        try {
+            List<StorePaymentConfig> list = storePaymentConfigService.list();
+            if (list == null || list.isEmpty()) {
+                log.debug("store_payment_config 无配置,跳过证书落盘");
+                return;
+            }
+            for (StorePaymentConfig config : list) {
+                try {
+                    //todo 暂时注销掉
+                    //writeCertFilesForConfig(config);
+                } catch (Exception e) {
+                    log.warn("店铺支付配置证书落盘失败 storeId={}", config.getStoreId(), e);
+                }
+            }
+        } catch (Exception e) {
+            log.error("支付配置证书初始化失败", e);
+        }
+    }
+
+    /**
+     * 为单条配置按 storeId + storeTel 建目录并写入证书文件,并将各证书的完整文件路径回写到 config 的路径字段。
+     */
+    protected void writeCertFilesForConfig(StorePaymentConfig config) throws Exception {
+        Integer storeId = config.getStoreId();
+        if (storeId == null) {
+            return;
+        }
+        String storeTel = null;
+        try {
+            StoreInfo store = storeInfoService.getById(storeId);
+            if (store != null && StringUtils.hasText(store.getStoreTel())) {
+                storeTel = store.getStoreTel();
+            }
+        } catch (Exception e) {
+            log.debug("获取店铺手机号失败 storeId={}", storeId, e);
+        }
+        String dirSegment = sanitizeDirSegment(storeTel);
+        String storeDirName = storeId + "_" + dirSegment;
+        Path baseDir = Paths.get(certBasePath).resolve(storeDirName);
+        if (!Files.exists(baseDir)) {
+            Files.createDirectories(baseDir);
+        }
+        String dirPath = baseDir.toAbsolutePath().toString();
+
+        // 支付宝:应用公钥证书、支付宝公钥证书、根证书
+        writeIfPresent(baseDir, config.getAppPublicCert(),
+                defaultName(config.getAppPublicCertName(), "app_public_cert.crt"),
+                (path, name) -> {
+                    config.setAppPublicCertPath(path);
+                    config.setAppPublicCertName(name);
+                });
+        writeIfPresent(baseDir, config.getAlipayPublicCert(),
+                defaultName(config.getAlipayPublicCertName(), "alipay_public_cert.crt"),
+                (path, name) -> {
+                    config.setAlipayPublicCertPath(path);
+                    config.setAlipayPublicCertName(name);
+                });
+        writeIfPresent(baseDir, config.getAlipayRootCert(),
+                defaultName(config.getAlipayRootCertName(), "alipay_root_cert.crt"),
+                (path, name) -> {
+                    config.setAlipayRootCertPath(path);
+                    config.setAlipayRootCertName(name);
+                });
+
+        // 微信:商户私钥、微信支付公钥
+        writeIfPresent(baseDir, config.getWechatPrivateKeyFile(),
+                defaultName(config.getWechatPrivateKeyName(), "wechat_private_key.pem"),
+                (path, name) -> {
+                    config.setWechatPrivateKeyPath(path);
+                    config.setWechatPrivateKeyName(name);
+                });
+        writeIfPresent(baseDir, config.getWechatPayPublicKeyFile(),
+                defaultName(config.getWechatPayPublicKeyFileName(), "wechat_public_key.pem"),
+                (path, name) -> {
+                    config.setWechatPayPublicKeyFilePath(path);
+                    config.setWechatPayPublicKeyFileName(name);
+                });
+
+        storePaymentConfigService.updateById(config);
+        log.info("店铺支付证书已落盘 storeId={}, dir={}", storeId, dirPath);
+    }
+
+    private static String sanitizeDirSegment(String storeTel) {
+        if (!StringUtils.hasText(storeTel)) {
+            return "no_tel";
+        }
+        return NON_ALNUM.matcher(storeTel.trim()).replaceAll("_");
+    }
+
+    private static String defaultName(String name, String defaultName) {
+        return StringUtils.hasText(name) ? name.trim() : defaultName;
+    }
+
+    private interface PathUpdater {
+        /** @param certFilePath 证书完整文件路径;@param fileName 文件名 */
+        void set(String certFilePath, String fileName);
+    }
+
+    private void writeIfPresent(Path baseDir, String content, String fileName, PathUpdater updater) throws Exception {
+        if (!StringUtils.hasText(content)) {
+            return;
+        }
+        Path file = baseDir.resolve(fileName);
+        Files.write(file, content.getBytes(StandardCharsets.UTF_8));
+        if (updater != null) {
+            String certFilePath = file.toAbsolutePath().toString();
+            updater.set(certFilePath, fileName);
+        }
+    }
+}