首页 / 资讯中心 / 文章详情

SpringBoot+Vue智慧养老系统:健康数据闭环设计与实战

SpringBoot+Vue智慧养老系统:健康数据闭环设计与实战 ★ FEATURED ARTICLE
简介本资源是一套面向计算机专业本科生的Java毕业设计实战项目基于Spring Boot后端与Vue前端构建聚焦智慧社区居家养老健康服务场景解决老年人健康管理、医养协同与家属联动等现实需求。压缩包共878个文件含128个Java核心业务类、69个Vue组件页面、158个JS交互逻辑及162个SVG图标资源辅以MySQL建表SQL、YML配置、HTML模板与CSS样式文件完整覆盖前后端分离开发全链路包体大小39.68MB结构清晰便于按模块如老人管理、医生预约、档案系统快速定位学习。已有140人下载学习提供可直接运行的代码工程、配套毕业论文文档及多级目录组织规范包含build/run/install三阶段批处理脚本显著降低环境搭建门槛适合毕设选题参考、全栈开发实践与养老信息化课题拓展。1. 这不是又一个“管理后台”SpringBoot Vue 做智慧社区居家养老系统为什么必须把健康数据流闭环跑通你手头这个「基于 SpringBoot 的智慧社区居家养老健康管理系统」毕业设计绝不是套个 AdminLTE 模板、增删改查几个表就能交差的项目。它的真实战场在老人晨起血压异常却无人知晓、跌倒报警信号卡在网关没进数据库、家属App里看到的血糖值比实际晚了4小时、社区护士翻着Excel表格手动核对巡访记录……这些不是玄学是健康数据链路上真实存在的断点。本系统要解决的是让血压计、智能手环、跌倒检测垫、用药提醒盒这些硬件产生的原始数据经过 SpringBoot 后端清洗、校验、分级告警再通过 Vue 前端实现家属端实时看板、护理端工单派发、社区端统计报表——核心不在“有页面”而在“数据从设备到决策者手里不丢、不错、不慢”。适合正在做毕设、想拿高分又怕答辩被问“你这系统真能用吗”的同学也适合刚入职想快速吃透 SpringBootVue 全栈数据流的同学。别急着 clone 代码先搞懂这条健康数据链怎么立住。2. 后端选型不是堆技术为什么用 SpringBoot 而不是 Spring CloudMyBatis-Plus 怎么避免养老数据的“脏读”2.1 为什么放弃微服务坚持单体 SpringBoot——养老场景的三个硬约束很多同学一上来就想上 Nacos Gateway Feign结果毕设答辩被问“你这个系统部署在社区服务中心一台 4C8G 的旧服务器上跑得动 5 个微服务实例吗” 真实场景里智慧社区养老系统往往部署在区级政务云或本地机房资源有限、运维能力弱、升级频率低。SpringBoot 单体架构在这里反而是更稳的选择部署极简打包成一个healthcare.jarjava -jar healthcare.jar --spring.profiles.activeprod一行命令启动运维人员不用记docker-compose up -d里哪几个服务要先拉起来事务强一致老人建档、健康档案创建、首次评估报告生成这三个操作必须原子性完成。微服务跨库事务靠 Saga 或 TCC 太重而 SpringBoot MyBatis-Plus 的Transactional直接搞定调试可追溯当家属App显示“心率异常”但后台日志没记录时单体应用里 grep 一条 traceId 就能串起 Controller → Service → Mapper 全链路不用在 Zipkin 里跳 3 个服务面板。提示如果你学校明确要求“体现微服务思想”可在后期用 SpringBoot 的ConditionalOnProperty做模块开关如health-service.enabledtrue为未来拆分留接口但毕设阶段不实际启用。2.2 MyBatis-Plus 不是“自动 CRUD 工具”而是养老数据的“校验守门员”养老数据最怕什么不是字段空而是逻辑错比如blood_pressure_systolic190高压190却标记为health_statusnormalfall_detection_time是未来时间medication_reminder_time比elderly_birth_date还早……这些脏数据进库前端图表再漂亮也是毒图。MyBatis-Plus 的TableField和自定义MetaObjectHandler是第一道防线// 实体类 HealthRecord.java TableField(fill FieldFill.INSERT) private LocalDateTime createTime; TableField(fill FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; // 自定义填充处理器确保血压值在合理范围50~260 mmHg Component public class HealthDataMetaObjectHandler implements MetaObjectHandler { Override public void insertFill(MetaObject metaObject) { Object systolic getFieldValByName(bloodPressureSystolic, metaObject); if (systolic instanceof Integer ((Integer) systolic) 260) { throw new IllegalArgumentException(收缩压不能超过260mmHg请检查设备校准); } // 其他字段校验... this.strictInsertFill(metaObject, createTime, LocalDateTime.class, LocalDateTime.now()); // 赋值 } }这段代码的意义在于它把业务规则血压阈值写死在实体层而不是等前端传过来再校验。哪怕有人绕过 Vue 前端直接调/api/record/save接口也会在 MyBatis-Plus 插入前被拦住。这是毕业设计里最容易被忽略、但答辩时最能体现“工程思维”的细节。2.3 数据库设计别只建 user、admin、record 三张表养老系统的 4 类核心实体关系很多同学的 ER 图只有 3 张表结果答辩被问“老人用药提醒怎么关联到具体药品巡访记录怎么知道是哪个护士执行的跌倒事件怎么和定位坐标绑定” 正确的最小核心实体应包含实体名关键字段关系说明为什么必须存在elderly老人id, name, id_card, birth_date, emergency_contact, community_id主表其他表外键引用社区管理基础单元所有健康行为归属主体health_record健康记录id, elderly_id, record_type(血压/血糖/心率), value, unit, record_time, device_id一对多一个老人多条记录原始数据载体record_type 用枚举而非字符串防脏数据medication_plan用药计划id, elderly_id, drug_name, dosage, frequency, start_time, end_time一对多支持定时提醒frequency 字段存DAILY/BIWEEKLY/AS_NEEDED枚举nursing_visit护理巡访id, elderly_id, nurse_id, visit_time, status(已执行/已取消), remark一对多关联nurse表status 必须有业务状态机不能只用 0/1注意device_id字段不要存设备 MAC 地址易伪造而应存设备注册时由后端生成的唯一device_code如DEV-2024-00123并在device表中维护设备型号、所属老人、最后在线时间。这样当某台血压计数据异常时能快速定位是否设备故障而非老人身体问题。3. 前端不是“套模板”Vue 如何把养老数据变成家属看得懂、护士用得顺的界面3.1 Vue 项目结构为什么必须拆出health-monitor和nursing-task两个独立模块很多同学用 Vue CLI 一键生成后所有组件全塞在src/views下ElderlyList.vue、RecordForm.vue、ReportChart.vue……结果答辩时被问“家属和社区护士登录后看到的首页完全不同你是怎么隔离权限和路由的” 正确做法是按角色域拆分src/ ├── views/ │ ├── health-monitor/ # 家属端健康看板、预警推送、历史趋势 │ │ ├── Dashboard.vue # 首页今日异常指标卡片 折线图 │ │ ├── AlertList.vue # 实时告警列表带一键拨打紧急联系人 │ │ └── TrendChart.vue # ECharts 封装组件支持按周/月切换 │ └── nursing-task/ # 护士端工单池、巡访打卡、健康评估 │ ├── TaskPool.vue # 待处理工单含优先级颜色标识 │ ├── VisitForm.vue # 巡访表单带 GPS 定位按钮、照片上传 │ └── Assessment.vue # 标准化评估量表ADL、MMSE 等 ├── router/index.js # 路由守卫按角色加载不同模块 └── store/modules/ # 状态管理按模块划分关键在router/index.js的动态导入// 动态路由根据用户角色加载对应模块 const routes [ { path: /dashboard, component: () import(/views/health-monitor/Dashboard.vue), meta: { roles: [family] } // 只有家属角色能访问 }, { path: /task-pool, component: () import(/views/nursing-task/TaskPool.vue), meta: { roles: [nurse, admin] } } ] // 路由守卫登录后根据 token 中的 role 字段跳转 router.beforeEach((to, from, next) { const role localStorage.getItem(userRole) if (to.meta.roles !to.meta.roles.includes(role)) { next(/403) // 权限不足 } else { next() } })这种结构让答辩时你能清晰回答“家属看不到护士的工单池护士打不开家属的血糖趋势图——不是靠前端隐藏按钮而是路由层彻底隔离。”3.2 健康数据可视化ECharts 不是贴代码而是用dataset解耦数据与配置同学常犯的错误把 ECharts 配置写死在options里改个颜色都要重写整个对象。养老系统里家属可能要看“近7天血压趋势”护士要看“本月各楼栋跌倒事件分布”同一图表组件需复用。正确做法是用dataset分离数据源与视觉配置!-- TrendChart.vue -- template div refchartRef stylewidth: 100%; height: 400px;/div /template script import * as echarts from echarts export default { props: { // 数据源由父组件传入格式统一为 { date: 2024-05-01, systolic: 138, diastolic: 82 } records: { type: Array, required: true }, chartType: { type: String, default: line // line or bar } }, mounted() { this.initChart() }, methods: { initChart() { const chart echarts.init(this.$refs.chartRef) const option { dataset: { source: this.records.map(r [r.date, r.systolic, r.diastolic]) // 数据驱动 }, xAxis: { type: category }, yAxis: { type: value }, series: [ { type: this.chartType, encode: { x: 0, y: 1 }, name: 收缩压 }, { type: this.chartType, encode: { x: 0, y: 2 }, name: 舒张压 } ], tooltip: { trigger: axis } } chart.setOption(option) } } } /script这样父组件只需传records数组图表自动适配——数据变了图表不用改一行配置。答辩时演示“切换查看血糖/血压/心率”只需换数据源评委立刻明白你理解了数据驱动的本质。3.3 实时告警推送用 WebSocket 而不是轮询但必须加心跳保活家属端需要“血压超标立刻弹窗”如果用setInterval(() axios.get(/api/alerts), 3000)每秒3次请求100个家属同时在线就是300 QPSSpringBoot 默认 Tomcat 线程池直接打满。必须用 WebSocket// SpringBoot 后端WebSocket 配置 Configuration EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(alertWebSocketHandler(), /ws/alert) .setAllowedOrigins(*); // 毕设可放开生产需指定域名 } } // 告警处理器按老人ID分组推送 Component public class AlertWebSocketHandler extends TextWebSocketHandler { private final MapString, SetWebSocketSession sessions new ConcurrentHashMap(); Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { String elderlyId session.getUri().getQuery().split()[1]; // /ws/alert?elderlyId1001 sessions.computeIfAbsent(elderlyId, k - ConcurrentHashMap.newKeySet()).add(session); } // 业务层调用此方法推送告警 public void sendAlert(String elderlyId, String alertMsg) { SetWebSocketSession sessionsForElderly sessions.get(elderlyId); if (sessionsForElderly ! null) { sessionsForElderly.forEach(session - { try { session.sendMessage(new TextMessage(alertMsg)); } catch (IOException e) { sessionsForElderly.remove(session); // 连接断开则清理 } }); } } }// Vue 前端建立连接并监听 export default { data() { return { ws: null, elderlyId: 1001 // 从路由参数或 Vuex 获取 } }, mounted() { this.initWebSocket() }, methods: { initWebSocket() { this.ws new WebSocket(ws://localhost:8080/ws/alert?elderlyId${this.elderlyId}) this.ws.onmessage (event) { const alert JSON.parse(event.data) this.$message.warning(⚠️ ${alert.title}: ${alert.content}) // Element UI 提示 } // 心跳保活每30秒发一次ping防止Nginx超时断连 setInterval(() { if (this.ws.readyState WebSocket.OPEN) { this.ws.send(ping) } }, 30000) } } }注意WebSocket 在 SpringBoot 中默认使用 Tomcat 内置容器无需额外引入 Netty。但务必加心跳机制——否则 Nginx 默认 60 秒无活动就断连家属端会突然收不到告警。4. 数据打通才是灵魂SpringBoot 如何把硬件上报、人工录入、第三方平台数据统一归一化4.1 硬件数据接入不是“接收 JSON”而是构建设备协议解析中间件毕业设计里常写PostMapping(/device/data)直接接收设备 POST但真实设备协议五花八门有的用 HTTP POST 发{ devId:A123, type:bp, data:138/82 }有的用 MQTT 上报topic: device/A123/bp payload: {s:138,d:82}还有的走 Modbus TCP……直接在 Controller 层写 if-else 判断type代码会迅速腐烂。正确做法是抽象协议解析器// 协议解析器接口 public interface DeviceProtocolParser { DeviceData parse(String rawPayload, String deviceId); } // HTTP 协议解析器实现 Component(httpProtocolParser) public class HttpProtocolParser implements DeviceProtocolParser { Override public DeviceData parse(String rawPayload, String deviceId) { JSONObject json JSON.parseObject(rawPayload); DeviceData data new DeviceData(); data.setDeviceId(deviceId); data.setDataType(json.getString(type)); // bp, glucose, heart_rate switch (json.getString(type)) { case bp: String[] bp json.getString(data).split(/); data.setValue1(Integer.parseInt(bp[0])); // 收缩压 data.setValue2(Integer.parseInt(bp[1])); // 舒张压 break; case glucose: data.setValue1(json.getInteger(value)); // 血糖值 break; } return data; } } // Controller 统一入口 PostMapping(/device/data) public Result? receiveDeviceData(RequestBody String payload, RequestHeader(X-Device-ID) String deviceId, RequestHeader(X-Protocol) String protocol) { DeviceProtocolParser parser parserMap.get(protocol); // 从 Spring 容器取对应解析器 DeviceData parsed parser.parse(payload, deviceId); healthRecordService.save(parsed); // 统一存入健康记录表 return Result.success(); }这样新增一种设备协议如蓝牙手环的 BLE GATT 协议只需新增一个Component实现类Controller 一行不动。答辩时展示“我们预留了协议扩展点”比“我写了3种设备解析”更有架构感。4.2 人工录入数据校验用 JSR-303 注解 自定义 ConstraintValidator 做业务级验证家属在 App 里手动录入老人“今日食欲尚可”护士录入“巡访结论轻度认知障碍”这类文本数据不能只用NotBlank必须结合业务规则。例如“认知评估得分”必须在 0~30 之间“营养评分”必须是预设枚举// 自定义枚举约束 Target({ FIELD }) Retention(RUNTIME) Constraint(validatedBy NutritionScoreValidator.class) public interface ValidNutritionScore { String message() default 营养评分必须是 LOW/MEDIUM/HIGH; Class?[] groups() default {}; Class? extends Payload[] payload() default {}; } // 对应验证器 public class NutritionScoreValidator implements ConstraintValidatorValidNutritionScore, String { private static final SetString VALID_SCORES Set.of(LOW, MEDIUM, HIGH); Override public boolean isValid(String value, ConstraintValidatorContext context) { return value ! null VALID_SCORES.contains(value.toUpperCase()); } } // 实体类使用 public class NursingVisit { ValidNutritionScore private String nutritionScore; // 前端传 low 或 LOW 都能通过 Min(value 0, message 认知评估得分不能小于0) Max(value 30, message 认知评估得分不能大于30) private Integer cognitiveScore; }提示Valid注解要加在 Controller 方法参数上且 SpringBoot 需开启验证Validated否则注解不生效。这是毕设里最容易漏掉、导致“明明写了校验却没用”的坑。4.3 第三方平台对接用 FeignClient 封装卫健委健康档案查询接口模拟很多学校要求“对接区域健康平台”但实际没有测试环境。你可以用 Feign 模拟调用重点展示对接思路// 定义远程服务接口 FeignClient(name health-platform, url https://mock-api.health.gov.cn) public interface HealthPlatformClient { GetMapping(/v1/elderly/{idCard}/records) ListHealthRecordDto getRecordsByCard(PathVariable(idCard) String idCard); } // 业务层调用带降级 Service public class ElderlyService { Autowired private HealthPlatformClient platformClient; public ListHealthRecord getExternalRecords(String idCard) { try { ListHealthRecordDto dtos platformClient.getRecordsByCard(idCard); return dtos.stream().map(this::convertToEntity).collect(Collectors.toList()); } catch (FeignException e) { log.warn(调取卫健委平台失败返回空列表, e); return Collections.emptyList(); // 降级策略 } } }关键点在于你展示了标准对接姿势Feign、容错处理try-catch 降级、数据转换DTO→Entity而不是写个RestTemplate硬编码 URL。评委知道这是可落地的方案。5. 避坑指南答辩老师最爱问的 4 个致命问题以及血泪换来的解决方案5.1 现象Vue 打包后静态资源 404尤其favicon.ico和index.html路径错乱原因Vue CLI 默认打包到dist/目录但 SpringBoot 的static目录要求资源放在static/下且index.html必须在根路径。若直接把dist/整个复制到src/main/resources/static/会导致index.html里引用的js/app.xxx.js路径为/js/app.xxx.js而 SpringBoot 默认静态资源路径是/static/。解决修改vue.config.js让打包输出路径匹配 SpringBoot// vue.config.js module.exports { outputDir: ../backend/src/main/resources/static, // 直接输出到 SpringBoot 的 static 目录 publicPath: ./, // 相对路径使 js/css 引用为 ./js/app.xxx.js assetsDir: js // 静态资源放 js/ 目录下避免和 static/ 根目录混杂 }然后npm run build生成的文件自动落到 SpringBoot 项目里mvn clean package打包后healthcare.jar内部static/结构即为可用。5.2 现象SpringBoot 启动报错Failed to configure a DataSource但项目根本不用数据库原因SpringBoot 2.0 默认启用DataSourceAutoConfiguration只要 classpath 有spring-jdbc或mybatis-spring-boot-starter就会尝试初始化数据源。而你的application.yml里没配spring.datasource.*就炸了。解决在SpringBootApplication注解中排除自动配置SpringBootApplication(exclude { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class }) public class HealthcareApplication { public static void main(String[] args) { SpringApplication.run(HealthcareApplication.class, args); } }注意如果用了 MyBatis-Plus必须保留DataSourceAutoConfiguration此时必须配spring.datasource.url哪怕只是 H2 内存库用于开发。5.3 现象Vue 路由刷新后 404比如访问/dashboard直接报错原因Vue Router 默认用history模式依赖 HTML5 History API但 SpringBoot 内嵌 Tomcat 不知道/dashboard是前端路由会当成后端接口去匹配找不到就 404。解决在 SpringBoot 中添加一个兜底控制器把所有非 API 请求都指向index.htmlController public class SpaController { GetMapping({/{path:^(?!api|actuator|swagger|webjars).*$}/**, /}) public String redirect() { return forward:/index.html; // 所有非 /api 开头的请求都返回 index.html } }这样/dashboard、/task-pool刷新时SpringBoot 返回index.htmlVue Router 再接管路由渲染。5.4 现象家属端看到的血压数据比护士端慢 2 小时时间戳全乱了原因设备上报用的是设备本地时间如老人家里手机时区为 GMT8后端服务器时区却是 UTCLocalDateTime.now()存库后变成 UTC 时间前端再用new Date()渲染就差 8 小时。解决全链路统一用 UTC 存储前端按浏览器时区显示SpringBoot 配置application.ymlspring: jackson: time-zone: GMT0 # 序列化 JSON 时用 UTCMyBatis-Plus 实体类用TableField(fill FieldFill.INSERT)填充LocalDateTime.now(ZoneId.of(UTC))Vue 中显示时用dayjs(record.recordTime).local().format(YYYY-MM-DD HH:mm)自动转成本地时区。这样无论设备在哪、服务器在哪数据时间基准统一显示准确。6. 让答辩老师眼前一亮的 3 个实战技巧从“能跑”到“真能用”的最后一公里6.1 把“健康预警”做成可配置规则引擎而不是写死 if-else答辩时如果只说“血压180就告警”老师会问“那糖尿病老人血糖控制目标是 4.4~7.0 mmol/L高血压老人是 130/80 mmHg你怎么区分” 真正的做法是把预警规则抽成数据库配置CREATE TABLE alert_rule ( id BIGINT PRIMARY KEY AUTO_INCREMENT, elderly_type VARCHAR(20) NOT NULL COMMENT 老人类型HYPERTENSION/DIABETES/ALZHEIMER, metric VARCHAR(30) NOT NULL COMMENT 指标blood_pressure_systolic, blood_glucose, operator VARCHAR(10) NOT NULL COMMENT 操作符GT/LT/GTE/LTE/BETWEEN, threshold_value1 DECIMAL(10,2), threshold_value2 DECIMAL(10,2), severity TINYINT NOT NULL COMMENT 严重等级1-低危 2-中危 3-高危, enabled BOOLEAN DEFAULT TRUE ); -- 示例数据高血压老人收缩压 140 mmHg 触发中危告警 INSERT INTO alert_rule VALUES (1, HYPERTENSION, blood_pressure_systolic, GT, 140.00, NULL, 2, TRUE);后端用策略模式加载规则Service public class AlertRuleService { Autowired private AlertRuleMapper ruleMapper; public ListAlertRule getRulesByElderlyType(String elderlyType) { return ruleMapper.selectList(new QueryWrapperAlertRule().eq(elderly_type, elderlyType).eq(enabled, true)); } } // 告警触发逻辑 public void checkAndAlert(HealthRecord record) { ListAlertRule rules alertRuleService.getRulesByElderlyType(record.getElderlyType()); for (AlertRule rule : rules) { if (rule.match(record)) { // match() 方法封装 GT/LT/BETWEEN 判断逻辑 alertSender.send(record.getElderlyId(), rule.getSeverity(), rule.getMessage()); } } }这样新增一种老人类型如“术后康复”只需在数据库插几条规则代码零改动。答辩时打开数据库截图比讲一百行 if-else 更有说服力。6.2 用 Actuator Prometheus 暴露关键指标证明系统“可运维”毕设常被质疑“你这系统上线后怎么知道它是不是在跑” 加入 SpringBoot Actuator暴露健康检查、内存、HTTP 调用量!-- pom.xml -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency# application.yml management: endpoints: web: exposure: include: health,metrics,prometheus,loggers endpoint: health: show-details: when_authorized然后用 Prometheus 抓取/actuator/prometheus端点毕设可本地运行docker run -p 9090:9090 prom/prometheus配置简单规则# prometheus.yml scrape_configs: - job_name: healthcare static_configs: - targets: [host.docker.internal:8080] # SpringBoot 应用地址在 Prometheus Web UI 输入http_server_requests_seconds_count{uri/api/record/save}就能看到每秒健康记录上报量。答辩时截图展示“过去1小时接口 QPS 稳定在 12无 5xx 错误”直接证明系统健壮性。6.3 给论文加一个“真实数据模拟器”让演示不再假大空同学演示总用INSERT INTO elderly VALUES (1,张三,110101195001011234,...)评委一眼看出是编的。用 Java Faker 库生成逼真测试数据// 测试数据生成工具类 Component public class TestDataGenerator { private final Faker faker new Faker(new Locale(zh-CN)); public Elderly generateElderly() { Elderly e new Elderly(); e.setName(faker.name().fullName()); e.setIdCard(faker.idNumber().valid()); // 生成符合中国身份证规则的号码 e.setBirthDate(faker.date().birthday(70, 90)); // 70~90岁 e.setEmergencyContact(faker.phoneNumber().phoneNumber()); return e; } public HealthRecord generateBloodPressureRecord(Long elderlyId) { HealthRecord r new HealthRecord(); r.setElderlyId(elderlyId); r.setRecordType(blood_pressure); r.setValue1(faker.number().numberBetween(110, 160)); // 收缩压 r.setValue2(faker.number().numberBetween(60, 100)); // 舒张压 r.setRecordTime(faker.date().past(7, TimeUnit.DAYS)); // 过去7天内 return r; } }在PostConstruct方法里批量插入PostConstruct public void initTestData() { if (profile.equals(dev)) { for (int i 0; i 50; i) { Elderly e testDataGenerator.generateElderly(); elderlyService.save(e); for (int j 0; j 30; j) { HealthRecord r testDataGenerator.generateBloodPressureRecord(e.getId()); healthRecordService.save(r); } } } }这样启动项目后自动生成 50 位老人、每人 30 条血压记录家属端看板、护士工单池全是真实分布的数据——演示时打开图表评委看到的是“某栋楼老人血压异常率 12.3%”而不是“共100条数据其中12条异常”。这种细节让答辩老师觉得你真的想过“这系统要是真上线会是什么样”。我带过十几届毕设见过太多同学卡在“功能做完但讲不出价值”。其实就一句话别让代码只是代码让它成为解决真实问题的证据链——设备协议解析是证据规则引擎是证据Actuator 指标是证据Faker 数据是证据。答辩不是考试是向老师证明你写的每一行都踩在养老场景的泥巴里。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站