news 2026/10/1 3:45:59

Hadoop+Spark+Hive空气质量预测系统:从数据链路到可视化全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Hadoop+Spark+Hive空气质量预测系统:从数据链路到可视化全解析

每年到毕业季,我都能收到一批类似的问题:老师,我的毕设题目是“基于Hadoop+Spark+Hive的空气质量预测系统”,但我只学过一点Java和Python,这题目是不是太大了?说实话,这类题目看着吓人,本质上是一套标准的大数据链路——采集、存储、计算、可视化、预测。把这五个模块拆明白,它就是一个可以按部就班做出来的工程系统,不是什么高不可攀的研究课题。

这篇文章我会从题目拆解开始,把Hadoop、Spark、Hive三件套在项目里各管哪一段、数据链路怎么设计、AQI预测模型怎么做、可视化大屏怎么搭、毕设四件套(源码、文档、PPT、讲解)怎么整理这些事一次说清楚,最后一章列一下我实测中踩过的坑。正在开题或者已经中期、准备冲刺答辩的同学,以及对大数据分析全流程感兴趣的开发者,都可以对照参考。

1. 题目拆解:一个“空气质量预测系统”背后到底藏着几个子系统

1.1 题目里的每个热词都对应一个必须交付的模块

很多同学拿到这个题目后,第一反应是“我要用Spark写一个模型,把空气质量预测出来”。这个想法没有错,但只覆盖了系统的五分之一。毕设题目里出现的每一个关键词,其实都对应一个评分点:

题目关键词对应模块必做交付物
Hadoop分布式存储HDFS上真实落地数据文件,NameNode/DataNode进程可运行
Spark分布式计算Spark作业执行数据清洗、统计分析和模型训练
Hive数据仓库Hive建库建表、分区表、数仓分层,能跑Hive SQL出结果
空气质量预测机器学习模型基于历史数据的AQI/浓度预测,有评估指标
可视化大屏展示ECharts可视化大屏,接真实查询结果

如果只做了预测模型而没有HDFS存储,或者只做了可视化而没有Hive层,都会在答辩时被评委一句话问住:“你的Hadoop体现在哪里?”所以第一件事就是把题目中的名词翻译成“可验收的功能清单”,再按清单去排期。

1.2 系统的边界:预测、分析、可视化分别做到什么程度

这个题目最容易踩的坑是“什么都想做,什么都做不深”。我的建议是把系统拆成三个层次:

第一层:分析为主,预测为辅。空气质量数据分析应该覆盖多个维度的统计:全国/城市/站点维度的AQI分布、时间趋势(小时/日/月/季节)、首要污染物识别、污染物间相关性、优良天数比例等。这一层用Spark SQL和Hive SQL就能完成,代码量不大,但成果最容易在PPT上展示。

第二层:预测必须能闭环。所谓闭环,不是训练完打印一个RMSE就结束,而是把预测结果落回Hive表,让可视化页面能查到“明天这个城市的AQI预测值是多少”,并和真实值做对比。答辩时评委看到曲线图上有真实值和预测值两根线,基本就不会追问模型细节了。

第三层:可视化承担“第一印象”。开幕式大屏的视觉冲击力直接决定评委对系统完成度的初始打分。大屏至少要有一张地图、一组趋势图、一组排名图,数据必须来自后端接口,不能是写死的静态数据。

1.3 常见误区:把大数据项目做成一个普通Web系统

我带过的学生里,至少有一半会把时间浪费在这个误区上:先用SpringBoot把增删改查写了个遍,再在前端堆了一堆表单页面,最后发现和“数据分析可视化”没有半毛钱关系。

记住,这个题目的核心动词是“分析”和“可视化”,不是“后台管理”。管理系统里的用户登录、数据录入、权限控制都属于加分项而不是必选项。如果时间不够,干脆不要做,把精力集中在大数据链路上;如果做了管理系统,也必须把“上传CSV到HDFS”“查看Hive表分区信息”“手动触发Spark作业”这类大数据相关操作放进去,这才和题目呼应。

提示:拿到题目的第一个星期,不要写任何代码。先画一张“数据流图”:数据源 → 采集程序 → HDFS → Hive → Spark分析/训练 → MySQL/预聚合结果 → 后端接口 → ECharts大屏。这张图画清楚,整个项目的骨架就稳了。

