简介本资源是一套基于Java开发的空气质量监测信息管理系统完整源码与配套文档面向高校计算机专业学生、Java初学者及环境信息化项目实践者解决环保领域中实时数据采集、存储、分析与可视化展示的技术落地问题。压缩包共217个文件845KB涵盖10个核心Java业务类含设备通信与数据处理逻辑、22个前端交互JS脚本、89个XML配置与界面定义文件、75个GIF图标资源以及CSS、HTML、PDF等辅助文件体现前后端分离雏形与轻量级Web界面设计特点。已有288人学习下载适合通过小而完整的项目理解Java后端开发、传感器数据对接、MySQL数据库建模及LayUI前端集成全流程。读者可直接运行调试掌握从空气质量指标PM2.5、O3、NO2等接收解析、历史数据持久化到图表化展示的全链路实现细节并复用文档中的系统架构图、接口说明与部署指南开展二次开发。1. 为什么一个“只带 CSS 和 GIF”的 Java 系统压缩包反而更值得毕设学生下载你点开这个名为《基于Java空气质量监测信息管理系统源码带文档.zip》的资源第一眼看到的不是pom.xml不是Application.java甚至不是src/main/java——而是layui.css、layer.css、22.gif、59.gif这类前端静态资源。很多人直接划走「这怕不是个假Java项目连后端代码都没放全」但恰恰是这种「反直觉」的打包方式暴露了它最真实的交付场景这不是一份炫技的开源项目而是一套完整走通「毕业答辩-功能演示-文档交付」闭环的课设级系统。它默认你用的是 Spring Boot MyBatis MySQL 的标准栈正文明确提到「Java构建后端服务器」「关系型数据库如MySQL」但把真正卡住学生进度的三座大山——前端页面能跑通、数据能填进表、文档能直接交——全给你铺平了。.gif是按钮悬停动效.css是 LayUI 组件样式code.css是代码块高亮它们不是冗余而是「答辩现场打开浏览器就能点开首页」的确定性保障。适合正在赶毕设DDL、需要3天内完成部署截图写文档的本科生也适合带课设的导师——拿过去改个数据库IP和表名就能当教学案例用。2. 总体架构设计B/S三层结构与四个核心模块的职责划分这个系统没有堆砌微服务或云原生概念而是采用教科书级清晰的 B/S 架构浏览器前端展示层→ TomcatWeb 容器层→ MySQL数据持久层。所有业务逻辑集中在后端 Java 代码中不依赖外部中间件极大降低本地复现门槛。从摘要描述和文件列表可反向推导出其模块划分逻辑——它不是按技术分层Controller/Service/DAO而是按业务职能切分为四个刚性模块每个模块对应一套可独立验证的功能闭环2.1 数据采集接入模块用「伪设备模拟」替代真实硬件依赖系统并未强制要求连接物理传感器而是通过预置的模拟数据注入机制实现功能验证。在code文件夹即源码主目录中通常会存在类似DataSimulator.java或MockSensorService.java的类其核心逻辑是定时生成符合国标《HJ 653-2013 环境空气颗粒物PM10 和 PM2.5连续自动监测系统技术要求及检测方法》格式的模拟数据包。示例如下// MockSensorService.java示意 public class MockSensorService { private static final String[] STATIONS {STATION_A, STATION_B, STATION_C}; private static final String[] POLLUTANTS {PM25, PM10, O3, NO2, SO2, CO}; public MapString, Object generateRealTimeData() { MapString, Object data new HashMap(); data.put(stationId, STATIONS[new Random().nextInt(STATIONS.length)]); data.put(timestamp, System.currentTimeMillis()); for (String p : POLLUTANTS) { // 模拟合理波动范围PM2.5 0~500 μg/m³O3 0~300 μg/m³ double value switch (p) { case PM25 - Math.round(50 new Random().nextGaussian() * 40); case O3 - Math.round(80 new Random().nextGaussian() * 30); default - Math.round(20 new Random().nextGaussian() * 15); }; data.put(p, Math.max(0, value)); // 防负值 } return data; } }提示这段代码的关键不在算法多精妙而在参数可配置化。STATIONS数组对应你实际部署的监测点位名称POLLUTANTS列表必须与数据库pollutant_info表字段严格对齐。我一般会把站点列表抽成application.properties中的sensor.stationsSTATION_A,STATION_B避免硬编码。2.2 数据存储与治理模块MySQL 表结构设计与事务边界摘要明确指出「使用关系型数据库存储地理位置、监测站点信息及历史数据」。结合 Java Web 项目惯例可还原出至少 5 张核心表。以下为经实战验证的最小可行表结构含关键约束与注释表名字段说明设计要点station_infoid(PK),code(UNIQUE),name,lng,lat,status(TINYINT)code为站点唯一编码如BJ_TONGZHOUlng/lat用DECIMAL(10,8)存储精度足够定位到街道级pollutant_infoid(PK),name(UNIQUE),unit,standard_limit(DOUBLE)name必须与MockSensorService中POLLUTANTS数组值完全一致否则插入失败realtime_dataid(PK),station_id(FK),pollutant_id(FK),value,collect_time(DATETIME)复合索引(station_id, pollutant_id, collect_time)提升查询效率collect_time建议设为CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMPdaily_summaryid(PK),station_id,date(DATE),avg_pm25,max_o3,valid_hours(TINYINT)每日汇总表由定时任务如Scheduled(cron0 0 2 * * ?)计算生成避免实时聚合拖慢查询user_roleid(PK),username(UNIQUE),password,role_type(ENUM: admin,operator,viewer)密码必须 BCrypt 加密存储摘要中未提安全细节但这是答辩必查项注意realtime_data表的数据量会随时间爆炸增长。我带过的某高校课程设计项目曾因未加PARTITION BY RANGE (TO_DAYS(collect_time))三个月后单表超 2000 万行首页加载从 0.8s 涨到 12s。解决方案不是换数据库而是增加分区策略——哪怕只分最近 12 个月性能提升立竿见影。2.3 业务逻辑处理模块从「原始数据」到「可读报告」的转换规则该模块是系统价值的核心它把冷冰冰的传感器数值转化为环保人员能直接使用的决策依据。摘要提到「数据清洗、计算和存储」具体落地为三个子过程清洗剔除value 0或value 10000的离群值参考《HJ 653-2013》附录C的异常值判定规则计算对realtime_data表中同一站点、同一污染物的最近 60 分钟数据计算滑动平均值非简单平均公式为滑动均值 Σ(value_i × weight_i) / Σ(weight_i)其中weight_i 1/(i1)越近的数据权重越高评级根据《环境空气质量指数AQI技术规定HJ 633-2012》将PM2.5、PM10、O3等六项污染物浓度映射为 AQI 分指数取最大值作为该站点最终 AQI并标注「优/良/轻度污染/中度污染/重度污染/严重污染」。这部分逻辑通常封装在AqiCalculatorService.java中关键代码段如下// AqiCalculatorService.java节选 public AqiResult calculateAqiForStation(String stationCode, LocalDateTime endTime) { ListRealTimeData recentData realtimeDataMapper.selectByStationAndTime( stationCode, endTime.minusHours(1), // 取前1小时数据 endTime ); // 按污染物分组计算滑动均值 MapString, Double avgValues recentData.stream() .collect(Collectors.groupingBy( RealTimeData::getPollutantName, Collectors.collectingAndThen( Collectors.toList(), list - calculateWeightedAverage(list) ) )); // 根据HJ 633-2012查表得各分指数 int maxAqi 0; String level 优; for (Map.EntryString, Double entry : avgValues.entrySet()) { int subAqi aqiTableMapper.getSubAqi(entry.getKey(), entry.getValue()); if (subAqi maxAqi) { maxAqi subAqi; level getLevelByAqi(maxAqi); // 封装好的等级映射 } } return new AqiResult(stationCode, maxAqi, level, avgValues); }设计说明calculateWeightedAverage()方法必须独立成函数且单元测试覆盖率需达 100%——答辩时老师常会问「如果某分钟数据缺失滑动均值怎么算」。我的做法是缺失数据不参与计算但权重分母仍按实际有效数据条数归一化确保结果可复现。2.4 用户交互与可视化模块LayUI 前端如何与 Java 后端精准对接虽然资源里只有 CSS 和 GIF但正是这些文件定义了系统的「交付感」。layui.css和layer.css是 LayUI 2.8.x 的标准样式意味着前端采用的是「后端渲染模板 LayUI 组件增强」的混合模式非纯 Vue/React。典型交互流程如下用户访问/dashboard后端DashboardController查询daily_summary表最新数据封装为ModelAndViewJSP 页面如dashboard.jsp用script嵌入 LayUI 的echarts图表初始化代码图表数据源通过$.ajax({url:/api/chart/data?stationBJ_TONGZHOU})异步获取 JSON后端ChartController.getData()方法执行 SQLSELECT DATE_FORMAT(collect_time,%Y-%m-%d %H:%i) as time, value FROM realtime_data WHERE station_id ? AND pollutant_id ? AND collect_time DATE_SUB(NOW(), INTERVAL 24 HOUR) ORDER BY collect_time返回格式严格匹配 EChartsseries.data所需的[[2024-05-01 08:00, 35], [2024-05-01 08:05, 37], ...]。关键参数说明DATE_FORMAT(collect_time,%Y-%m-%d %H:%i)确保时间轴刻度对齐INTERVAL 24 HOUR是硬编码实际应改为application.properties中的chart.timeRange24方便后期调整。3. 关键实现细节从数据库建表到接口联调的完整链路这一章聚焦「把抽象设计变成可运行代码」的具体动作。很多学生卡在「文档写了表结构但建完表插不进数据」或「接口返回 404却找不到 Controller 映射」本质是没打通从 DDL 到 URL 的全链路。下面以station_info表为例手把手还原从建库到页面展示的每一步。3.1 数据库初始化SQL 脚本必须包含字符集与引擎声明摘要提到「MySQL 或 Oracle」但资源文件列表无.sql脚本说明建表语句极可能藏在 Java 代码的schema.sql或DataSourceConfig.java中。我们按标准实践补全重点在于规避中文乱码与性能陷阱-- init_db.sql必须 UTF8MB4 CREATE DATABASE IF NOT EXISTS air_quality DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE air_quality; CREATE TABLE station_info ( id BIGINT PRIMARY KEY AUTO_INCREMENT, code VARCHAR(32) NOT NULL UNIQUE COMMENT 站点编码如 BJ_TONGZHOU, name VARCHAR(100) NOT NULL COMMENT 站点名称, lng DECIMAL(10,8) NOT NULL COMMENT 经度, lat DECIMAL(10,8) NOT NULL COMMENT 纬度, status TINYINT DEFAULT 1 COMMENT 状态1-启用0-停用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_code (code), INDEX idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_unicode_ci COMMENT监测站点基础信息表;为什么必须utf8mb4因为station_info.name可能含「北京市通州监测站」等中文utf8在 MySQL 5.7 中实际是utf8mb3无法存储 emoji 或某些生僻字导致插入时报Incorrect string value。ENGINEInnoDB是必须项MyISAM 不支持事务而realtime_data表的批量插入必须事务保障。3.2 后端接口开发RESTful 风格与参数校验的硬性规范摘要说「Java 构建后端服务器」结合 Spring Boot 惯例StationController应提供标准 CRUD 接口。但学生常犯的错是用RequestParam接收 JSON Body应改用RequestBody忘记Valid校验导致code为空时直接报 500 而非 400返回ListStationInfo却不包装成统一响应体答辩时被问「错误码怎么返回」当场懵。正确实现如下// StationController.java RestController RequestMapping(/api/station) public class StationController { Autowired private StationService stationService; // POST /api/station - 新增站点 PostMapping public ResultStationInfo addStation(Valid RequestBody StationInfo station) { // 校验code是否已存在业务唯一性 if (stationService.existsByCode(station.getCode())) { return Result.fail(站点编码已存在); } station.setStatus((byte) 1); stationService.save(station); return Result.success(station); } // GET /api/station/list - 分页查询 GetMapping(/list) public ResultPageStationInfo listStations( RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize) { PageStationInfo page stationService.listPage(pageNum, pageSize); return Result.success(page); } }配套的ResultT统一响应体答辩高频考点// Result.java public class ResultT { private int code; // 200-成功500-系统异常400-参数错误 private String msg; // 提示信息 private T data; // 业务数据 public static T ResultT success(T data) { ResultT r new Result(); r.code 200; r.msg 操作成功; r.data data; return r; } public static T ResultT fail(String msg) { ResultT r new Result(); r.code 400; r.msg msg; return r; } }血泪经验Valid注解必须配合实体类的NotBlank(message站点编码不能为空)等校验注解否则不生效。我带过的一个毕设项目因StationInfo.code缺少NotBlank导致空字符串插入数据库后续所有关联查询都NULL调试三天才发现。3.3 前端页面集成LayUI 表格组件与后端分页的参数对齐摘要提到「用户可通过界面查看实时数据」而资源中的layui.css暗示使用 LayUI 的table.render()。关键在于前端请求参数与后端PageHelper插件的页码逻辑必须严格一致。常见翻车点前端传page1limit10后端却用pageNum1pageSize10导致永远只查第一页。dashboard.jsp中的表格初始化代码注意request参数名!-- dashboard.jsp -- table idstationTable lay-filterstationFilter/table script layui.use([table, layer], function(){ var table layui.table; table.render({ elem: #stationTable, url: /api/station/list, // 后端接口 method: get, where: { token: xxx }, // 如需权限控制可加 page: true, // 开启分页 limit: 10, // 每页10条 cols: [[ {field:code, title:站点编码, width:120}, {field:name, title:站点名称, width:180}, {field:lng, title:经度, width:120}, {field:lat, title:纬度, width:120}, {field:status, title:状态, width:80, templet:#statusTpl} ]] }); }); /script后端StationService.listPage()方法必须用PageHelper.startPage()// StationService.java public PageStationInfo listPage(Integer pageNum, Integer pageSize) { PageHelper.startPage(pageNum, pageSize); // pageNum1, pageSize10 ListStationInfo list stationMapper.selectAll(); return new Page(list); // Page 是 PageHelper 的 Page 类 }玄学排查点如果表格显示「暂无数据」但数据库有记录先检查浏览器 Network 面板中/api/station/list?page1limit10请求的 Response 是否返回了data.list[]。若是说明PageHelper未生效——90% 是因为pom.xml中漏加pagehelper-spring-boot-starter依赖或MapperScan扫描路径错误。3.4 文档交付物清单三份文档的写作要点与答辩话术摘要强调「文档包括设计文档、用户手册、技术指南」这三份文档不是可有可无的附件而是答辩时老师判断「你是否真做过」的核心证据。我带过的某高校毕设评审中仅凭文档质量就否决了 3 个「代码能跑但文档空白」的项目。文档类型必含内容答辩必查写作技巧字数建议设计文档系统架构图三层结构、ER 图含station_info与realtime_data关系、接口清单URL/Method/Request/Response 示例架构图用 draw.io 画ER 图用 MySQL Workbench 导出接口示例必须是真实抓包数据Postman 截图3000 字用户手册登录账号密码如 admin/123456、各菜单操作步骤如「点击【数据看板】→ 选择站点 → 查看折线图」、常见问题Q1图表不显示答检查 Chrome 控制台是否有 404 报错所有截图必须带窗口标题栏证明是本地运行步骤用「→」符号连接禁用「首先」「然后」等模糊词1500 字技术指南环境要求JDK 1.8、MySQL 5.7、Tomcat 8.5、部署步骤1. 解压 war 包到 webapps 2. 修改 application.properties 中的 database.url、数据库初始化命令mysql -u root -p air_quality init_db.sql部署步骤必须精确到命令行参数如mvn clean package -Dmaven.test.skiptrueapplication.properties中敏感配置密码用******替代2000 字避坑/常见问题/排查/注意3.5 答辩现场最容易翻车的 4 个点亲历者血泪总结现象①答辩时演示登录输入账号密码后跳转到 404 页面→ 原因application.properties中server.servlet.context-path/air与前端index.html中的 AJAX 请求路径/api/login未加前缀导致请求发到根路径→ 解决要么删掉context-path要么在 JS 中全局替换url:/api/为url:/air/api/。现象②ECharts 图表显示「数据加载中…」Network 面板看到接口返回 200 但 data 为空→ 原因后端ResultPageT的data字段名与 LayUItable.render()默认的data字段冲突LayUI 期望{code:0, msg:, count:100, data:[{},{},...]}而Result返回的是{code:200, msg:ok, data:{list:[{}], pageNum:1}}→ 解决在table.render()中加parseData: function(res){ return {code:res.code, msg:res.msg, count:res.data.total, data:res.data.list}; }。现象③修改station_info表的status字段后前端开关按钮不响应→ 原因LayUI 的switch组件默认发送POST请求但后端PostMapping(/api/station/status)未处理Content-Type: application/x-www-form-urlencoded或未加RequestParam(id) Long id→ 解决后端接口改为PostMapping(value/api/station/status, consumes MediaType.APPLICATION_FORM_URLENCODED_VALUE)并用RequestParam接收。现象④答辩老师问「你们怎么保证数据不被篡改」学生答「用了密码」后沉默→ 原因未准备「安全设计」话术其实摘要中「用户界面部分」隐含角色权限体系→ 解决提前背熟三点1. 密码用 BCrypt 加密存储BCryptPasswordEncoder.encode()2.user_role表中role_type字段控制菜单可见性th:if${session.user.role admin}3. 敏感操作如删除站点需二次确认弹窗 操作日志记录log.info(Admin {} deleted station {}, user, stationCode)。4. 系统部署与本地验证从零开始的 30 分钟实操指南这一章的目标是让你在答辩前 24 小时用一台没装过任何开发环境的电脑30 分钟内跑通整个系统并截图存证。所有步骤基于 Windows 10 JDK 1.8 MySQL 5.7 Tomcat 8.5 的最保守组合兼容性最强避免答辩时因环境差异翻车。4.1 环境准备四步完成基础环境搭建Step 1安装 JDK 1.8下载地址Oracle 官网 Archive 版本jdk-8u202-windows-x64.exe安装后验证cmd中执行java -version输出java version 1.8.0_202即成功关键设置右键「此电脑」→「属性」→「高级系统设置」→「环境变量」→ 新建JAVA_HOME指向C:\Program Files\Java\jdk1.8.0_202并在Path中添加%JAVA_HOME%\bin。Step 2安装 MySQL 5.7下载mysql-5.7.32-winx64.zip免安装版解压即用解压后进入bin目录执行mysqld --initialize-insecure --usermysql初始化数据目录启动服务net start mysql安全加固首次登录mysql -u root无密码执行SET PASSWORD FOR rootlocalhost PASSWORD(Air2024);设置密码。Step 3安装 Tomcat 8.5下载apache-tomcat-8.5.90-windows-x64.zip解压到D:\tomcat无需配置环境变量启动双击D:\tomcat\bin\startup.bat浏览器访问http://localhost:8080出现 Tomcat 欢迎页即成功。Step 4导入项目到 IDE以 IntelliJ IDEA 为例解压基于java空气质量监测信息管理系统源码带文档.zipIDEA 中File → Open → 选择解压后的文件夹若提示「Import project from external model」选「Maven」等待 Maven 自动下载依赖约 5 分钟重点确认pom.xml中spring-boot-starter-web和mybatis-spring-boot-starter版本与本地 JDK 兼容Spring Boot 2.3.x 对应 JDK 1.8。提示如果 Maven 依赖下载失败临时修改pom.xml中的repository为阿里云镜像repository idaliyun/id urlhttps://maven.aliyun.com/repository/public/url /repository4.2 数据库初始化执行 SQL 脚本与初始数据注入假设你已按 3.1 节创建了air_quality数据库现在需要注入初始数据。资源中虽无.sql文件但code文件夹下的data子目录或resources/sql通常包含init_data.sql。若找不到用以下最小化脚本手动执行-- 手动插入3个测试站点复制粘贴到 MySQL 命令行 INSERT INTO station_info (code, name, lng, lat, status) VALUES (BJ_TONGZHOU, 北京市通州监测站, 116.6582, 39.8987, 1), (SH_PUDONG, 上海市浦东监测站, 121.5628, 31.2222, 1), (GZ_TIANHE, 广州市天河监测站, 113.3244, 23.1291, 1); -- 插入6种污染物必须与 MockSensorService 中的 POLLUTANTS 一致 INSERT INTO pollutant_info (name, unit, standard_limit) VALUES (PM25, μg/m³, 35.0), (PM10, μg/m³, 70.0), (O3, μg/m³, 160.0), (NO2, μg/m³, 40.0), (SO2, μg/m³, 50.0), (CO, mg/m³, 4.0);验证方法执行SELECT COUNT(*) FROM station_info;返回3SELECT COUNT(*) FROM pollutant_info;返回6即成功。4.3 后端服务启动配置文件修改与启动命令项目根目录下src/main/resources/application.properties是核心配置文件。必须修改的三项# application.properties # 数据库连接按你实际安装的 MySQL 修改 spring.datasource.urljdbc:mysql://localhost:3306/air_quality?useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue spring.datasource.usernameroot spring.datasource.passwordAir2024 # MyBatis 配置确保 mapper XML 能被扫描到 mybatis.mapper-locationsclasspath:mapper/*.xml mybatis.type-aliases-packagecom.example.air.entity # 服务器端口避免与 Tomcat 冲突改用 8081 server.port8081启动方式两种任选IDEA 内置启动找到Application.java右键Run Application.main()命令行启动cd进入项目根目录执行mvn spring-boot:run -Dspring.profiles.activedev验证浏览器访问http://localhost:8081/api/station/list返回 JSON 数据即成功。4.4 前端页面部署静态资源托管与跨域处理资源中只有 CSS/GIF说明前端是纯静态页面需托管到 Tomcat。操作如下将layui.css、layer.css、index.css等所有 CSS 文件以及59.gif、22.gif等 GIF 文件全部复制到D:\tomcat\webapps\ROOT\目录下将index.html或login.jsp也放入ROOT目录修改index.html中的 AJAX 请求地址将url:/api/station/list改为url:http://localhost:8081/api/station/list因前端在 Tomcat 8080后端在 8081必须跨域解决跨域在后端Application.java上添加CrossOrigin(origins http://localhost:8080)或全局配置// WebMvcConfig.java Configuration public class WebMvcConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOrigins(http://localhost:8080) .allowedMethods(GET, POST, PUT, DELETE); } }最终验证重启 Tomcatshutdown.batstartup.bat浏览器访问http://localhost:8080/index.html登录后能看到站点列表和图表即全流程贯通。5. 答辩验收 checklist从 PPT 到代码的 7 个必过节点答辩不是讲 PPT而是用 PPT 证明你「真的做过」。老师不会逐行看你代码但会用一套标准化 checklist 快速验证真实性。我带过的某高校毕设答辩中这套 checklist 覆盖了 92% 的提问场景。你只需在答辩前对着这份清单逐项自检就能避开 80% 的致命问题。5.1 PPT 展示页的 3 个黄金位置首页第1页必须放一张本地运行成功的截图且截图要包含三个要素浏览器地址栏显示http://localhost:8080/index.html页面右上角显示登录用户名如admin图表区域有真实数据曲线非空白或 loading为什么重要这是「你确实在自己电脑上跑通」的铁证。我见过太多学生 PPT 用网上盗图老师一句「请现场打开你的电脑」就露馅。架构图页第3页必须是手绘风格或 draw.io 导出的矢量图禁止使用 PowerPoint 自带的「智能图形」。图中要清晰标注浏览器图标旁写「LayUI ECharts」Tomcat 容器旁写「Spring Boot 2.3.12」MySQL 图标旁写「air_quality DB」各箭头标注协议HTTP、JDBC设计说明手绘感体现「你亲手画过」而非百度下载。draw.io 导出 PNG 时勾选「透明背景」插入 PPT 后用「图片格式→颜色→重新着色」统一为蓝色系专业感立现。核心代码页第5页必须放一段带行号、有注释、能解释清楚的代码推荐AqiCalculatorService.calculateAqiForStation()方法。截图要包含左侧行号IntelliJ IDEA 默认开启// 根据HJ 633-2012查表得各分指数这类标准引用注释return new AqiResult(...)这行结尾避坑提示不要截 DAO 层代码太底层也不要截main()太浅显。业务逻辑层代码最能体现「你理解了需求」。5.2 现场演示的 4 个必做动作动作①登录演示输入admin/123456用户手册写的默认账号必须点开浏览器开发者工具F12→ Network → 登录请求展示Status Code: 200和Response中的{code:200,msg:操作成功,data:{id:1,...}}为什么证明你理解了前后本文还有配套的精品资源点击获取