news 2026/10/13 3:28:30

SpringBoot多渠道支付网关:免签接入与非标能力实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot多渠道支付网关:免签接入与非标能力实战

简介:U神三方支付系统是一款面向Java开发者与支付系统学习者的SpringBoot实战项目,聚焦个人级多渠道聚合支付解决方案,帮助初学者理解主流支付网关对接、免签通道设计及特色支付场景(如话费慢充、小荷包、零钱口令)的工程实现。资源包共390个文件,含20个核心Java后端代码文件、216张界面与流程图PNG、54个前端交互JS脚本、26个HTML页面及配套CSS(含bootstrap.min.css、animate.css、bootsnav等UI框架),另有10个DOCX说明文档与2个TXT配置指引,完整呈现前后端分离架构与支付业务逻辑分层。压缩包大小为15.36MB,结构清晰,含uspay-main主模块、附赠资源.docx和说明文件.txt等实用材料,便于快速部署、调试与二次开发。目前已有69人学习下载,适合希望掌握SpringBoot支付集成、多平台API适配及安全支付流程设计的中初级Java工程师与毕业设计实践者。

1. 为什么一个“个人支付解决方案”需要自己搭?——当免签通道、多渠道聚合与话费慢充成为刚需

你有没有遇到过这样的场景:在做一个校园二手书交易平台时,学生用户死活不愿跳转到支付宝官方收银台;某次帮社区团长开发团购小程序,微信支付开通被卡在企业资质审核第三轮;又或者,给本地小商户做收款码聚合时,发现翼支付和云闪付的 SDK 文档里连 Java 示例都还是 Spring 3.x 的写法……这些不是边缘需求,而是真实压在一线开发者肩上的交付压力。标题里的「U神三方支付系统」,本质上不是一个玩具项目,而是一套面向中小实体、轻量级 SaaS 和个人开发者场景的支付能力下沉方案:它不追求金融级清结算,但必须能快速接入支付宝、微信、QQ 钱包、翼支付、云闪付五家主流渠道;它不提供资金存管,但要原生支持话费慢充、小荷包零钱、口令支付等非标能力;它不走银行直连,但通过「免签通道」(即合规的 ISV 代调用模式)绕过个体户无法申请支付接口的硬门槛。这不是替代微信/支付宝官方 SDK,而是补足它们在「非标场景」「轻量部署」「快速验证」三块的空白。适合正在做本地生活工具、校园服务类 App、小微 SaaS 后台,或需要绕过平台抽成做私域收款的开发者——尤其当你发现,官方文档里写着“仅限企业认证主体”,而你的营业执照还在快递路上时。


2. 从 ZIP 解压到可运行服务:SpringBoot 支付网关的最小启动路径

这个项目以.zip包形式交付,没有 Maven 仓库坐标,也没有 Docker Hub 镜像。这意味着你得亲手拆解它的结构、理解它的依赖边界、并亲手把它变成一个能curl通的 HTTP 服务。别急着改代码——先让服务跑起来,这是所有后续调试的物理基础。

2.1 解压结构与核心模块定位:认出哪几个文件是“心脏”

解压后你会看到典型的 SpringBoot 多模块结构:

Ushen-Payment/ ├── payment-core/ # 核心支付抽象层:定义 PayChannel、PayOrder、RefundRequest 等统一接口 ├── payment-alipay/ # 支付宝渠道实现:含 RSA2 签名、异步通知验签、沙箱环境适配 ├── payment-wechat/ # 微信支付 V3 实现:含平台证书自动下载、敏感字段 AES-GCM 解密 ├── payment-qq/ # QQ 钱包对接:基于其 OpenAPI 2.0,需手动配置 appid + key ├── payment-yifubao/ # 翼支付模块:调用其“翼支付开放平台”HTTP 接口,注意其回调地址必须为 HTTPS ├── payment-cloudpay/ # 云闪付模块:对接银联商务标准 API,需单独申请测试 merchantId ├── payment-web/ # SpringBoot Web 入口:含 /pay/unified、/notify/alipay 等 Controller └── config/ # application.yml 模板 + 各渠道密钥占位符