2. Hadoop、Spark、Hive三件套的分工逻辑:为什么这个组合是毕设标配

2.1 三件套各管一段,职责比性能更重要

很多资料在介绍三件套时喜欢讲技术原理,但对于做毕设的同学来说,更重要的是搞明白“我为什么要同时用三个东西”。我常用一个类比:HDFS是一个仓库,数据以文件形式原样放进去;Hive是给仓库配的档案管理员,你把一个文件结构告诉它,之后就能用SQL去翻数据;Spark是一支临时突击队,遇到复杂计算(比如清洗脏数据、分析趋势、跑模型)时,它能拉出数据集中计算,算完再把结果放回仓库。

具体到这个项目里,分工是这样的:

  • Hadoop(HDFS):保存所有原始数据。爬虫抓下来的JSON/CSV、预处理后的中间表,全都放在HDFS上。它解决的是“大量文件往哪放”的问题。
  • Hive:把HDFS上的文件“映射”成表结构,提供SQL查询能力。空气质量数据按日期分区后,Hive的查询效率远高于直接遍历文件。它解决的是“怎么方便查”的问题。
  • Spark:承担两类任务——一类是ETL,比如把多张表的字段合并、过滤缺失值;另一类是统计分析,比如计算全国各城市月均AQI。预测模型的训练也放在Spark作业里跑(或先做特征工程再交给Python调优)。它解决的是“复杂计算谁来算”的问题。

这套体系走通后,Hive和Spark都能以HDFS为数据底座独立运作,这也正是题目里三分之二关键词的来源。

2.2 集群规划:单机伪分布式、三节点集群还是Docker

这是开题后最纠结的问题之一。我的结论很直接:

  • 如果你的笔记本内存小于16G,用单机伪分布式足够了。Hadoop、Hive、Spark都可以在同一台机器上跑,只是进程都在一个节点上。毕设演示时,本地服务不依赖外部网络,稳定性最好。
  • 如果机器是24G以上内存,建议做三节点集群(一个Master,两个Worker),这样HDFS副本数可以设为3,Spark也能体现分布式计算的优势,答辩时可以说“这是一个真正的集群环境”。
  • Docker Compose一键拉起Hadoop集群的方式也可以,但有个坑:容器里资源规划不好会互相挤占内存,反而在演示时闹崩溃。如果是新手,我不建议毕设阶段用容器化。

无论选哪种,一定要保证Hive的元数据服务依赖的MySQL数据库独立于HDFS之外的路径,别把MySQL的数据目录误放到HDFS上面,否则两个系统会互相干扰,排查起来很痛苦。

2.3 内存与磁盘估算:伪分布式下多少配置够用

一台16G内存、2核CPU的笔记本电脑跑伪分布式,每项服务的推荐内存分配大致是:

进程/模块分配建议备注
NameNode + DataNode1GB左右Hadoop 2.x/3.x默认按机器内存比例,需要手动调低
YARN ResourceManager + NodeManager2GB留给Spark作业的Containers
HiveServer2 + Hive Metastore1GB元数据库MySQL单独占用
Spark Executor4-6GBDataFrame分析和模型训练用,太多会导致OOM
MySQL512MB存Hive元数据,别装太多其他库
可视化后端 + 前端1GBSpringBoot和Node服务

磁盘上,原始CSV和中间结果加起来通常1-2GB,但HDFS的副本和Spark缓存可能会额外占用,建议预留20GB空间。很多同学在虚拟机里只划20GB磁盘,最后Hive跑着跑着报“No space left”,就是这个原因。

3. 数据从哪来、存到哪、怎么分层:完整的数据链路设计

3.1 空气质量数据源:公共API、爬虫与模拟数据

要做预测和分析,第一步是拿到足够的真实数据。公共空气质量数据可以通过中国环境监测总站发布的空气质量数据接口或者环境数据开放平台获取,也有第三方平台(如和风天气、高德地图)提供AQI实况与预报数据。这些接口一般是返回JSON,包含站点代码、城市名称、时间、AQI、PM2.5、PM10、SO2、NO2、CO、O3等字段。

需要注意两点:

  1. 接口访问频率有限制,要控制抓取节奏,建议每小时抓一次,存成按日期命名的文件。
  2. 部分接口需要申请token,申请后先手动下载几条数据看看字段原始格式,再写采集程序。

