作者:Chenyun_922 · 开源地址:https://github.com/974294341-bit/hebei-policy
一、缘起:一个"触摸大屏查询"的需求
某次需求里提到,要在科技厅做政策查询大屏,最终交付要同时有 PC 电脑端 和 手机端小程序,并且两端数据互通。
功能要求很具体:

  • 左侧 政策分类树(3 级)
  • 右侧 政策列表,每页 10 条
  • 列表 按实际顺序倒序(最新发布的在最上面)
  • 支持分类树点击过滤、关键词搜索、时间范围、制定主体筛选
    参考对象是一个已上线的站点「科技政策一点通」。于是整个项目从逆向分析参考站点开始,再落地成自己的系统。
    二、技术选型
    层
    技术
    理由
    后端
    Spring Boot 3.4.5 + JdbcTemplate
    28 字段的遗留表,range/rank/year 是保留字,JdbcTemplate 比 JPA 映射更可控
    数据库
    H2(演示)+ MySQL(生产)双 profile
    开箱即跑,生产导入真实 policy.sql
    PC 端
    纯 HTML/CSS/JS
    一个列表页 + 一个详情页,无框架更轻
    小程序
    原生微信小程序
    与 PC 共用同一套 REST API
    核心原则:PC 端和小程序复用同一套后端接口,天然互通。
    三、第一步:逆向参考站点
    参考站点 kjzc.hebsti.cn/technology 是 Vue 2 + Webpack + Element UI 的 SPA,数据全部异步加载。从主 bundle 的 axios 配置里确认了 API 前缀:
    所有接口统一前缀:/prod-api → https://kjzc.hebsti.cn/prod-api
    关键发现:政策类接口完全开放,无需登录鉴权。 这让我们能把接口范式直接对标:
    GET /bus/pc/policyfulltext/getPolicyTypes 分类树(带各级数量)
    GET /bus/pc/policyfulltext/list 列表(分页 + 筛选)
    GET /bus/pc/policyfulltext/{id} 详情(含正文 HTML)
    合规提醒:开放接口适合做检索研究,请勿高频请求或商用转售。
    四、数据摸底:27.9MB 的 policy.sql 告诉我们什么
    拿着用户的 policy.sql(734 条政策)逐行解析 INSERT 后,有几个反直觉的事实决定了分类树怎么建:
  1. type 字段存的是叶子分类名("科技计划管理" 93 条、"综合" 87 条……共 19 个),正好对上需求文档里的树形叶子节点——不是一级分类
  2. category 字段全是 "其他",没有信息量
  3. range 是"名称 + 区划码":河北省(130000 HE)、全国(000000 QG)——制定主体筛选靠区划码判断(000000=国家,130000=河北,其他=外省)
  4. pubdata 是批量导入日期(全是 2022-06-20 / 2022-10-13),不具时间线意义
  5. 真正的发文时间是 viadata——"倒序"排的就是它
  6. text 是 Word 转出的 HTML 全文
    这一步踩过坑:最初以为 type 是一级分类,统计后才纠正。没做数据摸底,分类树就会建错层级。
    五、系统架构与核心接口
    ┌─────────────┐ ┌──────────────────────┐ ┌──────────┐
    │ PC 端 (Web) │ ──API──▶│ Spring Boot 后端 │ ──JDBC──▶│ H2/MySQL │
    ├─────────────┤ │ /api/categories │ │ policy │
    │ 微信小程序 │ ──API──▶│ /api/policies │ │ 表(28列)│
    └─────────────┘ │ /api/policies/{id} │ └──────────┘
    └──────────────────────┘
    REST 接口(PC 与小程序共用):
    接口
    作用
    GET /api/categories
    分类树(父级数量 = 自身 + 子类合计)
    GET /api/policies
    分页列表:pageNum/pageSize(默认10)/keyword/types/region/timeType
    GET /api/policies/{id}
    详情(含 text 全文 HTML)
    排序:ORDER BY viadata DESC, id DESC —— 即需求里的"按实际顺序倒排序"。
    六、功能亮点
    PC 端(参考原站界面)
  • 蓝色渐变 banner + 六个导航栏目
  • 左侧分类树:父级可折叠,勾选叶子节点过滤(支持多选)
  • 右侧:关键词搜索 + 时间(近一月/半年/一年)+ 制定主体(全部/国家/河北/外省)
  • 列表倒序 + 数字分页/跳页,每页 10 条
  • 详情页渲染全文 HTML
    微信小程序(深蓝主题,同一后端)
  • 搜索框 + 国家/河北/外省 tabs + 分类树抽屉 + 卡片列表(每页 10 条,触底加载)
  • 详情页用 rich-text 渲染政策全文
  • config.js 的 BASE_URL 指向电脑局域网 IP,手机扫码即可预览
    四个栏目页:政策动态 / 政策解读 / 政策问答 / 政策培训(目前为占位页,原站对应独立模块,后续可接入或由用户提供数据表)。
    七、踩坑实录(6 个真问题)
    坑 1:H2 保留字导致启动失败
    policy 表的 range、rank、year 是保留字,INSERT 没加反引号直接报语法错。
    修复:统一用 range、rank、year。
    坑 2:演示数据列数不匹配
    生成抽样数据时 text 后漏了一个 NULL,值 27 个、列名 28 个。
    修复:每行 28 个字段对应 28 个值。
    坑 3:批量文本替换没生效
    替换脚本跑了却 fixed rows: 0——因为 INSERT 行尾带分号,匹配模式没带分号。
    教训:做替换前先 tail 看一行的真实结尾。
    坑 4:端口被环境变量劫持
    SQL 过了,Tomcat 却起在随机端口 51345。排查发现沙盒环境变量 SERVER__PORT 被 Spring 宽松绑定覆盖配置。
    修复:启动显式指定 --server.port=8080(命令行优先级最高)。
    坑 5:jar 被占用无法重新打包
    改完代码 mvn package 报 Unable to rename ... .original。
    原因:服务还在跑,jar 被进程锁定。
    标准流程:先停服务 → 再打包 → 再启动。
    坑 6:导航栏目点不开(用户实测反馈)
    顶部"政策动态"等四个栏目是 javascript:void(0) 死链——当时只有"科技政策"有数据,其他先做了占位。
    修复:新增四个栏目页,导航全部接真实链接。
    彩蛋:GitHub 上传(环境特有的 TLS + OAuth 坑)
    GitHub 连接器的 OAuth 弹窗在本环境被拦截,且 Windows 的 TLS 证书吊销检查报 CRYPT_E_NO_REVOCATION_CHECK。最终用 PAT + git 命令行绕过:

git 关闭 schannel 吊销检查(沙盒里全局配置不生效,用内联参数)

git -c http.sslVerify=false -c http.schannelCheckRevoke=false push -f origin master

curl 等效:curl -k --ssl-no-revoke ...

同时把提交里的真名改为 GitHub 用户名,避免个人信息泄露。
八、运行与部署
H2 演示模式(零配置)
cd hebei-policy && mvn spring-boot:run

浏览器打开 http://localhost:8080

MySQL 生产模式(导入完整 734 条)
CREATE DATABASE policy DEFAULT CHARACTER SET utf8;
SOURCE policy.sql;
改 application.yml 中 mysql 段密码,再:
mvn spring-boot:run -Dspring-boot.run.profiles=mysql
微信小程序
微信开发者工具导入 miniprogram/ → 改 config.js 的 BASE_URL 为本机局域网 IP → 点「真机预览」扫码即可。
九、开源
完整源码(后端 + PC 端 + 小程序 + 逆向分析 + 调试记录)已开源:
🔗 https://github.com/974294341-bit/hebei-policy
十、小结
这个项目不大,但把"逆向参考 → 数据建模 → 全栈落地 → 调试 → 发布"走了一遍,几个值得记住的点:

  1. 动手前先摸数据:字段含义往往和直觉相反,摸底能少走很多弯路。
  2. 保留字是遗留表的常态:写 SQL 第一件事就是检查字段名。
  3. 部署环境会有意外:环境变量覆盖配置、文件被锁、TLS 校验坏掉——遇到"配置不生效"先查环境变量和进程占用。
  4. 开放不等于随便用:参考站点的开放接口适合研究,商用需注意合规。
    如果你也在做政策/文档类查询系统,欢迎参考或提 Issue。
posted on 2026-10-27 13:38  chenyun_922  阅读(5)  评论(0)    收藏  举报