提示:payment-web是唯一带@SpringBootApplication的模块,也是你mvn spring-boot:run的目标。其他模块均为jar依赖,不可独立启动。

2.2 本地运行前的三步密钥准备:跳过“找不到商户私钥”的玄学报错

SpringBoot 启动失败最常见的原因是密钥缺失。这个项目采用「运行时注入」而非「编译时硬编码」,所以你需要手动准备三类密钥:

  1. 支付宝沙箱密钥对:登录 open.alipay.com → 进入沙箱环境 → 下载「应用私钥(PKCS8)」和「支付宝公钥」→ 将私钥内容(-----BEGIN PRIVATE KEY-----...)粘贴到config/application.yml的alipay.app-private-key字段,注意删除换行并转义反斜杠;
  2. 微信支付平台证书:登录 pay.weixin.qq.com → 进入「API 安全」→ 下载「平台证书」→ 将.pem文件放入config/cert/wechat/目录,并在wechat.platform-cert-path中填写相对路径;
  3. QQ 钱包 & 翼支付 & 云闪付的 AppKey/AppSecret:这三家无沙箱,需用真实测试账号申请。若暂无,可先注释掉payment-qq等模块的@ComponentScan,只保留支付宝和微信启动验证流程。
# config/application.yml 片段 alipay: app-id: 2021000123456789 app-private-key: "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7..." alipay-public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu..." notify-url: "http://localhost:8080/notify/alipay" return-url: "http://localhost:8080/return/alipay"

2.3 用 curl 发起第一笔模拟支付:验证网关是否真正就绪

服务启动成功后(日志出现Started PaymentWebApplication in X.XXX seconds),执行以下命令发起一笔支付宝沙箱支付:

curl -X POST http://localhost:8080/pay/unified \ -H "Content-Type: application/json" \ -d '{ "channel": "alipay", "outTradeNo": "TEST20240520001", "subject": "测试商品", "totalAmount": 0.01, "notifyUrl": "http://localhost:8080/notify/alipay", "returnUrl": "http://localhost:8080/return/alipay" }'

预期返回:

{ "code": 200, "data": { "payUrl": "https://openapi.alipaydev.com/gateway.do?..." } }

逻辑说明:/pay/unified是统一支付入口,它根据channel参数动态选择PayChannel实现类(如AlipayChannel),组装请求参数,调用对应 SDK,最终返回支付跳转链接。totalAmount单位为元,支付宝沙箱要求 ≥0.01,否则返回INVALID_PARAMETER。

若返回500且日志报java.lang.NullPointerException at AlipayChannel.createOrder,大概率是app-private-key格式错误(常见于 Windows 记事本保存导致 BOM 头残留);若返回400且提示channel not supported,检查payment-alipay模块是否被正确引入(确认pom.xml中<module>payment-alipay</module>未被注释)。


3. 对接话费慢充、小荷包零钱、口令支付:非标能力的落地姿势

标题里“话费慢充”“小荷包零钱”“口令支付”不是营销话术,而是真实存在的、非银联/网联标准的支付延伸能力。它们不走通用支付协议,而是各家平台为特定场景定制的 API。这个项目把它们封装成PayType枚举,并在UnifiedPayService中做了路由分发。

3.1 话费慢充:为什么叫“慢充”?以及如何用支付宝接口实现

“慢充”指话费充值订单不即时到账,而是 T+1 或 T+2 批量结算。支付宝提供alipay.fund.trans.toaccount.transfer(单笔转账)和alipay.fund.trans.batch.transfer(批量转账)两个接口,但话费慢充实际调用的是其内部 B2B 渠道alipay.ebpp.recharge.item.pay—— 这个接口不对外开放文档,仅对签约话费运营商的 ISV 开放。本项目中,它被抽象为PayType.PHONE_SLOW_CHARGE,并在AlipayChannel中通过反射调用隐藏方法:

// payment-alipay/src/main/java/com/ushen/pay/alipay/AlipayChannel.java private String buildPhoneSlowChargeRequest(PayOrder order) { AlipayEbppRechargeItemPayRequest request = new AlipayEbppRechargeItemPayRequest(); request.setBizContent("{" + "\"item_id\":\"" + order.getExtParam("itemId") + "\"," + // 运营商分配的商品 ID,如 10086-CMCC-10 "\"mobile\":\"" + order.getExtParam("mobile") + "\"," + "\"amount\":\"" + order.getTotalAmount() + "\"" + "}"); // 注意:此处需使用支付宝分配的特殊 app_id,非普通沙箱 app_id request.putOtherTextParam("app_id", "2088123456789012"); return request; }