如果准备时间不够,或者接口临时挂了,还有一条退路:自己写一个“数据模拟器”,基于一份真实样例数据,加上随机扰动和季节性规律,生成几个月的历史数据。答辩时我建议如实说明“采集了XX天的真实数据,并用模拟数据扩展了历史周期”,这不算学术不端,反而显得你对数据质量有思考。

3.2 采集程序的落地姿势:Python定时任务写文件再上传

采集程序本身不需要复杂框架,Python的requests + pandas就够了。核心流程:

import requests import pandas as pd from datetime import datetime def fetch_air_quality(): url = "https://api.example.com/airquality" params = {"city": "beijing", "token": "your_token"} resp = requests.get(url, params=params, timeout=10) data = resp.json()["data"] df = pd.DataFrame(data) df["dt"] = datetime.now().strftime("%Y%m%d%H") return df def upload_to_hdfs(df): # 保存为本地CSV后使用hdfs命令上传 df.to_csv("/tmp/air_quality.csv", index=False) os.system("hdfs dfs -put -f /tmp/air_quality.csv " "/user/hive/warehouse/ods_air_quality/")

这里有一个值得注意的设计:HDFS的目录结构和Hive的外部分区表对应。你在往HDFS上传文件时,就要规划好year/month/day/hour这样的层级,这样建Hive分区表时可以直接靠目录结构默认解析,非常方便。

3.3 Hive数仓分层:ODS、DWD、ADS三层各做什么

一个像样的毕设,Hive不能只建一张表。建议至少做三层:

  • ODS层(原始数据层):原样存采集到的数据,文件名按日期分区,不修改、不过滤。这是整个数仓的“原始材料”。
  • DWD层(明细数据层):对ODS数据进行清洗和标准化,比如把时间格式统一、去掉数值为负或等于0的异常记录、城市名称别名归一。DWD层的表是整个分析模型的素材库。
  • ADS层(应用数据层):把分析结果汇总成一张张“已算好的表”,专门供可视化后端查询。比如“城市月均AQI表”“首要污染物分布表”“每日优良天数比例表”。

DWD层的核心清洗逻辑可以放进Spark作业里做,然后把清洗结果写回Hive。ADS层大多是聚合后的结果,行数很少,查询非常快,这也是避免后端接口超时的一个基础保障。

建表时建议用ORC格式 + Snappy压缩 + 按日期分区。示例:

CREATE EXTERNAL TABLE dwd_air_quality( city STRING, station_id STRING, aqi INT, pm25 DOUBLE, pm10 DOUBLE, so2 DOUBLE, no2 DOUBLE, co DOUBLE, o3 DOUBLE, temp DOUBLE, humidity DOUBLE ) PARTITIONED BY (dt STRING) STORED AS ORC LOCATION '/warehouse/dwd/dwd_air_quality';

使用外部表而不是内部表,是因为HDFS文件可能是采集程序直接写进去的,外部表删表时不会误删数据文件,调试期更安全。

3.4 小文件问题:多数人第一次跑Hive变慢的元凶

采集程序如果每十秒落一次CSV,一天就会产生几千个小文件。HDFS一怕文件太多,二怕文件太小,因为NameNode要维护大量元数据,Spark读数据时也会因为文件碎片化而把启动开销花在读文件上。这是“为什么我的Hive和Spark越跑越慢”的高频答案。

解决思路也简单:落地时压缩粒度,每天合并文件。比如采集程序每30分钟往临时目录写,一天结束后用一条Hive SQL把这个目录下的数据合并成一个分区文件:

INSERT OVERWRITE TABLE dwd_air_quality PARTITION(dt='2024-05-20') SELECT city, station_id, aqi, pm25, pm10, so2, no2, co, o3, temp, humidity FROM ods_air_quality WHERE dt='2024-05-20';

这条SQL天然会把小文件合并成大文件,之后再去查询,速度会有质的提升。关于小文件优化,我在后面的排障章节里还会具体展开。

4. AQI预测怎么做:从特征工程到Spark训练,再到结果落库

4.1 预测目标:预测数值还是预测等级

