简介面向使用Nacos 2.2.0及以上版本的微服务开发者这份资源提供了一种基于SPI机制为Nacos添加PostgreSQL数据源支持的插件实现。它解决了默认仅支持MySQL等数据库时Spring应用在切换数据源过程中需要改动核心代码的痛点用户只需替换springdatasource.zip即可完成数据库适配。压缩包共22个文件大小约53KB以13个Java源码文件为主辅以pom.xml、SQL初始化脚本及README等覆盖插件接入、建表与配置说明结构紧凑便于快速排查与二次开发。包内附赠文档和说明文件分别介绍了安装步骤与设计原理有助于理解SPI加载流程及数据源扩展方式。该资源已有267人学习下载既可用于生产环境快速集成也可作为面试中考察SPI机制、Nacos扩展点与模块化改造的实战参考材料。1. Nacos 只认 MySQL 和 Derby这份 PostgreSQL 插件让它不用改源码Nacos 从 2.2.0 开始引入数据源插件机制但官方文档里只给了 MySQL 和内置 Derby 的配置样例。实际生产环境已经有 PostgreSQL 基础设施的团队想换库第一反应要么改源码重新编译要么在 Spring 配置里硬塞一个 PG 驱动碰运气。这个数据源插件包把这条路走通了通过 SPI 机制扩展 Nacos 的数据源加载逻辑插件 jar 放进 plugins 目录、改几行 spring.datasource 配置PostgreSQL 就能成为配置中心的后端存储。适合正在搭微服务配置中心、数据库选型定在 PG、又不想维护 Nacos 魔改分支的团队。下面我把拆包、安装、迁移和排错的过程完整过一遍。2. SPI 插件的生效原理数据源加载路径与配置命中逻辑2.1 存储层抽象Derby、MySQL 与第三方数据源Nacos 的存储层在 2.x 里主要分两块内部运维数据用户、角色、权限和业务数据配置、历史配置、标签关系都走数据库。默认情况下单机模式内嵌 Derby这是 Nacos 自带的关系型数据库启动零依赖但数据落在本地文件里重启容易丢、多实例没法共享。官方要求集群模式必须接 MySQL这就把一批基础设施里没有 MySQL、或者 DBA 审批流程很长的团队挡在门外。PostgreSQL 在很多团队里其实是比 MySQL 更顺手的选型问题在于 Nacos 的核心代码里没有针对 PostgreSQL 的实现。在这种情况下2.2.0 开始引入的数据源插件机制就是正解。它的做法是把数据源实现从核心代码里剥出去定义好接口之后第三方通过 SPI 在运行时把实现类注册进来。好处是核心代码一点不碰、官方小版本升级能无缝跟进坏处是很多人不知道插件 jar 该放哪、配置项该怎么写导致插件明明装上了却不生效。这里要纠正一个常见误解很多人以为把 PostgreSQL JDBC 驱动扔进 Nacos 的 lib 目录、再把 spring.datasource.url 改成 jdbc:postgresql:// 就能跑起来。实际上 Nacos 的数据源加载器是按 platform 配置去 SPI 候选列表里挑实现的驱动只是底层的连接工具没有对应的插件实现类光有驱动等于没带钥匙。2.2 插件包结构jar 位置、SPI 声明与 classpath 加载顺序解压这个插件 zip 之后目录结构通常是这样的nacos-postgresql-plugin/ ├── lib/ │ ├── nacos-postgresql-datasource-plugin-1.0.0.jar │ └── postgresql-42.5.1.jar ├── conf/ │ └── postgresql-schema.sql └── README.md安装第一阶段不用关心插件内部怎么实现的先按三步走# 1. 把插件 jar 和 PG 驱动放到 nacos 的 plugins 目录 cp lib/*.jar $NACOS_HOME/plugins/ # 2. 把建表 SQL 放到 conf 目录后面手动执行 cp conf/postgresql-schema.sql $NACOS_HOME/conf/ # 3. 修改 application.properties 里的数据源配置提示plugins 目录如果不存在就手动建一个目录名不要写错。插件 jar 和 JDBC 驱动都要放进去只放插件不放驱动启动时会直接报 ClassNotFoundException只放驱动不放插件加载阶段就会报 No plugin found。关于加载顺序Nacos 在启动时会扫描 plugins 目录下的 jar用 SPI 方式读取 jar 内 META-INF/services 目录下的实现类声明。插件 jar 里有一个以 Nacos 扩展接口全限定名命名的文本文件内容是实现类的完整类名。Nacos 启动时把这个实现类和内置的 MySQL 实现放在同一个候选集合里最终通过 spring.datasource.platform 这个配置项决定用谁。所以插件放错位置、SPI 声明文件在打包时丢失、或者配置项没配对哪怕代码完全正确运行时也绕不过去。这个阶段最容易翻车的点在于Nacos 的 plugins 目录不是单纯的 classpath 扩充目录它是在数据源插件加载阶段被专门扫描的。如果你图省事把插件 jar 塞进 lib 目录而不是 plugins 目录SPI 扫描器根本看不到它日志里也不会有明确报错表现就是配置项写了像没写一样。2.3 配置项如何命中插件spring.datasource.platform 的判定规则关键就四行配置。下面是一个能直接用的 application.properties 片段### 指定数据源平台插件按这个值注册实现 spring.datasource.platformpostgresql ### JDBC 驱动类必须是 org.postgresql 开头 spring.datasource.driver-class-nameorg.postgresql.Driver ### 连接串字符编码显式指定 UTF8 spring.datasource.urljdbc:postgresql://127.0.0.1:5432/nacos?characterEncodingutf8connectTimeout3000socketTimeout3000autoReconnecttrue ### 数据库账号密码 spring.datasource.usernamenacos spring.datasource.passwordnacos123逐项解释。spring.datasource.platform 是命中插件的唯一标识插件实现类在注册时会声明自己支持哪个 platform 值Nacos 启动时根据这个值去找对应实现不会出现自动探测数据库类型这种事。driver-class-name 和 url 是连接数据库用的PostgreSQL 这边有个细节characterEncodingutf8 要显式写省得中文配置出现乱码再去猜原因connectTimeout 和 socketTimeout 建议设上否则数据库短暂不可用时Nacos 的连接池会一直挂起配置中心整个变卡。连接池参数也可以透传Nacos 底层用的是 HikariCP如果 PG 连接数不够用可以追加spring.datasource.hikari.maximum-pool-size20 spring.datasource.hikari.minimum-idle5这两个参数跟 PostgreSQL 的 max_connections 要对齐不要盲目调大。Nacos 集群模式下每个节点都会占连接节点数乘以 maximum-pool-size 不能超过 PG 的 max_connections否则会出现连接拒绝表现就是配置中心间歇性不可用。3. 接入 PostgreSQL安装步骤、参数配置与初始化建表3.1 前置检查版本对应关系动手前先确认三件事Nacos 版本、对应插件版本、PostgreSQL 版本。我见过最典型的翻车是没有看版本在 Nacos 2.1.x 上装了 2.2.0 的插件结果启动后配置完全不生效连报错都没有。版本对应关系大体是Nacos 2.2.0 及以上才有插件机制装这个 PG 插件没问题Nacos 1.x 完全没有插件机制要么升级 Nacos 要么放弃 PGPostgreSQL 10 以上基本都行PG 驱动选 42.x 系列跟 Java 8 兼容性最好。另外确认一下运行环境。Nacos 2.2.x 官方支持 JDK 8如果你跑在 JDK 17 上PG 驱动版本要选新一点的老驱动在 JDK 17 下会报模块访问错误。检查命令如下# 检查 Nacos 版本 cat $NACOS_HOME/VERSION 2/dev/null || ls $NACOS_HOME/lib/nacos-server*.jar # 检查 JDK 版本 java -version # 确认 plugins 目录可写 ls -ld $NACOS_HOME/plugins 2/dev/null || echo plugins dir not exists最后一条命令会提示 plugins 目录是否存在不存在就手动建。很多部署包默认没有这个目录这是正常的建好即可。3.2 安装解压、放 jar、改配置三件事安装动作就三步做完这三件事插件的安装就完成了。unzip nacos-postgresql-plugin.zip -d /tmp/nacos-pg-plugin cp /tmp/nacos-pg-plugin/lib/*.jar $NACOS_HOME/plugins/ cp /tmp/nacos-pg-plugin/conf/postgresql-schema.sql $NACOS_HOME/conf/第一行解压插件包到临时目录第二行把插件 jar 和 PG 驱动一次性复制过去第三行把建表脚本放到 conf 目录备用。接下来编辑 conf/application.properties在文件末尾追加或者替换原有的数据源配置段。如果你之前配置过 MySQL要把 spring.datasource.platform 从 mysql 改成 postgresqlurl 整个换掉driver-class-name 也要换。这里最容易踩的坑是只改了 url 和 driver忘了改 platform结果 Nacos 还是按 MySQL 的路径去加载。3.3 初始化数据库先建库再建表PostgreSQL 侧需要提前准备好数据库和账号用超级用户执行CREATE DATABASE nacos ENCODING UTF8 LC_COLLATE en_US.UTF-8 LC_CTYPE en_US.UTF-8 TEMPLATE template0; CREATE USER nacos WITH PASSWORD nacos123; GRANT ALL PRIVILEGES ON DATABASE nacos TO nacos; GRANT ALL ON SCHEMA public TO nacos;注意顺序问题。GRANT ALL PRIVILEGES ON DATABASE 只授权到数据库层面表级别的建表权限需要在 schema 上授权所以最后一条 GRANT ALL ON SCHEMA public 不能省。如果漏了启动时执行建表脚本会报 permission denied for schema public。如果公司规范不允许开放 public schema也可以新建独立 schema比如 nacos_config然后在连接串后面加 currentSchemanacos_config同时把建表脚本里的表名都加上 schema 前缀。建表脚本执行方式psql -h 127.0.0.1 -U nacos -d nacos -f $NACOS_HOME/conf/postgresql-schema.sql执行成功会输出一串 CREATE TABLE 和 CREATE INDEX。中间如果看到 ERROR 后跟 already exists说明之前建过表了可以继续往下走不影响启动。3.4 启动验证日志特征与 Open API 快速探测启动方式跟官方一致单机模式用sh $NACOS_HOME/bin/startup.sh -m standalone日志里盯两个地方。第一是启动日志前半段出现连接 PostgreSQL 的初始化信息说明数据源插件加载成功第二是启动日志末尾出现 Nacos started successfully 才算真正起来。如果启动失败了直接看 logs/start.out 里有没有 Failed to load datasource 或 No plugin of type dataSource found 这类关键报错再对照第 5 章的排错记录处理。起来之后用 Open API 做一次最小验证curl -X POST http://127.0.0.1:8848/nacos/v1/cs/configs \ -d dataIdtest001groupDEFAULT_GROUPcontenthello-from-pg然后用 psql 查询数据库确认这条配置真实写入了 PostgreSQLpsql -h 127.0.0.1 -U nacos -d nacos -c \ SELECT data_id, content, gmt_modified FROM config_info WHERE data_idtest001;如果能看到 content 是 hello-from-pg说明这条配置已经落进 PG插件生效了。这个最小验证是我每次装完插件必做的一步防止Nacos 起来了但数据其实还在 Derby的假象。4. 数据迁移从 MySQL 搬到 PostgreSQL 的表结构差异与一致性校验4.1 核心表字段对照Nacos 的存储模型里最核心的表是 config_info当前配置、config_history发布历史、his_config_info历史变更、config_tags_relation标签关系和 tenant_info命名空间。MySQL 环境下这些表由官方 schema.sql 建好到 PostgreSQL 里插件包自带的建表脚本已经在语法上做了转换但字段类型有差异搬数据前要对齐。逻辑字段MySQL 类型PostgreSQL 类型注意事项idbigint(20)bigintPG 没有 AUTO_INCREMENT用序列或 bigserialcontentlongtexttext存配置内容PG 的 text 无长度限制md5varchar(32)varchar(32)存内容哈希客户端本地缓存依赖它gmt_modifiedtimestamptimestampPG 没有 ON UPDATE 自动更新时间戳data_idvarchar(255)varchar(255)PG 对未加引号的表名自动转小写tenant_idvarchar(128)varchar(128)注意空字符串与 NULL 在查询时不等价重点说 gmt_modified。MySQL 表定义里经常写gmt_modified timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPPostgreSQL 不支持 ON UPDATE 子句插件建表脚本里会去掉这个逻辑。Nacos 本身的 SQL 是显式写入时间戳的影响不大但如果你自己写脚本往表里灌数据得记得手动更新这个字段否则会出现配置内容变了但修改时间没变的怪象。另外注意 PG 的表名大小写规则。Nacos 的表名都是小写这个没问题但如果你从 MySQL 导出的建表脚本里带着反引号和驼峰命名到 PG 里要么去掉反引号要么给表名加双引号否则会报 syntax error。插件自带的建表脚本已经处理好了直接用它即可。4.2 数据搬运方案SQL 转换与幂等写入从 MySQL 往 PG 搬配置数据最稳妥的做法不是 binlog 同步也不是图形化工具直连迁移而是先在目标库把表结构建好然后按主键分批查出来、再分批写入 PG。原因很简单Nacos 的配置表之间有历史表和标签表的关联直接倒数据容易把关联关系弄丢而分批写入可以控制进度、随时重试。# 在 MySQL 里导出 config_info 为 TSV mysql -h mysql_host -u root -p nacos -e \ SELECT id, data_id, group_id, tenant_id, app_name, content, md5, gmt_create, gmt_modified FROM config_info \ config_info.tsv # 用 psql copy 导入 PG psql -h 127.0.0.1 -U nacos -d nacos \ -c \copy config_info(id, data_id, group_id, tenant_id, app_name, content, md5, gmt_create, gmt_modified) FROM config_info.tsv WITH (FORMAT csv, DELIMITER E\t, NULL NULL)这个方案有两个细节。第一导出 SQL 里必须显式写列名不要用 SELECT *。因为 MySQL 和 PG 的系统表列顺序不一定一致直接 SELECT * 导出再导入容易出现 md5 串到 group_id 上去还不报错的惨剧。第二md5 字段一定要带上。Nacos 客户端的本地缓存校验依赖这个字段如果只是把 content 搬过去、md5 没搬计算出来的内容哈希跟库里存的对不上客户端会一直认为本地缓存是最新的永远拉不到更新。4.3 用 Python 脚本做迁移一致性校验搬运完不能只凭日志里没有 ERROR 就收工。我习惯用一个 Python 脚本做双端校验把 MySQL 和 PG 的表数据分别读出来按 data_id、group_id、tenant_id 组成联合键对比内容哈希。import hashlib import psycopg2 import pymysql PG_DSN dict(host127.0.0.1, port5432, dbnamenacos, usernacos, passwordnacos123) MY_DSN dict(host127.0.0.1, port3306, userroot, passwordchangeit, databasenacos, charsetutf8mb4) def load_rows(conn_config, is_pg): if is_pg: conn psycopg2.connect(**conn_config) else: conn pymysql.connect(**conn_config) cur conn.cursor() cur.execute( SELECT data_id, group_id, tenant_id, content, md5 FROM config_info ) rows cur.fetchall() cur.close() conn.close() return rows def digest(rows): d {} for data_id, group_id, tenant_id, content, md5 in rows: key (data_id or , group_id or , tenant_id or ) sha hashlib.md5((content or ).encode(utf-8)).hexdigest() d[key] (md5 or ).upper(), sha.upper() return d pg digest(load_rows(PG_DSN, is_pgTrue)) my digest(load_rows(MY_DSN, is_pgFalse)) mismatch 0 for key, (md5_db, md5_calc) in my.items(): if key not in pg: print(MISSING in PG:, key) mismatch 1 else: pg_md5_db, pg_md5_calc pg[key] if pg_md5_db ! md5_db: print(MD5 mismatch for, key, mysql:, md5_db, pg:, pg_md5_db) mismatch 1 print(total:, len(my), mismatch:, mismatch)逻辑说明脚本先从 MySQL 和 PG 分别读出配置表的主键字段和内容字段两边都按 data_id、group_id、tenant_id 组成联合键再用内容重新计算一次 MD5分别跟库里存的值以及对方库的值做对比。这样可以同时抓到两类问题内容被改过但库里 md5 没更新以及迁移过程中字段串位。参数说明is_pg 参数用于切换连接方式两种数据库的客户端库不一样digest 函数里 key 中 tenant_id 用空字符串兜底考虑到 MySQL 里存的是空字符串而 PG 里可能是 NULL联合键对不上时脚本会输出 MISSING。迁移完成后这个脚本输出应该是 total 两边一致、mismatch 为 0。5. 接入 PostgreSQL 避坑五条典型排错记录5.1 启动报 No plugin of type dataSource found现象Nacos 启动后start.out 里出现 No plugin of type dataSource found进程直接退出。原因最常见的是插件 jar 没放进 plugins 目录Nacos 在 SPI 扫描时找不到任何候选实现其次是 Nacos 版本低于 2.2.0插件机制不存在配置项被直接忽略连报错提示都没有。解决先确认版本在 2.2.0 以上再看 plugins 目录里有没有 jarls -l $NACOS_HOME/plugins/ unzip -p $NACOS_HOME/plugins/nacos-postgresql-datasource-plugin-1.0.0.jar META-INF/services/* 2/dev/null | head -20第二条命令用于检查插件 jar 里的 SPI 声明文件在打包时有没有丢失。如果看到插件文件存在但输出为空说明 jar 打包有问题换个包再试。5.2 中文配置乱码数据库编码不是 UTF8现象配置中心里发一条中文配置控制台显示正常但客户端拉下来变成一串问号或乱码。原因PostgreSQL 数据库创建时没有指定 UTF8 编码默认用了 SQL_ASCII 或 LATIN1Nacos 写入的 UTF8 字节被数据库按错误编码解释读出来自然就乱了。解决建库时显式指定编码用第 3 章那段 CREATE DATABASE ... ENCODING UTF8 重建。已经建过的库先检查psql -h 127.0.0.1 -U nacos -d nacos -c SHOW server_encoding;如果输出不是 UTF8把数据备份后重建数据库再灌回去。这个坑在测试环境最容易混过去因为纯英文配置内容看不出编码问题一旦有中文才发现所以初始化数据库时编码检查一定要做。5.3 建表权限不足permission denied for schema public现象启动或执行建表脚本时报错日志里有 permission denied for schema public。原因PostgreSQL 默认把数据库的 public schema 授权给 PUBLIC 角色但有些托管环境或 DBA 收紧了默认权限业务账号没有建表权限。前面 GRANT ALL PRIVILEGES ON DATABASE 只授权到数据库级没解决 schema 级问题。解决用超级用户执行GRANT ALL ON SCHEMA public TO nacos;如果公司规范不允许开放 public schema就新建独立 schema比如 nacos_config然后在连接串后面加上 currentSchemanacos_config建表脚本里的表名也要加 schema 前缀。这个问题在本地环境几乎不会遇到但换到托管环境就很常见建议第一次连接 PG 时先执行这条 SQL 探路。5.4 三个节点两个用的是 Derby现象Nacos 集群部署三台机器都能登录控制台但节点 A 发布的配置其他节点查不到重启后部分配置还丢了。原因集群模式下有的节点 application.properties 没改对仍然在用默认的 Derby 存储。控制台能登录不代表数据进了 PG每台机器各自为政数据自然不一致。解决逐台检查 spring.datasource.platform 和 spring.datasource.url确认所有节点指向同一个 PG 库。检查办法是直接连 PG 执行psql -h 127.0.0.1 -U nacos -d nacos -c SELECT count(*) FROM config_info;然后向某个节点发布一条测试配置再查一次 count如果数量没变说明那个节点根本没写 PG重点检查它的配置。这个检查在扩节点时尤其重要新加节点最容易带着默认配置就加入集群。5.5 配置发布成功但客户端拉取不到现象Open API 发布配置返回 true控制台也能看到但客户端第二次拉取拿的还是旧值。原因Nacos 客户端有本地缓存和先本地后远端的容错逻辑如果测试时客户端进程没重启local_cache 里的旧数据会一直生效。另外控制台的读取走的是服务端接口不走客户端缓存所以你会看到两边结果不一致。解决先排除客户端缓存因素用 curl 强制拉一次服务端数据curl http://127.0.0.1:8848/nacos/v1/cs/configs?dataIdtest001groupDEFAULT_GROUP如果 curl 能拿到新值问题在客户端缓存重启客户端进程即可。如果 curl 拿到的也是旧值回到 5.1 检查插件加载重点看发布时有没有报错、有没有写到别的库。这一步能准确区分客户端问题和存储层问题不用瞎猜。6. 进阶用 Python 回归脚本验证插件在集群模式下的稳定性6.1 用 docker-compose 搭一套隔离验证环境如果不想在公司集群里做实验可以用 docker-compose 本地起一套隔离环境把 PostgreSQL 和 Nacos 绑在同一个网络里。version: 3 services: postgres: image: postgres:14 environment: POSTGRES_DB: nacos POSTGRES_USER: nacos POSTGRES_PASSWORD: nacos123 ports: - 5432:5432 healthcheck: test: [CMD-SHELL, pg_isready -U nacos -d nacos] interval: 5s timeout: 3s retries: 20 nacos: image: nacos/nacos-server:v2.2.3 environment: MODE: standalone SPRING_DATASOURCE_PLATFORM: postgresql SPRING_DATASOURCE_DRIVER_CLASS_NAME: org.postgresql.Driver SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/nacos?characterEncodingutf8 SPRING_DATASOURCE_USERNAME: nacos SPRING_DATASOURCE_PASSWORD: nacos123 ports: - 8848:8848 depends_on: postgres: condition: service_healthy编排文件里有两个坑SPRING_DATASOURCE_URL 的主机名写的是 postgres不是 localhost因为在 compose 网络里服务名就是主机名Nacos 镜像版本要和插件要求的 2.2.0 匹配。启动顺序上先 docker compose up postgres -d等服务变成 healthy 再起 nacos不然 Nacos 第一次启动会因为连不上数据库而退出。6.2 回归脚本发布、读取、更新、删除四步走验证插件是否稳定不是发一条配置就完事而是把配置中心的常见操作都跑一遍。我习惯用 Python 脚本做四步回归。import requests BASE http://127.0.0.1:8848 CONFIG { dataId: plugin-regression, group: DEFAULT_GROUP, content: version1, } def publish(cfg): r requests.post(f{BASE}/nacos/v1/cs/configs, datacfg, timeout5) assert r.text true, r.text def get(data_id, group): r requests.get(f{BASE}/nacos/v1/cs/configs, params{dataId: data_id, group: group}, timeout5) return r.text def delete(data_id, group): r requests.delete(f{BASE}/nacos/v1/cs/configs, params{dataId: data_id, group: group}, timeout5) assert r.text true, r.text # 1. 发布 publish(CONFIG) # 2. 读取并校验 assert get(CONFIG[dataId], CONFIG[group]) version1 # 3. 更新内容后读取 CONFIG[content] version2 publish(CONFIG) assert get(CONFIG[dataId], CONFIG[group]) version2 # 4. 删除后确认生效 delete(CONFIG[dataId], CONFIG[group]) assert get(CONFIG[dataId], CONFIG[group]) dataId not found print(regression passed)逻辑说明脚本通过 Nacos 官方 Open API 依次执行发布、读取校验、更新、再读取校验、删除、确认删除生效。如果插件没有把数据真正落到 PostgreSQL读取阶段很难稳定通过因为存储层异常时 Nacos 通常返回错误而不是正常文本。参数说明发布时用 POST 表单dataId 和 group 是 Nacos 配置的联合主键删除接口返回 true 表示删除成功删除后再读取会拿到字符串 dataId not found。如果你要把这个脚本用在生产环境建议把 BASE 换成域名而非 IP并加上简单的重试逻辑避免测试期间网络抖动误报。6.3 我的收尾习惯改完数据源强制走一遍的最小验证链最后说一个我自己的习惯。每次在测试环境改完数据源配置我不会只看能启动就算成功而是强制走一遍最小验证链。第一步连 PostgreSQL 执行 select count(*) from config_info确认连接是通的第二步通过 Nacos Open API 发布一条测试配置再去数据库里查这条记录确认写入的是同一个库第三步重启 Nacos 进程再读这条配置确认重启后数据还在最后一步跑一遍上面的回归脚本。这个习惯的来历有点血泪。以前我一直以为能通过控制台发布配置就说明存储层没问题直到有一次在测试环境里把插件 jar 放错了目录控制台照样能发布但数据全部进了 Derby重启一次丢一半排查了整整一个下午。从那以后每次改完数据源我都强制走一遍这个最小验证链。如果你也需要把 Nacos 的数据源换成 PostgreSQL这个插件包值得下载下来照着这篇流程走一遍能省掉不少源码改造的功夫。希望帮到你。本文还有配套的精品资源点击获取