参数说明:itemId是关键,它由支付宝为你对接的运营商(移动/联通/电信)提供,格式如10086-CMCC-10(10 元面值);mobile必须为 11 位纯数字;app_id是支付宝为你单独开通的“话费充值专用 appId”,需邮件申请,不能复用普通支付 appId。

3.2 小荷包零钱:微信支付的“子账户”能力如何透出

“小荷包”是微信支付为商家提供的子账户体系,用于分账、资金归集或员工备用金。本项目将其映射为PayType.WECHAT_SUB_WALLET,调用微信支付 V3 的/v3/transfer/batches接口:

// payment-wechat/src/main/java/com/ushen/pay/wechat/WechatChannel.java public String createSubWalletTransfer(TransferOrder order) { // 构造微信子账户转账请求体 JsonObject body = new JsonObject(); body.addProperty("batch_no", order.getOutBatchNo()); // 商户自定义批次号 body.addProperty("batch_name", "小荷包充值"); body.addProperty("total_amount", (int)(order.getTotalAmount() * 100)); // 单位:分 body.addProperty("transfer_detail_list", buildDetailList(order.getDetails())); // 关键:指定 sub_mchid 为小荷包子商户号 String url = String.format("https://api.mch.weixin.qq.com/v3/transfer/batches?sub_mchid=%s", order.getExtParam("subMchId")); return wechatHttpClient.post(url, body.toString()); }

参数说明:subMchId是你在微信支付商户平台开通“小荷包”功能后获得的子商户号,格式为1900000100;transfer_detail_list是 JSON 数组,每个元素含transfer_out_no(子账户流水号)、amount(金额分)、openid(用户 openid);微信要求batch_no全局唯一,建议用UUID.randomUUID().toString().replace("-", "")生成。

3.3 口令支付:QQ 钱包的“扫码口令”如何生成与核销

QQ 钱包的口令支付(又称“扫码口令”)是一种无需用户安装 App 即可完成支付的方式:用户输入 6 位数字口令,QQ 钱包后台校验后直接扣款。本项目通过PayType.QQ_PASSWORD_PAY触发:

// payment-qq/src/main/java/com/ushen/pay/qq/QqChannel.java public String generatePasswordPayCode(PayOrder order) { QqPasswordPayRequest request = new QqPasswordPayRequest(); request.setAppId(qqConfig.getAppId()); request.setNonceStr(UUID.randomUUID().toString().replace("-", "")); request.setTimestamp(String.valueOf(System.currentTimeMillis() / 1000)); request.setOutTradeNo(order.getOutTradeNo()); request.setTotalFee((int)(order.getTotalAmount() * 100)); request.setSpbillCreateIp("127.0.0.1"); // 生成签名(QQ 钱包要求 HMAC-SHA256) String sign = HmacUtils.hmacSha256Hex(qqConfig.getAppKey(), "appid=" + request.getAppId() + "&nonce_str=" + request.getNonceStr() + "&out_trade_no=" + request.getOutTradeNo() + "&spbill_create_ip=" + request.getSpbillCreateIp() + "&timestamp=" + request.getTimestamp() + "&total_fee=" + request.getTotalFee()); request.setSign(sign); return qqHttpClient.post("https://qpay.qq.com/cgi-bin/qpay/create_password_pay.cgi", request.toXml()); }

参数说明:total_fee单位为分;nonce_str必须为 32 位随机字符串;sign是整个请求参数拼接后用appKey做 HMAC-SHA256 加密,再 hex 编码;返回结果含pay_code(6 位口令)和expire_time(口令有效期,单位秒),前端需倒计时提醒用户。


4. 免签通道的真相与边界:什么能做,什么坚决不能碰