这个题目里的“预测系统”至少有两种理解:预测未来的AQI数值,或者预测未来的空气质量等级(优/良/轻度污染/中度污染/重度污染/严重污染)。我建议做数值回归为主、等级分类为辅。原因是:评委容易理解回归结果;而且从数值映射到等级只需一条规则函数,加一个分类结果展示,几乎零成本,但答辩时能多讲一个点。

预测周期上,比较合理的是“基于当前时刻和过去24小时数据,预测未来3小时或未来24小时的变化趋势”。预测未来24小时需要特征里有完整的周期性信息,难度更高;预测未来3小时相对容易,而且演示时能直观看到“当前实测 vs 预测”的对齐效果。第一次做,推荐先做“未来3小时预测”,把链路跑通了再扩展。

4.2 特征工程:哪些因素真正影响AQI

不要一上来就做复杂模型,先把特征清单想清楚。基于实际项目经验,预测AQI最有效的特征可以归为四组:

  • 污染物浓度特征:上一时刻PM2.5、PM10、SO2、NO2、CO、O3浓度。它们是AQI计算的基础成分,重要性最高。
  • 气象特征:温度、湿度、气压、风速、风向。尤其是风速和湿度,对污染物扩散影响很大。
  • 时间特征:小时(0-23)、星期几、是否节假日、月份。用来捕捉交通高峰、供暖季、节假日等周期性变化。
  • 滞后特征:过去1小时、3小时、6小时、12小时、24小时的AQI值。这类特征对短期预测贡献巨大,相当于用历史走向约束未来走向。

滞后特征怎么构造?简单做法是用pandas的shift函数:

df["aqi_lag1"] = df["aqi"].shift(1) df["aqi_lag6"] = df["aqi"].shift(6) df["pm25_lag1"] = df["pm25"].shift(1)

但要注意,shift之后会产生NaN,需要统一丢弃。另外,在构造离线训练数据时,不能把未来时刻的数据混进特征里,否则就是典型的数据泄漏——训练时RMSE很好看,实际部署时完全失效。我在带学生的过程中不止一次看到这种“虚假好成绩”,评委如果问到“你的模型上线后准确率还这么高吗”,就会露馅。

4.3 模型选择与训练:Spark MLlib还是Python调参

这又是一个容易纠结的问题。如果你希望整个流程都能说成“Spark完成的”,那可以用Spark MLlib的随机森林回归器,代码简单、分布式训练、好交差。如果你希望预测效果更好、图表里的拟合线更漂亮,可以用Python的scikit-learn或XGBoost。我的建议是两者结合:Spark负责特征工程和大规模预处理,把清洗后的样本存成Parquet,然后交给Python训练模型;如果你的毕设里“大数据”的叙事线更重,也可以把Spark的Gradient-Boosted Trees跑一版作为主结果。

Spark MLlib训练随机森林的示例代码:

import org.apache.spark.ml.feature.VectorAssembler import org.apache.spark.ml.regression.RandomForestRegressor import org.apache.spark.ml.evaluation.RegressionEvaluator val featureCols = Array("pm25", "pm10", "so2", "no2", "co", "o3", "temp", "humidity", "wind_speed", "aqi_lag1", "aqi_lag6", "hour", "month") val assembler = new VectorAssembler() .setInputCols(featureCols) .setOutputCol("features") val rf = new RandomForestRegressor() .setLabelCol("aqi") .setFeaturesCol("features") .setNumTrees(100) .setMaxDepth(10)

需要注意的是,Spark MLlib的随机森林评估结果可以通过RegressionEvaluator设定rmse或mae直接输出,这正好对应毕设文档里要写的“评估指标”。

4.4 评估与落库:结果必须能被可视化查到

训练完成后,光把模型跑通还不够,还要做三件事:

  1. 在测试集上记录RMSE、MAE、R²,并以表格形式存到结果文件里,写进LW文档。建议也画一张“真实值vs预测值”的散点图或折线图,这张图是文档里的关键证据。
  2. 把预测结果写回Hive。建一张ads_aqi_predict表,字段包括city、dt、predict_time、predict_aqi、actual_aqi,这样可视化大屏的后端接口直接查这张表就能拿到预测对比数据。
  3. 写一个简单的定时触发逻辑。用Linux crontab或者Java定时任务,每天固定时间运行预测脚本,把新的预测结果写入当天分区。虽然做不出生产级的调度平台,但至少让系统有“持续运行”的感觉。

