ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Spring Boot与Vue.js健康管理信息系统设计实现与部署实践

Spring Boot与Vue.js健康管理信息系统设计实现与部署实践 我做了三年Java后端最近帮一个学弟把他的毕业设计从零到一完整搭了一遍题目是“基于Spring Boot与Vue.js的健康管理信息系统设计与实现”——说白了就是一个偏“养生”主题的全栈Web系统。这个题目在计算机毕业设计里属于典型的前后端分离项目技术栈主流、业务场景清晰、工作量也好控制很适合拿来练手或者直接作为毕设参考。这篇文章我就按我实际开发的顺序来聊聊怎么拆需求、怎么设计数据库、后端接口怎么写、前端页面怎么接以及那些老师在验收时不会告诉你、但实际开发里一定会踩的坑。全程用Spring Boot做后端、Vue.js做前端无论你是准备做类似题目的学生还是想系统学一遍前后端分离开发的初学者应该都能从中拿走点能直接用的东西。1. 内容整体设计与思路拆解1.1 这个“养生系统”到底要做什么毕设题目听起来玄乎叫“健康管理信息系统”本质上就是给普通用户提供一个记录身体状况、获取养生建议、管理日常健康习惯的工具类网站。我接到题目后第一件事不是打开IDE而是先把功能边界划清楚——这是很多同学容易忽略的一步拿到题目就急着建工程写代码结果做出来的东西答辩时自己都讲不清。我梳理下来这个系统核心要解决三个问题第一用户怎么维护自己的健康档案身高体重、血压心率、睡眠、饮食偏好等第二系统怎么根据这些数据给出针对性的养生建议第三用户怎么坚持执行这些建议打卡、记录、统计。围绕这三个问题功能模块就能划分得很清晰。我用思维导图把功能分成四块用户模块注册登录、个人信息、健康数据模块身体指标记录、养生日记、建议模块根据指标生成推荐计划、统计模块趋势图、打卡日历。每个模块再往下拆比如健康数据模块可以细分为基础指标录入、血压血糖记录、睡眠记录等子功能。这样一拆整个项目的工作量就变得可控了而且还能直观地向导师展示你的需求分析能力。1.2 为什么选Spring Boot Vue.js这套组合这套技术栈之所以成为毕业设计的主流选择背后是有逻辑的。后端选Spring Boot主要是因为它的自动配置和约定优于配置特性能让开发者把注意力集中在业务逻辑上而不用像早年SSH框架那样天天和XML配置文件搏斗。Spring Boot生态成熟集成MyBatis-Plus或者Spring Data JPA都很方便社区资料也极为丰富遇到问题一搜就能找到解决方案。前端选Vue.js则是因为它的渐进式框架设计非常适合中小型项目。Vue的响应式数据处理机制让页面状态管理变得很直观配合Element UI之类的组件库即使前端基础一般的人也能在短时间内做出像模像样的管理界面。更重要的是Vue全家桶Vue Router、Vuex/Pinia、Axios与Spring Boot的RESTful API对接非常顺畅前后端联调的学习成本低。还有一个选型上的考量是答辩体验。Spring Boot加Vue这套组合既不会显得太“玩具”也不像微服务架构那样容易把摊子铺得过大导致无法收尾。对于本科毕设来说这个技术栈的深度和广度都刚好够撑着讲半小时的答辩。1.3 整体架构设计前后端分离怎么分确定技术栈后接下来是架构设计。我采用的是标准的前后端分离架构前端是一个独立的Vue项目通过HTTP请求与后端API交互后端是一个Spring Boot单体服务负责业务逻辑处理和数据库操作。两者之间通过JSON格式的数据进行通信。这种架构的好处是职责清晰。前端只关心页面渲染和用户交互后端只关心业务规则和数据持久化两边可以并行开发。我在实际开发中的分工是先把后端API的接口文档用Swagger搭起来定义好每个接口的请求参数和响应结构然后交给前端同学照着文档写页面我自己同步把数据库表建好开始写业务逻辑。部署上为了简化流程我用了Nginx来托管前端构建后的静态文件同时把API请求反向代理到后端的8080端口。这里要注意一个细节前端开发时走Vite的代理生产环境走Nginx的代理两处都要配置否则会出现开发环境一切正常、部署上线后接口全部404的情况。这个问题我在导出前遇到过一次原因就是只配了开发代理忘了配Nginx。2. 核心模块设计与数据库建模2.1 用户模块不只是注册登录那么简单用户模块看起来简单实际设计时有不少细节要考虑。首先是注册流程我实现了用户名和邮箱双重校验、密码MD5加盐加密、图形验证码防机器人注册。在毕设答辩中这些细节往往是加分项因为评委想看到的不只是一个能跑通的CRUD而是具备基本安全意识的完整功能。登录这块我采用了JWTJSON Web Token无状态认证方案。用户登录成功后后端返回一个令牌前端把它存在本地之后每次请求都带着这个令牌。相比传统的Session方案JWT的优势在于后端不需要保存会话状态天然适合前后端分离的架构。实现时要注意令牌过期时间我一般设置为2小时刷新令牌设置为7天避免用户用着用着突然被踢下线。个人资料管理除了用户名、邮箱、手机号这些基础字段我还加了一个“健康偏好”字段用户可以勾选自己的养生目标——减肥、增肌、改善睡眠、调节血压等。这个字段直接关联到后面的养生计划推荐逻辑是有实际用途的不是花架子。2.2 健康数据模块用一张表还是多张表健康数据是这个系统的核心也是最需要动脑筋设计的地方。常见的设计方案有两种一种是用一张宽表字段包含身高、体重、BMI、血压、心率、血糖、睡眠时长等另一种是按数据类型拆成多张子表。我最终选了多表方案理由是灵活性和扩展性更好。我的数据库实际建了四张数据表基础指标表身高、体重、BMI、体脂率、生命体征表血压、心率、血氧、睡眠记录表入睡时间、醒来时间、深睡时长、饮食记录表早中晚餐内容和热量估算。每张表都通过user_id关联到用户同时记录创建时间。这种设计的优势很明显。比如做趋势图时只需要查询对应类型的一张表而不用每次从宽表里挑字段再比如以后想增加新的健康指标比如体温只需要新建一张表或者加一个字段不影响已有数据结构。但多表设计也有代价就是查询时需要联表比如首页要同时展示用户最近的各项健康数据就需要分别查询四张表再在Service层组装。这属于典型的“用代码复杂度换数据结构合理性”的取舍在毕业设计里是值得的。2.3 养生建议模块简单的规则引擎养生建议是这个系统的灵魂也是区别于普通信息管理系统的关键。我实现了一个轻量级的规则引擎原理非常简单定义一批规则每条规则有两个部分——触发条件和建议内容。系统每次收到用户的新健康数据时会遍历所有规则把满足条件的建议集合起来反馈给用户。举个例子当用户的BMI大于24时触发“控制体重”规则建议内容是“当前体重指数偏高建议控制碳水摄入每天进行30分钟中等强度运动”当睡眠时长小于6小时时触发“改善睡眠”规则建议内容是“睡眠时间偏短建议调整作息睡前1小时减少屏幕使用时间可尝试温水泡脚”。为了让规则管理更灵活我把规则表设计成可配置的管理员可以在后台添加、修改规则而不需要改代码。规则表的核心字段有指标类型、操作符大于/小于/介于、阈值、建议等级、建议内容。这种设计思路在工业界其实就是规则引擎的雏形放在毕设里讲能给答辩加分。2.4 数据库表结构设计的关键细节数据库表设计是整个项目的根基表建不好后面写业务代码时处处难受。我总结几个关键细节。第一是主键策略我所有的表都采用自增主键字段名统一使用id避免不同表间主键命名不一致的混乱。第二是时间字段用datetime类型存储默认值为CURRENT_TIMESTAMP这样插入记录时不用手动写时间。第三是软删除字段每张表都加一个deleted字段默认为0。这样做的好处是数据不会真正被物理删除用户可以找回误删的记录后台也可以做数据审计。第四是索引设计外键字段user_id、plan_id等一定要建索引否则数据量上来后查询会非常慢。我在2万条测试数据下验证过加了索引的查询耗时从800毫秒降到了50毫秒左右这个差距在答辩演示时是能被直观感受到的。建表我用了MyBatis-Plus的代码生成器根据数据库表结构自动生成实体类、Mapper接口、Service类省去了大量重复的模板代码编写工作。这里要注意的是代码生成器生成的代码基本能直接用但需要仔细检查字段类型映射比如MySQL的datetime会映射成LocalDateTime如果前端传来的时间格式不匹配就会出问题。3. 后端核心功能实现Spring Boot接口开发实录3.1 项目初始化与目录结构规划我创建这个项目用的是Spring Initializr选择Java 8版本Spring Boot 2.7.x。这里用Java 8而不是更近的17、21主要是为了兼容性和稳定性考虑——学校的服务器环境不一定支持新版本的Java而且网上大部分教程和资料都是基于Java 8写的。Spring Boot 2.7也是2.x系列的最后一个维护版本稳定性有保障。项目目录结构按照分层架构来组织controller接口层、service业务逻辑层、mapper数据持久层、entity实体类、dto数据传输对象、config配置类、common通用工具类和统一响应封装。这种分层结构的核心思想是解耦每一层只依赖下一层不跨层调用。优点是代码结构清晰、可维护性高缺点是有时候会显得繁琐——比如一个简单的查询可能要从controller到service再到mapper写三层代码。实际开发中我见过很多同学为了“图方便”把业务逻辑直接写在controller里这样确实写起来很快但后面问题特别多代码复用不了、单元测试写不了、一个接口出了问题要在一个几百行的controller里找。我强烈建议坚持分层前期辛苦一点后面省心百倍。3.2 统一返回格式与异常处理接口设计的第一步是约定返回格式。我定义了一个通用的响应类Result包含code、message、data三个字段。成功时code为200失败时根据情况返回400、401、500等错误码。所有接口的返回值都是Result类型的实例前端拿到后统一判断code再做后续处理。这种设计的核心原因是让前后端沟通有统一标准。如果没有统一格式有的接口返回对象有的返回数组有的返回null前端对接的时候就得每个接口单独处理效率极低还容易出错。而统一格式后前端可以在Axios的响应拦截器里统一处理错误极大简化了代码量。异常处理我用的是RestControllerAdvice加ExceptionHandler注解的方式。在Controller层不捕获业务异常全部抛到全局异常处理器中统一处理。这种方式的好处是业务代码里不需要try-catch包裹代码整洁同时某些特定类型的异常比如参数校验失败、数据不存在可以返回更友好的提示信息。我实测过引入全局异常处理后相关代码量减少了大半而且异常信息更规范了。3.3 健康数据接口实现以BMI计算为例我拿BMI这个例子讲一下完整的接口实现流程。前端用户输入身高和体重后点击保存请求到达后端的HealthDataController。Controller接收一个AddHealthDataRequest对象这个对象包含身高、体重、测量日期等字段。在Service层首先对参数进行校验——身高范围在80-250厘米之间体重范围在20-200公斤之间超出范围直接抛出参数异常。校验通过后计算BMI值公式是体重除以身高米的平方。这里要注意一个细节身高的单位是厘米而BMI计算公式要求米的单位所以计算前要先把厘米转成米即heightCm除以100。我见过不少同学在这个细节上出错导致算出来的BMI是真实值的万分之一数据完全不可用。计算完成后的BMI值会和身高体重一起存入数据库同时系统会调用规则引擎根据新的BMI值生成养生建议保存在建议表里。这个过程中还有一个小设计请求数据里的部分字段比如创建时间、更新状态不会由前端传入而是在后端自动补全。这样做既减少了前端的工作量又避免用户篡改关键字段。3.4 JWT认证与拦截器实现安全认证这块我用了JWT结合Spring拦截器的方式。具体实现是定义一个JwtInterceptor实现HandlerInterceptor接口在preHandle方法里从请求头获取token解析验证通过后放行不通过则直接返回401错误码。但这个拦截器不能对所有接口都生效。注册、登录、图形验证码三个接口是公开的不需要token。我的做法是在WebMvcConfigurer配置类中注册拦截器时通过addPathPatterns限定拦截范围用excludePathPatterns排除放行路径。这个环节有个容易踩的坑如果配置excludePathPatterns时的路径写错了比如前端请求是“/api/auth/login”而排除路径写的是“/api/user/login”就会导致登录接口也被拦截前端疯狂报401。另外有一点要特别提醒JWT密钥的安全性非常重要。我一开始把密钥直接写死在代码里后来意识到这是安全问题改成了从application.yml配置文件中读取。虽然对于毕业设计来说这个不是核心评分点但主动做这些改进在答辩时如果被问到安全问题能给出比“没考虑”好得多的回答。3.5 MyBatis-Plus的使用与动态SQL持久层我用了MyBatis-Plus它对MyBatis做了增强内置了通用的增删改查方法。多数场景下我只需要定义实体类和Mapper接口不需要写任何SQL语句。比如保存一条健康数据直接调用mapper.insert(entity)就行了非常方便。但有些复杂查询MyBatis-Plus的基础方法满足不了就需要写自定义SQL。比较典型的是健康趋势图的数据查询——需要按日期分组统计每天的平均睡眠时长、平均血压值这类聚合数据。这种场景我用Select注解直接写在Mapper接口方法上配合SQL语句来实现。还有一个典型的动态SQL场景健康记录的历史列表往往需要按条件筛选比如“查询最近七天的数据”或“查询血压异常的数据”。用MyBatis-Plus的LambdaQueryWrapper可以很方便地构造查询条件不需要拼接SQL字符串既安全又能避免SQL注入风险。我用LambdaQueryWrapper写过一个例子根据时间范围和指标类型两个可选条件查询判断是否为null来动态拼接查询条件代码可读性非常好。这种写法在答辩时也值得拿出来展示一下体现你对持久层框架掌握的深度。4. 前端核心功能实现Vue.js页面开发全流程4.1 前端工程搭建与目录结构前端项目我用Vue CLI创建的Vue版本选的2.6搭配Vue Router 3和Vuex 3。之所以没用Vue 3一是因为Element UI最稳定的版本对Vue 2支持得最好二是当时参考的很多教程都是Vue 2的遇到问题查资料方便。如果现在从头做也可以直接上Vue 3加Vite构建速度确实提升明显。这个选择没有绝对的对错核心是要保证项目在自己的掌控内能顺利做完。前端目录结构我按功能模块划分views目录放页面组件components目录放公共组件router目录放路由配置store目录放Vuex状态管理utils目录放封装好的Axios实例和公共方法api目录放接口调用文件。这种划分的好处是后期维护时能快速定位代码比如登录页面白屏了先去views/login.vue看看登录接口报了401先去api/user.js看看请求配置。4.2 Axios封装与请求拦截器前端对接后端接口最关键的一步是封装Axios。我创建了一个axios.js文件导出封装好的axios实例。这个实例设置了baseURL、请求超时时间并在请求拦截器里从localStorage取出token添加到请求头的Authorization字段。响应拦截器的处理逻辑更关键。这里做四件事一是当响应结果中code为200时直接返回data给调用的地方二是当code为401时token过期或非法清除本地登录状态并跳转到登录页三是当code为其他错误码时弹出错误提示并返回null四是当网络层发生错误比如后端服务挂了弹出统一的网络错误提示。这个封装的思路是“前端中间层”的思想所有页面的数据请求都走这个统一入口把重复的错误处理逻辑集中起来。没有这层封装的话每个页面都要写一遍错误处理的代码而且要写在每个接口调用处代码量大不说很容易遗漏。实际写完这个封装后业务组件里的接口调用代码会变得非常简洁基本就是一行调用然后处理成功情况。4.3 健康数据录入页面实现健康数据录入页面是这个系统前端工作量最大的页面之一。我用Element UI的表单组件来构建包含身高、体重、血压收缩压、血压舒张压、心率、睡眠时长、饮食备注等字段。表单开启校验功能比如身高必须是80到250之间的数字不满足要求时会有红色提示。录入完成点保存时前端先本地再次校验表单数据校验通过后调用API接口。这里有一个值得说的细节体重变化趋势是本系统的核心养生效能所以保存成功后会触发一次数据刷新自动更新旁边的体重趋势图。这个交互逻辑虽然简单但用户感知非常好——一点保存图表立刻有变化会让人觉得系统很“聪明”。为了提升用户体验我还在这个页面实现了“上一次信息回显”功能当用户再次录入数据时系统自动把上次的记录加载出来用户不用从零开始输入只需修改有变化的数值就能保存。这个功能是我自己加进去的工作量不大但是在实际演示时效果很好老师会觉得你考虑得很周全。4.4 数据可视化用ECharts展示健康趋势养生系统的数据可视化前端用的是ECharts。我做了三个图表一是体重趋势折线图展示用户最近30天体重变化二是血压分布散点图将收缩压和舒张压的测量值绘制成散点三是睡眠时长柱状图展示最近一周每天的睡眠时间。ECharts接入Vue的方式不复杂先在npm里安装echarts依赖然后在需要的组件中引入。但初始化图表有一个经典问题如果DOM还没渲染完就初始化ECharts实例图表会显示不出来。我处理这个问题的办法是在Vue组件的mounted钩子函数中初始化图表因为mounted表示组件已经挂载到真实DOM上这时可以安全地获取图表容器元素。图表数据的更新逻辑是这样的页面加载后请求后端接口获取最近的健康数据列表在前端对这些数据进行格式化比如把日期字段转为“MM-DD”格式然后作为series数据传给ECharts更新。这里要注意数据类型的一致性ECharts的折线图要求x轴数据和y轴数据是一一对应的数组如果后端返回的数据顺序乱了图表就会错乱。我在前端做了数据按日期排序的处理保证图表展示的正确性。4.5 Vuex状态管理与用户登录状态Vuex我用它来管理全局的用户登录状态和用户信息。在登录成功后前端会把用户信息和token一起保存到Vuex store中同时持久化到localStorage。刷新页面时在应用入口的created钩子中读取localStorage恢复Vuex中的用户状态避免用户每次刷新页面都变成未登录状态。这里有一个坑值得说明直接使用Vuex时刷新页面后store中的数据会全部清空因为Vuex是内存对象。所以必须在刷新页面时做一次“恢复会话”的处理。我的做法是在main.js入口文件里实例化Vuex store之前先执行一个初始化方法从localStorage读取token和用户信息并提交到store中。另外路由守卫也是必须的在router.beforeEach中判断用户访问需要登录的页面时是否已登录如果没有登录就重定向到登录页。路由表的配置我分了两类公开路由登录页、注册页、找回密码页和需要鉴权的路由首页、健康数据、养生计划、个人中心。这个配置放到路由守卫里做判断后凡是用户未登录直接输入网址访问受保护页面的都会被自动踢回登录页。这个体验很重要因为如果用户直接访问未授权页面时只是白屏或报错会给人很不专业的感觉。5. 系统部署与联调过程中踩过的坑5.1 前后端联调时的跨域问题前后端分离开发中最容易出的问题就是跨域。前端开发服务器启动在8080端口Vite默认后端运行在8081端口浏览器出于同源策略会拦截前端发出的跨域请求。这里先确认一件事如果前后端部署在同一个Nginx代理后面通过同一个域名和端口访问其实不存在跨域问题。跨域通常只发生在开发环境或者前后端分开部署时。我这次项目的解决方案是在后端配置CORS。具体做法是写一个WebMvcConfigurer配置类重写addCorsMappings方法允许所有来源、所有请求头、所有请求方法跨域访问。代码量很少但对前端来说是“救命”的配置。需要注意的是如果你同时配置了Spring Security并做认证CORS配置和Security的过滤器链顺序不对会导致跨域配置不生效表现为“配置了但还是报跨域错”。我当时遇到这个情况后把CORS配置放到了Security过滤器链的前面才解决。5.2 Vue.js DevTools插件打不开的排查开发Vue前端时Vue.js DevTools插件是调试神器。但有一个很常见的问题插件图标亮了但点开面板是空的或者直接显示“Vue.js not detected”。出现这个问题的原因主要有三个第一你打开的页面不是Vue应用比如地址栏还停留在浏览器默认的新标签页第二项目运行在开发模式下但插件版本和你的Vue版本不匹配Vue 2项目要用DevTools 5.xVue 3项目要匹配对应的Vue 3版本支持第三浏览器开启了隐私模式扩展程序默认不工作。我当时排查的路径是确认页面地址没错之后检查Vue版本和插件版本。因为项目是Vue 2.6而DevTools装的是最新版当时最新版对Vue 2的支持有个版本变动我换回Vue 2对应的DevTools版本后问题就解决了。如果你也遇到插件打不开的情况按这个顺序排查基本不会失手。5.3 系统构建与生产环境部署开发完所有功能后最后一步是如何把项目真正跑起来展示。前端需要执行npm run build生成dist静态文件目录。后端需要把Spring Boot项目打成jar包用java -jar命令启动。我是这样部署的云服务器上装好JDK和Nginx前端dist目录上传到服务器指定目录后端jar包也上传后运行。Nginx配置了两块静态文件路径指向前端dist目录遇到/api/开头的请求就反向代理到本地8081端口。整条链路是浏览器访问80端口Nginx返回前端静态文件前端发起的API请求被Nginx转发到后端jar进程后端处理完返回JSON数据前端渲染到页面上。部署环节我踩过的一个坑是防火墙端口未开放。后端进程明明已经启动但外部访问时接口一直超时。排查了半天最后发现是服务器安全组里没有放行8081端口。生产环境部署时一定要提前规划好需要开放的端口并且记得同时检查操作系统防火墙和云平台的安全组规则。5.4 若涉及文件上传的注意点我原本没打算做头像上传功能但后来考虑到展示效果还是加上了。这里有一个值得讲的点文件上传接口除了要处理文件流存储外还要注意上传路径的安全问题。我的做法是在服务器上单独创建一个uploads目录所有上传的文件都放这里面。文件名不直接用用户上传的原始名而是用UUID加原始文件扩展名重新生成这样避免了两类问题一是文件名冲突二是潜在的文件路径穿越风险。存储完成后数据库里保存的是文件访问的URL路径前端展示时直接通过这个路径访问图片。如果图片是保存在本地的需要在Nginx中额外配置一个静态资源映射比如/upload/路径对应服务器上的uploads目录目录。我在这个环节踩过一个小坑Nginx配置完没有重载配置文件结果访问图片一直404重启Nginx后才正常。6. 毕设答辩常见问题与避坑指南6.1 导师常问的技术问题储备做完项目只是成功的一半能条理清晰地讲出来才重要。在帮学弟准备答辩时我把评委老师大概率会问的问题总结了一遍分成了三类。第一类是技术选型类比如“为什么选Spring Boot不选SSH”“为什么用JWT不用Session”第二类是业务逻辑类比如“养生建议是怎么生成出来的”“如果BMI异常会有什么后续处理”第三类是系统设计类比如“你的系统能应对多少人并发”“数据库有没有做优化”。回答这些问题我的建议是提前准备好核心数据。比如高并发这个问题你可以说“目前系统是单体架构单机部署理论并发量大约在几千左右。如果要提升第一考虑的是后端加Redis做缓存降低数据库压力第二是Nginx做负载均衡横向扩展”。不一定真的做过负载均衡但至少要表达出你有思考过这个方向而不是哑口无言。6.2 演示环境的稳定预案答辩演示是最容易翻车的环节我的经验是必须准备一套离线演示环境。答辩当天网络状况不可控如果依赖在线环境万一云服务器连接不上或者域名解析出问题整个项目就白做了。我把前后端都打好了包在笔记本本地跑了一套顺便把所有API调通。这样即使外面的网络断了演示也能正常进行。另一个建议是准备几组测试数据。我在数据库里预置了一个演示账号里面有两三个月的健康记录打开页面就能看到有意义的图表和数据曲线而不是空空的界面。这个细节意义很大数据量稀少时折线图看起来是几个孤零零的点没有说服力数据丰富时趋势图一目了然老师能直观看到系统“有在用”的状态。6.3 从毕设到项目的扩展思路如果在毕业设计答辩之后想让这个项目继续产生价值有几个方向可以做。第一是加一个消息推送功能当用户某项健康指标出现异常时通过邮件或者短信给用户发送提醒。第二是增加一个设备对接模块接入智能手环等硬件设备读取用户的身体数据这样数据来源就不局限于手动录入系统的实用性强很多。第三是做一个数据分析维度上的升级不只做简单的趋势图还可以计算各项指标之间的相关性比如睡眠质量和体重变化之间的关系用图表呈现出来这会成为一个非常有亮点的功能。我个人的体会是毕业设计其实是一个把课堂知识串起来的过程。Spring Boot加Vue.js这套技术栈的价值不在于工具本身有多高深而在于它让你完整地走了一遍“需求分析—数据库设计—后端接口—前端页面—测试部署”的全流程。如果你正在做类似的项目建议不要只是为了“交差”而做而是把每个模块真正想清楚为什么这么做。这篇文章里写的这些设计和踩坑经验都是我实际做下来觉得最值得被记住的部分希望对你有帮助。
返回列表