标题中“提供免签通道”是高频搜索词,也是最容易引发误解的点。必须明确:这里没有“绕过监管”的技术,只有“合规借用 ISV 能力”的工程实践。所谓“免签”,是指本项目作为已通过微信/支付宝/QQ 钱包等平台认证的第三方服务商(ISV),允许下游个人开发者或小微商户,以“代调用”方式使用其支付能力,而无需自己申请商户号。这合法,但有严格边界。

4.1 免签通道的三种合法形态:你只能选其一

形态适用场景技术实现合规要点
ISV 代调用(推荐)你是一家 SaaS 公司,客户是理发店、奶茶店等小微商户在payment-web中配置客户专属subMerchantId,所有支付请求带上该 ID必须与平台签订《ISV 代调用协议》,且客户需在你后台完成实名认证(姓名+身份证+银行卡四要素)
沙箱环境直连仅用于开发测试,不涉及真实资金使用支付宝/微信沙箱账号,app_id为沙箱分配值沙箱交易不产生真实资金流,不可用于演示给客户看
测试商户号白名单你有多个测试用的个体户营业执照,已通过平台初审将测试商户号加入平台白名单,项目中切换app_id白名单需平台人工审核,周期 3-5 个工作日,且仅限测试,不可上线

注意:不存在“永久免签”“无需任何资质”的通道。所有声称“0 门槛免签”的方案,要么是沙箱(无效),要么是黑产(违法)。本项目只实现第一种——ISV 代调用。

4.2 代调用必须拦截的三个高危操作:否则会被封禁

即使你已签约 ISV,以下操作仍会导致平台风控拦截,甚至终止合作:

  1. 禁止透传用户银行卡信息:payment-web的UnifiedPayController中,PayOrder对象严禁包含bankCardNo、idCardNo、cvv等字段。所有敏感信息必须由前端调用平台 SDK(如微信wx.chooseInvoice)获取,后端只接收加密后的pay_data。
  2. 禁止修改订单金额:AlipayChannel.createOrder()方法内,totalAmount必须与数据库中pay_order表的amount字段完全一致。任何amount * 1.05类型的手续费加价,都会触发支付宝的“金额篡改”告警。
  3. 禁止伪造用户行为:QqChannel.generatePasswordPayCode()返回的pay_code有效期仅 5 分钟,且同一out_trade_no仅可生成一次。若前端反复点击“重新获取口令”,后端必须拒绝,返回{"code":400,"msg":"口令已生成,请勿重复提交"}。

4.3 如何自查是否踩线:用平台提供的“调用日志”反向验证

支付宝开放平台 → 进入「研发服务」→ 「调用日志查询」,筛选你使用的app_id,查看最近 100 条调用记录。重点检查:

  • response_code是否大量出现40001(签名错误)、40002(参数错误)、40004(业务规则错误);
  • call_source是否为ISV(而非SELF),确认走的是代调用链路;
  • biz_content中是否出现bank_card_no、id_card等明文字段(如有,立即下线相关接口)。

微信支付商户平台 → 「数据中心」→ 「API 调用明细」,同样筛选sub_mchid,检查err_code是否频繁出现SYSTEMERROR(通常因证书过期)或INVALID_REQUEST(参数非法)。


5. 生产环境必调的 5 个参数:从本地能跑通到线上稳如磐石

本地curl通只是万里长征第一步。当你要把服务部署到阿里云 ECS 或腾讯云 CVM 上,并接入真实商户时,以下 5 个参数必须手工调整,缺一不可。它们分散在application.yml、Nginx 配置、JVM 启动参数中,新手常因忽略其中某一项导致线上支付失败。

5.1server.tomcat.max-connections:为什么 200 不够用?

支付宝/微信的异步通知(notify)是高频短连接:一笔支付成功,平台会连续发起 3-5 次回调,确保你收到。若 Tomcat 连接数上限设为默认 200,当并发支付量 >50 笔/秒时,通知请求就会排队超时,导致“用户已付款,你没收到通知”的资损事故。

# config/application-prod.yml server: tomcat: max-connections: 10000 # 生产环境建议 5000~10000 accept-count: 500 # 当连接数满时,最多排队 500 个请求 max-threads: 500 # 最大工作线程数,建议 = max-connections * 0.8