我习惯在文档里放一张预测效果对比表,用三天的数据说明模型在晴天、降温、污染累积三种场景下的表现差异,这比只写一个平均误差更有说服力。

5. 可视化大屏的设计要点:颜值和逻辑都要在线

5.1 大屏该放哪几张图:信息层级决定了第一印象

可视化大屏是整个系统最容易拿分、也最容易翻车的地方。很多同学把ECharts的官方图例堆了十几个上去,页面花得像个跑马灯,评委根本找不到重点。我的建议是围绕三条主线设计:

  • 地理维度:一张中国地图,用散点或区域颜色表示各城市当前AQI。颜色分级参考标准:绿色0-50、黄色51-100、橙色101-150、红色151-200、紫色201-300、褐红色>300。这张图放在中间,一眼看出空间分布。
  • 时间维度:折线图展示“全国平均AQI近24小时变化”,可以同时画真实值和预测值两条线。放在地图下方或右侧,承接“预测”这个主题。
  • 对比与排名维度:左侧放“首要污染物占比”饼图/环形图,右侧放“空气质量最差Top10城市”横向柱状图。这样图与图之间形成互补,每张图都在回答一个问题。

可选的加分项还包括:雷达图展示单个城市六项污染物浓度;日历热力图展示一个月的优良天气日历。但加图的前提是数据能查得到,宁可少不要滥。

5.2 后端接口:别写一堆Mapper,直接查Hive/ADS表

可视化数据一般不需要高频实时读写,所以没必要把每一份数据都灌进MySQL再做一套CRUD。更轻量的方式是:

  • Spark/Hive跑批完成后结果落在ADS层。
  • 后端写一个Hive查询接口,直接通过JDBC读取ADS表返回JSON给前端。

示例接口逻辑(Java + SpringBoot 风格):

SELECT city, AVG(aqi) AS avg_aqi, MAX(pm25) AS max_pm25 FROM ads_city_aqi WHERE dt = '2024-05-20' GROUP BY city ORDER BY avg_aqi DESC LIMIT 10;

如果担心Hive查询延迟,可以在后端加一层Redis缓存,第一次查询后缓存5分钟,大屏轮询时走缓存,压力会小很多。

5.3 动效、交互与刷新:演示时最容易加分的细节

大屏是展示类页面,交互不需要复杂,但要有反馈。我会在前端加三个连招:

  1. 自动轮询,每30秒刷新一次数据,体现“系统在持续运行”。
  2. 数值动画,当页面加载时,大屏上的AQI数字用ECharts的animation完成从0到当前值的滚动,观众注意力会被动态数字吸引。
  3. 点击地图城市弹出详情,下面出现该城市6小时内的污染物浓度曲线。这一个交互就能让评委觉得“这不只是个静态展示页面”。

不过,轮询间隔不要太短,5秒一刷会给人卡顿感,而且后端不断查Hive容易把Metastore搞出并发告警。30秒一次是演示安全区。

5.4 配色与排版:拒绝花哨,但也不要病怏怏的颜色