逻辑说明:max-connections是 Tomcat 能同时处理的 TCP 连接总数;accept-count是连接队列长度;max-threads是实际处理请求的线程池大小。三者需按比例设置,否则会出现“连接被拒绝”或“线程饿死”。

5.2wechat.http-client.timeout:微信平台证书下载失败的根源

微信支付 V3 要求每次调用前,自动下载并校验平台证书。若服务器 DNS 解析慢或网络抖动,证书下载超时(默认 5 秒)会导致整个支付请求失败。必须显式延长:

# config/application-prod.yml wechat: http-client: connect-timeout: 10000 # 连接超时:10 秒 read-timeout: 30000 # 读取超时:30 秒 write-timeout: 10000 # 写入超时:10 秒

参数说明:connect-timeout是建立 TCP 连接的时间;read-timeout是从 socket 读取响应体的时间;write-timeout是向 socket 写入请求体的时间。微信证书下载 URL(https://api.mch.weixin.qq.com/v3/certificates)有时响应慢,30 秒是安全底线。

5.3alipay.notify-thread-pool.size:异步通知的线程池不能共享主业务线程池

支付宝通知接口/notify/alipay是无状态的,但需快速响应success字符串,否则平台会重试。若你把通知请求丢进@Async默认线程池(与下单、查询共用),当主业务线程池打满时,通知将无限排队,最终超时。

// payment-web/src/main/java/com/ushen/pay/config/NotifyThreadPoolConfig.java @Configuration public class NotifyThreadPoolConfig { @Bean("alipayNotifyExecutor") public Executor alipayNotifyExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); // 核心线程数 executor.setMaxPoolSize(50); // 最大线程数 executor.setQueueCapacity(1000); // 队列容量 executor.setThreadNamePrefix("alipay-notify-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }
// 在 NotifyController 中指定线程池 @Async("alipayNotifyExecutor") @PostMapping("/notify/alipay") public void handleAlipayNotify(@RequestBody String notifyData) { // 验签、更新订单状态、发送消息... }

5.4logging.level.com.ushen.pay=DEBUG:生产环境日志级别必须精确到模块

支付系统最怕“日志太多看不出问题”或“日志太少无法定位”。建议分层设置:

# config/application-prod.yml logging: level: root: INFO com.ushen.pay: DEBUG # 核心支付逻辑,输出请求/响应体 com.ushen.pay.alipay: TRACE # 支付宝模块,输出签名原文、加密后字符串 com.ushen.pay.wechat: TRACE # 微信模块,输出证书指纹、AES 解密过程 org.apache.http.wire: OFF # 关闭 HTTP 底层日志,避免泄露密钥

提示:TRACE级别会打印敏感信息(如私钥摘要),仅在排查问题时临时开启,问题解决后立即关闭。

5.5 JVM 启动参数:-Xmx 与 -XX:+UseG1GC 的黄金组合

支付网关是典型的 I/O 密集型服务,GC 停顿直接影响通知时效性。实测表明,-Xmx2g -XX:+UseG1GC是 4C8G 云服务器的最优解:

# 启动脚本 start.sh java -Xms2g -Xmx2g \ -XX:+UseG1GC \ -XX:MaxGCPauseMillis=200 \ -XX:+PrintGCDetails \ -Xloggc:/var/log/payment/gc.log \ -jar payment-web.jar --spring.profiles.active=prod

参数说明:-Xms2g -Xmx2g设堆内存为固定 2GB,避免 GC 时动态扩容;-XX:+UseG1GC启用 G1 垃圾收集器,适合大堆内存;-XX:MaxGCPauseMillis=200设定最大停顿时间目标为 200ms;-Xloggc将 GC 日志输出到独立文件,便于监控。


6. 我踩过的最深一个坑:支付宝异步通知验签时,charset参数引发的血泪经验

这事发生在我给某高校社团做活动报名系统时。系统上线三天,一切正常,第四天凌晨 2 点,支付宝突然停止发送通知,订单状态全部卡在“待支付”。我翻遍日志,发现/notify/alipay接口返回了500,但错误信息只有一行:java.security.SignatureException: Signature length not correct。

查了 6 小时,最终定位到AlipayNotifyService.verifyNotify()方法里这一行:

// 错误写法:从 request.getParameterMap() 获取参数,再拼接验签字符串 Map<String, String[]> parameterMap = request.getParameterMap(); String content = AlipaySignature.getSignCheckContent(parameterMap); boolean verified = AlipaySignature.rsaCheckV1(content, sign, alipayPublicKey, "UTF-8");

问题在于:request.getParameterMap()会自动对 URL 参数进行ISO-8859-1解码,而支付宝通知的notify_data字段是 XML,其中的中文(如<subject>测试商品</subject>)被错误解码成乱码,导致content字符串与支付宝原始签名原文不一致,验签必然失败。

正确解法是:放弃getParameterMap(),直接读取原始请求体,并手动指定 UTF-8 解码:

// 正确写法:读取原始 InputStream StringBuilder buffer = new StringBuilder(); BufferedReader reader = request.getReader(); String line; while ((line = reader.readLine()) != null) { buffer.append(line); } String rawBody = buffer.toString(); // 此时 rawBody 是原始 UTF-8 字符串 // 解析 XML,提取 biz_content Document doc = Jsoup.parse(rawBody, "", Parser.xmlParser()); Elements nodes = doc.select("notify"); if (!nodes.isEmpty()) { String bizContent = nodes.get(0).select("biz_content").text(); // bizContent 已是正确 UTF-8,可直接用于验签 boolean verified = AlipaySignature.rsaCheckV1( "notify_data=" + bizContent, // 注意:验签原文必须是 notify_data=xxx 形式 sign, alipayPublicKey, "UTF-8" ); }

教训:所有支付平台的异步通知,其请求体都是原始字节流,绝不能依赖容器的getParameterXXX()方法。微信通知、QQ 钱包通知同理。我把这个逻辑封装成了RawBodyHelper.readRawBody(request),现在所有通知接口第一行就是它。

另一个血泪经验:支付宝沙箱的sign_type固定为RSA2,但正式环境可能为RSA(老商户)或SM2(国密升级),必须在application.yml中配置alipay.sign-type,并在AlipaySignature.rsaCheckV1()调用时传入,不能写死。

希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 3:27:54

Java3D加载MS3D模型:从二进制解析到骨骼动画实战

简介&#xff1a;该加载器面向使用Java三维库的开发者&#xff0c;用于将常见的MS3D模型文件完整解析成可交互的三维场景&#xff0c;解决游戏开发或可视化项目中模型导入与动画驱动的问题。整个压缩包共包含3个文件&#xff0c;其中Java源码负责实现解析与转换逻辑&#xff0c…

作者头像 李华
网站建设 2026/10/13 3:27:16

合工大NLP实验包:HMM/CRF/LSTM中文任务实操指南

简介&#xff1a;本资源是合肥工业大学孙晓老师主讲的自然语言处理&#xff08;NLP&#xff09;课程配套实验资料包&#xff0c;面向高校计算机、人工智能及相关专业本科生与NLP初学者&#xff0c;聚焦词法分析、命名实体识别、情感分析、文本分类等核心任务的原理理解与工程实…

作者头像 李华
网站建设 2026/10/13 3:27:15

Code::Blocks 17.12:嵌入式开发与教学场景下的轻量可靠IDE方案

简介&#xff1a;本资源为开源C/C集成开发环境Code::Blocks 17.12的完整安装包&#xff08;codeblocks17.12.zip&#xff09;&#xff0c;面向初学者、嵌入式开发者及高校编程教学场景&#xff0c;解决跨平台C项目开发、调试与构建的一站式环境搭建问题。压缩包共2000个文件&am…

作者头像 李华
网站建设 2026/10/13 3:27:00

Python中元组的基础介绍及常用操作总结

前言 元组&#xff08;tuple&#xff09;是 Python 的内置序列类型之一&#xff0c;和列表长得很像&#xff0c;区别只有一个&#xff1a;元组不可变。创建之后不能增、不能删、不能改&#xff0c;任何看起来在「修改」元组的操作&#xff0c;实际都是新建了一个元组。正因为不…

作者头像 李华
网站建设 2026/10/13 3:26:14

STM32C5与CubeMX2实测:低功耗MCU与安全底座的新选择

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华