大屏配色推荐深色科技风:背景用深蓝黑(#0b1830之类),主题色使用亮青/荧光蓝(#00d4ff),警告色用橙黄(#ffaa00),污染等级颜色沿用环境标准的色系。深色背景的好处是:图表对比度高,投影到答辩屏幕上也不容易过曝。

排版上,常见的“左中右三层结构”最好用:左侧排行与占比,中间地图,右侧趋势与预测。页面宽度通常按1920x1080设计,要提前在会议上试投一次,避免字体过小、图表挤在一起的问题。

6. 毕设四件套的整理顺序:源码、文档、PPT、讲解

6.1 源码工程:目录清晰比代码技巧更重要

如果你计划把源码交给导师或评委审查,目录结构一定要让人一眼看懂。我推荐的工程划分方式:

air-quality-system/ ├──>spark-submit \ --master yarn \ --deploy-mode client \ --driver-memory 2g \ --executor-memory 3g \ --executor-cores 2 \ your_spark_job.py

同时把yarn-site.xml里的yarn.nodemanager.resource.memory-mb调成机器内存的75%左右,比如16G内存就设12G。伪分布式下如果既要跑Hive又要跑Spark,这个参数设得太高会互相挤爆内存。

7.3 版本兼容:Hive、Hadoop、Spark三者必须成套

Hive和Spark之间有很严格的版本搭配关系,最让人崩溃的是guava包冲突:Hadoop自带的guava版本和Hive/Spark带的guava版本不一致,启动Hive时就报NoClassDefFoundError。解决办法是去Hive的lib目录看一下实际guava版本,再在Hadoop的share目录找到对应版本,拷贝一份覆盖掉。

MySQL驱动也容易漏:Hive用MySQL存元数据时,必须在$HIVE_HOME/lib里放置mysql-connector-java.jar,否则启动Metastore就直接报连不上数据库。

7.4 可视化接口慢:预聚合表 + 缓存

最后一个坑在查询链路。如果你让前端直接查ODS层几百万条原始记录,然后在后端再用Java做分组聚合,接口响应时间能达到十几秒,大屏直接白屏转圈。我的优化思路是:让Spark把90%的聚合计算提前算完,生成ADS层结果表。

后端从ADS表查询时,通常一两秒就能出结果。如果还嫌慢,把热点查询结果缓存到Redis里,设一个5分钟的过期时间,大屏展示时的接口响应能压到200毫秒以内。这也能在答辩时顺带展示你具备基本的性能优化意识。

最后再分享一个我自己的经验:这类“热词密集”的毕设题目,最大的风险不是技术难点,而是前期结构不清导致后期返工。先把数据链路画出来、把每层表结构定下来、把模块与题目关键词对应上,再动手写代码,整个过程会顺利得多。如果能在时间规划上把最终两周单独留给文档、PPT和演示彩排,这个项目的天花板基本就在你的掌控之中了。

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

Inertial Explorer帮助手册下载:官方渠道与版本匹配全攻略

打开搜索引擎输入“Inertial Explorer帮助手册下载”,你大概率会遇到和我当初一样的困惑:满屏都是“我一运行IE它就自动打开Edge怎么办”“如何在Ubuntu里打开IE浏览器”这类内容。这些热搜词里确实藏着“IE”,但和我们要找的Inertial Explor…

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

HER算法:用“后见之明”破解强化学习稀疏奖励难题

如果只能用一个词概括复盘的力量,我会选hindsight。这个词翻译过来叫“后见之明”,听起来有点负面的意思——谁都知道事后诸葛亮容易当,可真正在算法世界里,hindsight被做成了Hindsight Experience Replay,也就是HER算…

作者头像 李华
网站建设 2026/10/1 3:43:30

Java开发者AI入门路线图:Spring AI与LangChain4j实战RAG

1. Java 开发者切入 AI 的真实路径拆解1.1 为什么 Java 开发者做 AI 总觉得“隔了一层”我做了十多年 Java 后端,从 SSH 时代一路写到 Spring Boot 微服务,中间也带过不少团队。这两年身边问得最多的问题就是:“我想转 AI,但我是写…

作者头像 李华
网站建设 2026/10/1 3:43:03

Java开发者AI应用开发实战:从Spring AI到RAG与Agent的90天路线

Java 圈子里这两年有个挺有意思的现象:面试造火箭的那套东西还没降温,招聘 JD 上又悄悄多了一行“有 AI 应用开发经验者优先”。很多写了五六年 CRUD 的兄弟一下子就慌了,觉得自己那套 Spring 全家桶、MyBatis、AQS 的知识体系,跟…

作者头像 李华
网站建设 2026/10/1 3:42:47

电商评论情感分析实战:Python端到端方案

简介:本资源是一套完整的电商评论情感分析实战项目,面向Python初学者、数据科学入门者及高校课程设计与毕业设计学生,聚焦NLP基础应用与机器学习全流程实践。包内共860个文件,涵盖478个Python源码(含完整注释&#xff…

作者头像 李华
网站建设 2026/10/1 3:42:28

Flutter鸿蒙适配实战:汉字笔画数查询工具开发全记录

Flutter 做跨平台不新鲜,但要是告诉你这套代码能直接跑在鸿蒙上,还顺手把汉字笔画数这种传统需求做成了智能学习工具,很多人第一反应是“又吹牛”。实际上我前阵子真这么干了一回,Flutter 3.x 环境 鸿蒙 Next 适配层,…

作者头像 李华